aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/9p-local.c52
-rw-r--r--hw/9pfs/9p-proxy.c1279
-rw-r--r--hw/9pfs/9p-proxy.h101
-rw-r--r--hw/9pfs/9p-synth.c24
-rw-r--r--hw/9pfs/9p-util-generic.c50
-rw-r--r--hw/9pfs/9p-util.h34
-rw-r--r--hw/9pfs/9p.c124
-rw-r--r--hw/9pfs/9p.h2
-rw-r--r--hw/9pfs/codir.c7
-rw-r--r--hw/9pfs/cofile.c7
-rw-r--r--hw/9pfs/cofs.c37
-rw-r--r--hw/9pfs/coth.h4
-rw-r--r--hw/9pfs/meson.build2
-rw-r--r--hw/9pfs/trace-events4
-rw-r--r--hw/9pfs/virtio-9p-device.c7
-rw-r--r--hw/Kconfig5
-rw-r--r--hw/acpi/Kconfig5
-rw-r--r--hw/acpi/acpi-cpu-hotplug-stub.c8
-rw-r--r--hw/acpi/acpi-mem-hotplug-stub.c5
-rw-r--r--hw/acpi/acpi-nvdimm-stub.c1
-rw-r--r--hw/acpi/acpi-pci-hotplug-stub.c8
-rw-r--r--hw/acpi/acpi-stub.c8
-rw-r--r--hw/acpi/acpi_generic_initiator.c148
-rw-r--r--hw/acpi/aml-build.c108
-rw-r--r--hw/acpi/core.c7
-rw-r--r--hw/acpi/cpu.c49
-rw-r--r--hw/acpi/cpu_hotplug.c3
-rw-r--r--hw/acpi/erst.c15
-rw-r--r--hw/acpi/generic_event_device.c48
-rw-r--r--hw/acpi/ghes-stub.c2
-rw-r--r--hw/acpi/ghes.c240
-rw-r--r--hw/acpi/hmat.c2
-rw-r--r--hw/acpi/hmat.h2
-rw-r--r--hw/acpi/ich9.c40
-rw-r--r--hw/acpi/ich9_tco.c2
-rw-r--r--hw/acpi/ich9_timer.c93
-rw-r--r--hw/acpi/ipmi.c3
-rw-r--r--hw/acpi/meson.build4
-rw-r--r--hw/acpi/pci.c242
-rw-r--r--hw/acpi/pcihp.c2
-rw-r--r--hw/acpi/piix4.c17
-rw-r--r--hw/acpi/vmclock.c179
-rw-r--r--hw/acpi/vmgenid.c7
-rw-r--r--hw/adc/Kconfig3
-rw-r--r--hw/adc/aspeed_adc.c15
-rw-r--r--hw/adc/max111x.c236
-rw-r--r--hw/adc/meson.build1
-rw-r--r--hw/adc/npcm7xx_adc.c5
-rw-r--r--hw/adc/stm32f2xx_adc.c4
-rw-r--r--hw/adc/zynq-xadc.c4
-rw-r--r--hw/alpha/dp264.c5
-rw-r--r--hw/alpha/typhoon.c3
-rw-r--r--hw/arm/Kconfig174
-rw-r--r--hw/arm/allwinner-a10.c22
-rw-r--r--hw/arm/allwinner-h3.c19
-rw-r--r--hw/arm/allwinner-r40.c13
-rw-r--r--hw/arm/armsse.c27
-rw-r--r--hw/arm/armv7m.c28
-rw-r--r--hw/arm/aspeed.c255
-rw-r--r--hw/arm/aspeed_ast10x0.c9
-rw-r--r--hw/arm/aspeed_ast2400.c15
-rw-r--r--hw/arm/aspeed_ast2600.c17
-rw-r--r--hw/arm/aspeed_ast27x0-fc.c200
-rw-r--r--hw/arm/aspeed_ast27x0-ssp.c294
-rw-r--r--hw/arm/aspeed_ast27x0-tsp.c294
-rw-r--r--hw/arm/aspeed_ast27x0.c592
-rw-r--r--hw/arm/aspeed_soc_common.c7
-rw-r--r--hw/arm/b-l475e-iot01a.c4
-rw-r--r--hw/arm/bananapi_m2u.c3
-rw-r--r--hw/arm/bcm2835_peripherals.c4
-rw-r--r--hw/arm/bcm2836.c10
-rw-r--r--hw/arm/bcm2838.c2
-rw-r--r--hw/arm/bcm2838_peripherals.c2
-rw-r--r--hw/arm/boot.c73
-rw-r--r--hw/arm/collie.c4
-rw-r--r--hw/arm/cubieboard.c1
-rw-r--r--hw/arm/digic.c4
-rw-r--r--hw/arm/digic_boards.c4
-rw-r--r--hw/arm/exynos4210.c17
-rw-r--r--hw/arm/exynos4_boards.c8
-rw-r--r--hw/arm/fby35.c8
-rw-r--r--hw/arm/fsl-imx25.c9
-rw-r--r--hw/arm/fsl-imx31.c6
-rw-r--r--hw/arm/fsl-imx6.c74
-rw-r--r--hw/arm/fsl-imx6ul.c73
-rw-r--r--hw/arm/fsl-imx7.c74
-rw-r--r--hw/arm/fsl-imx8mp.c712
-rw-r--r--hw/arm/gumstix.c141
-rw-r--r--hw/arm/highbank.c22
-rw-r--r--hw/arm/imx25_pdk.c3
-rw-r--r--hw/arm/imx8mp-evk.c103
-rw-r--r--hw/arm/integratorcp.c16
-rw-r--r--hw/arm/kzm.c8
-rw-r--r--hw/arm/mainstone.c175
-rw-r--r--hw/arm/mcimx6ul-evk.c3
-rw-r--r--hw/arm/mcimx7d-sabre.c3
-rw-r--r--hw/arm/meson.build132
-rw-r--r--hw/arm/microbit.c8
-rw-r--r--hw/arm/mps2-tz.c26
-rw-r--r--hw/arm/mps2.c22
-rw-r--r--hw/arm/mps3r.c10
-rw-r--r--hw/arm/msf2-soc.c11
-rw-r--r--hw/arm/msf2-som.c4
-rw-r--r--hw/arm/musca.c12
-rw-r--r--hw/arm/musicpal.c32
-rw-r--r--hw/arm/netduino2.c2
-rw-r--r--hw/arm/netduinoplus2.c2
-rw-r--r--hw/arm/npcm7xx.c19
-rw-r--r--hw/arm/npcm7xx_boards.c23
-rw-r--r--hw/arm/npcm8xx.c859
-rw-r--r--hw/arm/npcm8xx_boards.c254
-rw-r--r--hw/arm/nrf51_soc.c23
-rw-r--r--hw/arm/nseries.c1473
-rw-r--r--hw/arm/olimex-stm32-h405.c2
-rw-r--r--hw/arm/omap1.c1210
-rw-r--r--hw/arm/omap2.c2715
-rw-r--r--hw/arm/omap_sx1.c16
-rw-r--r--hw/arm/orangepi.c3
-rw-r--r--hw/arm/palm.c324
-rw-r--r--hw/arm/pxa2xx.c2393
-rw-r--r--hw/arm/pxa2xx_gpio.c365
-rw-r--r--hw/arm/pxa2xx_pic.c359
-rw-r--r--hw/arm/raspi.c15
-rw-r--r--hw/arm/raspi4b.c5
-rw-r--r--hw/arm/realview.c25
-rw-r--r--hw/arm/sabrelite.c3
-rw-r--r--hw/arm/sbsa-ref.c34
-rw-r--r--hw/arm/smmu-common.c36
-rw-r--r--hw/arm/smmu-internal.h5
-rw-r--r--hw/arm/smmuv3.c48
-rw-r--r--hw/arm/spitz.c1284
-rw-r--r--hw/arm/stellaris.c140
-rw-r--r--hw/arm/stm32f100_soc.c6
-rw-r--r--hw/arm/stm32f205_soc.c6
-rw-r--r--hw/arm/stm32f405_soc.c18
-rw-r--r--hw/arm/stm32l4x5_soc.c14
-rw-r--r--hw/arm/stm32vldiscovery.c2
-rw-r--r--hw/arm/strongarm.c24
-rw-r--r--hw/arm/strongarm.h2
-rw-r--r--hw/arm/tosa.c327
-rw-r--r--hw/arm/trace-events16
-rw-r--r--hw/arm/versatilepb.c17
-rw-r--r--hw/arm/vexpress.c21
-rw-r--r--hw/arm/virt-acpi-build.c32
-rw-r--r--hw/arm/virt.c396
-rw-r--r--hw/arm/xen-pvh.c106
-rw-r--r--hw/arm/xen-stubs.c30
-rw-r--r--hw/arm/xen_arm.c267
-rw-r--r--hw/arm/xilinx_zynq.c128
-rw-r--r--hw/arm/xlnx-versal-virt.c9
-rw-r--r--hw/arm/xlnx-versal.c23
-rw-r--r--hw/arm/xlnx-zcu102.c5
-rw-r--r--hw/arm/xlnx-zynqmp.c58
-rw-r--r--hw/arm/z2.c355
-rw-r--r--hw/audio/ac97.c15
-rw-r--r--hw/audio/adlib.c5
-rw-r--r--hw/audio/asc.c15
-rw-r--r--hw/audio/cs4231.c4
-rw-r--r--hw/audio/cs4231a.c15
-rw-r--r--hw/audio/es1370.c13
-rw-r--r--hw/audio/gus.c7
-rw-r--r--hw/audio/hda-codec.c27
-rw-r--r--hw/audio/intel-hda.c20
-rw-r--r--hw/audio/marvell_88w8618.c6
-rw-r--r--hw/audio/pcspk.c5
-rw-r--r--hw/audio/pl041.c7
-rw-r--r--hw/audio/sb16.c7
-rw-r--r--hw/audio/soundhw.c3
-rw-r--r--hw/audio/trace-events1
-rw-r--r--hw/audio/via-ac97.c15
-rw-r--r--hw/audio/virtio-snd-pci.c5
-rw-r--r--hw/audio/virtio-snd.c32
-rw-r--r--hw/audio/wm8750.c5
-rw-r--r--hw/avr/arduino.c10
-rw-r--r--hw/avr/atmega.c59
-rw-r--r--hw/avr/atmega.h1
-rw-r--r--hw/avr/boot.c8
-rw-r--r--hw/block/Kconfig12
-rw-r--r--hw/block/block.c9
-rw-r--r--hw/block/dataplane/xen-block.c4
-rw-r--r--hw/block/dataplane/xen-block.h2
-rw-r--r--hw/block/ecc.c91
-rw-r--r--hw/block/fdc-isa.c17
-rw-r--r--hw/block/fdc-sysbus.c16
-rw-r--r--hw/block/fdc.c11
-rw-r--r--hw/block/hd-geometry.c2
-rw-r--r--hw/block/m25p80.c83
-rw-r--r--hw/block/m25p80_sfdp.c73
-rw-r--r--hw/block/m25p80_sfdp.h3
-rw-r--r--hw/block/meson.build4
-rw-r--r--hw/block/nand.c836
-rw-r--r--hw/block/onenand.c872
-rw-r--r--hw/block/pflash_cfi01.c34
-rw-r--r--hw/block/pflash_cfi02.c9
-rw-r--r--hw/block/swim.c11
-rw-r--r--hw/block/tc58128.c211
-rw-r--r--hw/block/vhost-user-blk.c63
-rw-r--r--hw/block/virtio-blk.c223
-rw-r--r--hw/block/xen-block.c34
-rw-r--r--hw/char/Kconfig18
-rw-r--r--hw/char/avr_usart.c9
-rw-r--r--hw/char/bcm2835_aux.c13
-rw-r--r--hw/char/cadence_uart.c5
-rw-r--r--hw/char/cmsdk-apb-uart.c7
-rw-r--r--hw/char/debugcon.c5
-rw-r--r--hw/char/digic-uart.c7
-rw-r--r--hw/char/diva-gsp.c295
-rw-r--r--hw/char/escc.c95
-rw-r--r--hw/char/etraxfs_ser.c267
-rw-r--r--hw/char/exynos4210_uart.c7
-rw-r--r--hw/char/goldfish_tty.c11
-rw-r--r--hw/char/grlib_apbuart.c7
-rw-r--r--hw/char/ibex_uart.c7
-rw-r--r--hw/char/imx_serial.c80
-rw-r--r--hw/char/ipoctal232.c9
-rw-r--r--hw/char/mcf_uart.c23
-rw-r--r--hw/char/mchp_pfsoc_mmuart.c4
-rw-r--r--hw/char/meson.build7
-rw-r--r--hw/char/nrf51_uart.c7
-rw-r--r--hw/char/omap_uart.c117
-rw-r--r--hw/char/parallel-isa.c2
-rw-r--r--hw/char/parallel.c11
-rw-r--r--hw/char/pl011.c241
-rw-r--r--hw/char/renesas_sci.c7
-rw-r--r--hw/char/riscv_htif.c47
-rw-r--r--hw/char/sclpconsole-lm.c9
-rw-r--r--hw/char/sclpconsole.c7
-rw-r--r--hw/char/serial-isa.c10
-rw-r--r--hw/char/serial-mm.c156
-rw-r--r--hw/char/serial-pci-multi.c30
-rw-r--r--hw/char/serial-pci.c15
-rw-r--r--hw/char/serial.c142
-rw-r--r--hw/char/sh_serial.c61
-rw-r--r--hw/char/shakti_uart.c7
-rw-r--r--hw/char/sifive_uart.c137
-rw-r--r--hw/char/spapr_vty.c5
-rw-r--r--hw/char/stm32f2xx_usart.c56
-rw-r--r--hw/char/stm32l4x5_usart.c28
-rw-r--r--hw/char/terminal3270.c5
-rw-r--r--hw/char/trace-events24
-rw-r--r--hw/char/virtio-console.c7
-rw-r--r--hw/char/virtio-serial-bus.c17
-rw-r--r--hw/char/xen_console.c63
-rw-r--r--hw/char/xilinx_uartlite.c41
-rw-r--r--hw/core/Kconfig4
-rw-r--r--hw/core/bus.c4
-rw-r--r--hw/core/clock.c38
-rw-r--r--hw/core/cpu-common.c138
-rw-r--r--hw/core/cpu-sysemu.c144
-rw-r--r--hw/core/cpu-system.c305
-rw-r--r--hw/core/cpu-user.c49
-rw-r--r--hw/core/eif.c709
-rw-r--r--hw/core/eif.h22
-rw-r--r--hw/core/generic-loader.c20
-rw-r--r--hw/core/gpio.c3
-rw-r--r--hw/core/guest-loader.c9
-rw-r--r--hw/core/irq.c42
-rw-r--r--hw/core/loader-fit.c42
-rw-r--r--hw/core/loader.c85
-rw-r--r--hw/core/machine-hmp-cmds.c4
-rw-r--r--hw/core/machine-qmp-cmds.c36
-rw-r--r--hw/core/machine-smp.c136
-rw-r--r--hw/core/machine.c288
-rw-r--r--hw/core/meson.build7
-rw-r--r--hw/core/null-machine.c3
-rw-r--r--hw/core/numa.c12
-rw-r--r--hw/core/or-irq.c7
-rw-r--r--hw/core/platform-bus.c10
-rw-r--r--hw/core/ptimer.c4
-rw-r--r--hw/core/qdev-clock.c86
-rw-r--r--hw/core/qdev-hotplug.c45
-rw-r--r--hw/core/qdev-properties-system.c242
-rw-r--r--hw/core/qdev-properties.c210
-rw-r--r--hw/core/qdev-user.c19
-rw-r--r--hw/core/qdev.c149
-rw-r--r--hw/core/register.c2
-rw-r--r--hw/core/reset.c9
-rw-r--r--hw/core/resetcontainer.c3
-rw-r--r--hw/core/resettable.c24
-rw-r--r--hw/core/split-irq.c5
-rw-r--r--hw/core/sysbus-fdt.c29
-rw-r--r--hw/core/sysbus.c75
-rw-r--r--hw/core/uboot_image.h2
-rw-r--r--hw/core/vm-change-state-handler.c20
-rw-r--r--hw/cpu/a15mpcore.c46
-rw-r--r--hw/cpu/a9mpcore.c44
-rw-r--r--hw/cpu/arm11mpcore.c26
-rw-r--r--hw/cpu/cluster.c5
-rw-r--r--hw/cpu/core.c2
-rw-r--r--hw/cpu/realview_mpcore.c32
-rw-r--r--hw/cris/Kconfig11
-rw-r--r--hw/cris/axis_dev88.c351
-rw-r--r--hw/cris/boot.c102
-rw-r--r--hw/cris/boot.h16
-rw-r--r--hw/cris/meson.build5
-rw-r--r--hw/cxl/cxl-component-utils.c9
-rw-r--r--hw/cxl/cxl-device-utils.c26
-rw-r--r--hw/cxl/cxl-host.c4
-rw-r--r--hw/cxl/cxl-mailbox-utils.c742
-rw-r--r--hw/cxl/switch-mailbox-cci.c13
-rw-r--r--hw/display/Kconfig14
-rw-r--r--hw/display/apple-gfx-mmio.m285
-rw-r--r--hw/display/apple-gfx-pci.m157
-rw-r--r--hw/display/apple-gfx.h74
-rw-r--r--hw/display/apple-gfx.m880
-rw-r--r--hw/display/artist.c16
-rw-r--r--hw/display/ati.c9
-rw-r--r--hw/display/bcm2835_fb.c7
-rw-r--r--hw/display/blizzard.c1026
-rw-r--r--hw/display/bochs-display.c7
-rw-r--r--hw/display/cg3.c7
-rw-r--r--hw/display/cirrus_vga.c9
-rw-r--r--hw/display/cirrus_vga_isa.c5
-rw-r--r--hw/display/dm163.c6
-rw-r--r--hw/display/dpcd.c4
-rw-r--r--hw/display/edid-region.c2
-rw-r--r--hw/display/exynos4210_fimd.c7
-rw-r--r--hw/display/framebuffer.h2
-rw-r--r--hw/display/g364fb.c7
-rw-r--r--hw/display/i2c-ddc.c7
-rw-r--r--hw/display/jazz_led.c4
-rw-r--r--hw/display/macfb.c15
-rw-r--r--hw/display/meson.build6
-rw-r--r--hw/display/next-fb.c2
-rw-r--r--hw/display/omap_dss.c1093
-rw-r--r--hw/display/pl110.c5
-rw-r--r--hw/display/pxa2xx_lcd.c1451
-rw-r--r--hw/display/qxl-render.c2
-rw-r--r--hw/display/qxl.c48
-rw-r--r--hw/display/ramfb-standalone.c8
-rw-r--r--hw/display/ramfb.c2
-rw-r--r--hw/display/sii9022.c4
-rw-r--r--hw/display/sm501.c18
-rw-r--r--hw/display/ssd0303.c2
-rw-r--r--hw/display/ssd0323.c2
-rw-r--r--hw/display/tc6393xb.c568
-rw-r--r--hw/display/tcx.c8
-rw-r--r--hw/display/trace-events33
-rw-r--r--hw/display/vga-isa.c7
-rw-r--r--hw/display/vga-mmio.c7
-rw-r--r--hw/display/vga-pci.c16
-rw-r--r--hw/display/vga.c6
-rw-r--r--hw/display/vga_int.h4
-rw-r--r--hw/display/vhost-user-gpu.c38
-rw-r--r--hw/display/virtio-gpu-base.c6
-rw-r--r--hw/display/virtio-gpu-gl.c69
-rw-r--r--hw/display/virtio-gpu-pci-rutabaga.c2
-rw-r--r--hw/display/virtio-gpu-pci.c5
-rw-r--r--hw/display/virtio-gpu-rutabaga.c5
-rw-r--r--hw/display/virtio-gpu-udmabuf.c12
-rw-r--r--hw/display/virtio-gpu-virgl.c565
-rw-r--r--hw/display/virtio-gpu.c183
-rw-r--r--hw/display/virtio-vga.c5
-rw-r--r--hw/display/vmware_vga.c11
-rw-r--r--hw/display/xenfb.c2
-rw-r--r--hw/display/xlnx_dp.c7
-rw-r--r--hw/dma/bcm2835_dma.c4
-rw-r--r--hw/dma/etraxfs_dma.c781
-rw-r--r--hw/dma/i82374.c7
-rw-r--r--hw/dma/i8257.c9
-rw-r--r--hw/dma/meson.build2
-rw-r--r--hw/dma/omap_dma.c785
-rw-r--r--hw/dma/pl080.c7
-rw-r--r--hw/dma/pl330.c10
-rw-r--r--hw/dma/pxa2xx_dma.c591
-rw-r--r--hw/dma/rc4030.c8
-rw-r--r--hw/dma/sifive_pdma.c5
-rw-r--r--hw/dma/sparc32_dma.c14
-rw-r--r--hw/dma/xilinx_axidma.c16
-rw-r--r--hw/dma/xlnx-zdma.c7
-rw-r--r--hw/dma/xlnx-zynq-devcfg.c6
-rw-r--r--hw/dma/xlnx_csu_dma.c13
-rw-r--r--hw/dma/xlnx_dpdma.c4
-rw-r--r--hw/fsi/aspeed_apb2opb.c4
-rw-r--r--hw/fsi/cfam.c2
-rw-r--r--hw/fsi/fsi-master.c4
-rw-r--r--hw/fsi/fsi.c4
-rw-r--r--hw/fsi/lbus.c4
-rw-r--r--hw/gpio/Kconfig15
-rw-r--r--hw/gpio/aspeed_gpio.c444
-rw-r--r--hw/gpio/bcm2835_gpio.c4
-rw-r--r--hw/gpio/bcm2838_gpio.c5
-rw-r--r--hw/gpio/gpio_key.c4
-rw-r--r--hw/gpio/gpio_pwr.c2
-rw-r--r--hw/gpio/imx_gpio.c29
-rw-r--r--hw/gpio/max7310.c217
-rw-r--r--hw/gpio/meson.build3
-rw-r--r--hw/gpio/mpc8xxx.c26
-rw-r--r--hw/gpio/npcm7xx_gpio.c8
-rw-r--r--hw/gpio/nrf51_gpio.c5
-rw-r--r--hw/gpio/omap_gpio.c592
-rw-r--r--hw/gpio/pca9552.c11
-rw-r--r--hw/gpio/pca9554.c12
-rw-r--r--hw/gpio/pcf8574.c4
-rw-r--r--hw/gpio/pl061.c6
-rw-r--r--hw/gpio/sifive_gpio.c7
-rw-r--r--hw/gpio/stm32l4x5_gpio.c5
-rw-r--r--hw/gpio/trace-events5
-rw-r--r--hw/gpio/zaurus.c2
-rw-r--r--hw/hppa/Kconfig3
-rw-r--r--hw/hppa/hppa_hardware.h36
-rw-r--r--hw/hppa/machine.c151
-rw-r--r--hw/hyperv/hv-balloon-our_range_memslots.h2
-rw-r--r--hw/hyperv/hv-balloon.c27
-rw-r--r--hw/hyperv/hyperv.c15
-rw-r--r--hw/hyperv/hyperv_testdev.c9
-rw-r--r--hw/hyperv/meson.build11
-rw-r--r--hw/hyperv/syndbg.c15
-rw-r--r--hw/hyperv/vmbus.c33
-rw-r--r--hw/i2c/allwinner-i2c.c4
-rw-r--r--hw/i2c/aspeed_i2c.c335
-rw-r--r--hw/i2c/bcm2835_i2c.c4
-rw-r--r--hw/i2c/bitbang_i2c.c2
-rw-r--r--hw/i2c/core.c5
-rw-r--r--hw/i2c/exynos4210_i2c.c4
-rw-r--r--hw/i2c/i2c_mux_pca954x.c9
-rw-r--r--hw/i2c/imx_i2c.c36
-rw-r--r--hw/i2c/microbit_i2c.c4
-rw-r--r--hw/i2c/mpc_i2c.c33
-rw-r--r--hw/i2c/npcm7xx_smbus.c2
-rw-r--r--hw/i2c/omap_i2c.c185
-rw-r--r--hw/i2c/pm_smbus.c1
-rw-r--r--hw/i2c/pmbus_device.c2
-rw-r--r--hw/i2c/ppc4xx_i2c.c4
-rw-r--r--hw/i2c/smbus_eeprom.c23
-rw-r--r--hw/i2c/smbus_ich9.c4
-rw-r--r--hw/i2c/smbus_slave.c2
-rw-r--r--hw/i2c/trace-events10
-rw-r--r--hw/i386/Kconfig17
-rw-r--r--hw/i386/acpi-build.c206
-rw-r--r--hw/i386/acpi-build.h2
-rw-r--r--hw/i386/acpi-common.c2
-rw-r--r--hw/i386/acpi-microvm.c2
-rw-r--r--hw/i386/amd_iommu.c221
-rw-r--r--hw/i386/amd_iommu.h12
-rw-r--r--hw/i386/fw_cfg.c16
-rw-r--r--hw/i386/intel_iommu.c908
-rw-r--r--hw/i386/intel_iommu_internal.h128
-rw-r--r--hw/i386/kvm/apic.c13
-rw-r--r--hw/i386/kvm/clock.c16
-rw-r--r--hw/i386/kvm/i8254.c11
-rw-r--r--hw/i386/kvm/i8259.c6
-rw-r--r--hw/i386/kvm/ioapic.c9
-rw-r--r--hw/i386/kvm/xen-stubs.c13
-rw-r--r--hw/i386/kvm/xen_evtchn.c72
-rw-r--r--hw/i386/kvm/xen_evtchn.h2
-rw-r--r--hw/i386/kvm/xen_gnttab.c8
-rw-r--r--hw/i386/kvm/xen_overlay.c10
-rw-r--r--hw/i386/kvm/xen_primary_console.c6
-rw-r--r--hw/i386/kvm/xen_xenstore.c14
-rw-r--r--hw/i386/meson.build2
-rw-r--r--hw/i386/microvm-dt.c4
-rw-r--r--hw/i386/microvm.c94
-rw-r--r--hw/i386/monitor.c4
-rw-r--r--hw/i386/multiboot.c46
-rw-r--r--hw/i386/nitro_enclave.c353
-rw-r--r--hw/i386/pc.c138
-rw-r--r--hw/i386/pc_piix.c81
-rw-r--r--hw/i386/pc_q35.c72
-rw-r--r--hw/i386/pc_sysfw.c13
-rw-r--r--hw/i386/pc_sysfw_ovmf.c1
-rw-r--r--hw/i386/port92.c6
-rw-r--r--hw/i386/sgx-epc.c9
-rw-r--r--hw/i386/sgx-stub.c6
-rw-r--r--hw/i386/sgx.c40
-rw-r--r--hw/i386/tdvf-hob.c130
-rw-r--r--hw/i386/tdvf-hob.h26
-rw-r--r--hw/i386/tdvf.c189
-rw-r--r--hw/i386/trace-events1
-rw-r--r--hw/i386/vapic.c19
-rw-r--r--hw/i386/vmmouse.c7
-rw-r--r--hw/i386/vmport.c12
-rw-r--r--hw/i386/x86-common.c141
-rw-r--r--hw/i386/x86-cpu.c6
-rw-r--r--hw/i386/x86-iommu.c9
-rw-r--r--hw/i386/x86.c9
-rw-r--r--hw/i386/xen/meson.build1
-rw-r--r--hw/i386/xen/xen-hvm.c12
-rw-r--r--hw/i386/xen/xen-pvh.c125
-rw-r--r--hw/i386/xen/xen_apic.c4
-rw-r--r--hw/i386/xen/xen_platform.c12
-rw-r--r--hw/i386/xen/xen_pvdevice.c7
-rw-r--r--hw/ide/Kconfig10
-rw-r--r--hw/ide/ahci-allwinner.c4
-rw-r--r--hw/ide/ahci-internal.h1
-rw-r--r--hw/ide/ahci-sysbus.c90
-rw-r--r--hw/ide/ahci.c113
-rw-r--r--hw/ide/atapi.c2
-rw-r--r--hw/ide/cf.c5
-rw-r--r--hw/ide/cmd646.c11
-rw-r--r--hw/ide/core.c15
-rw-r--r--hw/ide/ich.c27
-rw-r--r--hw/ide/ide-bus.c8
-rw-r--r--hw/ide/ide-dev.c21
-rw-r--r--hw/ide/isa.c9
-rw-r--r--hw/ide/macio.c20
-rw-r--r--hw/ide/meson.build2
-rw-r--r--hw/ide/microdrive.c644
-rw-r--r--hw/ide/mmio.c9
-rw-r--r--hw/ide/pci.c4
-rw-r--r--hw/ide/piix.c8
-rw-r--r--hw/ide/sii3112.c4
-rw-r--r--hw/ide/via.c6
-rw-r--r--hw/input/Kconfig13
-rw-r--r--hw/input/adb-kbd.c4
-rw-r--r--hw/input/adb-mouse.c65
-rw-r--r--hw/input/adb.c4
-rw-r--r--hw/input/ads7846.c186
-rw-r--r--hw/input/lasips2.c10
-rw-r--r--hw/input/lm832x.c528
-rw-r--r--hw/input/meson.build5
-rw-r--r--hw/input/pckbd.c20
-rw-r--r--hw/input/pl050.c6
-rw-r--r--hw/input/ps2.c10
-rw-r--r--hw/input/pxa2xx_keypad.c331
-rw-r--r--hw/input/stellaris_gamepad.c5
-rw-r--r--hw/input/trace-events3
-rw-r--r--hw/input/tsc2005.c571
-rw-r--r--hw/input/tsc210x.c1241
-rw-r--r--hw/input/virtio-input-hid.c15
-rw-r--r--hw/input/virtio-input-host.c6
-rw-r--r--hw/input/virtio-input.c8
-rw-r--r--hw/intc/Kconfig6
-rw-r--r--hw/intc/allwinner-a10-pic.c6
-rw-r--r--hw/intc/apic.c7
-rw-r--r--hw/intc/apic_common.c9
-rw-r--r--hw/intc/arm_gic.c19
-rw-r--r--hw/intc/arm_gic_common.c10
-rw-r--r--hw/intc/arm_gic_kvm.c13
-rw-r--r--hw/intc/arm_gicv2m.c7
-rw-r--r--hw/intc/arm_gicv3.c2
-rw-r--r--hw/intc/arm_gicv3_common.c9
-rw-r--r--hw/intc/arm_gicv3_cpuif.c27
-rw-r--r--hw/intc/arm_gicv3_its.c49
-rw-r--r--hw/intc/arm_gicv3_its_common.c4
-rw-r--r--hw/intc/arm_gicv3_its_kvm.c9
-rw-r--r--hw/intc/arm_gicv3_kvm.c6
-rw-r--r--hw/intc/armv7m_nvic.c13
-rw-r--r--hw/intc/aspeed_intc.c1095
-rw-r--r--hw/intc/aspeed_vic.c4
-rw-r--r--hw/intc/bcm2835_ic.c4
-rw-r--r--hw/intc/bcm2836_control.c4
-rw-r--r--hw/intc/etraxfs_pic.c172
-rw-r--r--hw/intc/exynos4210_combiner.c7
-rw-r--r--hw/intc/exynos4210_gic.c5
-rw-r--r--hw/intc/goldfish_pic.c9
-rw-r--r--hw/intc/grlib_irqmp.c7
-rw-r--r--hw/intc/heathrow_pic.c4
-rw-r--r--hw/intc/i8259.c9
-rw-r--r--hw/intc/i8259_common.c7
-rw-r--r--hw/intc/imx_avic.c4
-rw-r--r--hw/intc/imx_gpcv2.c4
-rw-r--r--hw/intc/ioapic.c11
-rw-r--r--hw/intc/ioapic_common.c4
-rw-r--r--hw/intc/ioapic_internal.h2
-rw-r--r--hw/intc/loongarch_extioi.c224
-rw-r--r--hw/intc/loongarch_extioi_common.c248
-rw-r--r--hw/intc/loongarch_extioi_kvm.c140
-rw-r--r--hw/intc/loongarch_ipi.c200
-rw-r--r--hw/intc/loongarch_ipi_kvm.c85
-rw-r--r--hw/intc/loongarch_pch_msi.c24
-rw-r--r--hw/intc/loongarch_pch_pic.c474
-rw-r--r--hw/intc/loongarch_pic_common.c135
-rw-r--r--hw/intc/loongarch_pic_kvm.c89
-rw-r--r--hw/intc/loongson_ipi.c52
-rw-r--r--hw/intc/loongson_ipi_common.c71
-rw-r--r--hw/intc/m68k_irqc.c9
-rw-r--r--hw/intc/meson.build15
-rw-r--r--hw/intc/mips_gic.c12
-rw-r--r--hw/intc/omap_intc.c448
-rw-r--r--hw/intc/ompic.c7
-rw-r--r--hw/intc/openpic.c27
-rw-r--r--hw/intc/openpic_kvm.c9
-rw-r--r--hw/intc/pl190.c4
-rw-r--r--hw/intc/pnv_xive.c23
-rw-r--r--hw/intc/pnv_xive2.c225
-rw-r--r--hw/intc/ppc-uic.c7
-rw-r--r--hw/intc/realview_gic.c2
-rw-r--r--hw/intc/riscv_aclint.c10
-rw-r--r--hw/intc/riscv_aplic.c198
-rw-r--r--hw/intc/riscv_imsic.c108
-rw-r--r--hw/intc/rx_icu.c5
-rw-r--r--hw/intc/s390_flic.c33
-rw-r--r--hw/intc/s390_flic_kvm.c6
-rw-r--r--hw/intc/sifive_plic.c24
-rw-r--r--hw/intc/slavio_intctl.c6
-rw-r--r--hw/intc/spapr_xive.c19
-rw-r--r--hw/intc/spapr_xive_kvm.c10
-rw-r--r--hw/intc/trace-events39
-rw-r--r--hw/intc/xics.c30
-rw-r--r--hw/intc/xics_kvm.c2
-rw-r--r--hw/intc/xics_pnv.c2
-rw-r--r--hw/intc/xics_spapr.c4
-rw-r--r--hw/intc/xilinx_intc.c60
-rw-r--r--hw/intc/xive.c443
-rw-r--r--hw/intc/xive2.c1030
-rw-r--r--hw/intc/xlnx-pmu-iomod-intc.c7
-rw-r--r--hw/intc/xlnx-zynqmp-ipi.c4
-rw-r--r--hw/ipack/Kconfig4
-rw-r--r--hw/ipack/ipack.c10
-rw-r--r--hw/ipack/meson.build3
-rw-r--r--hw/ipack/tpci200.c10
-rw-r--r--hw/ipmi/ipmi.c9
-rw-r--r--hw/ipmi/ipmi_bmc_extern.c14
-rw-r--r--hw/ipmi/ipmi_bmc_sim.c123
-rw-r--r--hw/ipmi/ipmi_bt.c10
-rw-r--r--hw/ipmi/ipmi_kcs.c5
-rw-r--r--hw/ipmi/isa_ipmi_bt.c11
-rw-r--r--hw/ipmi/isa_ipmi_kcs.c20
-rw-r--r--hw/ipmi/pci_ipmi_bt.c54
-rw-r--r--hw/ipmi/pci_ipmi_kcs.c15
-rw-r--r--hw/ipmi/smbus_ipmi.c4
-rw-r--r--hw/isa/fdc37m81x-superio.c2
-rw-r--r--hw/isa/i82378.c4
-rw-r--r--hw/isa/isa-bus.c8
-rw-r--r--hw/isa/isa-superio.c6
-rw-r--r--hw/isa/lpc_ich9.c28
-rw-r--r--hw/isa/pc87312.c7
-rw-r--r--hw/isa/piix.c15
-rw-r--r--hw/isa/smc37c669-superio.c2
-rw-r--r--hw/isa/vt82c686.c41
-rw-r--r--hw/loongarch/Kconfig4
-rw-r--r--hw/loongarch/boot.c187
-rw-r--r--hw/loongarch/fw_cfg.c2
-rw-r--r--hw/loongarch/meson.build8
-rw-r--r--hw/loongarch/virt-acpi-build.c (renamed from hw/loongarch/acpi-build.c)129
-rw-r--r--hw/loongarch/virt-fdt-build.c534
-rw-r--r--hw/loongarch/virt.c984
-rw-r--r--hw/m68k/Kconfig1
-rw-r--r--hw/m68k/an5206.c4
-rw-r--r--hw/m68k/bootinfo.h30
-rw-r--r--hw/m68k/mcf5206.c11
-rw-r--r--hw/m68k/mcf5208.c24
-rw-r--r--hw/m68k/mcf_intc.c9
-rw-r--r--hw/m68k/next-cube.c1037
-rw-r--r--hw/m68k/next-kbd.c164
-rw-r--r--hw/m68k/q800-glue.c7
-rw-r--r--hw/m68k/q800.c19
-rw-r--r--hw/m68k/virt.c38
-rw-r--r--hw/mem/cxl_type3.c105
-rw-r--r--hw/mem/memory-device.c4
-rw-r--r--hw/mem/npcm7xx_mc.c2
-rw-r--r--hw/mem/nvdimm.c7
-rw-r--r--hw/mem/pc-dimm.c11
-rw-r--r--hw/mem/sparse-mem.c8
-rw-r--r--hw/meson.build5
-rw-r--r--hw/microblaze/Kconfig2
-rw-r--r--hw/microblaze/boot.c16
-rw-r--r--hw/microblaze/boot.h4
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c15
-rw-r--r--hw/microblaze/petalogix_s3adsp1800_mmu.c68
-rw-r--r--hw/microblaze/xlnx-zynqmp-pmu.c11
-rw-r--r--hw/mips/Kconfig10
-rw-r--r--hw/mips/boston.c36
-rw-r--r--hw/mips/cps.c13
-rw-r--r--hw/mips/fuloong2e.c12
-rw-r--r--hw/mips/jazz.c30
-rw-r--r--hw/mips/loongson3_bootp.c16
-rw-r--r--hw/mips/loongson3_bootp.h1
-rw-r--r--hw/mips/loongson3_virt.c80
-rw-r--r--hw/mips/malta.c42
-rw-r--r--hw/mips/meson.build5
-rw-r--r--hw/mips/mips_int.c2
-rw-r--r--hw/mips/mipssim.c27
-rw-r--r--hw/misc/Kconfig27
-rw-r--r--hw/misc/a9scu.c7
-rw-r--r--hw/misc/allwinner-a10-ccm.c4
-rw-r--r--hw/misc/allwinner-a10-dramc.c4
-rw-r--r--hw/misc/allwinner-cpucfg.c6
-rw-r--r--hw/misc/allwinner-h3-ccu.c6
-rw-r--r--hw/misc/allwinner-h3-dramc.c15
-rw-r--r--hw/misc/allwinner-h3-sysctrl.c7
-rw-r--r--hw/misc/allwinner-r40-ccu.c6
-rw-r--r--hw/misc/allwinner-r40-dramc.c19
-rw-r--r--hw/misc/allwinner-sid.c9
-rw-r--r--hw/misc/allwinner-sramc.c8
-rw-r--r--hw/misc/applesmc.c9
-rw-r--r--hw/misc/arm11scu.c5
-rw-r--r--hw/misc/arm_l2x0.c7
-rw-r--r--hw/misc/arm_sysctl.c11
-rw-r--r--hw/misc/armsse-cpu-pwrctrl.c4
-rw-r--r--hw/misc/armsse-cpuid.c5
-rw-r--r--hw/misc/armsse-mhu.c4
-rw-r--r--hw/misc/armv7m_ras.c2
-rw-r--r--hw/misc/aspeed_hace.c558
-rw-r--r--hw/misc/aspeed_i3c.c11
-rw-r--r--hw/misc/aspeed_lpc.c7
-rw-r--r--hw/misc/aspeed_peci.c4
-rw-r--r--hw/misc/aspeed_sbc.c9
-rw-r--r--hw/misc/aspeed_scu.c53
-rw-r--r--hw/misc/aspeed_sdmc.c17
-rw-r--r--hw/misc/aspeed_sli.c6
-rw-r--r--hw/misc/aspeed_xdma.c10
-rw-r--r--hw/misc/auxbus.c6
-rw-r--r--hw/misc/avr_power.c4
-rw-r--r--hw/misc/axp2xx.c6
-rw-r--r--hw/misc/bcm2835_cprman.c29
-rw-r--r--hw/misc/bcm2835_mbox.c4
-rw-r--r--hw/misc/bcm2835_mphi.c4
-rw-r--r--hw/misc/bcm2835_powermgt.c6
-rw-r--r--hw/misc/bcm2835_property.c7
-rw-r--r--hw/misc/bcm2835_rng.c4
-rw-r--r--hw/misc/bcm2835_thermal.c4
-rw-r--r--hw/misc/cbus.c619
-rw-r--r--hw/misc/debugexit.c7
-rw-r--r--hw/misc/djmemc.c2
-rw-r--r--hw/misc/eccmemctl.c7
-rw-r--r--hw/misc/edu.c23
-rw-r--r--hw/misc/empty_slot.c5
-rw-r--r--hw/misc/exynos4210_clk.c4
-rw-r--r--hw/misc/exynos4210_pmu.c6
-rw-r--r--hw/misc/exynos4210_rng.c4
-rw-r--r--hw/misc/grlib_ahb_apb_pnp.c4
-rw-r--r--hw/misc/i2c-echo.c12
-rw-r--r--hw/misc/imx25_ccm.c4
-rw-r--r--hw/misc/imx31_ccm.c4
-rw-r--r--hw/misc/imx6_ccm.c5
-rw-r--r--hw/misc/imx6_src.c27
-rw-r--r--hw/misc/imx6ul_ccm.c4
-rw-r--r--hw/misc/imx7_ccm.c8
-rw-r--r--hw/misc/imx7_gpr.c2
-rw-r--r--hw/misc/imx7_snvs.c10
-rw-r--r--hw/misc/imx7_src.c4
-rw-r--r--hw/misc/imx8mp_analog.c160
-rw-r--r--hw/misc/imx8mp_ccm.c175
-rw-r--r--hw/misc/imx_rngc.c4
-rw-r--r--hw/misc/iosb.c2
-rw-r--r--hw/misc/iotkit-secctl.c7
-rw-r--r--hw/misc/iotkit-sysctl.c9
-rw-r--r--hw/misc/iotkit-sysinfo.c5
-rw-r--r--hw/misc/ivshmem-flat.c458
-rw-r--r--hw/misc/ivshmem-pci.c (renamed from hw/misc/ivshmem.c)20
-rw-r--r--hw/misc/lasi.c8
-rw-r--r--hw/misc/led.c7
-rw-r--r--hw/misc/mac_via.c17
-rw-r--r--hw/misc/macio/cuda.c13
-rw-r--r--hw/misc/macio/gpio.c27
-rw-r--r--hw/misc/macio/mac_dbdma.c6
-rw-r--r--hw/misc/macio/macio.c14
-rw-r--r--hw/misc/macio/pmu.c13
-rw-r--r--hw/misc/macio/trace-events3
-rw-r--r--hw/misc/mchp_pfsoc_dmc.c5
-rw-r--r--hw/misc/mchp_pfsoc_ioscb.c2
-rw-r--r--hw/misc/mchp_pfsoc_sysreg.c9
-rw-r--r--hw/misc/meson.build18
-rw-r--r--hw/misc/mips_cmgcr.c7
-rw-r--r--hw/misc/mips_cpc.c9
-rw-r--r--hw/misc/mips_itu.c7
-rw-r--r--hw/misc/mos6522.c5
-rw-r--r--hw/misc/mps2-fpgaio.c9
-rw-r--r--hw/misc/mps2-scc.c7
-rw-r--r--hw/misc/msf2-sysreg.c7
-rw-r--r--hw/misc/mst_fpga.c269
-rw-r--r--hw/misc/npcm7xx_gcr.c265
-rw-r--r--hw/misc/npcm7xx_mft.c7
-rw-r--r--hw/misc/npcm7xx_pwm.c2
-rw-r--r--hw/misc/npcm7xx_rng.c2
-rw-r--r--hw/misc/npcm_clk.c (renamed from hw/misc/npcm7xx_clk.c)250
-rw-r--r--hw/misc/npcm_gcr.c482
-rw-r--r--hw/misc/nrf51_rng.c17
-rw-r--r--hw/misc/omap_clk.c995
-rw-r--r--hw/misc/omap_gpmc.c898
-rw-r--r--hw/misc/omap_l4.c162
-rw-r--r--hw/misc/omap_sdrc.c167
-rw-r--r--hw/misc/omap_tap.c117
-rw-r--r--hw/misc/pc-testdev.c2
-rw-r--r--hw/misc/pci-testdev.c23
-rw-r--r--hw/misc/pvpanic-isa.c9
-rw-r--r--hw/misc/pvpanic-mmio.c60
-rw-r--r--hw/misc/pvpanic-pci.c9
-rw-r--r--hw/misc/pvpanic.c2
-rw-r--r--hw/misc/sbsa_ec.c4
-rw-r--r--hw/misc/sifive_e_aon.c9
-rw-r--r--hw/misc/sifive_test.c4
-rw-r--r--hw/misc/sifive_u_otp.c9
-rw-r--r--hw/misc/sifive_u_prci.c4
-rw-r--r--hw/misc/slavio_misc.c6
-rw-r--r--hw/misc/stm32_rcc.c162
-rw-r--r--hw/misc/stm32f2xx_syscfg.c4
-rw-r--r--hw/misc/stm32f4xx_exti.c4
-rw-r--r--hw/misc/stm32f4xx_syscfg.c4
-rw-r--r--hw/misc/stm32l4x5_exti.c2
-rw-r--r--hw/misc/stm32l4x5_rcc.c13
-rw-r--r--hw/misc/stm32l4x5_syscfg.c21
-rw-r--r--hw/misc/trace-events53
-rw-r--r--hw/misc/tz-mpc.c9
-rw-r--r--hw/misc/tz-msc.c7
-rw-r--r--hw/misc/tz-ppc.c7
-rw-r--r--hw/misc/unimp.c5
-rw-r--r--hw/misc/virt_ctrl.c6
-rw-r--r--hw/misc/vmcoreinfo.c39
-rw-r--r--hw/misc/xlnx-versal-cframe-reg.c12
-rw-r--r--hw/misc/xlnx-versal-cfu.c26
-rw-r--r--hw/misc/xlnx-versal-crl.c2
-rw-r--r--hw/misc/xlnx-versal-pmc-iou-slcr.c3
-rw-r--r--hw/misc/xlnx-versal-trng.c26
-rw-r--r--hw/misc/xlnx-versal-xramc.c5
-rw-r--r--hw/misc/xlnx-zynqmp-apu-ctrl.c2
-rw-r--r--hw/misc/xlnx-zynqmp-crf.c2
-rw-r--r--hw/misc/zynq_slcr.c7
-rw-r--r--hw/net/Kconfig5
-rw-r--r--hw/net/allwinner-sun8i-emac.c12
-rw-r--r--hw/net/allwinner_emac.c9
-rw-r--r--hw/net/cadence_gem.c37
-rw-r--r--hw/net/can/can_kvaser_pci.c10
-rw-r--r--hw/net/can/can_mioe3680_pci.c10
-rw-r--r--hw/net/can/can_pcm3680_pci.c10
-rw-r--r--hw/net/can/can_sja1000.c2
-rw-r--r--hw/net/can/ctucan_core.c5
-rw-r--r--hw/net/can/ctucan_pci.c10
-rw-r--r--hw/net/can/xlnx-versal-canfd.c186
-rw-r--r--hw/net/can/xlnx-zynqmp-can.c5
-rw-r--r--hw/net/dp8393x.c9
-rw-r--r--hw/net/e1000.c110
-rw-r--r--hw/net/e1000e.c12
-rw-r--r--hw/net/e1000e_core.c6
-rw-r--r--hw/net/e1000x_regs.h2
-rw-r--r--hw/net/eepro100.c23
-rw-r--r--hw/net/etraxfs_eth.c688
-rw-r--r--hw/net/fsl_etsec/etsec.c34
-rw-r--r--hw/net/fsl_etsec/miim.c19
-rw-r--r--hw/net/ftgmac100.c19
-rw-r--r--hw/net/i82596.c44
-rw-r--r--hw/net/i82596.h4
-rw-r--r--hw/net/igb.c22
-rw-r--r--hw/net/igb_core.c6
-rw-r--r--hw/net/igb_regs.h2
-rw-r--r--hw/net/igbvf.c4
-rw-r--r--hw/net/imx_fec.c159
-rw-r--r--hw/net/lan9118.c147
-rw-r--r--hw/net/lan9118_phy.c222
-rw-r--r--hw/net/lance.c9
-rw-r--r--hw/net/lasi_i82596.c9
-rw-r--r--hw/net/mcf_fec.c10
-rw-r--r--hw/net/meson.build3
-rw-r--r--hw/net/mipsnet.c7
-rw-r--r--hw/net/msf2-emac.c7
-rw-r--r--hw/net/mv88w8618_eth.c7
-rw-r--r--hw/net/ne2000-isa.c7
-rw-r--r--hw/net/ne2000-pci.c9
-rw-r--r--hw/net/ne2000.c2
-rw-r--r--hw/net/net_rx_pkt.c16
-rw-r--r--hw/net/net_rx_pkt.h17
-rw-r--r--hw/net/net_tx_pkt.c4
-rw-r--r--hw/net/npcm7xx_emc.c12
-rw-r--r--hw/net/npcm_gmac.c14
-rw-r--r--hw/net/npcm_pcs.c410
-rw-r--r--hw/net/opencores_eth.c7
-rw-r--r--hw/net/pcnet-pci.c13
-rw-r--r--hw/net/pcnet.h2
-rw-r--r--hw/net/rocker/rocker-hmp-cmds.c2
-rw-r--r--hw/net/rocker/rocker.c14
-rw-r--r--hw/net/rocker/rocker.h15
-rw-r--r--hw/net/rocker/rocker_hw.h20
-rw-r--r--hw/net/rocker/rocker_of_dpa.c53
-rw-r--r--hw/net/rtl8139.c19
-rw-r--r--hw/net/smc91c111.c167
-rw-r--r--hw/net/spapr_llan.c7
-rw-r--r--hw/net/stellaris_enet.c9
-rw-r--r--hw/net/sungem.c11
-rw-r--r--hw/net/sunhme.c11
-rw-r--r--hw/net/trace-events30
-rw-r--r--hw/net/tulip.c13
-rw-r--r--hw/net/vhost_net.c168
-rw-r--r--hw/net/virtio-net.c278
-rw-r--r--hw/net/vmxnet3.c57
-rw-r--r--hw/net/vmxnet3.h4
-rw-r--r--hw/net/xen_nic.c20
-rw-r--r--hw/net/xgmac.c7
-rw-r--r--hw/net/xilinx_axienet.c16
-rw-r--r--hw/net/xilinx_ethlite.c410
-rw-r--r--hw/nubus/mac-nubus-bridge.c2
-rw-r--r--hw/nubus/nubus-bridge.c5
-rw-r--r--hw/nubus/nubus-bus.c2
-rw-r--r--hw/nubus/nubus-device.c12
-rw-r--r--hw/nubus/nubus-virtio-mmio.c2
-rw-r--r--hw/nvme/ctrl.c792
-rw-r--r--hw/nvme/dif.c7
-rw-r--r--hw/nvme/nguid.c6
-rw-r--r--hw/nvme/ns.c80
-rw-r--r--hw/nvme/nvme.h31
-rw-r--r--hw/nvme/subsys.c15
-rw-r--r--hw/nvme/trace-events1
-rw-r--r--hw/nvram/bcm2835_otp.c2
-rw-r--r--hw/nvram/chrp_nvram.c2
-rw-r--r--hw/nvram/ds1225y.c5
-rw-r--r--hw/nvram/eeprom_at24c.c32
-rw-r--r--hw/nvram/fw_cfg-acpi.c2
-rw-r--r--hw/nvram/fw_cfg.c178
-rw-r--r--hw/nvram/mac_nvram.c11
-rw-r--r--hw/nvram/npcm7xx_otp.c6
-rw-r--r--hw/nvram/nrf51_nvm.c7
-rw-r--r--hw/nvram/spapr_nvram.c13
-rw-r--r--hw/nvram/xlnx-bbram.c22
-rw-r--r--hw/nvram/xlnx-efuse.c11
-rw-r--r--hw/nvram/xlnx-versal-efuse-cache.c6
-rw-r--r--hw/nvram/xlnx-versal-efuse-ctrl.c13
-rw-r--r--hw/nvram/xlnx-zynqmp-efuse.c19
-rw-r--r--hw/openrisc/Kconfig4
-rw-r--r--hw/openrisc/boot.c17
-rw-r--r--hw/openrisc/cputimer.c28
-rw-r--r--hw/openrisc/openrisc_sim.c46
-rw-r--r--hw/openrisc/virt.c32
-rw-r--r--hw/pci-bridge/Kconfig5
-rw-r--r--hw/pci-bridge/cxl_downstream.c28
-rw-r--r--hw/pci-bridge/cxl_root_port.c12
-rw-r--r--hw/pci-bridge/cxl_upstream.c19
-rw-r--r--hw/pci-bridge/gen_pcie_root_port.c5
-rw-r--r--hw/pci-bridge/i82801b11.c6
-rw-r--r--hw/pci-bridge/ioh3420.c2
-rw-r--r--hw/pci-bridge/meson.build2
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c13
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c55
-rw-r--r--hw/pci-bridge/pcie_pci_bridge.c12
-rw-r--r--hw/pci-bridge/pcie_root_port.c7
-rw-r--r--hw/pci-bridge/simba.c6
-rw-r--r--hw/pci-bridge/xio3130_downstream.c9
-rw-r--r--hw/pci-bridge/xio3130_upstream.c6
-rw-r--r--hw/pci-host/Kconfig3
-rw-r--r--hw/pci-host/articia.c10
-rw-r--r--hw/pci-host/astro.c68
-rw-r--r--hw/pci-host/bonito.c8
-rw-r--r--hw/pci-host/designware.c125
-rw-r--r--hw/pci-host/dino.c7
-rw-r--r--hw/pci-host/fsl_imx8m_phy.c98
-rw-r--r--hw/pci-host/gpex-acpi.c7
-rw-r--r--hw/pci-host/gpex.c52
-rw-r--r--hw/pci-host/grackle.c9
-rw-r--r--hw/pci-host/gt64120.c95
-rw-r--r--hw/pci-host/i440fx.c9
-rw-r--r--hw/pci-host/meson.build1
-rw-r--r--hw/pci-host/mv64361.c16
-rw-r--r--hw/pci-host/pnv_phb.c14
-rw-r--r--hw/pci-host/pnv_phb3.c11
-rw-r--r--hw/pci-host/pnv_phb3_msi.c4
-rw-r--r--hw/pci-host/pnv_phb3_pbcq.c4
-rw-r--r--hw/pci-host/pnv_phb4.c11
-rw-r--r--hw/pci-host/pnv_phb4_pec.c68
-rw-r--r--hw/pci-host/ppc440_pcix.c4
-rw-r--r--hw/pci-host/ppc4xx_pci.c8
-rw-r--r--hw/pci-host/ppce500.c61
-rw-r--r--hw/pci-host/q35.c24
-rw-r--r--hw/pci-host/raven.c94
-rw-r--r--hw/pci-host/remote.c4
-rw-r--r--hw/pci-host/sabre.c13
-rw-r--r--hw/pci-host/sh_pci.c6
-rw-r--r--hw/pci-host/uninorth.c30
-rw-r--r--hw/pci-host/versatile.c15
-rw-r--r--hw/pci-host/xen_igd_pt.c3
-rw-r--r--hw/pci-host/xilinx-pcie.c11
-rw-r--r--hw/pci/msi.c2
-rw-r--r--hw/pci/msix.c15
-rw-r--r--hw/pci/pci-hmp-cmds.c28
-rw-r--r--hw/pci/pci-stub.c6
-rw-r--r--hw/pci/pci.c541
-rw-r--r--hw/pci/pci_bridge.c12
-rw-r--r--hw/pci/pci_host.c15
-rw-r--r--hw/pci/pcie.c203
-rw-r--r--hw/pci/pcie_port.c26
-rw-r--r--hw/pci/pcie_sriov.c413
-rw-r--r--hw/pci/trace-events8
-rw-r--r--hw/pcmcia/Kconfig2
-rw-r--r--hw/pcmcia/meson.build2
-rw-r--r--hw/pcmcia/pcmcia.c24
-rw-r--r--hw/pcmcia/pxa2xx.c248
-rw-r--r--hw/ppc/Kconfig17
-rw-r--r--hw/ppc/amigaone.c290
-rw-r--r--hw/ppc/e500.c98
-rw-r--r--hw/ppc/e500.h6
-rw-r--r--hw/ppc/e500plat.c10
-rw-r--r--hw/ppc/mac_newworld.c27
-rw-r--r--hw/ppc/mac_oldworld.c24
-rw-r--r--hw/ppc/meson.build3
-rw-r--r--hw/ppc/mpc8544_guts.c34
-rw-r--r--hw/ppc/mpc8544ds.c6
-rw-r--r--hw/ppc/pef.c6
-rw-r--r--hw/ppc/pegasos2.c61
-rw-r--r--hw/ppc/pnv.c262
-rw-r--r--hw/ppc/pnv_adu.c19
-rw-r--r--hw/ppc/pnv_bmc.c30
-rw-r--r--hw/ppc/pnv_chiptod.c15
-rw-r--r--hw/ppc/pnv_core.c37
-rw-r--r--hw/ppc/pnv_homer.c245
-rw-r--r--hw/ppc/pnv_i2c.c9
-rw-r--r--hw/ppc/pnv_lpc.c116
-rw-r--r--hw/ppc/pnv_n1_chiplet.c4
-rw-r--r--hw/ppc/pnv_nest_pervasive.c6
-rw-r--r--hw/ppc/pnv_occ.c672
-rw-r--r--hw/ppc/pnv_pnor.c11
-rw-r--r--hw/ppc/pnv_psi.c23
-rw-r--r--hw/ppc/pnv_sbe.c6
-rw-r--r--hw/ppc/pnv_xscom.c2
-rw-r--r--hw/ppc/ppc.c25
-rw-r--r--hw/ppc/ppc405.h186
-rw-r--r--hw/ppc/ppc405_boards.c520
-rw-r--r--hw/ppc/ppc405_uc.c1217
-rw-r--r--hw/ppc/ppc440_bamboo.c43
-rw-r--r--hw/ppc/ppc440_uc.c7
-rw-r--r--hw/ppc/ppc4xx_devs.c20
-rw-r--r--hw/ppc/ppc4xx_sdram.c16
-rw-r--r--hw/ppc/ppc_booke.c15
-rw-r--r--hw/ppc/ppce500_spin.c36
-rw-r--r--hw/ppc/prep.c33
-rw-r--r--hw/ppc/prep_systemio.c9
-rw-r--r--hw/ppc/rs6000_mc.c11
-rw-r--r--hw/ppc/sam460ex.c65
-rw-r--r--hw/ppc/spapr.c555
-rw-r--r--hw/ppc/spapr_caps.c52
-rw-r--r--hw/ppc/spapr_cpu_core.c41
-rw-r--r--hw/ppc/spapr_drc.c51
-rw-r--r--hw/ppc/spapr_events.c7
-rw-r--r--hw/ppc/spapr_hcall.c41
-rw-r--r--hw/ppc/spapr_iommu.c11
-rw-r--r--hw/ppc/spapr_irq.c2
-rw-r--r--hw/ppc/spapr_nested.c136
-rw-r--r--hw/ppc/spapr_nvdimm.c14
-rw-r--r--hw/ppc/spapr_ovec.c3
-rw-r--r--hw/ppc/spapr_pci.c117
-rw-r--r--hw/ppc/spapr_pci_vfio.c6
-rw-r--r--hw/ppc/spapr_rng.c9
-rw-r--r--hw/ppc/spapr_rtas.c18
-rw-r--r--hw/ppc/spapr_rtc.c6
-rw-r--r--hw/ppc/spapr_tpm_proxy.c11
-rw-r--r--hw/ppc/spapr_vio.c12
-rw-r--r--hw/ppc/spapr_vof.c2
-rw-r--r--hw/ppc/virtex_ml507.c46
-rw-r--r--hw/ppc/vof.c4
-rw-r--r--hw/remote/iohub.c13
-rw-r--r--hw/remote/iommu.c4
-rw-r--r--hw/remote/machine.c6
-rw-r--r--hw/remote/memory.c2
-rw-r--r--hw/remote/message.c4
-rw-r--r--hw/remote/mpqemu-link.c4
-rw-r--r--hw/remote/proxy-memory-listener.c4
-rw-r--r--hw/remote/proxy.c11
-rw-r--r--hw/remote/remote-obj.c6
-rw-r--r--hw/remote/vfio-user-obj.c12
-rw-r--r--hw/riscv/Kconfig14
-rw-r--r--hw/riscv/boot.c159
-rw-r--r--hw/riscv/meson.build3
-rw-r--r--hw/riscv/microblaze-v-generic.c189
-rw-r--r--hw/riscv/microchip_pfsoc.c174
-rw-r--r--hw/riscv/numa.c2
-rw-r--r--hw/riscv/opentitan.c17
-rw-r--r--hw/riscv/riscv-iommu-bits.h468
-rw-r--r--hw/riscv/riscv-iommu-hpm.c381
-rw-r--r--hw/riscv/riscv-iommu-hpm.h33
-rw-r--r--hw/riscv/riscv-iommu-pci.c217
-rw-r--r--hw/riscv/riscv-iommu-sys.c248
-rw-r--r--hw/riscv/riscv-iommu.c2679
-rw-r--r--hw/riscv/riscv-iommu.h157
-rw-r--r--hw/riscv/riscv_hart.c105
-rw-r--r--hw/riscv/shakti_c.c21
-rw-r--r--hw/riscv/sifive_e.c11
-rw-r--r--hw/riscv/sifive_u.c40
-rw-r--r--hw/riscv/spike.c25
-rw-r--r--hw/riscv/trace-events26
-rw-r--r--hw/riscv/trace.h1
-rw-r--r--hw/riscv/virt-acpi-build.c244
-rw-r--r--hw/riscv/virt.c548
-rw-r--r--hw/rtc/Kconfig9
-rw-r--r--hw/rtc/allwinner-rtc.c17
-rw-r--r--hw/rtc/aspeed_rtc.c6
-rw-r--r--hw/rtc/ds1338.c32
-rw-r--r--hw/rtc/exynos4210_rtc.c6
-rw-r--r--hw/rtc/goldfish_rtc.c67
-rw-r--r--hw/rtc/ls7a_rtc.c8
-rw-r--r--hw/rtc/m41t80.c4
-rw-r--r--hw/rtc/m48t59-isa.c15
-rw-r--r--hw/rtc/m48t59.c24
-rw-r--r--hw/rtc/mc146818rtc.c35
-rw-r--r--hw/rtc/meson.build2
-rw-r--r--hw/rtc/pl031.c9
-rw-r--r--hw/rtc/rs5c372.c236
-rw-r--r--hw/rtc/sun4v-rtc.c2
-rw-r--r--hw/rtc/trace-events8
-rw-r--r--hw/rtc/twl92230.c882
-rw-r--r--hw/rtc/xlnx-zynqmp-rtc.c8
-rw-r--r--hw/rx/rx-gdbsim.c19
-rw-r--r--hw/rx/rx62n.c13
-rw-r--r--hw/s390x/3270-ccw.c7
-rw-r--r--hw/s390x/Kconfig2
-rw-r--r--hw/s390x/ap-bridge.c6
-rw-r--r--hw/s390x/ap-device.c2
-rw-r--r--hw/s390x/ap-stub.c21
-rw-r--r--hw/s390x/ccw-device.c56
-rw-r--r--hw/s390x/ccw-device.h7
-rw-r--r--hw/s390x/cpu-topology.c10
-rw-r--r--hw/s390x/css-bridge.c23
-rw-r--r--hw/s390x/css.c41
-rw-r--r--hw/s390x/event-facility.c45
-rw-r--r--hw/s390x/ipl.c313
-rw-r--r--hw/s390x/ipl.h134
-rw-r--r--hw/s390x/meson.build12
-rw-r--r--hw/s390x/s390-ccw.c4
-rw-r--r--hw/s390x/s390-hypercall.c85
-rw-r--r--hw/s390x/s390-hypercall.h25
-rw-r--r--hw/s390x/s390-pci-bus.c110
-rw-r--r--hw/s390x/s390-pci-inst.c184
-rw-r--r--hw/s390x/s390-pci-vfio.c33
-rw-r--r--hw/s390x/s390-skeys-kvm.c4
-rw-r--r--hw/s390x/s390-skeys.c78
-rw-r--r--hw/s390x/s390-stattrib-kvm.c75
-rw-r--r--hw/s390x/s390-stattrib.c16
-rw-r--r--hw/s390x/s390-virtio-ccw.c613
-rw-r--r--hw/s390x/s390-virtio-hcall.c41
-rw-r--r--hw/s390x/s390-virtio-hcall.h25
-rw-r--r--hw/s390x/sclp.c28
-rw-r--r--hw/s390x/sclpcpi.c212
-rw-r--r--hw/s390x/sclpcpu.c4
-rw-r--r--hw/s390x/sclpquiesce.c6
-rw-r--r--hw/s390x/tod-kvm.c4
-rw-r--r--hw/s390x/tod-tcg.c4
-rw-r--r--hw/s390x/tod.c8
-rw-r--r--hw/s390x/vhost-scsi-ccw.c5
-rw-r--r--hw/s390x/vhost-user-fs-ccw.c5
-rw-r--r--hw/s390x/vhost-vsock-ccw.c5
-rw-r--r--hw/s390x/virtio-ccw-9p.c5
-rw-r--r--hw/s390x/virtio-ccw-balloon.c5
-rw-r--r--hw/s390x/virtio-ccw-blk.c6
-rw-r--r--hw/s390x/virtio-ccw-crypto.c5
-rw-r--r--hw/s390x/virtio-ccw-gpu.c5
-rw-r--r--hw/s390x/virtio-ccw-input.c5
-rw-r--r--hw/s390x/virtio-ccw-md-stubs.c24
-rw-r--r--hw/s390x/virtio-ccw-md.c153
-rw-r--r--hw/s390x/virtio-ccw-md.h44
-rw-r--r--hw/s390x/virtio-ccw-mem.c225
-rw-r--r--hw/s390x/virtio-ccw-mem.h34
-rw-r--r--hw/s390x/virtio-ccw-net.c6
-rw-r--r--hw/s390x/virtio-ccw-rng.c5
-rw-r--r--hw/s390x/virtio-ccw-scsi.c5
-rw-r--r--hw/s390x/virtio-ccw-serial.c5
-rw-r--r--hw/s390x/virtio-ccw.c28
-rw-r--r--hw/s390x/virtio-ccw.h2
-rw-r--r--hw/scsi/esp-pci.c8
-rw-r--r--hw/scsi/esp.c11
-rw-r--r--hw/scsi/lsi53c895a.c14
-rw-r--r--hw/scsi/megasas.c55
-rw-r--r--hw/scsi/mptendian.c2
-rw-r--r--hw/scsi/mptsas.c13
-rw-r--r--hw/scsi/scsi-bus.c142
-rw-r--r--hw/scsi/scsi-disk.c188
-rw-r--r--hw/scsi/scsi-generic.c9
-rw-r--r--hw/scsi/spapr_vscsi.c5
-rw-r--r--hw/scsi/vhost-scsi-common.c13
-rw-r--r--hw/scsi/vhost-scsi.c20
-rw-r--r--hw/scsi/vhost-user-scsi.c27
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c105
-rw-r--r--hw/scsi/virtio-scsi.c519
-rw-r--r--hw/scsi/vmw_pvscsi.c76
-rw-r--r--hw/scsi/vmw_pvscsi.h4
-rw-r--r--hw/sd/allwinner-sdhost.c26
-rw-r--r--hw/sd/aspeed_sdhci.c110
-rw-r--r--hw/sd/bcm2835_sdhost.c6
-rw-r--r--hw/sd/cadence_sdhci.c4
-rw-r--r--hw/sd/meson.build1
-rw-r--r--hw/sd/npcm7xx_sdhci.c4
-rw-r--r--hw/sd/omap_mmc.c309
-rw-r--r--hw/sd/pl181.c8
-rw-r--r--hw/sd/pxa2xx_mmci.c594
-rw-r--r--hw/sd/sd.c134
-rw-r--r--hw/sd/sdhci-internal.h2
-rw-r--r--hw/sd/sdhci-pci.c9
-rw-r--r--hw/sd/sdhci.c198
-rw-r--r--hw/sd/ssi-sd.c6
-rw-r--r--hw/sd/trace-events4
-rw-r--r--hw/sensor/adm1266.c2
-rw-r--r--hw/sensor/adm1272.c2
-rw-r--r--hw/sensor/dps310.c4
-rw-r--r--hw/sensor/emc141x.c8
-rw-r--r--hw/sensor/isl_pmbus_vr.c10
-rw-r--r--hw/sensor/lsm303dlhc_mag.c4
-rw-r--r--hw/sensor/max31785.c2
-rw-r--r--hw/sensor/max34451.c2
-rw-r--r--hw/sensor/tmp105.c75
-rw-r--r--hw/sensor/tmp421.c8
-rw-r--r--hw/sensor/trace-events6
-rw-r--r--hw/sensor/trace.h1
-rw-r--r--hw/sh4/Kconfig7
-rw-r--r--hw/sh4/meson.build1
-rw-r--r--hw/sh4/r2d.c45
-rw-r--r--hw/sh4/sh7750.c62
-rw-r--r--hw/sh4/shix.c86
-rw-r--r--hw/smbios/smbios.c5
-rw-r--r--hw/smbios/smbios_legacy.c2
-rw-r--r--hw/smbios/smbios_type_38.c7
-rw-r--r--hw/sparc/leon3.c8
-rw-r--r--hw/sparc/sun4m.c58
-rw-r--r--hw/sparc/sun4m_iommu.c14
-rw-r--r--hw/sparc64/Kconfig1
-rw-r--r--hw/sparc64/niagara.c10
-rw-r--r--hw/sparc64/sparc64.c2
-rw-r--r--hw/sparc64/sun4u.c52
-rw-r--r--hw/sparc64/sun4u_iommu.c9
-rw-r--r--hw/ssi/Kconfig4
-rw-r--r--hw/ssi/allwinner-a10-spi.c561
-rw-r--r--hw/ssi/aspeed_smc.c88
-rw-r--r--hw/ssi/bcm2835_spi.c4
-rw-r--r--hw/ssi/ibex_spi_host.c8
-rw-r--r--hw/ssi/imx_spi.c4
-rw-r--r--hw/ssi/meson.build2
-rw-r--r--hw/ssi/mss-spi.c4
-rw-r--r--hw/ssi/npcm7xx_fiu.c21
-rw-r--r--hw/ssi/npcm_pspi.c2
-rw-r--r--hw/ssi/omap_spi.c380
-rw-r--r--hw/ssi/pl022.c4
-rw-r--r--hw/ssi/pnv_spi.c375
-rw-r--r--hw/ssi/sifive_spi.c7
-rw-r--r--hw/ssi/ssi.c7
-rw-r--r--hw/ssi/stm32f2xx_spi.c4
-rw-r--r--hw/ssi/trace-events10
-rw-r--r--hw/ssi/xilinx_spi.c39
-rw-r--r--hw/ssi/xilinx_spips.c22
-rw-r--r--hw/ssi/xlnx-versal-ospi.c7
-rw-r--r--hw/timer/Kconfig9
-rw-r--r--hw/timer/a9gtimer.c9
-rw-r--r--hw/timer/allwinner-a10-pit.c9
-rw-r--r--hw/timer/arm_mptimer.c7
-rw-r--r--hw/timer/arm_timer.c5
-rw-r--r--hw/timer/armv7m_systick.c4
-rw-r--r--hw/timer/aspeed_timer.c293
-rw-r--r--hw/timer/avr_timer16.c7
-rw-r--r--hw/timer/bcm2835_systmr.c4
-rw-r--r--hw/timer/cadence_ttc.c2
-rw-r--r--hw/timer/cmsdk-apb-dualtimer.c4
-rw-r--r--hw/timer/cmsdk-apb-timer.c4
-rw-r--r--hw/timer/digic-timer.c4
-rw-r--r--hw/timer/etraxfs_timer.c407
-rw-r--r--hw/timer/exynos4210_mct.c6
-rw-r--r--hw/timer/exynos4210_pwm.c4
-rw-r--r--hw/timer/grlib_gptimer.c7
-rw-r--r--hw/timer/hpet.c248
-rw-r--r--hw/timer/i8254.c4
-rw-r--r--hw/timer/i8254_common.c5
-rw-r--r--hw/timer/ibex_timer.c7
-rw-r--r--hw/timer/imx_epit.c4
-rw-r--r--hw/timer/imx_gpt.c51
-rw-r--r--hw/timer/meson.build7
-rw-r--r--hw/timer/mss-timer.c5
-rw-r--r--hw/timer/npcm7xx_timer.c2
-rw-r--r--hw/timer/nrf51_timer.c7
-rw-r--r--hw/timer/omap_gptimer.c512
-rw-r--r--hw/timer/omap_synctimer.c110
-rw-r--r--hw/timer/pxa2xx_timer.c116
-rw-r--r--hw/timer/renesas_cmt.c7
-rw-r--r--hw/timer/renesas_tmr.c7
-rw-r--r--hw/timer/sh_timer.c2
-rw-r--r--hw/timer/sifive_pwm.c7
-rw-r--r--hw/timer/slavio_timer.c7
-rw-r--r--hw/timer/sse-counter.c4
-rw-r--r--hw/timer/sse-timer.c7
-rw-r--r--hw/timer/stellaris-gptm.c2
-rw-r--r--hw/timer/stm32f2xx_timer.c7
-rw-r--r--hw/timer/trace-events8
-rw-r--r--hw/timer/xilinx_timer.c46
-rw-r--r--hw/tpm/tpm_crb.c17
-rw-r--r--hw/tpm/tpm_ppi.c2
-rw-r--r--hw/tpm/tpm_ppi.h2
-rw-r--r--hw/tpm/tpm_prop.h2
-rw-r--r--hw/tpm/tpm_spapr.c12
-rw-r--r--hw/tpm/tpm_tis.h2
-rw-r--r--hw/tpm/tpm_tis_common.c4
-rw-r--r--hw/tpm/tpm_tis_i2c.c13
-rw-r--r--hw/tpm/tpm_tis_isa.c9
-rw-r--r--hw/tpm/tpm_tis_sysbus.c12
-rw-r--r--hw/tricore/tc27x_soc.c9
-rw-r--r--hw/tricore/triboard.c10
-rw-r--r--hw/tricore/tricore_testboard.c2
-rw-r--r--hw/tricore/tricore_testdevice.c11
-rw-r--r--hw/uefi/Kconfig3
-rw-r--r--hw/uefi/LIMITATIONS.md7
-rw-r--r--hw/uefi/hardware-info.c31
-rw-r--r--hw/uefi/meson.build21
-rw-r--r--hw/uefi/trace-events17
-rw-r--r--hw/uefi/var-service-auth.c361
-rw-r--r--hw/uefi/var-service-core.c322
-rw-r--r--hw/uefi/var-service-guid.c99
-rw-r--r--hw/uefi/var-service-json.c257
-rw-r--r--hw/uefi/var-service-pkcs7-stub.c16
-rw-r--r--hw/uefi/var-service-pkcs7.c436
-rw-r--r--hw/uefi/var-service-policy.c370
-rw-r--r--hw/uefi/var-service-siglist.c212
-rw-r--r--hw/uefi/var-service-sysbus.c124
-rw-r--r--hw/uefi/var-service-utils.c241
-rw-r--r--hw/uefi/var-service-vars.c725
-rw-r--r--hw/ufs/lu.c9
-rw-r--r--hw/ufs/ufs.c126
-rw-r--r--hw/ufs/ufs.h3
-rw-r--r--hw/usb/Kconfig12
-rw-r--r--hw/usb/bus-stub.c2
-rw-r--r--hw/usb/bus.c16
-rw-r--r--hw/usb/canokey.c11
-rw-r--r--hw/usb/canokey.h4
-rw-r--r--hw/usb/ccid-card-emulated.c5
-rw-r--r--hw/usb/ccid-card-passthru.c5
-rw-r--r--hw/usb/chipidea.c2
-rw-r--r--hw/usb/dev-audio.c5
-rw-r--r--hw/usb/dev-hid.c17
-rw-r--r--hw/usb/dev-hub.c6
-rw-r--r--hw/usb/dev-mtp.c7
-rw-r--r--hw/usb/dev-network.c7
-rw-r--r--hw/usb/dev-serial.c16
-rw-r--r--hw/usb/dev-smartcard-reader.c13
-rw-r--r--hw/usb/dev-storage-bot.c2
-rw-r--r--hw/usb/dev-storage-classic.c9
-rw-r--r--hw/usb/dev-storage.c19
-rw-r--r--hw/usb/dev-uas.c6
-rw-r--r--hw/usb/dev-wacom.c2
-rw-r--r--hw/usb/hcd-dwc2.c5
-rw-r--r--hw/usb/hcd-dwc2.h2
-rw-r--r--hw/usb/hcd-dwc3.c12
-rw-r--r--hw/usb/hcd-ehci-pci.c15
-rw-r--r--hw/usb/hcd-ehci-sysbus.c139
-rw-r--r--hw/usb/hcd-ehci.c5
-rw-r--r--hw/usb/hcd-ehci.h2
-rw-r--r--hw/usb/hcd-musb.c1553
-rw-r--r--hw/usb/hcd-ohci-pci.c9
-rw-r--r--hw/usb/hcd-ohci-sysbus.c7
-rw-r--r--hw/usb/hcd-ohci.c2
-rw-r--r--hw/usb/hcd-ohci.h2
-rw-r--r--hw/usb/hcd-uhci.c142
-rw-r--r--hw/usb/hcd-uhci.h4
-rw-r--r--hw/usb/hcd-xhci-nec.c12
-rw-r--r--hw/usb/hcd-xhci-pci.c41
-rw-r--r--hw/usb/hcd-xhci-pci.h1
-rw-r--r--hw/usb/hcd-xhci-sysbus.c7
-rw-r--r--hw/usb/hcd-xhci.c50
-rw-r--r--hw/usb/hcd-xhci.h7
-rw-r--r--hw/usb/host-libusb.c9
-rw-r--r--hw/usb/imx-usb-phy.c4
-rw-r--r--hw/usb/libhw.c2
-rw-r--r--hw/usb/meson.build4
-rw-r--r--hw/usb/redirect.c9
-rw-r--r--hw/usb/tusb6010.c850
-rw-r--r--hw/usb/u2f-emulated.c5
-rw-r--r--hw/usb/u2f-passthru.c5
-rw-r--r--hw/usb/u2f.c2
-rw-r--r--hw/usb/xen-usb.c10
-rw-r--r--hw/usb/xlnx-usb-subsystem.c2
-rw-r--r--hw/usb/xlnx-versal-usb2-ctrl-regs.c2
-rw-r--r--hw/vfio-user/Kconfig7
-rw-r--r--hw/vfio-user/container.c370
-rw-r--r--hw/vfio-user/container.h23
-rw-r--r--hw/vfio-user/device.c441
-rw-r--r--hw/vfio-user/device.h24
-rw-r--r--hw/vfio-user/meson.build11
-rw-r--r--hw/vfio-user/pci.c475
-rw-r--r--hw/vfio-user/protocol.h242
-rw-r--r--hw/vfio-user/proxy.c1356
-rw-r--r--hw/vfio-user/proxy.h135
-rw-r--r--hw/vfio-user/trace-events20
-rw-r--r--hw/vfio-user/trace.h4
-rw-r--r--hw/vfio/Kconfig2
-rw-r--r--hw/vfio/amd-xgbe.c6
-rw-r--r--hw/vfio/ap.c139
-rw-r--r--hw/vfio/calxeda-xgmac.c6
-rw-r--r--hw/vfio/ccw.c94
-rw-r--r--hw/vfio/container-base.c210
-rw-r--r--hw/vfio/container.c428
-rw-r--r--hw/vfio/cpr-legacy.c287
-rw-r--r--hw/vfio/cpr.c41
-rw-r--r--hw/vfio/device.c576
-rw-r--r--hw/vfio/display.c18
-rw-r--r--hw/vfio/helpers.c664
-rw-r--r--hw/vfio/igd.c751
-rw-r--r--hw/vfio/iommufd.c144
-rw-r--r--hw/vfio/listener.c (renamed from hw/vfio/common.c)742
-rw-r--r--hw/vfio/meson.build31
-rw-r--r--hw/vfio/migration-multifd.c685
-rw-r--r--hw/vfio/migration-multifd.h34
-rw-r--r--hw/vfio/migration.c237
-rw-r--r--hw/vfio/pci-quirks.c117
-rw-r--r--hw/vfio/pci-quirks.h72
-rw-r--r--hw/vfio/pci.c1008
-rw-r--r--hw/vfio/pci.h51
-rw-r--r--hw/vfio/platform.c64
-rw-r--r--hw/vfio/region.c403
-rw-r--r--hw/vfio/spapr.c91
-rw-r--r--hw/vfio/trace-events71
-rw-r--r--hw/vfio/trace.h3
-rw-r--r--hw/vfio/vfio-display.h42
-rw-r--r--hw/vfio/vfio-helpers.h35
-rw-r--r--hw/vfio/vfio-iommufd.h34
-rw-r--r--hw/vfio/vfio-listener.h15
-rw-r--r--hw/vfio/vfio-migration-internal.h74
-rw-r--r--hw/virtio/Kconfig18
-rw-r--r--hw/virtio/cbor-helpers.c321
-rw-r--r--hw/virtio/iothread-vq-mapping.c131
-rw-r--r--hw/virtio/meson.build6
-rw-r--r--hw/virtio/trace-events2
-rw-r--r--hw/virtio/vdpa-dev-pci.c8
-rw-r--r--hw/virtio/vdpa-dev.c14
-rw-r--r--hw/virtio/vhost-iova-tree.c115
-rw-r--r--hw/virtio/vhost-iova-tree.h10
-rw-r--r--hw/virtio/vhost-scsi-pci.c5
-rw-r--r--hw/virtio/vhost-shadow-virtqueue.c79
-rw-r--r--hw/virtio/vhost-shadow-virtqueue.h5
-rw-r--r--hw/virtio/vhost-user-base.c25
-rw-r--r--hw/virtio/vhost-user-blk-pci.c5
-rw-r--r--hw/virtio/vhost-user-device-pci.c3
-rw-r--r--hw/virtio/vhost-user-device.c5
-rw-r--r--hw/virtio/vhost-user-fs-pci.c5
-rw-r--r--hw/virtio/vhost-user-fs.c31
-rw-r--r--hw/virtio/vhost-user-gpio-pci.c2
-rw-r--r--hw/virtio/vhost-user-gpio.c5
-rw-r--r--hw/virtio/vhost-user-i2c-pci.c2
-rw-r--r--hw/virtio/vhost-user-i2c.c5
-rw-r--r--hw/virtio/vhost-user-input.c5
-rw-r--r--hw/virtio/vhost-user-rng-pci.c5
-rw-r--r--hw/virtio/vhost-user-rng.c5
-rw-r--r--hw/virtio/vhost-user-scmi-pci.c2
-rw-r--r--hw/virtio/vhost-user-scmi.c34
-rw-r--r--hw/virtio/vhost-user-scsi-pci.c7
-rw-r--r--hw/virtio/vhost-user-snd-pci.c7
-rw-r--r--hw/virtio/vhost-user-snd.c23
-rw-r--r--hw/virtio/vhost-user-vsock-pci.c6
-rw-r--r--hw/virtio/vhost-user-vsock.c21
-rw-r--r--hw/virtio/vhost-user.c69
-rw-r--r--hw/virtio/vhost-vdpa.c160
-rw-r--r--hw/virtio/vhost-vsock-common.c17
-rw-r--r--hw/virtio/vhost-vsock-pci.c5
-rw-r--r--hw/virtio/vhost-vsock.c16
-rw-r--r--hw/virtio/vhost.c101
-rw-r--r--hw/virtio/virtio-9p-pci.c5
-rw-r--r--hw/virtio/virtio-acpi.c2
-rw-r--r--hw/virtio/virtio-balloon-pci.c14
-rw-r--r--hw/virtio/virtio-balloon.c58
-rw-r--r--hw/virtio/virtio-blk-pci.c5
-rw-r--r--hw/virtio/virtio-bus.c4
-rw-r--r--hw/virtio/virtio-crypto-pci.c5
-rw-r--r--hw/virtio/virtio-crypto.c52
-rw-r--r--hw/virtio/virtio-hmp-cmds.c2
-rw-r--r--hw/virtio/virtio-input-pci.c10
-rw-r--r--hw/virtio/virtio-iommu-pci.c5
-rw-r--r--hw/virtio/virtio-iommu.c30
-rw-r--r--hw/virtio/virtio-md-pci.c2
-rw-r--r--hw/virtio/virtio-mem-pci.c14
-rw-r--r--hw/virtio/virtio-mem.c203
-rw-r--r--hw/virtio/virtio-mmio.c13
-rw-r--r--hw/virtio/virtio-net-pci.c6
-rw-r--r--hw/virtio/virtio-nsm-pci.c73
-rw-r--r--hw/virtio/virtio-nsm.c1737
-rw-r--r--hw/virtio/virtio-pci.c116
-rw-r--r--hw/virtio/virtio-pmem-pci.c2
-rw-r--r--hw/virtio/virtio-pmem.c7
-rw-r--r--hw/virtio/virtio-qmp.c13
-rw-r--r--hw/virtio/virtio-rng-pci.c5
-rw-r--r--hw/virtio/virtio-rng.c14
-rw-r--r--hw/virtio/virtio-scsi-pci.c5
-rw-r--r--hw/virtio/virtio-serial-pci.c5
-rw-r--r--hw/virtio/virtio.c147
-rw-r--r--hw/vmapple/Kconfig34
-rw-r--r--hw/vmapple/aes.c581
-rw-r--r--hw/vmapple/bdif.c274
-rw-r--r--hw/vmapple/cfg.c195
-rw-r--r--hw/vmapple/meson.build7
-rw-r--r--hw/vmapple/trace-events21
-rw-r--r--hw/vmapple/trace.h2
-rw-r--r--hw/vmapple/virtio-blk.c205
-rw-r--r--hw/vmapple/vmapple.c618
-rw-r--r--hw/watchdog/allwinner-wdt.c10
-rw-r--r--hw/watchdog/cmsdk-apb-watchdog.c44
-rw-r--r--hw/watchdog/sbsa_gwdt.c12
-rw-r--r--hw/watchdog/spapr_watchdog.c2
-rw-r--r--hw/watchdog/watchdog.c6
-rw-r--r--hw/watchdog/wdt_aspeed.c39
-rw-r--r--hw/watchdog/wdt_diag288.c8
-rw-r--r--hw/watchdog/wdt_i6300esb.c8
-rw-r--r--hw/watchdog/wdt_ib700.c6
-rw-r--r--hw/watchdog/wdt_imx2.c10
-rw-r--r--hw/xen/meson.build4
-rw-r--r--hw/xen/trace-events6
-rw-r--r--hw/xen/xen-bus-helper.c37
-rw-r--r--hw/xen/xen-bus.c35
-rw-r--r--hw/xen/xen-hvm-common.c114
-rw-r--r--hw/xen/xen-legacy-backend.c50
-rw-r--r--hw/xen/xen-mapcache.c37
-rw-r--r--hw/xen/xen-pvh-common.c399
-rw-r--r--hw/xen/xen_devconfig.c12
-rw-r--r--hw/xen/xen_pt.c67
-rw-r--r--hw/xen/xen_pt_graphics.c4
-rw-r--r--hw/xen/xen_pvdev.c8
-rw-r--r--hw/xen/xen_stubs.c51
-rw-r--r--hw/xenpv/xen_machine_pv.c4
-rw-r--r--hw/xtensa/Kconfig2
-rw-r--r--hw/xtensa/bootparam.h1
-rw-r--r--hw/xtensa/pic_cpu.c1
-rw-r--r--hw/xtensa/sim.c9
-rw-r--r--hw/xtensa/virt.c6
-rw-r--r--hw/xtensa/xtensa_memory.c2
-rw-r--r--hw/xtensa/xtfpga.c44
1491 files changed, 61332 insertions, 58116 deletions
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 1b1f3b9..31e2162 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -766,16 +766,19 @@ out:
return err;
}
-static int local_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
+static int local_fid_fd(int fid_type, V9fsFidOpenState *fs)
{
- int err, fd;
-
if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
+ return dirfd(fs->dir.stream);
} else {
- fd = fs->fd;
+ return fs->fd;
}
+}
+
+static int local_fstat(FsContext *fs_ctx, int fid_type,
+ V9fsFidOpenState *fs, struct stat *stbuf)
+{
+ int err, fd = local_fid_fd(fid_type, fs);
err = fstat(fd, stbuf);
if (err) {
@@ -1039,6 +1042,14 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
return ret;
}
+static int local_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ int fd = local_fid_fd(fid_type, fs);
+
+ return ftruncate(fd, size);
+}
+
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
char *dirpath = g_path_get_dirname(fs_path->data);
@@ -1089,6 +1100,14 @@ out:
return ret;
}
+static int local_futimens(FsContext *s, int fid_type, V9fsFidOpenState *fs,
+ const struct timespec *times)
+{
+ int fd = local_fid_fd(fid_type, fs);
+
+ return qemu_futimens(fd, times);
+}
+
static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
int flags)
{
@@ -1167,13 +1186,7 @@ out:
static int local_fsync(FsContext *ctx, int fid_type,
V9fsFidOpenState *fs, int datasync)
{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
+ int fd = local_fid_fd(fid_type, fs);
if (datasync) {
return qemu_fdatasync(fd);
@@ -1538,6 +1551,9 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
"[remap|forbid|warn]\n");
return -1;
}
+ } else {
+ fse->export_flags &= ~V9FS_FORBID_MULTIDEVS;
+ fse->export_flags |= V9FS_REMAP_INODES;
}
if (!path) {
@@ -1572,6 +1588,13 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
return 0;
}
+static bool local_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs)
+{
+ return
+ (fid_type == P9_FID_FILE && fs->fd != -1) ||
+ (fid_type == P9_FID_DIR && fs->dir.stream != NULL);
+}
+
FileOperations local_ops = {
.parse_opts = local_parse_opts,
.init = local_init,
@@ -1609,4 +1632,7 @@ FileOperations local_ops = {
.name_to_path = local_name_to_path,
.renameat = local_renameat,
.unlinkat = local_unlinkat,
+ .has_valid_file_handle = local_has_valid_file_handle,
+ .ftruncate = local_ftruncate,
+ .futimens = local_futimens,
};
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
deleted file mode 100644
index 7aac49a..0000000
--- a/hw/9pfs/9p-proxy.c
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-/*
- * Not so fast! You might want to read the 9p developer docs first:
- * https://wiki.qemu.org/Documentation/9p
- */
-
-/*
- * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
- * removed in a future version of QEMU!
- */
-
-#include "qemu/osdep.h"
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "9p.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "qemu/option.h"
-#include "fsdev/qemu-fsdev.h"
-#include "9p-proxy.h"
-
-typedef struct V9fsProxy {
- int sockfd;
- QemuMutex mutex;
- struct iovec in_iovec;
- struct iovec out_iovec;
-} V9fsProxy;
-
-/*
- * Return received file descriptor on success in *status.
- * errno is also returned on *status (which will be < 0)
- * return < 0 on transport error.
- */
-static int v9fs_receivefd(int sockfd, int *status)
-{
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- int retval, data, fd;
- union MsgControl msg_control;
-
- iov.iov_base = &data;
- iov.iov_len = sizeof(data);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &msg_control;
- msg.msg_controllen = sizeof(msg_control);
-
- do {
- retval = recvmsg(sockfd, &msg, 0);
- } while (retval < 0 && errno == EINTR);
- if (retval <= 0) {
- return retval;
- }
- /*
- * data is set to V9FS_FD_VALID, if ancillary data is sent. If this
- * request doesn't need ancillary data (fd) or an error occurred,
- * data is set to negative errno value.
- */
- if (data != V9FS_FD_VALID) {
- *status = data;
- return 0;
- }
- /*
- * File descriptor (fd) is sent in the ancillary data. Check if we
- * indeed received it. One of the reasons to fail to receive it is if
- * we exceeded the maximum number of file descriptors!
- */
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS) {
- continue;
- }
- fd = *((int *)CMSG_DATA(cmsg));
- *status = fd;
- return 0;
- }
- *status = -ENFILE; /* Ancillary data sent but not received */
- return 0;
-}
-
-static ssize_t socket_read(int sockfd, void *buff, size_t size)
-{
- ssize_t retval, total = 0;
-
- while (size) {
- retval = read(sockfd, buff, size);
- if (retval == 0) {
- return -EIO;
- }
- if (retval < 0) {
- if (errno == EINTR) {
- continue;
- }
- return -errno;
- }
- size -= retval;
- buff += retval;
- total += retval;
- }
- return total;
-}
-
-/* Converts proxy_statfs to VFS statfs structure */
-static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs)
-{
- memset(stfs, 0, sizeof(*stfs));
- stfs->f_type = prstfs->f_type;
- stfs->f_bsize = prstfs->f_bsize;
- stfs->f_blocks = prstfs->f_blocks;
- stfs->f_bfree = prstfs->f_bfree;
- stfs->f_bavail = prstfs->f_bavail;
- stfs->f_files = prstfs->f_files;
- stfs->f_ffree = prstfs->f_ffree;
-#ifdef CONFIG_DARWIN
- /* f_namelen and f_frsize do not exist on Darwin */
- stfs->f_fsid.val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
- stfs->f_fsid.val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
-#else
- stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
- stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
- stfs->f_namelen = prstfs->f_namelen;
- stfs->f_frsize = prstfs->f_frsize;
-#endif
-}
-
-/* Converts proxy_stat structure to VFS stat structure */
-static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
-{
- memset(stbuf, 0, sizeof(*stbuf));
- stbuf->st_dev = prstat->st_dev;
- stbuf->st_ino = prstat->st_ino;
- stbuf->st_nlink = prstat->st_nlink;
- stbuf->st_mode = prstat->st_mode;
- stbuf->st_uid = prstat->st_uid;
- stbuf->st_gid = prstat->st_gid;
- stbuf->st_rdev = prstat->st_rdev;
- stbuf->st_size = prstat->st_size;
- stbuf->st_blksize = prstat->st_blksize;
- stbuf->st_blocks = prstat->st_blocks;
- stbuf->st_atime = prstat->st_atim_sec;
- stbuf->st_mtime = prstat->st_mtim_sec;
- stbuf->st_ctime = prstat->st_ctim_sec;
-#ifdef CONFIG_DARWIN
- stbuf->st_atimespec.tv_sec = prstat->st_atim_sec;
- stbuf->st_mtimespec.tv_sec = prstat->st_mtim_sec;
- stbuf->st_ctimespec.tv_sec = prstat->st_ctim_sec;
- stbuf->st_atimespec.tv_nsec = prstat->st_atim_nsec;
- stbuf->st_mtimespec.tv_nsec = prstat->st_mtim_nsec;
- stbuf->st_ctimespec.tv_nsec = prstat->st_ctim_nsec;
-#else
- stbuf->st_atim.tv_sec = prstat->st_atim_sec;
- stbuf->st_mtim.tv_sec = prstat->st_mtim_sec;
- stbuf->st_ctim.tv_sec = prstat->st_ctim_sec;
- stbuf->st_atim.tv_nsec = prstat->st_atim_nsec;
- stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec;
- stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec;
-#endif
-}
-
-/*
- * Response contains two parts
- * {header, data}
- * header.type == T_ERROR, data -> -errno
- * header.type == T_SUCCESS, data -> response
- * size of errno/response is given by header.size
- * returns < 0, on transport error. response is
- * valid only if status >= 0.
- */
-static int v9fs_receive_response(V9fsProxy *proxy, int type,
- int *status, void *response)
-{
- int retval;
- ProxyHeader header;
- struct iovec *reply = &proxy->in_iovec;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- assert(retval == 4 * 2);
- /*
- * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
- * return -ENOBUFS
- */
- if (header.size > PROXY_MAX_IO_SZ) {
- int count;
- while (header.size > 0) {
- count = MIN(PROXY_MAX_IO_SZ, header.size);
- count = socket_read(proxy->sockfd, reply->iov_base, count);
- if (count < 0) {
- return count;
- }
- header.size -= count;
- }
- *status = -ENOBUFS;
- return 0;
- }
-
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- /* there was an error during processing request */
- if (header.type == T_ERROR) {
- int ret;
- ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- assert(ret == 4);
- return 0;
- }
-
- switch (type) {
- case T_LSTAT: {
- ProxyStat prstat;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqdddqqqqqqqqqq", &prstat.st_dev,
- &prstat.st_ino, &prstat.st_nlink,
- &prstat.st_mode, &prstat.st_uid,
- &prstat.st_gid, &prstat.st_rdev,
- &prstat.st_size, &prstat.st_blksize,
- &prstat.st_blocks,
- &prstat.st_atim_sec, &prstat.st_atim_nsec,
- &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
- &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
- assert(retval == 8 * 3 + 4 * 3 + 8 * 10);
- prstat_to_stat(response, &prstat);
- break;
- }
- case T_STATFS: {
- ProxyStatFS prstfs;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqqqqqqqqq", &prstfs.f_type,
- &prstfs.f_bsize, &prstfs.f_blocks,
- &prstfs.f_bfree, &prstfs.f_bavail,
- &prstfs.f_files, &prstfs.f_ffree,
- &prstfs.f_fsid[0], &prstfs.f_fsid[1],
- &prstfs.f_namelen, &prstfs.f_frsize);
- assert(retval == 8 * 11);
- prstatfs_to_statfs(response, &prstfs);
- break;
- }
- case T_READLINK: {
- V9fsString target;
- v9fs_string_init(&target);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
- strcpy(response, target.data);
- v9fs_string_free(&target);
- break;
- }
- case T_LGETXATTR:
- case T_LLISTXATTR: {
- V9fsString xattr;
- v9fs_string_init(&xattr);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr);
- memcpy(response, xattr.data, xattr.size);
- v9fs_string_free(&xattr);
- break;
- }
- case T_GETVERSION:
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
- assert(retval == 8);
- break;
- default:
- return -1;
- }
- if (retval < 0) {
- *status = retval;
- }
- return 0;
-}
-
-/*
- * return < 0 on transport error.
- * *status is valid only if return >= 0
- */
-static int v9fs_receive_status(V9fsProxy *proxy,
- struct iovec *reply, int *status)
-{
- int retval;
- ProxyHeader header;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- assert(retval == 4 * 2);
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- assert(retval == 4);
- return 0;
-}
-
-/*
- * Proxy->header and proxy->request written to socket by QEMU process.
- * This request read by proxy helper process
- * returns 0 on success and -errno on error
- */
-static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
-{
- dev_t rdev;
- va_list ap;
- int size = 0;
- int retval = 0;
- uint64_t offset;
- ProxyHeader header = { 0, 0};
- struct timespec spec[2];
- int flags, mode, uid, gid;
- V9fsString *name, *value;
- V9fsString *path, *oldpath;
- struct iovec *iovec = NULL, *reply = NULL;
-
- qemu_mutex_lock(&proxy->mutex);
-
- if (proxy->sockfd == -1) {
- retval = -EIO;
- goto err_out;
- }
- iovec = &proxy->out_iovec;
- reply = &proxy->in_iovec;
- va_start(ap, response);
- switch (type) {
- case T_OPEN:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_OPEN;
- }
- break;
- case T_CREATE:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
- flags, mode, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CREATE;
- }
- break;
- case T_MKNOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- rdev = va_arg(ap, long int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
- uid, gid, path, mode, rdev);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKNOD;
- }
- break;
- case T_MKDIR:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
- uid, gid, path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKDIR;
- }
- break;
- case T_SYMLINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
- uid, gid, oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_SYMLINK;
- }
- break;
- case T_LINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
- oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LINK;
- }
- break;
- case T_LSTAT:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSTAT;
- }
- break;
- case T_READLINK:
- path = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size);
- if (retval > 0) {
- header.size = retval;
- header.type = T_READLINK;
- }
- break;
- case T_STATFS:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_STATFS;
- }
- break;
- case T_CHMOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHMOD;
- }
- break;
- case T_CHOWN:
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHOWN;
- }
- break;
- case T_TRUNCATE:
- path = va_arg(ap, V9fsString *);
- offset = va_arg(ap, uint64_t);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset);
- if (retval > 0) {
- header.size = retval;
- header.type = T_TRUNCATE;
- }
- break;
- case T_UTIME:
- path = va_arg(ap, V9fsString *);
- spec[0].tv_sec = va_arg(ap, long);
- spec[0].tv_nsec = va_arg(ap, long);
- spec[1].tv_sec = va_arg(ap, long);
- spec[1].tv_nsec = va_arg(ap, long);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path,
- spec[0].tv_sec, spec[1].tv_nsec,
- spec[1].tv_sec, spec[1].tv_nsec);
- if (retval > 0) {
- header.size = retval;
- header.type = T_UTIME;
- }
- break;
- case T_RENAME:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_RENAME;
- }
- break;
- case T_REMOVE:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_REMOVE;
- }
- break;
- case T_LGETXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ,
- "dss", size, path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LGETXATTR;
- }
- break;
- case T_LLISTXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LLISTXATTR;
- }
- break;
- case T_LSETXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- value = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd",
- path, name, value, size, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSETXATTR;
- }
- break;
- case T_LREMOVEXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LREMOVEXATTR;
- }
- break;
- case T_GETVERSION:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_GETVERSION;
- }
- break;
- default:
- error_report("Invalid type %d", type);
- retval = -EINVAL;
- break;
- }
- va_end(ap);
-
- if (retval < 0) {
- goto err_out;
- }
-
- /* marshal the header details */
- retval = proxy_marshal(iovec, 0, "dd", header.type, header.size);
- assert(retval == 4 * 2);
- header.size += PROXY_HDR_SZ;
-
- retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size);
- if (retval != header.size) {
- goto close_error;
- }
-
- switch (type) {
- case T_OPEN:
- case T_CREATE:
- /*
- * A file descriptor is returned as response for
- * T_OPEN,T_CREATE on success
- */
- if (v9fs_receivefd(proxy->sockfd, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_MKNOD:
- case T_MKDIR:
- case T_SYMLINK:
- case T_LINK:
- case T_CHMOD:
- case T_CHOWN:
- case T_RENAME:
- case T_TRUNCATE:
- case T_UTIME:
- case T_REMOVE:
- case T_LSETXATTR:
- case T_LREMOVEXATTR:
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_LSTAT:
- case T_READLINK:
- case T_STATFS:
- case T_GETVERSION:
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- break;
- case T_LGETXATTR:
- case T_LLISTXATTR:
- if (!size) {
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- } else {
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- }
- break;
- }
-
-err_out:
- qemu_mutex_unlock(&proxy->mutex);
- return retval;
-
-close_error:
- close(proxy->sockfd);
- proxy->sockfd = -1;
- qemu_mutex_unlock(&proxy->mutex);
- return -EIO;
-}
-
-static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
- char *buf, size_t bufsz)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return strlen(buf);
-}
-
-static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return close(fs->fd);
-}
-
-static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return closedir(fs->dir.stream);
-}
-
-static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- int serrno, fd;
-
- fs->dir.stream = NULL;
- fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY);
- if (fd < 0) {
- errno = -fd;
- return -1;
- }
- fs->dir.stream = fdopendir(fd);
- if (!fs->dir.stream) {
- serrno = errno;
- close(fd);
- errno = serrno;
- return -1;
- }
- return 0;
-}
-
-static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- rewinddir(fs->dir.stream);
-}
-
-static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return telldir(fs->dir.stream);
-}
-
-static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- struct dirent *entry;
- entry = readdir(fs->dir.stream);
-#ifdef CONFIG_DARWIN
- if (!entry) {
- return NULL;
- }
- int td;
- td = telldir(fs->dir.stream);
- /* If telldir fails, fail the entire readdir call */
- if (td < 0) {
- return NULL;
- }
- entry->d_seekoff = td;
-#endif
- return entry;
-}
-
-static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- seekdir(fs->dir.stream, off);
-}
-
-static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-#ifdef CONFIG_PREADV
- ret = preadv(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = readv(fs->fd, iov, iovcnt);
- }
-#endif
- return ret;
-}
-
-static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-
-#ifdef CONFIG_PREADV
- ret = pwritev(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = writev(fs->fd, iov, iovcnt);
- }
-#endif
-#ifdef CONFIG_SYNC_FILE_RANGE
- if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
- /*
- * Initiate a writeback. This is not a data integrity sync.
- * We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is specified.
- */
- sync_file_range(fs->fd, offset, ret,
- SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
- }
-#endif
- return ret;
-}
-
-static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path,
- credp->fc_mode);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname,
- credp->fc_mode, credp->fc_rdev,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname,
- credp->fc_mode, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
- return fstat(fd, stbuf);
-}
-
-static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp, V9fsFidOpenState *fs)
-{
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags,
- credp->fc_mode, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *dir_path, const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname, target;
-
- v9fs_string_init(&fullname);
- v9fs_string_init(&target);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- v9fs_string_sprintf(&target, "%s", oldpath);
-
- retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- v9fs_string_free(&target);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
- V9fsPath *dirpath, const char *name)
-{
- int retval;
- V9fsString newpath;
-
- v9fs_string_init(&newpath);
- v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
-
- retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath);
- v9fs_string_free(&newpath);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
-{
- int retval;
-
- retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return 0;
-}
-
-static int proxy_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- int retval;
- V9fsString oldname, newname;
-
- v9fs_string_init(&oldname);
- v9fs_string_init(&newname);
-
- v9fs_string_sprintf(&oldname, "%s", oldpath);
- v9fs_string_sprintf(&newname, "%s", newpath);
- retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname);
- v9fs_string_free(&oldname);
- v9fs_string_free(&newname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path,
- credp->fc_uid, credp->fc_gid);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
- const struct timespec *buf)
-{
- int retval;
- retval = v9fs_request(s->private, T_UTIME, NULL, fs_path,
- buf[0].tv_sec, buf[0].tv_nsec,
- buf[1].tv_sec, buf[1].tv_nsec);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_remove(FsContext *ctx, const char *path)
-{
- int retval;
- V9fsString name;
- v9fs_string_init(&name);
- v9fs_string_sprintf(&name, "%s", path);
- retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name);
- v9fs_string_free(&name);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
-
- if (datasync) {
- return qemu_fdatasync(fd);
- } else {
- return fsync(fd);
- }
-}
-
-static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
-{
- int retval;
- retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name, void *value, size_t size)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path,
- &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
- void *value, size_t size)
-{
- int retval;
- retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
- void *value, size_t size, int flags)
-{
- int retval;
- V9fsString xname, xvalue;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
-
- v9fs_string_init(&xvalue);
- xvalue.size = size;
- xvalue.data = g_malloc(size);
- memcpy(xvalue.data, value, size);
-
- retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname,
- &xvalue, size, flags);
- v9fs_string_free(&xname);
- v9fs_string_free(&xvalue);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- if (dir_path) {
- v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
- } else {
- v9fs_path_sprintf(target, "%s", name);
- }
- return 0;
-}
-
-static int proxy_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- int ret;
- V9fsString old_full_name, new_full_name;
-
- v9fs_string_init(&old_full_name);
- v9fs_string_init(&new_full_name);
-
- v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
- v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
-
- ret = proxy_rename(ctx, old_full_name.data, new_full_name.data);
- v9fs_string_free(&old_full_name);
- v9fs_string_free(&new_full_name);
- return ret;
-}
-
-static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- int ret;
- V9fsString fullname;
- v9fs_string_init(&fullname);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
- ret = proxy_remove(ctx, fullname.data);
- v9fs_string_free(&fullname);
-
- return ret;
-}
-
-static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
- mode_t st_mode, uint64_t *st_gen)
-{
- int err;
-
- /* Do not try to open special files like device nodes, fifos etc
- * we can get fd for regular files and directories only
- */
- if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
- errno = ENOTTY;
- return -1;
- }
- err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path);
- if (err < 0) {
- errno = -err;
- err = -1;
- }
- return err;
-}
-
-static int connect_namedsocket(const char *path, Error **errp)
-{
- int sockfd;
- struct sockaddr_un helper;
-
- if (strlen(path) >= sizeof(helper.sun_path)) {
- error_setg(errp, "socket name too long");
- return -1;
- }
- sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sockfd < 0) {
- error_setg_errno(errp, errno, "failed to create client socket");
- return -1;
- }
- strcpy(helper.sun_path, path);
- helper.sun_family = AF_UNIX;
- if (connect(sockfd, (struct sockaddr *)&helper, sizeof(helper)) < 0) {
- error_setg_errno(errp, errno, "failed to connect to '%s'", path);
- close(sockfd);
- return -1;
- }
-
- /* remove the socket for security reasons */
- unlink(path);
- return sockfd;
-}
-
-static void error_append_socket_sockfd_hint(Error *const *errp)
-{
- error_append_hint(errp, "Either specify socket=/some/path where /some/path"
- " points to a listening AF_UNIX socket or sock_fd=fd"
- " where fd is a file descriptor to a connected AF_UNIX"
- " socket\n");
-}
-
-static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp)
-{
- const char *socket = qemu_opt_get(opts, "socket");
- const char *sock_fd = qemu_opt_get(opts, "sock_fd");
-
- if (!socket && !sock_fd) {
- error_setg(errp, "both socket and sock_fd properties are missing");
- error_append_socket_sockfd_hint(errp);
- return -1;
- }
- if (socket && sock_fd) {
- error_setg(errp, "both socket and sock_fd properties are set");
- error_append_socket_sockfd_hint(errp);
- return -1;
- }
- if (socket) {
- fs->path = g_strdup(socket);
- fs->export_flags |= V9FS_PROXY_SOCK_NAME;
- } else {
- fs->path = g_strdup(sock_fd);
- fs->export_flags |= V9FS_PROXY_SOCK_FD;
- }
- return 0;
-}
-
-static int proxy_init(FsContext *ctx, Error **errp)
-{
- V9fsProxy *proxy = g_new(V9fsProxy, 1);
- int sock_id;
-
- if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- sock_id = connect_namedsocket(ctx->fs_root, errp);
- } else {
- sock_id = atoi(ctx->fs_root);
- if (sock_id < 0) {
- error_setg(errp, "socket descriptor not initialized");
- }
- }
- if (sock_id < 0) {
- g_free(proxy);
- return -1;
- }
- g_free(ctx->fs_root);
- ctx->fs_root = NULL;
-
- proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
- proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
-
- ctx->private = proxy;
- proxy->sockfd = sock_id;
- qemu_mutex_init(&proxy->mutex);
-
- ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
- ctx->exops.get_st_gen = proxy_ioc_getversion;
- return 0;
-}
-
-static void proxy_cleanup(FsContext *ctx)
-{
- V9fsProxy *proxy = ctx->private;
-
- if (!proxy) {
- return;
- }
-
- g_free(proxy->out_iovec.iov_base);
- g_free(proxy->in_iovec.iov_base);
- if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- close(proxy->sockfd);
- }
- g_free(proxy);
-}
-
-FileOperations proxy_ops = {
- .parse_opts = proxy_parse_opts,
- .init = proxy_init,
- .cleanup = proxy_cleanup,
- .lstat = proxy_lstat,
- .readlink = proxy_readlink,
- .close = proxy_close,
- .closedir = proxy_closedir,
- .open = proxy_open,
- .opendir = proxy_opendir,
- .rewinddir = proxy_rewinddir,
- .telldir = proxy_telldir,
- .readdir = proxy_readdir,
- .seekdir = proxy_seekdir,
- .preadv = proxy_preadv,
- .pwritev = proxy_pwritev,
- .chmod = proxy_chmod,
- .mknod = proxy_mknod,
- .mkdir = proxy_mkdir,
- .fstat = proxy_fstat,
- .open2 = proxy_open2,
- .symlink = proxy_symlink,
- .link = proxy_link,
- .truncate = proxy_truncate,
- .rename = proxy_rename,
- .chown = proxy_chown,
- .utimensat = proxy_utimensat,
- .remove = proxy_remove,
- .fsync = proxy_fsync,
- .statfs = proxy_statfs,
- .lgetxattr = proxy_lgetxattr,
- .llistxattr = proxy_llistxattr,
- .lsetxattr = proxy_lsetxattr,
- .lremovexattr = proxy_lremovexattr,
- .name_to_path = proxy_name_to_path,
- .renameat = proxy_renameat,
- .unlinkat = proxy_unlinkat,
-};
diff --git a/hw/9pfs/9p-proxy.h b/hw/9pfs/9p-proxy.h
deleted file mode 100644
index 9be4718..0000000
--- a/hw/9pfs/9p-proxy.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-/*
- * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
- * removed in a future version of QEMU!
- */
-
-#ifndef QEMU_9P_PROXY_H
-#define QEMU_9P_PROXY_H
-
-#define PROXY_MAX_IO_SZ (64 * 1024)
-#define V9FS_FD_VALID INT_MAX
-
-/*
- * proxy iovec only support one element and
- * marsha/unmarshal doesn't do little endian conversion.
- */
-#define proxy_unmarshal(in_sg, offset, fmt, args...) \
- v9fs_iov_unmarshal(in_sg, 1, offset, 0, fmt, ##args)
-#define proxy_marshal(out_sg, offset, fmt, args...) \
- v9fs_iov_marshal(out_sg, 1, offset, 0, fmt, ##args)
-
-union MsgControl {
- struct cmsghdr cmsg;
- char control[CMSG_SPACE(sizeof(int))];
-};
-
-typedef struct {
- uint32_t type;
- uint32_t size;
-} ProxyHeader;
-
-#define PROXY_HDR_SZ (sizeof(ProxyHeader))
-
-enum {
- T_SUCCESS = 0,
- T_ERROR,
- T_OPEN,
- T_CREATE,
- T_MKNOD,
- T_MKDIR,
- T_SYMLINK,
- T_LINK,
- T_LSTAT,
- T_READLINK,
- T_STATFS,
- T_CHMOD,
- T_CHOWN,
- T_TRUNCATE,
- T_UTIME,
- T_RENAME,
- T_REMOVE,
- T_LGETXATTR,
- T_LLISTXATTR,
- T_LSETXATTR,
- T_LREMOVEXATTR,
- T_GETVERSION,
-};
-
-typedef struct {
- uint64_t st_dev;
- uint64_t st_ino;
- uint64_t st_nlink;
- uint32_t st_mode;
- uint32_t st_uid;
- uint32_t st_gid;
- uint64_t st_rdev;
- uint64_t st_size;
- uint64_t st_blksize;
- uint64_t st_blocks;
- uint64_t st_atim_sec;
- uint64_t st_atim_nsec;
- uint64_t st_mtim_sec;
- uint64_t st_mtim_nsec;
- uint64_t st_ctim_sec;
- uint64_t st_ctim_nsec;
-} ProxyStat;
-
-typedef struct {
- uint64_t f_type;
- uint64_t f_bsize;
- uint64_t f_blocks;
- uint64_t f_bfree;
- uint64_t f_bavail;
- uint64_t f_files;
- uint64_t f_ffree;
- uint64_t f_fsid[2];
- uint64_t f_namelen;
- uint64_t f_frsize;
-} ProxyStatFS;
-#endif
diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index 0ac79a5..9cd1884 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -24,7 +24,7 @@
#include "qemu/rcu.h"
#include "qemu/rcu_queue.h"
#include "qemu/cutils.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
/* Root node for synth file system */
static V9fsSynthNode synth_root = {
@@ -356,6 +356,13 @@ static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
return -1;
}
+static int synth_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
{
errno = EPERM;
@@ -417,6 +424,13 @@ static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
return 0;
}
+static int synth_futimens(FsContext *fs_ctx, int fid_type, V9fsFidOpenState *fs,
+ const struct timespec *buf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
static int synth_remove(FsContext *ctx, const char *path)
{
errno = EPERM;
@@ -615,6 +629,11 @@ static int synth_init(FsContext *ctx, Error **errp)
return 0;
}
+static bool synth_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs)
+{
+ return false;
+}
+
FileOperations synth_ops = {
.init = synth_init,
.lstat = synth_lstat,
@@ -650,4 +669,7 @@ FileOperations synth_ops = {
.name_to_path = synth_name_to_path,
.renameat = synth_renameat,
.unlinkat = synth_unlinkat,
+ .has_valid_file_handle = synth_has_valid_file_handle,
+ .ftruncate = synth_ftruncate,
+ .futimens = synth_futimens,
};
diff --git a/hw/9pfs/9p-util-generic.c b/hw/9pfs/9p-util-generic.c
new file mode 100644
index 0000000..4c1e9c8
--- /dev/null
+++ b/hw/9pfs/9p-util-generic.c
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "9p-util.h"
+#include <glib/gstrfuncs.h>
+
+char *qemu_open_flags_tostr(int flags)
+{
+ int acc = flags & O_ACCMODE;
+ return g_strconcat(
+ (acc == O_WRONLY) ? "WRONLY" : (acc == O_RDONLY) ? "RDONLY" : "RDWR",
+ (flags & O_CREAT) ? "|CREAT" : "",
+ (flags & O_EXCL) ? "|EXCL" : "",
+ (flags & O_NOCTTY) ? "|NOCTTY" : "",
+ (flags & O_TRUNC) ? "|TRUNC" : "",
+ (flags & O_APPEND) ? "|APPEND" : "",
+ (flags & O_NONBLOCK) ? "|NONBLOCK" : "",
+ (flags & O_DSYNC) ? "|DSYNC" : "",
+ #ifdef O_DIRECT
+ (flags & O_DIRECT) ? "|DIRECT" : "",
+ #endif
+ (flags & O_LARGEFILE) ? "|LARGEFILE" : "",
+ (flags & O_DIRECTORY) ? "|DIRECTORY" : "",
+ (flags & O_NOFOLLOW) ? "|NOFOLLOW" : "",
+ #ifdef O_NOATIME
+ (flags & O_NOATIME) ? "|NOATIME" : "",
+ #endif
+ #ifdef O_CLOEXEC
+ (flags & O_CLOEXEC) ? "|CLOEXEC" : "",
+ #endif
+ #ifdef __O_SYNC
+ (flags & __O_SYNC) ? "|SYNC" : "",
+ #else
+ ((flags & O_SYNC) == O_SYNC) ? "|SYNC" : "",
+ #endif
+ #ifdef O_PATH
+ (flags & O_PATH) ? "|PATH" : "",
+ #endif
+ #ifdef __O_TMPFILE
+ (flags & __O_TMPFILE) ? "|TMPFILE" : "",
+ #elif defined(O_TMPFILE)
+ ((flags & O_TMPFILE) == O_TMPFILE) ? "|TMPFILE" : "",
+ #endif
+ /* O_NDELAY is usually just an alias of O_NONBLOCK */
+ #if defined(O_NDELAY) && O_NDELAY != O_NONBLOCK
+ (flags & O_NDELAY) ? "|NDELAY" : "",
+ #endif
+ NULL /* always last (required NULL termination) */
+ );
+}
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index 51c94b0..a1924fe 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -103,6 +103,7 @@ static inline int errno_to_dotl(int err) {
#define qemu_renameat renameat
#define qemu_utimensat utimensat
#define qemu_unlinkat unlinkat
+#define qemu_futimens futimens
static inline void close_preserve_errno(int fd)
{
@@ -177,20 +178,27 @@ again:
return -1;
}
- if (close_if_special_file(fd) < 0) {
- return -1;
- }
-
- serrno = errno;
- /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't
- * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat()
- * ignored it anyway.
- */
+ /* Only if O_PATH is not set ... */
if (!(flags & O_PATH_9P_UTIL)) {
+ /*
+ * Prevent I/O on special files (device files, etc.) on host side,
+ * however it is safe and required to allow opening them with O_PATH,
+ * as this is limited to (required) path based operations only.
+ */
+ if (close_if_special_file(fd) < 0) {
+ return -1;
+ }
+
+ serrno = errno;
+ /*
+ * O_NONBLOCK was only needed to open the file. Let's drop it. We don't
+ * do that with O_PATH since fcntl(F_SETFL) isn't supported, and
+ * openat() ignored it anyway.
+ */
ret = fcntl(fd, F_SETFL, flags);
assert(!ret);
+ errno = serrno;
}
- errno = serrno;
return fd;
}
@@ -260,4 +268,10 @@ int pthread_fchdir_np(int fd) __attribute__((weak_import));
#endif
int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
+/*
+ * Returns a newly allocated string presentation of open() flags, intended
+ * for debugging (tracing) purposes only.
+ */
+char *qemu_open_flags_tostr(int flags);
+
#endif
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index af636cf..8b001b9 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -434,16 +434,24 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
V9fsFidState *f;
GHashTableIter iter;
gpointer fid;
+ int err;
+ int nclosed = 0;
+
+ /* prevent multiple coroutines running this function simultaniously */
+ if (s->reclaiming) {
+ return;
+ }
+ s->reclaiming = true;
g_hash_table_iter_init(&iter, s->fids);
QSLIST_HEAD(, V9fsFidState) reclaim_list =
QSLIST_HEAD_INITIALIZER(reclaim_list);
+ /* Pick FIDs to be closed, collect them on reclaim_list. */
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &f)) {
/*
- * Unlink fids cannot be reclaimed. Check
- * for them and skip them. Also skip fids
+ * Unlinked fids cannot be reclaimed, skip those, and also skip fids
* currently being operated on.
*/
if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
@@ -493,23 +501,42 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
}
}
/*
- * Now close the fid in reclaim list. Free them if they
- * are already clunked.
+ * Close the picked FIDs altogether on a background I/O driver thread. Do
+ * this all at once to keep latency (i.e. amount of thread hops between main
+ * thread <-> fs driver background thread) as low as possible.
*/
+ v9fs_co_run_in_worker({
+ QSLIST_FOREACH(f, &reclaim_list, reclaim_next) {
+ err = (f->fid_type == P9_FID_DIR) ?
+ s->ops->closedir(&s->ctx, &f->fs_reclaim) :
+ s->ops->close(&s->ctx, &f->fs_reclaim);
+
+ /* 'man 2 close' suggests to ignore close() errors except of EBADF */
+ if (unlikely(err && errno == EBADF)) {
+ /*
+ * unexpected case as FIDs were picked above by having a valid
+ * file descriptor
+ */
+ error_report("9pfs: v9fs_reclaim_fd() WARNING: close() failed with EBADF");
+ } else {
+ /* total_open_fd must only be mutated on main thread */
+ nclosed++;
+ }
+ }
+ });
+ total_open_fd -= nclosed;
+ /* Free the closed FIDs. */
while (!QSLIST_EMPTY(&reclaim_list)) {
f = QSLIST_FIRST(&reclaim_list);
QSLIST_REMOVE(&reclaim_list, f, V9fsFidState, reclaim_next);
- if (f->fid_type == P9_FID_FILE) {
- v9fs_co_close(pdu, &f->fs_reclaim);
- } else if (f->fid_type == P9_FID_DIR) {
- v9fs_co_closedir(pdu, &f->fs_reclaim);
- }
/*
* Now drop the fid reference, free it
* if clunked.
*/
put_fid(pdu, f);
}
+
+ s->reclaiming = false;
}
/*
@@ -1574,6 +1601,11 @@ out_nofid:
pdu_complete(pdu, err);
}
+static bool fid_has_valid_file_handle(V9fsState *s, V9fsFidState *fidp)
+{
+ return s->ops->has_valid_file_handle(fidp->fid_type, &fidp->fs);
+}
+
static void coroutine_fn v9fs_getattr(void *opaque)
{
int32_t fid;
@@ -1596,11 +1628,11 @@ static void coroutine_fn v9fs_getattr(void *opaque)
retval = -ENOENT;
goto out_nofid;
}
- /*
- * Currently we only support BASIC fields in stat, so there is no
- * need to look at request_mask.
- */
- retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+ if (fid_has_valid_file_handle(pdu->s, fidp)) {
+ retval = v9fs_co_fstat(pdu, fidp, &stbuf);
+ } else {
+ retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+ }
if (retval < 0) {
goto out;
}
@@ -1703,7 +1735,11 @@ static void coroutine_fn v9fs_setattr(void *opaque)
} else {
times[1].tv_nsec = UTIME_OMIT;
}
- err = v9fs_co_utimensat(pdu, &fidp->path, times);
+ if (fid_has_valid_file_handle(pdu->s, fidp)) {
+ err = v9fs_co_futimens(pdu, fidp, times);
+ } else {
+ err = v9fs_co_utimensat(pdu, &fidp->path, times);
+ }
if (err < 0) {
goto out;
}
@@ -1728,7 +1764,11 @@ static void coroutine_fn v9fs_setattr(void *opaque)
}
}
if (v9iattr.valid & (P9_ATTR_SIZE)) {
- err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+ if (fid_has_valid_file_handle(pdu->s, fidp)) {
+ err = v9fs_co_ftruncate(pdu, fidp, v9iattr.size);
+ } else {
+ err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+ }
if (err < 0) {
goto out;
}
@@ -1772,6 +1812,21 @@ static bool same_stat_id(const struct stat *a, const struct stat *b)
return a->st_dev == b->st_dev && a->st_ino == b->st_ino;
}
+/*
+ * Returns a (newly allocated) comma-separated string presentation of the
+ * passed array for logging (tracing) purpose for trace event "v9fs_walk".
+ *
+ * It is caller's responsibility to free the returned string.
+ */
+static char *trace_v9fs_walk_wnames(V9fsString *wnames, size_t nwnames)
+{
+ g_autofree char **arr = g_malloc0_n(nwnames + 1, sizeof(char *));
+ for (size_t i = 0; i < nwnames; ++i) {
+ arr[i] = wnames[i].data;
+ }
+ return g_strjoinv(", ", arr);
+}
+
static void coroutine_fn v9fs_walk(void *opaque)
{
int name_idx, nwalked;
@@ -1785,6 +1840,7 @@ static void coroutine_fn v9fs_walk(void *opaque)
size_t offset = 7;
int32_t fid, newfid;
P9ARRAY_REF(V9fsString) wnames = NULL;
+ g_autofree char *trace_wnames = NULL;
V9fsFidState *fidp;
V9fsFidState *newfidp = NULL;
V9fsPDU *pdu = opaque;
@@ -1798,11 +1854,9 @@ static void coroutine_fn v9fs_walk(void *opaque)
}
offset += err;
- trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
-
if (nwnames > P9_MAXWELEM) {
err = -EINVAL;
- goto out_nofid;
+ goto out_nofid_nownames;
}
if (nwnames) {
P9ARRAY_NEW(V9fsString, wnames, nwnames);
@@ -1812,15 +1866,23 @@ static void coroutine_fn v9fs_walk(void *opaque)
for (i = 0; i < nwnames; i++) {
err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
if (err < 0) {
- goto out_nofid;
+ goto out_nofid_nownames;
}
if (name_is_illegal(wnames[i].data)) {
err = -ENOENT;
- goto out_nofid;
+ goto out_nofid_nownames;
}
offset += err;
}
+ if (trace_event_get_state_backends(TRACE_V9FS_WALK)) {
+ trace_wnames = trace_v9fs_walk_wnames(wnames, nwnames);
+ trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames,
+ trace_wnames);
+ }
+ } else {
+ trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames, "");
}
+
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
@@ -1955,7 +2017,11 @@ out:
}
v9fs_path_free(&dpath);
v9fs_path_free(&path);
+ goto out_pdu_complete;
+out_nofid_nownames:
+ trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames, "<?>");
out_nofid:
+out_pdu_complete:
pdu_complete(pdu, err);
}
@@ -1980,6 +2046,7 @@ static void coroutine_fn v9fs_open(void *opaque)
V9fsFidState *fidp;
V9fsPDU *pdu = opaque;
V9fsState *s = pdu->s;
+ g_autofree char *trace_oflags = NULL;
if (s->proto_version == V9FS_PROTO_2000L) {
err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
@@ -1991,7 +2058,13 @@ static void coroutine_fn v9fs_open(void *opaque)
if (err < 0) {
goto out_nofid;
}
- trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
+ if (trace_event_get_state_backends(TRACE_V9FS_OPEN)) {
+ trace_oflags = qemu_open_flags_tostr(
+ (s->proto_version == V9FS_PROTO_2000L) ?
+ dotl_to_open_flags(mode) : omode_to_uflags(mode)
+ );
+ trace_v9fs_open(pdu->tag, pdu->id, fid, mode, trace_oflags);
+ }
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
@@ -2587,6 +2660,11 @@ static void coroutine_fn v9fs_readdir(void *opaque)
retval = -EINVAL;
goto out_nofid;
}
+ if (fidp->fid_type != P9_FID_DIR) {
+ warn_report_once("9p: bad client: T_readdir on non-directory stream");
+ retval = -ENOTDIR;
+ goto out;
+ }
if (!fidp->fs.dir.stream) {
retval = -EINVAL;
goto out;
@@ -4284,6 +4362,8 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
s->ctx.fst = &fse->fst;
fsdev_throttle_init(s->ctx.fst);
+ s->reclaiming = false;
+
rc = 0;
out:
if (rc) {
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index a6f59ab..259ad32 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -280,7 +280,6 @@ struct V9fsFidState {
uid_t uid;
int ref;
bool clunked;
- QSIMPLEQ_ENTRY(V9fsFidState) next;
QSLIST_ENTRY(V9fsFidState) reclaim_next;
};
@@ -363,6 +362,7 @@ struct V9fsState {
uint64_t qp_ndevices; /* Amount of entries in qpd_table. */
uint16_t qp_affix_next;
uint64_t qp_fullpath_next;
+ bool reclaiming;
};
/* 9p2000.L open flags */
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 2068a47..bce7dd9 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -20,6 +20,7 @@
#include "fsdev/qemu-fsdev.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
+#include "qemu/error-report.h"
#include "coth.h"
#include "9p-xattr.h"
#include "9p-util.h"
@@ -353,7 +354,11 @@ int coroutine_fn v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
err = -errno;
}
});
- if (!err) {
+ /* 'man 2 close' suggests to ignore close() errors except of EBADF */
+ if (unlikely(err && errno == EBADF)) {
+ /* unexpected case as we should have checked for a valid file handle */
+ error_report("9pfs: WARNING: v9fs_co_closedir() failed with EBADF");
+ } else {
total_open_fd--;
}
return err;
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 71174c3..6e775c8 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -20,6 +20,7 @@
#include "fsdev/qemu-fsdev.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
+#include "qemu/error-report.h"
#include "coth.h"
int coroutine_fn v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
@@ -197,7 +198,11 @@ int coroutine_fn v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
err = -errno;
}
});
- if (!err) {
+ /* 'man 2 close' suggests to ignore close() errors except of EBADF */
+ if (unlikely(err && errno == EBADF)) {
+ /* unexpected case as we should have checked for a valid file handle */
+ error_report("9pfs: WARNING: v9fs_co_close() failed with EBADF");
+ } else {
total_open_fd--;
}
return err;
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 67e3ae5..12fa8c9 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -139,6 +139,25 @@ int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
return err;
}
+int coroutine_fn v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp,
+ struct timespec times[2])
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->futimens(&s->ctx, fidp->fid_type, &fidp->fs, times);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ return err;
+}
+
int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid,
gid_t gid)
{
@@ -184,6 +203,24 @@ int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
return err;
}
+int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size)
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->ftruncate(&s->ctx, fidp->fid_type, &fidp->fs, size);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ return err;
+}
+
int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp,
V9fsString *name, uid_t uid, gid_t gid,
dev_t dev, mode_t mode, struct stat *stbuf)
diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h
index 2c54249..7906fa7 100644
--- a/hw/9pfs/coth.h
+++ b/hw/9pfs/coth.h
@@ -71,8 +71,12 @@ int coroutine_fn v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *);
int coroutine_fn v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *);
int coroutine_fn v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
int coroutine_fn v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
+int coroutine_fn v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp,
+ struct timespec times[2]);
int coroutine_fn v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
int coroutine_fn v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
+int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp,
+ off_t size);
int coroutine_fn v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
int coroutine_fn v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
V9fsString *, void *, size_t);
diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build
index f1b62fa..d35d4f4 100644
--- a/hw/9pfs/meson.build
+++ b/hw/9pfs/meson.build
@@ -2,8 +2,8 @@ fs_ss = ss.source_set()
fs_ss.add(files(
'9p-local.c',
'9p-posix-acl.c',
- '9p-proxy.c',
'9p-synth.c',
+ '9p-util-generic.c',
'9p-xattr-user.c',
'9p-xattr.c',
'9p.c',
diff --git a/hw/9pfs/trace-events b/hw/9pfs/trace-events
index a12e55c..0e0fc37 100644
--- a/hw/9pfs/trace-events
+++ b/hw/9pfs/trace-events
@@ -11,9 +11,9 @@ v9fs_stat(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
v9fs_stat_return(uint16_t tag, uint8_t id, int32_t mode, int32_t atime, int32_t mtime, int64_t length) "tag %d id %d stat={mode %d atime %d mtime %d length %"PRId64"}"
v9fs_getattr(uint16_t tag, uint8_t id, int32_t fid, uint64_t request_mask) "tag %d id %d fid %d request_mask %"PRIu64
v9fs_getattr_return(uint16_t tag, uint8_t id, uint64_t result_mask, uint32_t mode, uint32_t uid, uint32_t gid) "tag %d id %d getattr={result_mask %"PRId64" mode %u uid %u gid %u}"
-v9fs_walk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames) "tag %d id %d fid %d newfid %d nwnames %d"
+v9fs_walk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames, const char* wnames) "tag=%d id=%d fid=%d newfid=%d nwnames=%d wnames={%s}"
v9fs_walk_return(uint16_t tag, uint8_t id, uint16_t nwnames, void* qids) "tag %d id %d nwnames %d qids %p"
-v9fs_open(uint16_t tag, uint8_t id, int32_t fid, int32_t mode) "tag %d id %d fid %d mode %d"
+v9fs_open(uint16_t tag, uint8_t id, int32_t fid, int32_t mode, const char* oflags) "tag=%d id=%d fid=%d mode=%d(%s)"
v9fs_open_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode, uint32_t gid) "tag %d id %d dfid %d flags %d mode %d gid %u"
v9fs_lcreate_return(uint16_t tag, uint8_t id, uint8_t type, uint32_t version, uint64_t path, int32_t iounit) "tag %u id %u qid={type %u version %u path %"PRIu64"} iounit %d"
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index efa41cf..81b91e4 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -26,7 +26,7 @@
#include "hw/virtio/virtio-access.h"
#include "qemu/iov.h"
#include "qemu/module.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
static void virtio_9p_push_and_notify(V9fsPDU *pdu)
{
@@ -243,13 +243,12 @@ static const VMStateDescription vmstate_virtio_9p = {
},
};
-static Property virtio_9p_properties[] = {
+static const Property virtio_9p_properties[] = {
DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag),
DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_9p_class_init(ObjectClass *klass, void *data)
+static void virtio_9p_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/Kconfig b/hw/Kconfig
index f7866e7..9e6c789 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -27,7 +27,6 @@ source nvme/Kconfig
source nvram/Kconfig
source pci-bridge/Kconfig
source pci-host/Kconfig
-source pcmcia/Kconfig
source pci/Kconfig
source remote/Kconfig
source rtc/Kconfig
@@ -38,10 +37,13 @@ source smbios/Kconfig
source ssi/Kconfig
source timer/Kconfig
source tpm/Kconfig
+source uefi/Kconfig
source ufs/Kconfig
source usb/Kconfig
source virtio/Kconfig
source vfio/Kconfig
+source vfio-user/Kconfig
+source vmapple/Kconfig
source xen/Kconfig
source watchdog/Kconfig
@@ -50,7 +52,6 @@ source arm/Kconfig
source cpu/Kconfig
source alpha/Kconfig
source avr/Kconfig
-source cris/Kconfig
source hppa/Kconfig
source i386/Kconfig
source loongarch/Kconfig
diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
index e07d320..1d4e9f0 100644
--- a/hw/acpi/Kconfig
+++ b/hw/acpi/Kconfig
@@ -60,6 +60,11 @@ config ACPI_VMGENID
default y
depends on PC
+config ACPI_VMCLOCK
+ bool
+ default y
+ depends on PC
+
config ACPI_VIOT
bool
depends on ACPI
diff --git a/hw/acpi/acpi-cpu-hotplug-stub.c b/hw/acpi/acpi-cpu-hotplug-stub.c
index c6c61bb..9872dd5 100644
--- a/hw/acpi/acpi-cpu-hotplug-stub.c
+++ b/hw/acpi/acpi-cpu-hotplug-stub.c
@@ -10,47 +10,39 @@ void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu,
CPUHotplugState *cpuhp_state,
uint16_t io_port)
{
- return;
}
void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
AcpiCpuHotplug *gpe_cpu, uint16_t base)
{
- return;
}
void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
CPUHotplugState *state, hwaddr base_addr)
{
- return;
}
void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list)
{
- return;
}
void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
CPUHotplugState *cpu_st, DeviceState *dev, Error **errp)
{
- return;
}
void legacy_acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
AcpiCpuHotplug *g, DeviceState *dev, Error **errp)
{
- return;
}
void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st,
DeviceState *dev, Error **errp)
{
- return;
}
void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
CPUHotplugState *cpu_st,
DeviceState *dev, Error **errp)
{
- return;
}
diff --git a/hw/acpi/acpi-mem-hotplug-stub.c b/hw/acpi/acpi-mem-hotplug-stub.c
index 73a076a..7ad0fdc 100644
--- a/hw/acpi/acpi-mem-hotplug-stub.c
+++ b/hw/acpi/acpi-mem-hotplug-stub.c
@@ -7,29 +7,24 @@ const VMStateDescription vmstate_memory_hotplug;
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
MemHotplugState *state, hwaddr io_base)
{
- return;
}
void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list)
{
- return;
}
void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
DeviceState *dev, Error **errp)
{
- return;
}
void acpi_memory_unplug_cb(MemHotplugState *mem_st,
DeviceState *dev, Error **errp)
{
- return;
}
void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev,
MemHotplugState *mem_st,
DeviceState *dev, Error **errp)
{
- return;
}
diff --git a/hw/acpi/acpi-nvdimm-stub.c b/hw/acpi/acpi-nvdimm-stub.c
index 8baff9b..65f491d 100644
--- a/hw/acpi/acpi-nvdimm-stub.c
+++ b/hw/acpi/acpi-nvdimm-stub.c
@@ -4,5 +4,4 @@
void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev)
{
- return;
}
diff --git a/hw/acpi/acpi-pci-hotplug-stub.c b/hw/acpi/acpi-pci-hotplug-stub.c
index dcee3ad..b7bc6e4 100644
--- a/hw/acpi/acpi-pci-hotplug-stub.c
+++ b/hw/acpi/acpi-pci-hotplug-stub.c
@@ -7,40 +7,34 @@ const VMStateDescription vmstate_acpi_pcihp_pci_status;
void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
MemoryRegion *address_space_io, uint16_t io_base)
{
- return;
}
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp)
{
- return;
}
void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- return;
}
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp)
{
- return;
}
void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
AcpiPciHpState *s, DeviceState *dev,
Error **errp)
{
- return;
}
void acpi_pcihp_reset(AcpiPciHpState *s)
{
- return;
}
-bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus)
+bool acpi_pcihp_is_hotpluggable_bus(AcpiPciHpState *s, BusState *bus)
{
return true;
}
diff --git a/hw/acpi/acpi-stub.c b/hw/acpi/acpi-stub.c
index e268ce9..fd0b62f 100644
--- a/hw/acpi/acpi-stub.c
+++ b/hw/acpi/acpi-stub.c
@@ -21,7 +21,15 @@
#include "qemu/osdep.h"
#include "hw/acpi/acpi.h"
+char unsigned *acpi_tables;
+size_t acpi_tables_len;
+
void acpi_table_add(const QemuOpts *opts, Error **errp)
{
g_assert_not_reached();
}
+
+bool acpi_builtin(void)
+{
+ return false;
+}
diff --git a/hw/acpi/acpi_generic_initiator.c b/hw/acpi/acpi_generic_initiator.c
deleted file mode 100644
index 17b9a05..0000000
--- a/hw/acpi/acpi_generic_initiator.c
+++ /dev/null
@@ -1,148 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved
- */
-
-#include "qemu/osdep.h"
-#include "hw/acpi/acpi_generic_initiator.h"
-#include "hw/acpi/aml-build.h"
-#include "hw/boards.h"
-#include "hw/pci/pci_device.h"
-#include "qemu/error-report.h"
-
-typedef struct AcpiGenericInitiatorClass {
- ObjectClass parent_class;
-} AcpiGenericInitiatorClass;
-
-OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
- ACPI_GENERIC_INITIATOR, OBJECT,
- { TYPE_USER_CREATABLE },
- { NULL })
-
-OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
-
-static void acpi_generic_initiator_init(Object *obj)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
-
- gi->node = MAX_NODES;
- gi->pci_dev = NULL;
-}
-
-static void acpi_generic_initiator_finalize(Object *obj)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
-
- g_free(gi->pci_dev);
-}
-
-static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
- Error **errp)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
-
- gi->pci_dev = g_strdup(val);
-}
-
-static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
- MachineState *ms = MACHINE(qdev_get_machine());
- uint32_t value;
-
- if (!visit_type_uint32(v, name, &value, errp)) {
- return;
- }
-
- if (value >= MAX_NODES) {
- error_printf("%s: Invalid NUMA node specified\n",
- TYPE_ACPI_GENERIC_INITIATOR);
- exit(1);
- }
-
- gi->node = value;
- ms->numa_state->nodes[gi->node].has_gi = true;
-}
-
-static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
-{
- object_class_property_add_str(oc, "pci-dev", NULL,
- acpi_generic_initiator_set_pci_device);
- object_class_property_add(oc, "node", "int", NULL,
- acpi_generic_initiator_set_node, NULL, NULL);
-}
-
-/*
- * ACPI 6.3:
- * Table 5-78 Generic Initiator Affinity Structure
- */
-static void
-build_srat_generic_pci_initiator_affinity(GArray *table_data, int node,
- PCIDeviceHandle *handle)
-{
- uint8_t index;
-
- build_append_int_noprefix(table_data, 5, 1); /* Type */
- build_append_int_noprefix(table_data, 32, 1); /* Length */
- build_append_int_noprefix(table_data, 0, 1); /* Reserved */
- build_append_int_noprefix(table_data, 1, 1); /* Device Handle Type: PCI */
- build_append_int_noprefix(table_data, node, 4); /* Proximity Domain */
-
- /* Device Handle - PCI */
- build_append_int_noprefix(table_data, handle->segment, 2);
- build_append_int_noprefix(table_data, handle->bdf, 2);
- for (index = 0; index < 12; index++) {
- build_append_int_noprefix(table_data, 0, 1);
- }
-
- build_append_int_noprefix(table_data, GEN_AFFINITY_ENABLED, 4); /* Flags */
- build_append_int_noprefix(table_data, 0, 4); /* Reserved */
-}
-
-static int build_all_acpi_generic_initiators(Object *obj, void *opaque)
-{
- MachineState *ms = MACHINE(qdev_get_machine());
- AcpiGenericInitiator *gi;
- GArray *table_data = opaque;
- PCIDeviceHandle dev_handle;
- PCIDevice *pci_dev;
- Object *o;
-
- if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
- return 0;
- }
-
- gi = ACPI_GENERIC_INITIATOR(obj);
- if (gi->node >= ms->numa_state->num_nodes) {
- error_printf("%s: Specified node %d is invalid.\n",
- TYPE_ACPI_GENERIC_INITIATOR, gi->node);
- exit(1);
- }
-
- o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
- if (!o) {
- error_printf("%s: Specified device must be a PCI device.\n",
- TYPE_ACPI_GENERIC_INITIATOR);
- exit(1);
- }
-
- pci_dev = PCI_DEVICE(o);
-
- dev_handle.segment = 0;
- dev_handle.bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)),
- pci_dev->devfn);
-
- build_srat_generic_pci_initiator_affinity(table_data,
- gi->node, &dev_handle);
-
- return 0;
-}
-
-void build_srat_generic_pci_initiator(GArray *table_data)
-{
- object_child_foreach_recursive(object_get_root(),
- build_all_acpi_generic_initiators,
- table_data);
-}
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 6d4517c..f8f93a9 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -24,7 +24,7 @@
#include "hw/acpi/aml-build.h"
#include "qemu/bswap.h"
#include "qemu/bitops.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#include "hw/boards.h"
#include "hw/acpi/tpm.h"
#include "hw/pci/pci_host.h"
@@ -534,8 +534,7 @@ void aml_append(Aml *parent_ctx, Aml *child)
case AML_NO_OPCODE:
break;
default:
- assert(0);
- break;
+ g_assert_not_reached();
}
build_append_array(parent_ctx->buf, buf);
build_free_array(buf);
@@ -1939,6 +1938,89 @@ void build_srat_memory(GArray *table_data, uint64_t base,
}
/*
+ * ACPI Spec Revision 6.3
+ * Table 5-80 Device Handle - PCI
+ */
+static void build_append_srat_pci_device_handle(GArray *table_data,
+ uint16_t segment,
+ uint8_t bus, uint8_t devfn)
+{
+ /* PCI segment number */
+ build_append_int_noprefix(table_data, segment, 2);
+ /* PCI Bus Device Function */
+ build_append_int_noprefix(table_data, bus, 1);
+ build_append_int_noprefix(table_data, devfn, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 12);
+}
+
+static void build_append_srat_acpi_device_handle(GArray *table_data,
+ const char *hid,
+ uint32_t uid)
+{
+ assert(strlen(hid) == 8);
+ /* Device Handle - ACPI */
+ for (int i = 0; i < 8; i++) {
+ build_append_int_noprefix(table_data, hid[i], 1);
+ }
+ build_append_int_noprefix(table_data, uid, 4);
+ build_append_int_noprefix(table_data, 0, 4);
+}
+
+/*
+ * ACPI spec, Revision 6.3
+ * 5.2.16.6 Generic Initiator Affinity Structure
+ * With PCI Device Handle.
+ */
+void build_srat_pci_generic_initiator(GArray *table_data, uint32_t node,
+ uint16_t segment, uint8_t bus,
+ uint8_t devfn)
+{
+ /* Type */
+ build_append_int_noprefix(table_data, 5, 1);
+ /* Length */
+ build_append_int_noprefix(table_data, 32, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 1);
+ /* Device Handle Type: PCI */
+ build_append_int_noprefix(table_data, 1, 1);
+ /* Proximity Domain */
+ build_append_int_noprefix(table_data, node, 4);
+ /* Device Handle */
+ build_append_srat_pci_device_handle(table_data, segment, bus, devfn);
+ /* Flags - GI Enabled */
+ build_append_int_noprefix(table_data, 1, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+}
+
+/*
+ * ACPI spec, Revision 6.5
+ * 5.2.16.7 Generic Port Affinity Structure
+ * With ACPI Device Handle.
+ */
+void build_srat_acpi_generic_port(GArray *table_data, uint32_t node,
+ const char *hid, uint32_t uid)
+{
+ /* Type */
+ build_append_int_noprefix(table_data, 6, 1);
+ /* Length */
+ build_append_int_noprefix(table_data, 32, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 1);
+ /* Device Handle Type: ACPI */
+ build_append_int_noprefix(table_data, 0, 1);
+ /* Proximity Domain */
+ build_append_int_noprefix(table_data, node, 4);
+ /* Device Handle */
+ build_append_srat_acpi_device_handle(table_data, hid, uid);
+ /* Flags - GP Enabled */
+ build_append_int_noprefix(table_data, 1, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+}
+
+/*
* ACPI spec 5.2.17 System Locality Distance Information Table
* (Revision 2.0 or later)
*/
@@ -1996,7 +2078,7 @@ static void build_processor_hierarchy_node(GArray *tbl, uint32_t flags,
void build_spcr(GArray *table_data, BIOSLinker *linker,
const AcpiSpcrData *f, const uint8_t rev,
- const char *oem_id, const char *oem_table_id)
+ const char *oem_id, const char *oem_table_id, const char *name)
{
AcpiTable table = { .sig = "SPCR", .rev = rev, .oem_id = oem_id,
.oem_table_id = oem_table_id };
@@ -2042,9 +2124,21 @@ void build_spcr(GArray *table_data, BIOSLinker *linker,
build_append_int_noprefix(table_data, f->pci_flags, 4);
/* PCI Segment */
build_append_int_noprefix(table_data, f->pci_segment, 1);
- /* Reserved */
- build_append_int_noprefix(table_data, 0, 4);
-
+ if (rev < 4) {
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+ } else {
+ /* UartClkFreq */
+ build_append_int_noprefix(table_data, f->uart_clk_freq, 4);
+ /* PreciseBaudrate */
+ build_append_int_noprefix(table_data, f->precise_baudrate, 4);
+ /* NameSpaceStringLength */
+ build_append_int_noprefix(table_data, f->namespace_string_length, 2);
+ /* NameSpaceStringOffset */
+ build_append_int_noprefix(table_data, f->namespace_string_offset, 2);
+ /* NamespaceString[] */
+ g_array_append_vals(table_data, name, f->namespace_string_length);
+ }
acpi_table_end(linker, &table);
}
/*
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
index ec5e127..58f8964 100644
--- a/hw/acpi/core.c
+++ b/hw/acpi/core.c
@@ -31,7 +31,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/option.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "trace.h"
struct acpi_table_header {
@@ -78,6 +78,11 @@ static void acpi_register_config(void)
opts_init(acpi_register_config);
+bool acpi_builtin(void)
+{
+ return true;
+}
+
static int acpi_checksum(const uint8_t *data, int len)
{
int sum, i;
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 5cb60ca..6f1ae79 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -5,7 +5,7 @@
#include "qapi/error.h"
#include "qapi/qapi-events-acpi.h"
#include "trace.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
#define ACPI_CPU_FLAGS_OFFSET_RW 4
@@ -235,8 +235,8 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev)
{
- CPUClass *k = CPU_GET_CLASS(dev);
- uint64_t cpu_arch_id = k->get_arch_id(CPU(dev));
+ CPUState *cpu = CPU(dev);
+ uint64_t cpu_arch_id = cpu->cc->get_arch_id(cpu);
int i;
for (i = 0; i < cpu_st->dev_count; i++) {
@@ -327,6 +327,7 @@ const VMStateDescription vmstate_cpu_hotplug = {
#define CPU_EJECT_METHOD "CEJ0"
#define CPU_OST_METHOD "COST"
#define CPU_ADDED_LIST "CNEW"
+#define CPU_EJ_LIST "CEJL"
#define CPU_ENABLED "CPEN"
#define CPU_SELECTOR "CSEL"
@@ -488,7 +489,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
method = aml_method(CPU_SCAN_METHOD, 0, AML_SERIALIZED);
{
const uint8_t max_cpus_per_pass = 255;
- Aml *else_ctx;
Aml *while_ctx, *while_ctx2;
Aml *has_event = aml_local(0);
Aml *dev_chk = aml_int(1);
@@ -499,6 +499,8 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
Aml *uid = aml_local(3);
Aml *has_job = aml_local(4);
Aml *new_cpus = aml_name(CPU_ADDED_LIST);
+ Aml *ej_cpus = aml_name(CPU_EJ_LIST);
+ Aml *num_ej_cpus = aml_local(5);
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
@@ -513,6 +515,8 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
*/
aml_append(method, aml_name_decl(CPU_ADDED_LIST,
aml_package(max_cpus_per_pass)));
+ aml_append(method, aml_name_decl(CPU_EJ_LIST,
+ aml_package(max_cpus_per_pass)));
aml_append(method, aml_store(zero, uid));
aml_append(method, aml_store(one, has_job));
@@ -527,6 +531,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(while_ctx2, aml_store(one, has_event));
aml_append(while_ctx2, aml_store(zero, num_added_cpus));
+ aml_append(while_ctx2, aml_store(zero, num_ej_cpus));
/*
* Scan CPUs, till there are CPUs with events or
@@ -559,8 +564,10 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
* if CPU_ADDED_LIST is full, exit inner loop and process
* collected CPUs
*/
- ifctx = aml_if(
- aml_equal(num_added_cpus, aml_int(max_cpus_per_pass)));
+ ifctx = aml_if(aml_lor(
+ aml_equal(num_added_cpus, aml_int(max_cpus_per_pass)),
+ aml_equal(num_ej_cpus, aml_int(max_cpus_per_pass))
+ ));
{
aml_append(ifctx, aml_store(one, has_job));
aml_append(ifctx, aml_break());
@@ -577,16 +584,16 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(ifctx, aml_store(one, has_event));
}
aml_append(while_ctx, ifctx);
- else_ctx = aml_else();
+
ifctx = aml_if(aml_equal(rm_evt, one));
{
- aml_append(ifctx,
- aml_call2(CPU_NOTIFY_METHOD, uid, eject_req));
- aml_append(ifctx, aml_store(one, rm_evt));
+ /* cache to be removed CPUs to Notify later */
+ aml_append(ifctx, aml_store(uid,
+ aml_index(ej_cpus, num_ej_cpus)));
+ aml_append(ifctx, aml_increment(num_ej_cpus));
aml_append(ifctx, aml_store(one, has_event));
}
- aml_append(else_ctx, ifctx);
- aml_append(while_ctx, else_ctx);
+ aml_append(while_ctx, ifctx);
aml_append(while_ctx, aml_increment(uid));
}
aml_append(while_ctx2, while_ctx);
@@ -620,6 +627,24 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(while_ctx, aml_increment(cpu_idx));
}
aml_append(while_ctx2, while_ctx);
+
+ /*
+ * Notify OSPM about to be removed CPUs and clear remove flag
+ */
+ aml_append(while_ctx2, aml_store(zero, cpu_idx));
+ while_ctx = aml_while(aml_lless(cpu_idx, num_ej_cpus));
+ {
+ aml_append(while_ctx,
+ aml_store(aml_derefof(aml_index(ej_cpus, cpu_idx)),
+ uid));
+ aml_append(while_ctx,
+ aml_call2(CPU_NOTIFY_METHOD, uid, eject_req));
+ aml_append(while_ctx, aml_store(uid, cpu_selector));
+ aml_append(while_ctx, aml_store(one, rm_evt));
+ aml_append(while_ctx, aml_increment(cpu_idx));
+ }
+ aml_append(while_ctx2, while_ctx);
+
/*
* If another batch is needed, then it will resume scanning
* exactly at -- and not after -- the last CPU that's currently
diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c
index 83b8bc5..aa0e1e3 100644
--- a/hw/acpi/cpu_hotplug.c
+++ b/hw/acpi/cpu_hotplug.c
@@ -62,10 +62,9 @@ static const MemoryRegionOps AcpiCpuHotplug_ops = {
static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu,
bool *swtchd_to_modern)
{
- CPUClass *k = CPU_GET_CLASS(cpu);
int64_t cpu_id;
- cpu_id = k->get_arch_id(cpu);
+ cpu_id = cpu->cc->get_arch_id(cpu);
if ((cpu_id / 8) >= ACPI_GPE_PROC_LEN) {
object_property_set_bool(g->device, "cpu-hotplug-legacy", false,
&error_abort);
diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
index b2f1b13..099cabb 100644
--- a/hw/acpi/erst.c
+++ b/hw/acpi/erst.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/qdev-core.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qom/object.h"
#include "hw/pci/pci_device.h"
#include "qom/object_interfaces.h"
@@ -23,8 +23,8 @@
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/bios-linker-loader.h"
-#include "exec/address-spaces.h"
-#include "sysemu/hostmem.h"
+#include "system/address-spaces.h"
+#include "system/hostmem.h"
#include "hw/acpi/erst.h"
#include "trace.h"
@@ -1011,15 +1011,14 @@ static void erst_reset(DeviceState *dev)
trace_acpi_erst_reset_out(le32_to_cpu(s->header->record_count));
}
-static Property erst_properties[] = {
+static const Property erst_properties[] = {
DEFINE_PROP_LINK(ACPI_ERST_MEMDEV_PROP, ERSTDeviceState, hostmem,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
DEFINE_PROP_UINT32(ACPI_ERST_RECORD_SIZE_PROP, ERSTDeviceState,
default_record_size, ERST_RECORD_SIZE),
- DEFINE_PROP_END_OF_LIST(),
};
-static void erst_class_init(ObjectClass *klass, void *data)
+static void erst_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1030,7 +1029,7 @@ static void erst_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_REDHAT_ACPI_ERST;
k->revision = 0x00;
k->class_id = PCI_CLASS_OTHERS;
- dc->reset = erst_reset;
+ device_class_set_legacy_reset(dc, erst_reset);
dc->vmsd = &erst_vmstate;
dc->user_creatable = true;
dc->hotpluggable = false;
@@ -1045,7 +1044,7 @@ static const TypeInfo erst_type_info = {
.parent = TYPE_PCI_DEVICE,
.class_init = erst_class_init,
.instance_size = sizeof(ERSTDeviceState),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 15b4c3e..7a62f8d 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -19,7 +19,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
static const uint32_t ged_supported_events[] = {
ACPI_GED_MEM_HOTPLUG_EVT,
@@ -201,9 +201,9 @@ static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
switch (addr) {
case ACPI_GED_REG_SLEEP_CTL:
- slp_typ = (data >> 2) & 0x07;
- slp_en = (data >> 5) & 0x01;
- if (slp_en && slp_typ == 5) {
+ slp_typ = (data >> ACPI_GED_SLP_TYP_POS) & ACPI_GED_SLP_TYP_MASK;
+ slp_en = !!(data & ACPI_GED_SLP_EN);
+ if (slp_en && slp_typ == ACPI_GED_SLP_TYP_S5) {
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
return;
@@ -316,9 +316,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
qemu_irq_pulse(s->irq);
}
-static Property acpi_ged_properties[] = {
+static const Property acpi_ged_properties[] = {
DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_memhp_state = {
@@ -331,6 +330,24 @@ static const VMStateDescription vmstate_memhp_state = {
}
};
+static bool cpuhp_needed(void *opaque)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+
+ return mc->has_hotpluggable_cpus;
+}
+
+static const VMStateDescription vmstate_cpuhp_state = {
+ .name = "acpi-ged/cpuhp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpuhp_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_ged_state = {
.name = "acpi-ged-state",
.version_id = 1,
@@ -346,7 +363,7 @@ static const VMStateDescription vmstate_ghes = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
- VMSTATE_UINT64(ghes_addr_le, AcpiGhesState),
+ VMSTATE_UINT64(hw_error_le, AcpiGhesState),
VMSTATE_END_OF_LIST()
},
};
@@ -354,7 +371,7 @@ static const VMStateDescription vmstate_ghes = {
static bool ghes_needed(void *opaque)
{
AcpiGedState *s = opaque;
- return s->ghes_state.ghes_addr_le;
+ return s->ghes_state.hw_error_le;
}
static const VMStateDescription vmstate_ghes_state = {
@@ -379,6 +396,7 @@ static const VMStateDescription vmstate_acpi_ged = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_memhp_state,
+ &vmstate_cpuhp_state,
&vmstate_ghes_state,
NULL
}
@@ -440,18 +458,18 @@ static void acpi_ged_initfn(Object *obj)
* container for memory hotplug IO and expose it as GED sysbus
* MMIO so that boards can map it separately.
*/
- memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
- MEMORY_HOTPLUG_IO_LEN);
- sysbus_init_mmio(sbd, &s->container_memhp);
- acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
- &s->memhp_state, 0);
+ memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
+ MEMORY_HOTPLUG_IO_LEN);
+ sysbus_init_mmio(sbd, &s->container_memhp);
+ acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
+ &s->memhp_state, 0);
memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st,
TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT);
sysbus_init_mmio(sbd, &ged_st->regs);
}
-static void acpi_ged_class_init(ObjectClass *class, void *data)
+static void acpi_ged_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
@@ -476,7 +494,7 @@ static const TypeInfo acpi_ged_info = {
.instance_size = sizeof(AcpiGedState),
.instance_init = acpi_ged_initfn,
.class_init = acpi_ged_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
{ }
diff --git a/hw/acpi/ghes-stub.c b/hw/acpi/ghes-stub.c
index c315de1..7cec181 100644
--- a/hw/acpi/ghes-stub.c
+++ b/hw/acpi/ghes-stub.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "hw/acpi/ghes.h"
-int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
+int acpi_ghes_memory_errors(uint16_t source_id, uint64_t physical_address)
{
return -1;
}
diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c
index e9511d9..b85bb48 100644
--- a/hw/acpi/ghes.c
+++ b/hw/acpi/ghes.c
@@ -28,15 +28,12 @@
#include "hw/nvram/fw_cfg.h"
#include "qemu/uuid.h"
-#define ACPI_GHES_ERRORS_FW_CFG_FILE "etc/hardware_errors"
-#define ACPI_GHES_DATA_ADDR_FW_CFG_FILE "etc/hardware_errors_addr"
+#define ACPI_HW_ERROR_FW_CFG_FILE "etc/hardware_errors"
+#define ACPI_HW_ERROR_ADDR_FW_CFG_FILE "etc/hardware_errors_addr"
/* The max size in bytes for one error block */
#define ACPI_GHES_MAX_RAW_DATA_LENGTH (1 * KiB)
-/* Now only support ARMv8 SEA notification type error source */
-#define ACPI_GHES_ERROR_SOURCE_COUNT 1
-
/* Generic Hardware Error Source version 2 */
#define ACPI_GHES_SOURCE_GENERIC_ERROR_V2 10
@@ -184,51 +181,24 @@ static void acpi_ghes_build_append_mem_cper(GArray *table,
build_append_int_noprefix(table, 0, 7);
}
-static int acpi_ghes_record_mem_error(uint64_t error_block_address,
- uint64_t error_physical_addr)
+static void
+ghes_gen_err_data_uncorrectable_recoverable(GArray *block,
+ const uint8_t *section_type,
+ int data_length)
{
- GArray *block;
-
- /* Memory Error Section Type */
- const uint8_t uefi_cper_mem_sec[] =
- UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \
- 0xED, 0x7C, 0x83, 0xB1);
-
/* invalid fru id: ACPI 4.0: 17.3.2.6.1 Generic Error Data,
* Table 17-13 Generic Error Data Entry
*/
QemuUUID fru_id = {};
- uint32_t data_length;
-
- block = g_array_new(false, true /* clear */, 1);
-
- /* This is the length if adding a new generic error data entry*/
- data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH;
- /*
- * It should not run out of the preallocated memory if adding a new generic
- * error data entry
- */
- assert((data_length + ACPI_GHES_GESB_SIZE) <=
- ACPI_GHES_MAX_RAW_DATA_LENGTH);
/* Build the new generic error status block header */
acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE,
0, 0, data_length, ACPI_CPER_SEV_RECOVERABLE);
/* Build this new generic error data entry header */
- acpi_ghes_generic_error_data(block, uefi_cper_mem_sec,
+ acpi_ghes_generic_error_data(block, section_type,
ACPI_CPER_SEV_RECOVERABLE, 0, 0,
ACPI_GHES_MEM_CPER_LENGTH, fru_id, 0);
-
- /* Build the memory section CPER for above new generic error data entry */
- acpi_ghes_build_append_mem_cper(block, error_physical_addr);
-
- /* Write the generic error data entry into guest memory */
- cpu_physical_memory_write(error_block_address, block->data, block->len);
-
- g_array_free(block, true);
-
- return 0;
}
/*
@@ -236,7 +206,7 @@ static int acpi_ghes_record_mem_error(uint64_t error_block_address,
* Initialize "etc/hardware_errors" and "etc/hardware_errors_addr" fw_cfg blobs.
* See docs/specs/acpi_hest_ghes.rst for blobs format.
*/
-void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
+static void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
{
int i, error_status_block_offset;
@@ -264,7 +234,7 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
ACPI_GHES_MAX_RAW_DATA_LENGTH * ACPI_GHES_ERROR_SOURCE_COUNT);
/* Tell guest firmware to place hardware_errors blob into RAM */
- bios_linker_loader_alloc(linker, ACPI_GHES_ERRORS_FW_CFG_FILE,
+ bios_linker_loader_alloc(linker, ACPI_HW_ERROR_FW_CFG_FILE,
hardware_errors, sizeof(uint64_t), false);
for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) {
@@ -273,23 +243,31 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
* corresponding "Generic Error Status Block"
*/
bios_linker_loader_add_pointer(linker,
- ACPI_GHES_ERRORS_FW_CFG_FILE, sizeof(uint64_t) * i,
- sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE,
- error_status_block_offset + i * ACPI_GHES_MAX_RAW_DATA_LENGTH);
+ ACPI_HW_ERROR_FW_CFG_FILE,
+ sizeof(uint64_t) * i,
+ sizeof(uint64_t),
+ ACPI_HW_ERROR_FW_CFG_FILE,
+ error_status_block_offset +
+ i * ACPI_GHES_MAX_RAW_DATA_LENGTH);
}
/*
* tell firmware to write hardware_errors GPA into
* hardware_errors_addr fw_cfg, once the former has been initialized.
*/
- bios_linker_loader_write_pointer(linker, ACPI_GHES_DATA_ADDR_FW_CFG_FILE,
- 0, sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE, 0);
+ bios_linker_loader_write_pointer(linker, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, 0,
+ sizeof(uint64_t),
+ ACPI_HW_ERROR_FW_CFG_FILE, 0);
}
/* Build Generic Hardware Error Source version 2 (GHESv2) */
-static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
+static void build_ghes_v2(GArray *table_data,
+ BIOSLinker *linker,
+ enum AcpiGhesNotifyType notify,
+ uint16_t source_id)
{
uint64_t address_offset;
+
/*
* Type:
* Generic Hardware Error Source version 2(GHESv2 - Type 10)
@@ -316,21 +294,13 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0,
4 /* QWord access */, 0);
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
- address_offset + GAS_ADDR_OFFSET, sizeof(uint64_t),
- ACPI_GHES_ERRORS_FW_CFG_FILE, source_id * sizeof(uint64_t));
+ address_offset + GAS_ADDR_OFFSET,
+ sizeof(uint64_t),
+ ACPI_HW_ERROR_FW_CFG_FILE,
+ source_id * sizeof(uint64_t));
- switch (source_id) {
- case ACPI_HEST_SRC_ID_SEA:
- /*
- * Notification Structure
- * Now only enable ARMv8 SEA notification type
- */
- build_ghes_hw_error_notification(table_data, ACPI_GHES_NOTIFY_SEA);
- break;
- default:
- error_report("Not support this error source");
- abort();
- }
+ /* Notification Structure */
+ build_ghes_hw_error_notification(table_data, notify);
/* Error Status Block Length */
build_append_int_noprefix(table_data, ACPI_GHES_MAX_RAW_DATA_LENGTH, 4);
@@ -344,9 +314,11 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0x40, 0,
4 /* QWord access */, 0);
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
- address_offset + GAS_ADDR_OFFSET,
- sizeof(uint64_t), ACPI_GHES_ERRORS_FW_CFG_FILE,
- (ACPI_GHES_ERROR_SOURCE_COUNT + source_id) * sizeof(uint64_t));
+ address_offset + GAS_ADDR_OFFSET,
+ sizeof(uint64_t),
+ ACPI_HW_ERROR_FW_CFG_FILE,
+ (ACPI_GHES_ERROR_SOURCE_COUNT + source_id)
+ * sizeof(uint64_t));
/*
* Read Ack Preserve field
@@ -359,17 +331,21 @@ static void build_ghes_v2(GArray *table_data, int source_id, BIOSLinker *linker)
}
/* Build Hardware Error Source Table */
-void acpi_build_hest(GArray *table_data, BIOSLinker *linker,
+void acpi_build_hest(GArray *table_data, GArray *hardware_errors,
+ BIOSLinker *linker,
const char *oem_id, const char *oem_table_id)
{
AcpiTable table = { .sig = "HEST", .rev = 1,
.oem_id = oem_id, .oem_table_id = oem_table_id };
+ build_ghes_error_table(hardware_errors, linker);
+
acpi_table_begin(&table, table_data);
/* Error Source Count */
build_append_int_noprefix(table_data, ACPI_GHES_ERROR_SOURCE_COUNT, 4);
- build_ghes_v2(table_data, ACPI_HEST_SRC_ID_SEA, linker);
+ build_ghes_v2(table_data, linker,
+ ACPI_GHES_NOTIFY_SEA, ACPI_HEST_SRC_ID_SEA);
acpi_table_end(linker, &table);
}
@@ -378,70 +354,130 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s,
GArray *hardware_error)
{
/* Create a read-only fw_cfg file for GHES */
- fw_cfg_add_file(s, ACPI_GHES_ERRORS_FW_CFG_FILE, hardware_error->data,
+ fw_cfg_add_file(s, ACPI_HW_ERROR_FW_CFG_FILE, hardware_error->data,
hardware_error->len);
/* Create a read-write fw_cfg file for Address */
- fw_cfg_add_file_callback(s, ACPI_GHES_DATA_ADDR_FW_CFG_FILE, NULL, NULL,
- NULL, &(ags->ghes_addr_le), sizeof(ags->ghes_addr_le), false);
+ fw_cfg_add_file_callback(s, ACPI_HW_ERROR_ADDR_FW_CFG_FILE, NULL, NULL,
+ NULL, &(ags->hw_error_le), sizeof(ags->hw_error_le), false);
ags->present = true;
}
-int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address)
+static void get_hw_error_offsets(uint64_t ghes_addr,
+ uint64_t *cper_addr,
+ uint64_t *read_ack_register_addr)
+{
+ if (!ghes_addr) {
+ return;
+ }
+
+ /*
+ * non-HEST version supports only one source, so no need to change
+ * the start offset based on the source ID. Also, we can't validate
+ * the source ID, as it is stored inside the HEST table.
+ */
+
+ cpu_physical_memory_read(ghes_addr, cper_addr,
+ sizeof(*cper_addr));
+
+ *cper_addr = le64_to_cpu(*cper_addr);
+
+ /*
+ * As the current version supports only one source, the ack offset is
+ * just sizeof(uint64_t).
+ */
+ *read_ack_register_addr = ghes_addr + sizeof(uint64_t);
+}
+
+static void ghes_record_cper_errors(const void *cper, size_t len,
+ uint16_t source_id, Error **errp)
{
- uint64_t error_block_addr, read_ack_register_addr, read_ack_register = 0;
- uint64_t start_addr;
- bool ret = -1;
+ uint64_t cper_addr = 0, read_ack_register_addr = 0, read_ack_register;
AcpiGedState *acpi_ged_state;
AcpiGhesState *ags;
- assert(source_id < ACPI_HEST_SRC_ID_RESERVED);
+ if (len > ACPI_GHES_MAX_RAW_DATA_LENGTH) {
+ error_setg(errp, "GHES CPER record is too big: %zd", len);
+ return;
+ }
acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED,
NULL));
- g_assert(acpi_ged_state);
+ if (!acpi_ged_state) {
+ error_setg(errp, "Can't find ACPI_GED object");
+ return;
+ }
ags = &acpi_ged_state->ghes_state;
- start_addr = le64_to_cpu(ags->ghes_addr_le);
+ assert(ACPI_GHES_ERROR_SOURCE_COUNT == 1);
+ get_hw_error_offsets(le64_to_cpu(ags->hw_error_le),
+ &cper_addr, &read_ack_register_addr);
+
+ if (!cper_addr) {
+ error_setg(errp, "can not find Generic Error Status Block");
+ return;
+ }
+
+ cpu_physical_memory_read(read_ack_register_addr,
+ &read_ack_register, sizeof(read_ack_register));
+
+ /* zero means OSPM does not acknowledge the error */
+ if (!read_ack_register) {
+ error_setg(errp,
+ "OSPM does not acknowledge previous error,"
+ " so can not record CPER for current error anymore");
+ return;
+ }
+
+ read_ack_register = cpu_to_le64(0);
+ /*
+ * Clear the Read Ack Register, OSPM will write 1 to this register when
+ * it acknowledges the error.
+ */
+ cpu_physical_memory_write(read_ack_register_addr,
+ &read_ack_register, sizeof(uint64_t));
+
+ /* Write the generic error data entry into guest memory */
+ cpu_physical_memory_write(cper_addr, cper, len);
+}
- if (physical_address) {
+int acpi_ghes_memory_errors(uint16_t source_id, uint64_t physical_address)
+{
+ /* Memory Error Section Type */
+ const uint8_t guid[] =
+ UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \
+ 0xED, 0x7C, 0x83, 0xB1);
+ Error *errp = NULL;
+ int data_length;
+ GArray *block;
- if (source_id < ACPI_HEST_SRC_ID_RESERVED) {
- start_addr += source_id * sizeof(uint64_t);
- }
+ block = g_array_new(false, true /* clear */, 1);
- cpu_physical_memory_read(start_addr, &error_block_addr,
- sizeof(error_block_addr));
+ data_length = ACPI_GHES_DATA_LENGTH + ACPI_GHES_MEM_CPER_LENGTH;
+ /*
+ * It should not run out of the preallocated memory if adding a new generic
+ * error data entry
+ */
+ assert((data_length + ACPI_GHES_GESB_SIZE) <=
+ ACPI_GHES_MAX_RAW_DATA_LENGTH);
- error_block_addr = le64_to_cpu(error_block_addr);
+ ghes_gen_err_data_uncorrectable_recoverable(block, guid, data_length);
- read_ack_register_addr = start_addr +
- ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t);
+ /* Build the memory section CPER for above new generic error data entry */
+ acpi_ghes_build_append_mem_cper(block, physical_address);
- cpu_physical_memory_read(read_ack_register_addr,
- &read_ack_register, sizeof(read_ack_register));
+ /* Report the error */
+ ghes_record_cper_errors(block->data, block->len, source_id, &errp);
- /* zero means OSPM does not acknowledge the error */
- if (!read_ack_register) {
- error_report("OSPM does not acknowledge previous error,"
- " so can not record CPER for current error anymore");
- } else if (error_block_addr) {
- read_ack_register = cpu_to_le64(0);
- /*
- * Clear the Read Ack Register, OSPM will write it to 1 when
- * it acknowledges this error.
- */
- cpu_physical_memory_write(read_ack_register_addr,
- &read_ack_register, sizeof(uint64_t));
+ g_array_free(block, true);
- ret = acpi_ghes_record_mem_error(error_block_addr,
- physical_address);
- } else
- error_report("can not find Generic Error Status Block");
+ if (errp) {
+ error_report_err(errp);
+ return -1;
}
- return ret;
+ return 0;
}
bool acpi_ghes_present(void)
diff --git a/hw/acpi/hmat.c b/hw/acpi/hmat.c
index 9b1662b..ca7b183 100644
--- a/hw/acpi/hmat.c
+++ b/hw/acpi/hmat.c
@@ -26,7 +26,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/hmat.h"
diff --git a/hw/acpi/hmat.h b/hw/acpi/hmat.h
index fd989cb..362b05e 100644
--- a/hw/acpi/hmat.h
+++ b/hw/acpi/hmat.h
@@ -28,7 +28,7 @@
#define HMAT_H
#include "hw/acpi/bios-linker-loader.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
/*
* ACPI 6.3: 5.2.27.3 Memory Proximity Domain Attributes Structure,
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 02d8546..967b674 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -31,24 +31,16 @@
#include "migration/vmstate.h"
#include "qemu/timer.h"
#include "hw/core/cpu.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/ich9_tco.h"
+#include "hw/acpi/ich9_timer.h"
#include "hw/southbridge/ich9.h"
#include "hw/mem/pc-dimm.h"
#include "hw/mem/nvdimm.h"
-//#define DEBUG
-
-#ifdef DEBUG
-#define ICH9_DEBUG(fmt, ...) \
-do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
-#else
-#define ICH9_DEBUG(fmt, ...) do { } while (0)
-#endif
-
static void ich9_pm_update_sci_fn(ACPIREGS *regs)
{
ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
@@ -108,6 +100,18 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
}
pm->smi_en &= ~pm->smi_en_wmask;
pm->smi_en |= (val & pm->smi_en_wmask);
+ if (pm->swsmi_timer_enabled) {
+ ich9_pm_update_swsmi_timer(pm, pm->smi_en &
+ ICH9_PMIO_SMI_EN_SWSMI_EN);
+ }
+ if (pm->periodic_timer_enabled) {
+ ich9_pm_update_periodic_timer(pm, pm->smi_en &
+ ICH9_PMIO_SMI_EN_PERIODIC_EN);
+ }
+ break;
+ case 4:
+ pm->smi_sts &= ~pm->smi_sts_wmask;
+ pm->smi_sts |= (val & pm->smi_sts_wmask);
break;
}
}
@@ -122,8 +126,6 @@ static const MemoryRegionOps ich9_smi_ops = {
void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
{
- ICH9_DEBUG("to 0x%x\n", pm_io_base);
-
assert((pm_io_base & ICH9_PMIO_MASK) == 0);
pm->pm_io_base = pm_io_base;
@@ -286,6 +288,8 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
{
+ pm->smi_sts_wmask = 0;
+
memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
memory_region_set_enabled(&pm->io, false);
memory_region_add_subregion(pci_address_space_io(lpc_pci),
@@ -305,6 +309,14 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
"acpi-smi", 8);
memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
+ if (pm->swsmi_timer_enabled) {
+ ich9_pm_swsmi_timer_init(pm);
+ }
+
+ if (pm->periodic_timer_enabled) {
+ ich9_pm_periodic_timer_init(pm);
+ }
+
if (pm->enable_tco) {
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
}
@@ -547,7 +559,7 @@ void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus)
{
ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
- return acpi_pcihp_is_hotpluggbale_bus(&lpc->pm.acpi_pci_hotplug, bus);
+ return acpi_pcihp_is_hotpluggable_bus(&lpc->pm.acpi_pci_hotplug, bus);
}
void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
diff --git a/hw/acpi/ich9_tco.c b/hw/acpi/ich9_tco.c
index 8160621..6300db6 100644
--- a/hw/acpi/ich9_tco.c
+++ b/hw/acpi/ich9_tco.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "hw/southbridge/ich9.h"
#include "migration/vmstate.h"
diff --git a/hw/acpi/ich9_timer.c b/hw/acpi/ich9_timer.c
new file mode 100644
index 0000000..5b1c910
--- /dev/null
+++ b/hw/acpi/ich9_timer.c
@@ -0,0 +1,93 @@
+/*
+ * QEMU ICH9 Timer emulation
+ *
+ * Copyright (c) 2024 Dominic Prinz <git@dprinz.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/cpu.h"
+#include "hw/pci/pci.h"
+#include "hw/southbridge/ich9.h"
+#include "qemu/timer.h"
+
+#include "hw/acpi/ich9_timer.h"
+
+void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable)
+{
+ uint16_t swsmi_rate_sel;
+ int64_t expire_time;
+ ICH9LPCState *lpc;
+
+ if (enable) {
+ lpc = container_of(pm, ICH9LPCState, pm);
+ swsmi_rate_sel =
+ (pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_3) & 0xc0) >> 6;
+
+ if (swsmi_rate_sel == 0) {
+ expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1500000LL;
+ } else {
+ expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ 8 * (1 << swsmi_rate_sel) * 1000000LL;
+ }
+
+ timer_mod(pm->swsmi_timer, expire_time);
+ } else {
+ timer_del(pm->swsmi_timer);
+ }
+}
+
+static void ich9_pm_swsmi_timer_expired(void *opaque)
+{
+ ICH9LPCPMRegs *pm = opaque;
+
+ pm->smi_sts |= ICH9_PMIO_SMI_STS_SWSMI_STS;
+ ich9_generate_smi();
+
+ ich9_pm_update_swsmi_timer(pm, pm->smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN);
+}
+
+void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm)
+{
+ pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_SWSMI_STS;
+ pm->swsmi_timer =
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_swsmi_timer_expired, pm);
+}
+
+void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable)
+{
+ uint16_t per_smi_sel;
+ int64_t expire_time;
+ ICH9LPCState *lpc;
+
+ if (enable) {
+ lpc = container_of(pm, ICH9LPCState, pm);
+ per_smi_sel = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1) & 3;
+ expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ 8 * (1 << (3 - per_smi_sel)) * NANOSECONDS_PER_SECOND;
+
+ timer_mod(pm->periodic_timer, expire_time);
+ } else {
+ timer_del(pm->periodic_timer);
+ }
+}
+
+static void ich9_pm_periodic_timer_expired(void *opaque)
+{
+ ICH9LPCPMRegs *pm = opaque;
+
+ pm->smi_sts = ICH9_PMIO_SMI_STS_PERIODIC_STS;
+ ich9_generate_smi();
+
+ ich9_pm_update_periodic_timer(pm,
+ pm->smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN);
+}
+
+void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm)
+{
+ pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_PERIODIC_STS;
+ pm->periodic_timer =
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_periodic_timer_expired, pm);
+}
diff --git a/hw/acpi/ipmi.c b/hw/acpi/ipmi.c
index a20e57d..39f8f2f 100644
--- a/hw/acpi/ipmi.c
+++ b/hw/acpi/ipmi.c
@@ -55,7 +55,8 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info)
abort();
}
- if (info->interrupt_number) {
+ /* Should PCI interrupts also be appended? */
+ if (info->irq_source == IPMI_ISA_IRQ && info->interrupt_number) {
aml_append(crs, aml_irq_no_flags(info->interrupt_number));
}
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index fa5c07d..73f02b9 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -1,6 +1,5 @@
acpi_ss = ss.source_set()
acpi_ss.add(files(
- 'acpi_generic_initiator.c',
'acpi_interface.c',
'aml-build.c',
'bios-linker-loader.c',
@@ -16,6 +15,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_false: files('acpi-nvdimm-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCI', if_true: files('pci.c'))
acpi_ss.add(when: 'CONFIG_ACPI_CXL', if_true: files('cxl.c'), if_false: files('cxl-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_VMCLOCK', if_true: files('vmclock.c'))
acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device.c'))
acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c'))
acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c'))
@@ -24,7 +24,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
-acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c', 'ich9_timer.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
diff --git a/hw/acpi/pci.c b/hw/acpi/pci.c
index 20b70dc..d511a85 100644
--- a/hw/acpi/pci.c
+++ b/hw/acpi/pci.c
@@ -24,8 +24,14 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qom/object_interfaces.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/pci.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_device.h"
#include "hw/pci/pcie_host.h"
/*
@@ -59,3 +65,239 @@ void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
acpi_table_end(linker, &table);
}
+
+typedef struct AcpiGenericInitiator {
+ /* private */
+ Object parent;
+
+ /* public */
+ char *pci_dev;
+ uint32_t node;
+} AcpiGenericInitiator;
+
+typedef struct AcpiGenericInitiatorClass {
+ ObjectClass parent_class;
+} AcpiGenericInitiatorClass;
+
+#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator"
+
+OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
+ ACPI_GENERIC_INITIATOR, OBJECT,
+ { TYPE_USER_CREATABLE },
+ { NULL })
+
+OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
+
+static void acpi_generic_initiator_init(Object *obj)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+
+ gi->node = MAX_NODES;
+ gi->pci_dev = NULL;
+}
+
+static void acpi_generic_initiator_finalize(Object *obj)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+
+ g_free(gi->pci_dev);
+}
+
+static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
+ Error **errp)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+
+ gi->pci_dev = g_strdup(val);
+}
+
+static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+ MachineState *ms = MACHINE(qdev_get_machine());
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ if (value >= MAX_NODES) {
+ error_printf("%s: Invalid NUMA node specified\n",
+ TYPE_ACPI_GENERIC_INITIATOR);
+ exit(1);
+ }
+
+ gi->node = value;
+ ms->numa_state->nodes[gi->node].has_gi = true;
+}
+
+static void acpi_generic_initiator_class_init(ObjectClass *oc, const void *data)
+{
+ object_class_property_add_str(oc, "pci-dev", NULL,
+ acpi_generic_initiator_set_pci_device);
+ object_class_property_set_description(oc, "pci-dev",
+ "PCI device to associate with the node");
+ object_class_property_add(oc, "node", "int", NULL,
+ acpi_generic_initiator_set_node, NULL, NULL);
+ object_class_property_set_description(oc, "node",
+ "NUMA node associated with the PCI device");
+}
+
+static int build_acpi_generic_initiator(Object *obj, void *opaque)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ AcpiGenericInitiator *gi;
+ GArray *table_data = opaque;
+ int32_t devfn;
+ uint8_t bus;
+ Object *o;
+
+ if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
+ return 0;
+ }
+
+ gi = ACPI_GENERIC_INITIATOR(obj);
+ if (gi->node >= ms->numa_state->num_nodes) {
+ error_printf("%s: Specified node %d is invalid.\n",
+ TYPE_ACPI_GENERIC_INITIATOR, gi->node);
+ exit(1);
+ }
+
+ o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
+ if (!o) {
+ error_printf("%s: Specified device must be a PCI device.\n",
+ TYPE_ACPI_GENERIC_INITIATOR);
+ exit(1);
+ }
+
+ bus = object_property_get_uint(o, "busnr", &error_fatal);
+ devfn = object_property_get_uint(o, "addr", &error_fatal);
+ /* devfn is constrained in PCI to be 8 bit but storage is an int32_t */
+ assert(devfn >= 0 && devfn < PCI_DEVFN_MAX);
+
+ build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn);
+
+ return 0;
+}
+
+typedef struct AcpiGenericPort {
+ /* private */
+ Object parent;
+
+ /* public */
+ char *pci_bus;
+ uint32_t node;
+} AcpiGenericPort;
+
+typedef struct AcpiGenericPortClass {
+ ObjectClass parent_class;
+} AcpiGenericPortClass;
+
+#define TYPE_ACPI_GENERIC_PORT "acpi-generic-port"
+
+OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericPort, acpi_generic_port,
+ ACPI_GENERIC_PORT, OBJECT,
+ { TYPE_USER_CREATABLE },
+ { NULL })
+
+OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort, ACPI_GENERIC_PORT)
+
+static void acpi_generic_port_init(Object *obj)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+
+ gp->node = MAX_NODES;
+ gp->pci_bus = NULL;
+}
+
+static void acpi_generic_port_finalize(Object *obj)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+
+ g_free(gp->pci_bus);
+}
+
+static void acpi_generic_port_set_pci_bus(Object *obj, const char *val,
+ Error **errp)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+
+ gp->pci_bus = g_strdup(val);
+}
+
+static void acpi_generic_port_set_node(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ if (value >= MAX_NODES) {
+ error_printf("%s: Invalid NUMA node specified\n",
+ TYPE_ACPI_GENERIC_INITIATOR);
+ exit(1);
+ }
+
+ gp->node = value;
+}
+
+static void acpi_generic_port_class_init(ObjectClass *oc, const void *data)
+{
+ object_class_property_add_str(oc, "pci-bus", NULL,
+ acpi_generic_port_set_pci_bus);
+ object_class_property_set_description(oc, "pci-bus",
+ "PCI Bus of the host bridge associated with this GP affinity structure");
+ object_class_property_add(oc, "node", "int", NULL,
+ acpi_generic_port_set_node, NULL, NULL);
+ object_class_property_set_description(oc, "node",
+ "The NUMA node like ID to index HMAT/SLIT NUMA properties involving GP");
+}
+
+static int build_acpi_generic_port(Object *obj, void *opaque)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ const char *hid = "ACPI0016";
+ GArray *table_data = opaque;
+ AcpiGenericPort *gp;
+ uint32_t uid;
+ Object *o;
+
+ if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_PORT)) {
+ return 0;
+ }
+
+ gp = ACPI_GENERIC_PORT(obj);
+
+ if (gp->node >= ms->numa_state->num_nodes) {
+ error_printf("%s: node %d is invalid.\n",
+ TYPE_ACPI_GENERIC_PORT, gp->node);
+ exit(1);
+ }
+
+ o = object_resolve_path_type(gp->pci_bus, TYPE_PXB_CXL_BUS, NULL);
+ if (!o) {
+ error_printf("%s: device must be a CXL host bridge.\n",
+ TYPE_ACPI_GENERIC_PORT);
+ exit(1);
+ }
+
+ uid = object_property_get_uint(o, "acpi_uid", &error_fatal);
+ build_srat_acpi_generic_port(table_data, gp->node, hid, uid);
+
+ return 0;
+}
+
+void build_srat_generic_affinity_structures(GArray *table_data)
+{
+ object_child_foreach_recursive(object_get_root(),
+ build_acpi_generic_initiator,
+ table_data);
+ object_child_foreach_recursive(object_get_root(), build_acpi_generic_port,
+ table_data);
+}
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 5f79c90..aac9001 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -371,7 +371,7 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
}
-bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus)
+bool acpi_pcihp_is_hotpluggable_bus(AcpiPciHpState *s, BusState *bus)
{
Object *o = OBJECT(bus->parent);
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index debe1ad..d98b80d 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -28,9 +28,9 @@
#include "hw/acpi/acpi.h"
#include "hw/acpi/pcihp.h"
#include "hw/acpi/piix4.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/xen.h"
+#include "system/runstate.h"
+#include "system/system.h"
+#include "system/xen.h"
#include "qapi/error.h"
#include "qemu/range.h"
#include "hw/acpi/cpu_hotplug.h"
@@ -406,7 +406,7 @@ static bool piix4_is_hotpluggable_bus(HotplugHandler *hotplug_dev,
BusState *bus)
{
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
- return acpi_pcihp_is_hotpluggbale_bus(&s->acpi_pci_hotplug, bus);
+ return acpi_pcihp_is_hotpluggable_bus(&s->acpi_pci_hotplug, bus);
}
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
@@ -602,7 +602,7 @@ static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
acpi_send_gpe_event(&s->ar, s->irq, ev);
}
-static Property piix4_pm_properties[] = {
+static const Property piix4_pm_properties[] = {
DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
@@ -617,10 +617,9 @@ static Property piix4_pm_properties[] = {
DEFINE_PROP_BOOL("smm-enabled", PIIX4PMState, smm_enabled, false),
DEFINE_PROP_BOOL("x-not-migrate-acpi-index", PIIX4PMState,
not_migrate_acpi_index, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void piix4_pm_class_init(ObjectClass *klass, void *data)
+static void piix4_pm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -633,7 +632,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
k->revision = 0x03;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
- dc->reset = piix4_pm_reset;
+ device_class_set_legacy_reset(dc, piix4_pm_reset);
dc->desc = "PM";
dc->vmsd = &vmstate_acpi;
device_class_set_props(dc, piix4_pm_properties);
@@ -658,7 +657,7 @@ static const TypeInfo piix4_pm_info = {
.instance_init = piix4_pm_init,
.instance_size = sizeof(PIIX4PMState),
.class_init = piix4_pm_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
diff --git a/hw/acpi/vmclock.c b/hw/acpi/vmclock.c
new file mode 100644
index 0000000..c582c0c
--- /dev/null
+++ b/hw/acpi/vmclock.c
@@ -0,0 +1,179 @@
+/*
+ * Virtual Machine Clock Device
+ *
+ * Copyright © 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Authors: David Woodhouse <dwmw2@infradead.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "hw/i386/e820_memory_layout.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/vmclock.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "migration/vmstate.h"
+#include "system/reset.h"
+
+#include "standard-headers/linux/vmclock-abi.h"
+
+void vmclock_build_acpi(VmclockState *vms, GArray *table_data,
+ BIOSLinker *linker, const char *oem_id)
+{
+ Aml *ssdt, *dev, *scope, *crs;
+ AcpiTable table = { .sig = "SSDT", .rev = 1,
+ .oem_id = oem_id, .oem_table_id = "VMCLOCK" };
+
+ /* Put VMCLOCK into a separate SSDT table */
+ acpi_table_begin(&table, table_data);
+ ssdt = init_aml_allocator();
+
+ scope = aml_scope("\\_SB");
+ dev = aml_device("VCLK");
+ aml_append(dev, aml_name_decl("_HID", aml_string("AMZNC10C")));
+ aml_append(dev, aml_name_decl("_CID", aml_string("VMCLOCK")));
+ aml_append(dev, aml_name_decl("_DDN", aml_string("VMCLOCK")));
+
+ /* Simple status method */
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
+
+ crs = aml_resource_template();
+ aml_append(crs, aml_qword_memory(AML_POS_DECODE,
+ AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_CACHEABLE, AML_READ_ONLY,
+ 0xffffffffffffffffULL,
+ vms->physaddr,
+ vms->physaddr + VMCLOCK_SIZE - 1,
+ 0, VMCLOCK_SIZE));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+ aml_append(ssdt, scope);
+
+ g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
+ acpi_table_end(linker, &table);
+ free_aml_allocator();
+}
+
+static void vmclock_update_guest(VmclockState *vms)
+{
+ uint64_t disruption_marker;
+ uint32_t seq_count;
+
+ if (!vms->clk) {
+ return;
+ }
+
+ seq_count = le32_to_cpu(vms->clk->seq_count) | 1;
+ vms->clk->seq_count = cpu_to_le32(seq_count);
+ /* These barriers pair with read barriers in the guest */
+ smp_wmb();
+
+ disruption_marker = le64_to_cpu(vms->clk->disruption_marker);
+ disruption_marker++;
+ vms->clk->disruption_marker = cpu_to_le64(disruption_marker);
+
+ /* These barriers pair with read barriers in the guest */
+ smp_wmb();
+ vms->clk->seq_count = cpu_to_le32(seq_count + 1);
+}
+
+/*
+ * After restoring an image, we need to update the guest memory to notify
+ * it of clock disruption.
+ */
+static int vmclock_post_load(void *opaque, int version_id)
+{
+ VmclockState *vms = opaque;
+
+ vmclock_update_guest(vms);
+ return 0;
+}
+
+static const VMStateDescription vmstate_vmclock = {
+ .name = "vmclock",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = vmclock_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(physaddr, VmclockState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void vmclock_handle_reset(void *opaque)
+{
+ VmclockState *vms = VMCLOCK(opaque);
+
+ if (!memory_region_is_mapped(&vms->clk_page)) {
+ memory_region_add_subregion_overlap(get_system_memory(),
+ vms->physaddr,
+ &vms->clk_page, 0);
+ }
+}
+
+static void vmclock_realize(DeviceState *dev, Error **errp)
+{
+ VmclockState *vms = VMCLOCK(dev);
+
+ /*
+ * Given that this function is executing, there is at least one VMCLOCK
+ * device. Check if there are several.
+ */
+ if (!find_vmclock_dev()) {
+ error_setg(errp, "at most one %s device is permitted", TYPE_VMCLOCK);
+ return;
+ }
+
+ vms->physaddr = VMCLOCK_ADDR;
+
+ e820_add_entry(vms->physaddr, VMCLOCK_SIZE, E820_RESERVED);
+
+ memory_region_init_ram(&vms->clk_page, OBJECT(dev), "vmclock_page",
+ VMCLOCK_SIZE, &error_abort);
+ memory_region_set_enabled(&vms->clk_page, true);
+ vms->clk = memory_region_get_ram_ptr(&vms->clk_page);
+ memset(vms->clk, 0, VMCLOCK_SIZE);
+
+ vms->clk->magic = cpu_to_le32(VMCLOCK_MAGIC);
+ vms->clk->size = cpu_to_le16(VMCLOCK_SIZE);
+ vms->clk->version = cpu_to_le16(1);
+
+ /* These are all zero and thus default, but be explicit */
+ vms->clk->clock_status = VMCLOCK_STATUS_UNKNOWN;
+ vms->clk->counter_id = VMCLOCK_COUNTER_INVALID;
+
+ qemu_register_reset(vmclock_handle_reset, vms);
+
+ vmclock_update_guest(vms);
+}
+
+static void vmclock_device_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_vmclock;
+ dc->realize = vmclock_realize;
+ dc->hotpluggable = false;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo vmclock_device_info = {
+ .name = TYPE_VMCLOCK,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VmclockState),
+ .class_init = vmclock_device_class_init,
+};
+
+static void vmclock_register_types(void)
+{
+ type_register_static(&vmclock_device_info);
+}
+
+type_init(vmclock_register_types)
diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
index e63c8af..fac3d6d 100644
--- a/hw/acpi/vmgenid.c
+++ b/hw/acpi/vmgenid.c
@@ -20,7 +20,7 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "migration/vmstate.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
void vmgenid_build_acpi(VmGenIdState *vms, GArray *table_data, GArray *guid,
BIOSLinker *linker, const char *oem_id)
@@ -214,12 +214,11 @@ static void vmgenid_realize(DeviceState *dev, Error **errp)
vmgenid_update_guest(vms);
}
-static Property vmgenid_device_properties[] = {
+static const Property vmgenid_device_properties[] = {
DEFINE_PROP_UUID(VMGENID_GUID, VmGenIdState, guid),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vmgenid_device_class_init(ObjectClass *klass, void *data)
+static void vmgenid_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/adc/Kconfig b/hw/adc/Kconfig
index a825bd3..25d2229 100644
--- a/hw/adc/Kconfig
+++ b/hw/adc/Kconfig
@@ -1,5 +1,2 @@
config STM32F2XX_ADC
bool
-
-config MAX111X
- bool
diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c
index 48328ef..3e820ca 100644
--- a/hw/adc/aspeed_adc.c
+++ b/hw/adc/aspeed_adc.c
@@ -286,18 +286,17 @@ static const VMStateDescription vmstate_aspeed_adc_engine = {
}
};
-static Property aspeed_adc_engine_properties[] = {
+static const Property aspeed_adc_engine_properties[] = {
DEFINE_PROP_UINT32("engine-id", AspeedADCEngineState, engine_id, 0),
DEFINE_PROP_UINT32("nr-channels", AspeedADCEngineState, nr_channels, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data)
+static void aspeed_adc_engine_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_adc_engine_realize;
- dc->reset = aspeed_adc_engine_reset;
+ device_class_set_legacy_reset(dc, aspeed_adc_engine_reset);
device_class_set_props(dc, aspeed_adc_engine_properties);
dc->desc = "Aspeed Analog-to-Digital Engine";
dc->vmsd = &vmstate_aspeed_adc_engine;
@@ -370,7 +369,7 @@ static void aspeed_adc_realize(DeviceState *dev, Error **errp)
}
}
-static void aspeed_adc_class_init(ObjectClass *klass, void *data)
+static void aspeed_adc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
@@ -380,7 +379,7 @@ static void aspeed_adc_class_init(ObjectClass *klass, void *data)
aac->nr_engines = 1;
}
-static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_adc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
@@ -389,7 +388,7 @@ static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data)
aac->nr_engines = 2;
}
-static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_adc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
@@ -398,7 +397,7 @@ static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data)
aac->nr_engines = 2;
}
-static void aspeed_2700_adc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_adc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
diff --git a/hw/adc/max111x.c b/hw/adc/max111x.c
deleted file mode 100644
index 957d177..0000000
--- a/hw/adc/max111x.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Maxim MAX1110/1111 ADC chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/adc/max111x.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "hw/qdev-properties.h"
-
-/* Control-byte bitfields */
-#define CB_PD0 (1 << 0)
-#define CB_PD1 (1 << 1)
-#define CB_SGL (1 << 2)
-#define CB_UNI (1 << 3)
-#define CB_SEL0 (1 << 4)
-#define CB_SEL1 (1 << 5)
-#define CB_SEL2 (1 << 6)
-#define CB_START (1 << 7)
-
-#define CHANNEL_NUM(v, b0, b1, b2) \
- ((((v) >> (2 + (b0))) & 4) | \
- (((v) >> (3 + (b1))) & 2) | \
- (((v) >> (4 + (b2))) & 1))
-
-static uint32_t max111x_read(MAX111xState *s)
-{
- if (!s->tb1)
- return 0;
-
- switch (s->cycle ++) {
- case 1:
- return s->rb2;
- case 2:
- return s->rb3;
- }
-
- return 0;
-}
-
-/* Interpret a control-byte */
-static void max111x_write(MAX111xState *s, uint32_t value)
-{
- int measure, chan;
-
- /* Ignore the value if START bit is zero */
- if (!(value & CB_START))
- return;
-
- s->cycle = 0;
-
- if (!(value & CB_PD1)) {
- s->tb1 = 0;
- return;
- }
-
- s->tb1 = value;
-
- if (s->inputs == 8)
- chan = CHANNEL_NUM(value, 1, 0, 2);
- else
- chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
-
- if (value & CB_SGL)
- measure = s->input[chan] - s->com;
- else
- measure = s->input[chan] - s->input[chan ^ 1];
-
- if (!(value & CB_UNI))
- measure ^= 0x80;
-
- s->rb2 = (measure >> 2) & 0x3f;
- s->rb3 = (measure << 6) & 0xc0;
-
- /* FIXME: When should the IRQ be lowered? */
- qemu_irq_raise(s->interrupt);
-}
-
-static uint32_t max111x_transfer(SSIPeripheral *dev, uint32_t value)
-{
- MAX111xState *s = MAX_111X(dev);
- max111x_write(s, value);
- return max111x_read(s);
-}
-
-static const VMStateDescription vmstate_max111x = {
- .name = "max111x",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(parent_obj, MAX111xState),
- VMSTATE_UINT8(tb1, MAX111xState),
- VMSTATE_UINT8(rb2, MAX111xState),
- VMSTATE_UINT8(rb3, MAX111xState),
- VMSTATE_INT32_EQUAL(inputs, MAX111xState, NULL),
- VMSTATE_INT32(com, MAX111xState),
- VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
- vmstate_info_uint8, uint8_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void max111x_input_set(void *opaque, int line, int value)
-{
- MAX111xState *s = MAX_111X(opaque);
-
- assert(line >= 0 && line < s->inputs);
- s->input[line] = value;
-}
-
-static int max111x_init(SSIPeripheral *d, int inputs)
-{
- DeviceState *dev = DEVICE(d);
- MAX111xState *s = MAX_111X(dev);
-
- qdev_init_gpio_out(dev, &s->interrupt, 1);
- qdev_init_gpio_in(dev, max111x_input_set, inputs);
-
- s->inputs = inputs;
-
- return 0;
-}
-
-static void max1110_realize(SSIPeripheral *dev, Error **errp)
-{
- max111x_init(dev, 8);
-}
-
-static void max1111_realize(SSIPeripheral *dev, Error **errp)
-{
- max111x_init(dev, 4);
-}
-
-static void max111x_reset(DeviceState *dev)
-{
- MAX111xState *s = MAX_111X(dev);
- int i;
-
- for (i = 0; i < s->inputs; i++) {
- s->input[i] = s->reset_input[i];
- }
- s->com = 0;
- s->tb1 = 0;
- s->rb2 = 0;
- s->rb3 = 0;
- s->cycle = 0;
-}
-
-static Property max1110_properties[] = {
- /* Reset values for ADC inputs */
- DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0),
- DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0),
- DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0),
- DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property max1111_properties[] = {
- /* Reset values for ADC inputs */
- DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0),
- DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0),
- DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0),
- DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0),
- DEFINE_PROP_UINT8("input4", MAX111xState, reset_input[4], 0xb0),
- DEFINE_PROP_UINT8("input5", MAX111xState, reset_input[5], 0xa0),
- DEFINE_PROP_UINT8("input6", MAX111xState, reset_input[6], 0x90),
- DEFINE_PROP_UINT8("input7", MAX111xState, reset_input[7], 0x80),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void max111x_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->transfer = max111x_transfer;
- dc->reset = max111x_reset;
- dc->vmsd = &vmstate_max111x;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo max111x_info = {
- .name = TYPE_MAX_111X,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(MAX111xState),
- .class_init = max111x_class_init,
- .abstract = true,
-};
-
-static void max1110_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = max1110_realize;
- device_class_set_props(dc, max1110_properties);
-}
-
-static const TypeInfo max1110_info = {
- .name = TYPE_MAX_1110,
- .parent = TYPE_MAX_111X,
- .class_init = max1110_class_init,
-};
-
-static void max1111_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = max1111_realize;
- device_class_set_props(dc, max1111_properties);
-}
-
-static const TypeInfo max1111_info = {
- .name = TYPE_MAX_1111,
- .parent = TYPE_MAX_111X,
- .class_init = max1111_class_init,
-};
-
-static void max111x_register_types(void)
-{
- type_register_static(&max111x_info);
- type_register_static(&max1110_info);
- type_register_static(&max1111_info);
-}
-
-type_init(max111x_register_types)
diff --git a/hw/adc/meson.build b/hw/adc/meson.build
index a4f85b7..7f7acc1 100644
--- a/hw/adc/meson.build
+++ b/hw/adc/meson.build
@@ -2,4 +2,3 @@ system_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_adc.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
system_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq-xadc.c'))
-system_ss.add(when: 'CONFIG_MAX111X', if_true: files('max111x.c'))
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
index de8469d..ddb219d 100644
--- a/hw/adc/npcm7xx_adc.c
+++ b/hw/adc/npcm7xx_adc.c
@@ -267,12 +267,11 @@ static const VMStateDescription vmstate_npcm7xx_adc = {
},
};
-static Property npcm7xx_timer_properties[] = {
+static const Property npcm7xx_timer_properties[] = {
DEFINE_PROP_UINT32("iref", NPCM7xxADCState, iref, NPCM7XX_ADC_DEFAULT_IREF),
- DEFINE_PROP_END_OF_LIST(),
};
-static void npcm7xx_adc_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_adc_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c
index e9df6ea..a490ae6 100644
--- a/hw/adc/stm32f2xx_adc.c
+++ b/hw/adc/stm32f2xx_adc.c
@@ -284,11 +284,11 @@ static void stm32f2xx_adc_init(Object *obj)
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
-static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data)
+static void stm32f2xx_adc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_adc_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_adc_reset);
dc->vmsd = &vmstate_stm32f2xx_adc;
}
diff --git a/hw/adc/zynq-xadc.c b/hw/adc/zynq-xadc.c
index 3426831..748a51b 100644
--- a/hw/adc/zynq-xadc.c
+++ b/hw/adc/zynq-xadc.c
@@ -281,12 +281,12 @@ static const VMStateDescription vmstate_zynq_xadc = {
}
};
-static void zynq_xadc_class_init(ObjectClass *klass, void *data)
+static void zynq_xadc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_zynq_xadc;
- dc->reset = zynq_xadc_reset;
+ device_class_set_legacy_reset(dc, zynq_xadc_reset);
}
static const TypeInfo zynq_xadc_info = {
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
index 52a1fa3..19562b5 100644
--- a/hw/alpha/dp264.c
+++ b/hw/alpha/dp264.c
@@ -8,6 +8,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "exec/target_page.h"
#include "elf.h"
#include "hw/loader.h"
#include "alpha_sys.h"
@@ -144,7 +145,7 @@ static void clipper_init(MachineState *machine)
}
size = load_elf(palcode_filename, NULL, cpu_alpha_superpage_to_phys,
NULL, &palcode_entry, NULL, NULL, NULL,
- 0, EM_ALPHA, 0, 0);
+ ELFDATA2LSB, EM_ALPHA, 0, 0);
if (size < 0) {
error_report("could not load palcode '%s'", palcode_filename);
exit(1);
@@ -163,7 +164,7 @@ static void clipper_init(MachineState *machine)
size = load_elf(kernel_filename, NULL, cpu_alpha_superpage_to_phys,
NULL, &kernel_entry, &kernel_low, NULL, NULL,
- 0, EM_ALPHA, 0, 0);
+ ELFDATA2LSB, EM_ALPHA, 0, 0);
if (size < 0) {
error_report("could not load kernel '%s'", kernel_filename);
exit(1);
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index e8711ae..4c56f98 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -9,6 +9,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/units.h"
+#include "exec/cpu-interrupt.h"
#include "qapi/error.h"
#include "hw/pci/pci_host.h"
#include "cpu.h"
@@ -934,7 +935,7 @@ static const TypeInfo typhoon_pcihost_info = {
};
static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 1ad60da..f543d94 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -2,6 +2,7 @@ config ARM_VIRT
bool
default y
depends on ARM
+ depends on TCG || KVM || HVF
imply PCI_DEVICES
imply TEST_DEVICES
imply VFIO_AMD_XGBE
@@ -37,13 +38,6 @@ config ARM_VIRT
select ACPI_CXL
select ACPI_HMAT
-config CHEETAH
- bool
- default y
- depends on TCG && ARM
- select OMAP
- select TSC210X
-
config CUBIEBOARD
bool
default y
@@ -77,7 +71,7 @@ config HIGHBANK
depends on TCG && ARM
select A9MPCORE
select A15MPCORE
- select AHCI
+ select AHCI_SYSBUS
select ARM_TIMER # sp804
select ARM_V7M
select PL011 # UART
@@ -101,14 +95,6 @@ config INTEGRATOR
select PL181 # display
select SMC91C111
-config MAINSTONE
- bool
- default y
- depends on TCG && ARM
- select PXA2XX
- select PFLASH_CFI01
- select SMC91C111
-
config MPS3R
bool
default y
@@ -119,7 +105,7 @@ config MUSCA
default y
depends on TCG && ARM
select ARMSSE
- select PL011
+ select PL011 # UART
select PL031
select SPLIT_IRQ
select UNIMP
@@ -136,7 +122,7 @@ config MUSICPAL
select MARVELL_88W8618
select PTIMER
select PFLASH_CFI02
- select SERIAL
+ select SERIAL_MM
select WM8750
config NETDUINO2
@@ -157,79 +143,13 @@ config OLIMEX_STM32_H405
depends on TCG && ARM
select STM32F405_SOC
-config NSERIES
- bool
- default y
- depends on TCG && ARM
- select OMAP
- select TMP105 # temperature sensor
- select BLIZZARD # LCD/TV controller
- select ONENAND
- select TSC210X # touchscreen/sensors/audio
- select TSC2005 # touchscreen/sensors/keypad
- select LM832X # GPIO keyboard chip
- select TWL92230 # energy-management
- select TUSB6010
-
config OMAP
bool
select FRAMEBUFFER
select I2C
- select ECC
- select NAND
select PFLASH_CFI01
select SD
- select SERIAL
-
-config PXA2XX
- bool
- select FRAMEBUFFER
- select I2C
- select SERIAL
- select SD
- select SSI
- select USB_OHCI_SYSBUS
- select PCMCIA
-
-config GUMSTIX
- bool
- default y
- depends on TCG && ARM
- select PFLASH_CFI01
- select SMC91C111
- select PXA2XX
-
-config TOSA
- bool
- default y
- depends on TCG && ARM
- select ZAURUS # scoop
- select MICRODRIVE
- select PXA2XX
- select LED
-
-config SPITZ
- bool
- default y
- depends on TCG && ARM
- select ADS7846 # touch-screen controller
- select MAX111X # A/D converter
- select WM8750 # audio codec
- select MAX7310 # GPIO expander
- select ZAURUS # scoop
- select NAND # memory
- select ECC # Error-correcting for NAND
- select MICRODRIVE
- select PXA2XX
-
-config Z2
- bool
- default y
- depends on TCG && ARM
- select PFLASH_CFI01
- select WM8750
- select PL011 # UART
- select PXA2XX
+ select SERIAL_MM
config REALVIEW
bool
@@ -248,7 +168,7 @@ config REALVIEW
select WM8750 # audio codec
select LSI_SCSI_PCI
select PCI
- select PL011 # UART
+ select PL011 # UART
select PL031 # RTC
select PL041 # audio codec
select PL050 # keyboard/mouse
@@ -267,7 +187,7 @@ config SBSA_REF
depends on TCG && AARCH64
imply PCI_DEVICES
select DEVICE_TREE
- select AHCI
+ select AHCI_SYSBUS
select ARM_SMMUV3
select GPIO_KEY
select PCI_EXPRESS
@@ -316,14 +236,15 @@ config STM32VLDISCOVERY
config STRONGARM
bool
- select PXA2XX
+ select PXA2XX_TIMER
+ select SSI
config COLLIE
bool
default y
depends on TCG && ARM
select PFLASH_CFI01
- select ZAURUS # scoop
+ select ZAURUS_SCOOP
select STRONGARM
config SX1
@@ -374,7 +295,7 @@ config ZYNQ
select PL330
select SDHCI
select SSI_M25P80
- select USB_EHCI_SYSBUS
+ select USB_CHIPIDEA
select XILINX # UART
select XILINX_AXI
select XILINX_SPI
@@ -390,7 +311,7 @@ config ARM_V7M
config ALLWINNER_A10
bool
- select AHCI
+ select AHCI_SYSBUS
select ALLWINNER_A10_PIT
select ALLWINNER_A10_PIC
select ALLWINNER_A10_CCM
@@ -398,8 +319,9 @@ config ALLWINNER_A10
select ALLWINNER_WDT
select ALLWINNER_EMAC
select ALLWINNER_I2C
+ select ALLWINNER_A10_SPI
select AXP2XX_PMU
- select SERIAL
+ select SERIAL_MM
select UNIMP
select USB_OHCI_SYSBUS
@@ -411,7 +333,7 @@ config ALLWINNER_H3
select ALLWINNER_SUN8I_EMAC
select ALLWINNER_I2C
select ALLWINNER_WDT
- select SERIAL
+ select SERIAL_MM
select ARM_TIMER
select ARM_GIC
select UNIMP
@@ -422,12 +344,12 @@ config ALLWINNER_H3
config ALLWINNER_R40
bool
default y if TCG && ARM
- select AHCI
+ select AHCI_SYSBUS
select ALLWINNER_SRAMC
select ALLWINNER_A10_PIT
select ALLWINNER_WDT
select AXP2XX_PMU
- select SERIAL
+ select SERIAL_MM
select ARM_TIMER
select ARM_GIC
select UNIMP
@@ -466,6 +388,7 @@ config STM32F405_SOC
bool
select ARM_V7M
select OR_IRQ
+ select STM32_RCC
select STM32F4XX_SYSCFG
select STM32F4XX_EXTI
@@ -490,7 +413,7 @@ config XLNX_ZYNQMP_ARM
bool
default y if PIXMAN
depends on TCG && AARCH64
- select AHCI
+ select AHCI_SYSBUS
select ARM_GIC
select CADENCE
select CPU_CLUSTER
@@ -515,7 +438,7 @@ config XLNX_VERSAL
select ARM_GIC
select CPU_CLUSTER
select DEVICE_TREE
- select PL011
+ select PL011 # UART
select CADENCE
select VIRTIO_MMIO
select UNIMP
@@ -542,12 +465,25 @@ config NPCM7XX
select ISL_PMBUS_VR
select PL310 # cache controller
select PMBUS
- select SERIAL
+ select SERIAL_MM
select SSI
select UNIMP
select PCA954X
select USB_OHCI_SYSBUS
+config NPCM8XX
+ bool
+ default y
+ depends on TCG && AARCH64
+ select ARM_GIC
+ select SMBUS
+ select PL310 # cache controller
+ select NPCM7XX
+ select SERIAL
+ select SSI
+ select UNIMP
+
+
config FSL_IMX25
bool
default y
@@ -556,6 +492,7 @@ config FSL_IMX25
select IMX
select IMX_FEC
select IMX_I2C
+ select USB_CHIPIDEA
select WDT_IMX2
select SDHCI
@@ -564,7 +501,7 @@ config FSL_IMX31
default y
depends on TCG && ARM
imply I2C_DEVICES
- select SERIAL
+ select SERIAL_MM
select IMX
select IMX_I2C
select WDT_IMX2
@@ -583,6 +520,8 @@ config FSL_IMX6
select PL310 # cache controller
select PCI_EXPRESS_DESIGNWARE
select SDHCI
+ select USB_CHIPIDEA
+ select OR_IRQ
config ASPEED_SOC
bool
@@ -593,7 +532,7 @@ config ASPEED_SOC
select I2C
select DPS310
select PCA9552
- select SERIAL
+ select SERIAL_MM
select SMBUS_EEPROM
select PCA954X
select SSI
@@ -606,6 +545,7 @@ config ASPEED_SOC
select PMBUS
select MAX31785
select FSI_APB2OPB_ASPEED
+ select AT24C
config MPS2
bool
@@ -639,7 +579,33 @@ config FSL_IMX7
select WDT_IMX2
select PCI_EXPRESS_DESIGNWARE
select SDHCI
+ select OR_IRQ
select UNIMP
+ select USB_CHIPIDEA
+
+config FSL_IMX8MP
+ bool
+ imply I2C_DEVICES
+ imply PCI_DEVICES
+ select ARM_GIC
+ select FSL_IMX8MP_ANALOG
+ select FSL_IMX8MP_CCM
+ select IMX
+ select IMX_FEC
+ select IMX_I2C
+ select OR_IRQ
+ select PCI_EXPRESS_DESIGNWARE
+ select PCI_EXPRESS_FSL_IMX8M_PHY
+ select SDHCI
+ select UNIMP
+ select USB_DWC3
+ select WDT_IMX2
+
+config FSL_IMX8MP_EVK
+ bool
+ default y
+ depends on TCG && AARCH64
+ select FSL_IMX8MP
config ARM_SMMUV3
bool
@@ -655,6 +621,7 @@ config FSL_IMX6UL
select IMX_I2C
select WDT_IMX2
select SDHCI
+ select USB_CHIPIDEA
select UNIMP
config MICROBIT
@@ -681,15 +648,10 @@ config MSF2
bool
select ARM_V7M
select PTIMER
- select SERIAL
+ select SERIAL_MM
select SSI
select UNIMP
-config ZAURUS
- bool
- select NAND
- select ECC
-
config ARMSSE
bool
select ARM_V7M
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
index 57d5d80..dc910d4 100644
--- a/hw/arm/allwinner-a10.c
+++ b/hw/arm/allwinner-a10.c
@@ -17,12 +17,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/sysbus.h"
#include "hw/arm/allwinner-a10.h"
#include "hw/misc/unimp.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/usb/hcd-ohci.h"
#include "hw/loader.h"
@@ -35,6 +36,7 @@
#define AW_A10_PIC_REG_BASE 0x01c20400
#define AW_A10_PIT_REG_BASE 0x01c20c00
#define AW_A10_UART0_REG_BASE 0x01c28000
+#define AW_A10_SPI0_BASE 0x01c05000
#define AW_A10_EMAC_BASE 0x01c0b000
#define AW_A10_EHCI_BASE 0x01c14000
#define AW_A10_OHCI_BASE 0x01c14400
@@ -49,9 +51,8 @@ void allwinner_a10_bootrom_setup(AwA10State *s, BlockBackend *blk)
g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size);
if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) {
- error_setg(&error_fatal, "%s: failed to read BlockBackend data",
- __func__);
- return;
+ error_report("%s: failed to read BlockBackend data", __func__);
+ exit(1);
}
rom_add_blob("allwinner-a10.bootrom", buffer, rom_size,
@@ -80,6 +81,8 @@ static void aw_a10_init(Object *obj)
object_initialize_child(obj, "i2c0", &s->i2c0, TYPE_AW_I2C);
+ object_initialize_child(obj, "spi0", &s->spi0, TYPE_AW_A10_SPI);
+
for (size_t i = 0; i < AW_A10_NUM_USB; i++) {
object_initialize_child(obj, "ehci[*]", &s->ehci[i],
TYPE_PLATFORM_EHCI);
@@ -155,7 +158,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
/* FIXME use a qdev chardev prop instead of serial_hd() */
serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2,
qdev_get_gpio_in(dev, 1),
- 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
+ 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
for (size_t i = 0; i < AW_A10_NUM_USB; i++) {
g_autofree char *bus = g_strdup_printf("usb-bus.%zu", i);
@@ -195,12 +198,17 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c0), 0, AW_A10_I2C0_BASE);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0, qdev_get_gpio_in(dev, 7));
+ /* SPI */
+ sysbus_realize(SYS_BUS_DEVICE(&s->spi0), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi0), 0, AW_A10_SPI0_BASE);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi0), 0, qdev_get_gpio_in(dev, 10));
+
/* WDT */
sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_fatal);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->wdt), 0, AW_A10_WDT_BASE, 1);
}
-static void aw_a10_class_init(ObjectClass *oc, void *data)
+static void aw_a10_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 6870c3f..edffc21 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -24,11 +24,11 @@
#include "qemu/units.h"
#include "hw/qdev-core.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/misc/unimp.h"
#include "hw/usb/hcd-ehci.h"
#include "hw/loader.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/arm/allwinner-h3.h"
#include "target/arm/cpu-qom.h"
#include "target/arm/gtimer.h"
@@ -182,9 +182,8 @@ void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk)
g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size);
if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) {
- error_setg(&error_fatal, "%s: failed to read BlockBackend data",
- __func__);
- return;
+ error_report("%s: failed to read BlockBackend data", __func__);
+ exit(1);
}
rom_add_blob("allwinner-h3.bootrom", buffer, rom_size,
@@ -409,19 +408,19 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
/* UART0. For future clocktree API: All UARTS are connected to APB2_CLK. */
serial_mm_init(get_system_memory(), s->memmap[AW_H3_DEV_UART0], 2,
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART0),
- 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
+ 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
/* UART1 */
serial_mm_init(get_system_memory(), s->memmap[AW_H3_DEV_UART1], 2,
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART1),
- 115200, serial_hd(1), DEVICE_NATIVE_ENDIAN);
+ 115200, serial_hd(1), DEVICE_LITTLE_ENDIAN);
/* UART2 */
serial_mm_init(get_system_memory(), s->memmap[AW_H3_DEV_UART2], 2,
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART2),
- 115200, serial_hd(2), DEVICE_NATIVE_ENDIAN);
+ 115200, serial_hd(2), DEVICE_LITTLE_ENDIAN);
/* UART3 */
serial_mm_init(get_system_memory(), s->memmap[AW_H3_DEV_UART3], 2,
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART3),
- 115200, serial_hd(3), DEVICE_NATIVE_ENDIAN);
+ 115200, serial_hd(3), DEVICE_LITTLE_ENDIAN);
/* DRAMC */
sysbus_realize(SYS_BUS_DEVICE(&s->dramc), &error_fatal);
@@ -467,7 +466,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
}
}
-static void allwinner_h3_class_init(ObjectClass *oc, void *data)
+static void allwinner_h3_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
index b8c7202..0bf7008 100644
--- a/hw/arm/allwinner-r40.c
+++ b/hw/arm/allwinner-r40.c
@@ -26,11 +26,11 @@
#include "hw/boards.h"
#include "hw/qdev-core.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/misc/unimp.h"
#include "hw/usb/hcd-ehci.h"
#include "hw/loader.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/arm/allwinner-r40.h"
#include "hw/misc/allwinner-r40-dramc.h"
#include "target/arm/cpu-qom.h"
@@ -231,9 +231,8 @@ bool allwinner_r40_bootrom_setup(AwR40State *s, BlockBackend *blk, int unit)
struct boot_file_head *head = (struct boot_file_head *)buffer;
if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) {
- error_setg(&error_fatal, "%s: failed to read BlockBackend data",
- __func__);
- return false;
+ error_report("%s: failed to read BlockBackend data", __func__);
+ exit(1);
}
/* we only check the magic string here. */
@@ -493,7 +492,7 @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
serial_mm_init(get_system_memory(), addr, 2,
qdev_get_gpio_in(DEVICE(&s->gic), uart_irqs[i]),
- 115200, serial_hd(i), DEVICE_NATIVE_ENDIAN);
+ 115200, serial_hd(i), DEVICE_LITTLE_ENDIAN);
}
/* I2C */
@@ -540,7 +539,7 @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
}
}
-static void allwinner_r40_class_init(ObjectClass *oc, void *data)
+static void allwinner_r40_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 91502d1..50ab7f4 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -72,12 +72,13 @@ struct ARMSSEInfo {
bool has_cpu_pwrctrl;
bool has_sse_counter;
bool has_tcms;
- Property *props;
+ uint8_t props_count;
+ const Property *props;
const ARMSSEDeviceInfo *devinfo;
const bool *irq_is_common;
};
-static Property iotkit_properties[] = {
+static const Property iotkit_properties[] = {
DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
@@ -87,10 +88,9 @@ static Property iotkit_properties[] = {
DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true),
DEFINE_PROP_UINT32("CPU0_MPU_NS", ARMSSE, cpu_mpu_ns[0], 8),
DEFINE_PROP_UINT32("CPU0_MPU_S", ARMSSE, cpu_mpu_s[0], 8),
- DEFINE_PROP_END_OF_LIST()
};
-static Property sse200_properties[] = {
+static const Property sse200_properties[] = {
DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
@@ -104,10 +104,9 @@ static Property sse200_properties[] = {
DEFINE_PROP_UINT32("CPU0_MPU_S", ARMSSE, cpu_mpu_s[0], 8),
DEFINE_PROP_UINT32("CPU1_MPU_NS", ARMSSE, cpu_mpu_ns[1], 8),
DEFINE_PROP_UINT32("CPU1_MPU_S", ARMSSE, cpu_mpu_s[1], 8),
- DEFINE_PROP_END_OF_LIST()
};
-static Property sse300_properties[] = {
+static const Property sse300_properties[] = {
DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
@@ -117,7 +116,6 @@ static Property sse300_properties[] = {
DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true),
DEFINE_PROP_UINT32("CPU0_MPU_NS", ARMSSE, cpu_mpu_ns[0], 8),
DEFINE_PROP_UINT32("CPU0_MPU_S", ARMSSE, cpu_mpu_s[0], 8),
- DEFINE_PROP_END_OF_LIST()
};
static const ARMSSEDeviceInfo iotkit_devices[] = {
@@ -528,6 +526,7 @@ static const ARMSSEInfo armsse_variants[] = {
.has_sse_counter = false,
.has_tcms = false,
.props = iotkit_properties,
+ .props_count = ARRAY_SIZE(iotkit_properties),
.devinfo = iotkit_devices,
.irq_is_common = sse200_irq_is_common,
},
@@ -549,6 +548,7 @@ static const ARMSSEInfo armsse_variants[] = {
.has_sse_counter = false,
.has_tcms = false,
.props = sse200_properties,
+ .props_count = ARRAY_SIZE(sse200_properties),
.devinfo = sse200_devices,
.irq_is_common = sse200_irq_is_common,
},
@@ -570,6 +570,7 @@ static const ARMSSEInfo armsse_variants[] = {
.has_sse_counter = true,
.has_tcms = true,
.props = sse300_properties,
+ .props_count = ARRAY_SIZE(sse300_properties),
.devinfo = sse300_devices,
.irq_is_common = sse300_irq_is_common,
},
@@ -1690,7 +1691,7 @@ static void armsse_reset(DeviceState *dev)
s->nsccfg = 0;
}
-static void armsse_class_init(ObjectClass *klass, void *data)
+static void armsse_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass);
@@ -1699,8 +1700,8 @@ static void armsse_class_init(ObjectClass *klass, void *data)
dc->realize = armsse_realize;
dc->vmsd = &armsse_vmstate;
- device_class_set_props(dc, info->props);
- dc->reset = armsse_reset;
+ device_class_set_props_n(dc, info->props, info->props_count);
+ device_class_set_legacy_reset(dc, armsse_reset);
iic->check = armsse_idau_check;
asc->info = info;
}
@@ -1712,7 +1713,7 @@ static const TypeInfo armsse_info = {
.class_size = sizeof(ARMSSEClass),
.instance_init = armsse_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_IDAU_INTERFACE },
{ }
}
@@ -1729,9 +1730,9 @@ static void armsse_register_types(void)
.name = armsse_variants[i].name,
.parent = TYPE_ARM_SSE,
.class_init = armsse_class_init,
- .class_data = (void *)&armsse_variants[i],
+ .class_data = &armsse_variants[i],
};
- type_register(&ti);
+ type_register_static(&ti);
}
}
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 7c68525..cea3eb4 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -16,7 +16,7 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-clock.h"
#include "elf.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/log.h"
@@ -140,7 +140,7 @@ static MemTxResult v7m_sysreg_ns_write(void *opaque, hwaddr addr,
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
return memory_region_dispatch_write(mr, addr, value,
- size_memop(size) | MO_TE, attrs);
+ size_memop(size) | MO_LE, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
@@ -160,7 +160,7 @@ static MemTxResult v7m_sysreg_ns_read(void *opaque, hwaddr addr,
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
return memory_region_dispatch_read(mr, addr, data,
- size_memop(size) | MO_TE, attrs);
+ size_memop(size) | MO_LE, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
@@ -174,7 +174,7 @@ static MemTxResult v7m_sysreg_ns_read(void *opaque, hwaddr addr,
static const MemoryRegionOps v7m_sysreg_ns_ops = {
.read_with_attrs = v7m_sysreg_ns_read,
.write_with_attrs = v7m_sysreg_ns_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static MemTxResult v7m_systick_write(void *opaque, hwaddr addr,
@@ -187,7 +187,7 @@ static MemTxResult v7m_systick_write(void *opaque, hwaddr addr,
/* Direct the access to the correct systick */
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
return memory_region_dispatch_write(mr, addr, value,
- size_memop(size) | MO_TE, attrs);
+ size_memop(size) | MO_LE, attrs);
}
static MemTxResult v7m_systick_read(void *opaque, hwaddr addr,
@@ -199,14 +199,14 @@ static MemTxResult v7m_systick_read(void *opaque, hwaddr addr,
/* Direct the access to the correct systick */
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
- return memory_region_dispatch_read(mr, addr, data, size_memop(size) | MO_TE,
- attrs);
+ return memory_region_dispatch_read(mr, addr, data,
+ size_memop(size) | MO_LE, attrs);
}
static const MemoryRegionOps v7m_systick_ops = {
.read_with_attrs = v7m_systick_read,
.write_with_attrs = v7m_systick_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
/*
@@ -538,7 +538,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
}
}
-static Property armv7m_properties[] = {
+static const Property armv7m_properties[] = {
DEFINE_PROP_STRING("cpu-type", ARMv7MState, cpu_type),
DEFINE_PROP_LINK("memory", ARMv7MState, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
@@ -552,7 +552,6 @@ static Property armv7m_properties[] = {
DEFINE_PROP_BOOL("dsp", ARMv7MState, dsp, true),
DEFINE_PROP_UINT32("mpu-ns-regions", ARMv7MState, mpu_ns_regions, UINT_MAX),
DEFINE_PROP_UINT32("mpu-s-regions", ARMv7MState, mpu_s_regions, UINT_MAX),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_armv7m = {
@@ -566,7 +565,7 @@ static const VMStateDescription vmstate_armv7m = {
}
};
-static void armv7m_class_init(ObjectClass *klass, void *data)
+static void armv7m_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -609,7 +608,7 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename,
if (kernel_filename) {
image_size = load_elf_as(kernel_filename, NULL, NULL, NULL,
&entry, NULL, NULL,
- NULL, 0, EM_ARM, 1, 0, as);
+ NULL, ELFDATA2LSB, EM_ARM, 1, 0, as);
if (image_size < 0) {
image_size = load_image_targphys_as(kernel_filename, mem_base,
mem_size, as);
@@ -631,14 +630,13 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename,
qemu_register_reset(armv7m_reset, cpu);
}
-static Property bitband_properties[] = {
+static const Property bitband_properties[] = {
DEFINE_PROP_UINT32("base", BitBandState, base, 0),
DEFINE_PROP_LINK("source-memory", BitBandState, source_memory,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void bitband_class_init(ObjectClass *klass, void *data)
+static void bitband_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index fd5603f..d0b3336 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -23,13 +23,14 @@
#include "hw/sensor/tmp105.h"
#include "hw/misc/led.h"
#include "hw/qdev-properties.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/reset.h"
+#include "system/block-backend.h"
+#include "system/reset.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
+#include "qemu/datadir.h"
#include "qemu/units.h"
#include "hw/qdev-clock.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static struct arm_boot_info aspeed_board_binfo = {
.board_id = -1, /* device-tree-only board */
@@ -181,14 +182,12 @@ struct AspeedMachineState {
#ifdef TARGET_AARCH64
/* AST2700 evb hardware value */
-#define AST2700_EVB_HW_STRAP1 0x000000C0
-#define AST2700_EVB_HW_STRAP2 0x00000003
+/* SCU HW Strap1 */
+#define AST2700_EVB_HW_STRAP1 0x00000800
+/* SCUIO HW Strap1 */
+#define AST2700_EVB_HW_STRAP2 0x00000700
#endif
-/* Tacoma hardware value */
-#define TACOMA_BMC_HW_STRAP1 0x00000000
-#define TACOMA_BMC_HW_STRAP2 0x00000040
-
/* Rainier hardware value: (QEMU prototype) */
#define RAINIER_BMC_HW_STRAP1 (0x00422016 | SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC)
#define RAINIER_BMC_HW_STRAP2 0x80000848
@@ -307,6 +306,33 @@ static void aspeed_install_boot_rom(AspeedMachineState *bmc, BlockBackend *blk,
rom_size, &error_abort);
}
+#define VBOOTROM_FILE_NAME "ast27x0_bootrom.bin"
+
+/*
+ * This function locates the vbootrom image file specified via the command line
+ * using the -bios option. It loads the specified image into the vbootrom
+ * memory region and handles errors if the file cannot be found or loaded.
+ */
+static void aspeed_load_vbootrom(AspeedMachineState *bmc, const char *bios_name,
+ Error **errp)
+{
+ g_autofree char *filename = NULL;
+ AspeedSoCState *soc = bmc->soc;
+ int ret;
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (!filename) {
+ error_setg(errp, "Could not find vbootrom image '%s'", bios_name);
+ return;
+ }
+
+ ret = load_image_mr(filename, &soc->vbootrom);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load vbootrom image '%s'", bios_name);
+ return;
+ }
+}
+
void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
unsigned int count, int unit0)
{
@@ -338,10 +364,20 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo, bool emmc,
return;
}
card = qdev_new(emmc ? TYPE_EMMC : TYPE_SD_CARD);
- if (emmc) {
+
+ /*
+ * Force the boot properties of the eMMC device only when the
+ * machine is strapped to boot from eMMC. Without these
+ * settings, the machine would not boot.
+ *
+ * This also allows the machine to use an eMMC device without
+ * boot areas when booting from the flash device (or -kernel)
+ * Ideally, the device and its properties should be defined on
+ * the command line.
+ */
+ if (emmc && boot_emmc) {
qdev_prop_set_uint64(card, "boot-partition-size", 1 * MiB);
- qdev_prop_set_uint8(card, "boot-config",
- boot_emmc ? 0x1 << 3 : 0x0);
+ qdev_prop_set_uint8(card, "boot-config", 0x1 << 3);
}
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
&error_fatal);
@@ -358,11 +394,11 @@ static void connect_serial_hds_to_uarts(AspeedMachineState *bmc)
int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default;
aspeed_soc_uart_set_chr(s, uart_chosen, serial_hd(0));
- for (int i = 1, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) {
+ for (int i = 1, uart = sc->uarts_base; i < sc->uarts_num; uart++) {
if (uart == uart_chosen) {
continue;
}
- aspeed_soc_uart_set_chr(s, uart, serial_hd(i));
+ aspeed_soc_uart_set_chr(s, uart, serial_hd(i++));
}
}
@@ -372,6 +408,7 @@ static void aspeed_machine_init(MachineState *machine)
AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
AspeedSoCClass *sc;
int i;
+ const char *bios_name = NULL;
DriveInfo *emmc0 = NULL;
bool boot_emmc;
@@ -403,6 +440,12 @@ static void aspeed_machine_init(MachineState *machine)
OBJECT(get_system_memory()), &error_abort);
object_property_set_link(OBJECT(bmc->soc), "dram",
OBJECT(machine->ram), &error_abort);
+ if (amc->sdhci_wp_inverted) {
+ for (i = 0; i < bmc->soc->sdhci.num_slots; i++) {
+ object_property_set_bool(OBJECT(&bmc->soc->sdhci.slots[i]),
+ "wp-inverted", true, &error_abort);
+ }
+ }
if (machine->kernel_filename) {
/*
* When booting with a -kernel command line there is no u-boot
@@ -444,14 +487,14 @@ static void aspeed_machine_init(MachineState *machine)
amc->i2c_init(bmc);
}
- for (i = 0; i < bmc->soc->sdhci.num_slots; i++) {
+ for (i = 0; i < bmc->soc->sdhci.num_slots && defaults_enabled(); i++) {
sdhci_attach_drive(&bmc->soc->sdhci.slots[i],
drive_get(IF_SD, 0, i), false, false);
}
boot_emmc = sc->boot_from_emmc(bmc->soc);
- if (bmc->soc->emmc.num_slots) {
+ if (bmc->soc->emmc.num_slots && defaults_enabled()) {
emmc0 = drive_get(IF_SD, 0, bmc->soc->sdhci.num_slots);
sdhci_attach_drive(&bmc->soc->emmc.slots[0], emmc0, true, boot_emmc);
}
@@ -468,6 +511,11 @@ static void aspeed_machine_init(MachineState *machine)
}
}
+ if (amc->vbootrom) {
+ bios_name = machine->firmware ?: VBOOTROM_FILE_NAME;
+ aspeed_load_vbootrom(bmc, bios_name, &error_abort);
+ }
+
arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo);
}
@@ -1213,7 +1261,7 @@ static void aspeed_machine_ast2600_class_emmc_init(ObjectClass *oc)
"Set or unset boot from EMMC");
}
-static void aspeed_machine_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1229,7 +1277,8 @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data)
aspeed_machine_class_props_init(oc);
}
-static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_palmetto_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1241,11 +1290,13 @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx25l25635f";
amc->num_cs = 1;
amc->i2c_init = palmetto_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 256 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1257,12 +1308,13 @@ static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx25l25635e";
amc->num_cs = 1;
amc->i2c_init = quanta_q71l_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 128 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
}
static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc,
- void *data)
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1275,12 +1327,13 @@ static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc,
amc->num_cs = 1;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON;
amc->i2c_init = palmetto_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 256 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
}
static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc,
- void *data)
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1293,11 +1346,13 @@ static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc,
amc->num_cs = 1;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON;
amc->i2c_init = palmetto_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
}
-static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1309,11 +1364,13 @@ static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx25l25635f";
amc->num_cs = 1;
amc->i2c_init = ast2500_evb_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1326,11 +1383,13 @@ static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx25l25635e";
amc->num_cs = 2;
amc->i2c_init = yosemitev2_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_romulus_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1342,11 +1401,13 @@ static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->i2c_init = romulus_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_tiogapass_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1359,11 +1420,13 @@ static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx25l25635e";
amc->num_cs = 2;
amc->i2c_init = tiogapass_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_sonorapass_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1375,11 +1438,13 @@ static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->i2c_init = sonorapass_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_witherspoon_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1391,11 +1456,13 @@ static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data)
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->i2c_init = witherspoon_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1409,33 +1476,15 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data)
amc->num_cs = 1;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON |
ASPEED_MAC3_ON;
+ amc->sdhci_wp_inverted = true;
amc->i2c_init = ast2600_evb_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
aspeed_machine_ast2600_class_emmc_init(oc);
};
-static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
-
- mc->desc = "OpenPOWER Tacoma BMC (Cortex-A7)";
- amc->soc_name = "ast2600-a3";
- amc->hw_strap1 = TACOMA_BMC_HW_STRAP1;
- amc->hw_strap2 = TACOMA_BMC_HW_STRAP2;
- amc->fmc_model = "mx66l1g45g";
- amc->spi_model = "mx66l1g45g";
- amc->num_cs = 2;
- amc->macs_mask = ASPEED_MAC2_ON;
- amc->i2c_init = witherspoon_bmc_i2c_init; /* Same board layout */
- mc->default_ram_size = 1 * GiB;
- aspeed_machine_class_init_cpus_defaults(mc);
-
- mc->deprecation_reason = "Please use the similar 'rainier-bmc' machine";
-};
-
-static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_g220a_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1448,11 +1497,13 @@ static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data)
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON;
amc->i2c_init = g220a_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1024 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1465,11 +1516,12 @@ static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, void *data)
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON;
amc->i2c_init = fp5280g2_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
-static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_rainier_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1483,6 +1535,7 @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data)
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON;
amc->i2c_init = rainier_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
aspeed_machine_ast2600_class_emmc_init(oc);
@@ -1490,7 +1543,7 @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data)
#define FUJI_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB)
-static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_fuji_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1505,13 +1558,15 @@ static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data)
amc->macs_mask = ASPEED_MAC3_ON;
amc->i2c_init = fuji_bmc_i2c_init;
amc->uart_default = ASPEED_DEV_UART1;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = FUJI_BMC_RAM_SIZE;
aspeed_machine_class_init_cpus_defaults(mc);
};
#define BLETCHLEY_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB)
-static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_bletchley_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1525,16 +1580,17 @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data)
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC2_ON;
amc->i2c_init = bletchley_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = BLETCHLEY_BMC_RAM_SIZE;
aspeed_machine_class_init_cpus_defaults(mc);
}
-static void fby35_reset(MachineState *state, ShutdownCause reason)
+static void fby35_reset(MachineState *state, ResetType type)
{
AspeedMachineState *bmc = ASPEED_MACHINE(state);
AspeedGPIOState *gpio = &bmc->soc->gpio;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/* Board ID: 7 (Class-1, 4 slots) */
object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal);
@@ -1555,7 +1611,7 @@ static void fby35_reset(MachineState *state, ShutdownCause reason)
object_property_set_bool(OBJECT(gpio), "gpioB5", false, &error_fatal);
}
-static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data)
+static void aspeed_machine_fby35_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1566,6 +1622,7 @@ static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data)
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC3_ON;
amc->i2c_init = fby35_i2c_init;
+ mc->auto_create_sdcard = true;
/* FIXME: Replace this macro with something more general */
mc->default_ram_size = FUJI_BMC_RAM_SIZE;
aspeed_machine_class_init_cpus_defaults(mc);
@@ -1594,18 +1651,20 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
connect_serial_hds_to_uarts(bmc);
qdev_realize(DEVICE(bmc->soc), NULL, &error_abort);
- aspeed_board_init_flashes(&bmc->soc->fmc,
- bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
- amc->num_cs,
- 0);
+ if (defaults_enabled()) {
+ aspeed_board_init_flashes(&bmc->soc->fmc,
+ bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
+ amc->num_cs,
+ 0);
- aspeed_board_init_flashes(&bmc->soc->spi[0],
- bmc->spi_model ? bmc->spi_model : amc->spi_model,
- amc->num_cs, amc->num_cs);
+ aspeed_board_init_flashes(&bmc->soc->spi[0],
+ bmc->spi_model ? bmc->spi_model : amc->spi_model,
+ amc->num_cs, amc->num_cs);
- aspeed_board_init_flashes(&bmc->soc->spi[1],
- bmc->spi_model ? bmc->spi_model : amc->spi_model,
- amc->num_cs, (amc->num_cs * 2));
+ aspeed_board_init_flashes(&bmc->soc->spi[1],
+ bmc->spi_model ? bmc->spi_model : amc->spi_model,
+ amc->num_cs, (amc->num_cs * 2));
+ }
if (amc->i2c_init) {
amc->i2c_init(bmc);
@@ -1630,7 +1689,7 @@ static void ast1030_evb_i2c_init(AspeedMachineState *bmc)
}
static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
- void *data)
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1642,20 +1701,31 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
mc->init = aspeed_minibmc_machine_init;
amc->i2c_init = ast1030_evb_i2c_init;
mc->default_ram_size = 0;
- amc->fmc_model = "sst25vf032b";
- amc->spi_model = "sst25vf032b";
+ amc->fmc_model = "w25q80bl";
+ amc->spi_model = "w25q256";
amc->num_cs = 2;
amc->macs_mask = 0;
aspeed_machine_class_init_cpus_defaults(mc);
}
#ifdef TARGET_AARCH64
-static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
+static void ast2700_evb_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = bmc->soc;
+
+ /* LM75 is compatible with TMP105 driver */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0),
+ TYPE_TMP105, 0x4d);
+}
+
+static void aspeed_machine_ast2700a0_evb_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
- mc->desc = "Aspeed AST2700 EVB (Cortex-A35)";
+ mc->alias = "ast2700-evb";
+ mc->desc = "Aspeed AST2700 A0 EVB (Cortex-A35)";
amc->soc_name = "ast2700-a0";
amc->hw_strap1 = AST2700_EVB_HW_STRAP1;
amc->hw_strap2 = AST2700_EVB_HW_STRAP2;
@@ -1664,13 +1734,38 @@ static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
amc->uart_default = ASPEED_DEV_UART12;
+ amc->i2c_init = ast2700_evb_i2c_init;
+ amc->vbootrom = true;
+ mc->auto_create_sdcard = true;
+ mc->default_ram_size = 1 * GiB;
+ aspeed_machine_class_init_cpus_defaults(mc);
+}
+
+static void aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc,
+ const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+ mc->desc = "Aspeed AST2700 A1 EVB (Cortex-A35)";
+ amc->soc_name = "ast2700-a1";
+ amc->hw_strap1 = AST2700_EVB_HW_STRAP1;
+ amc->hw_strap2 = AST2700_EVB_HW_STRAP2;
+ amc->fmc_model = "w25q01jvq";
+ amc->spi_model = "w25q512jv";
+ amc->num_cs = 2;
+ amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
+ amc->uart_default = ASPEED_DEV_UART12;
+ amc->i2c_init = ast2700_evb_i2c_init;
+ amc->vbootrom = true;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
}
#endif
static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc,
- void *data)
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1684,12 +1779,13 @@ static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc,
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON;
amc->i2c_init = qcom_dc_scm_bmc_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc,
- void *data)
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
@@ -1703,6 +1799,7 @@ static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc,
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON;
amc->i2c_init = qcom_dc_scm_firework_i2c_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
};
@@ -1745,10 +1842,6 @@ static const TypeInfo aspeed_machine_types[] = {
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_yosemitev2_class_init,
}, {
- .name = MACHINE_TYPE_NAME("tacoma-bmc"),
- .parent = TYPE_ASPEED_MACHINE,
- .class_init = aspeed_machine_tacoma_class_init,
- }, {
.name = MACHINE_TYPE_NAME("tiogapass-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_tiogapass_class_init,
@@ -1794,9 +1887,13 @@ static const TypeInfo aspeed_machine_types[] = {
.class_init = aspeed_minibmc_machine_ast1030_evb_class_init,
#ifdef TARGET_AARCH64
}, {
- .name = MACHINE_TYPE_NAME("ast2700-evb"),
+ .name = MACHINE_TYPE_NAME("ast2700a0-evb"),
+ .parent = TYPE_ASPEED_MACHINE,
+ .class_init = aspeed_machine_ast2700a0_evb_class_init,
+ }, {
+ .name = MACHINE_TYPE_NAME("ast2700a1-evb"),
.parent = TYPE_ASPEED_MACHINE,
- .class_init = aspeed_machine_ast2700_evb_class_init,
+ .class_init = aspeed_machine_ast2700a1_evb_class_init,
#endif
}, {
.name = TYPE_ASPEED_MACHINE,
diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c
index 9f98ad8..e6e1ee6 100644
--- a/hw/arm/aspeed_ast10x0.c
+++ b/hw/arm/aspeed_ast10x0.c
@@ -11,8 +11,8 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
@@ -116,7 +116,7 @@ static void aspeed_soc_ast1030_init(Object *obj)
char typename[64];
int i;
- if (sscanf(sc->name, "%7s", socname) != 1) {
+ if (sscanf(object_get_typename(obj), "%7s", socname) != 1) {
g_assert_not_reached();
}
@@ -415,7 +415,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
sc->memmap[ASPEED_DEV_JTAG1], 0x20);
}
-static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data)
+static void aspeed_soc_ast1030_class_init(ObjectClass *klass, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO cortex-m4f */
@@ -428,7 +428,6 @@ static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data)
dc->user_creatable = false;
dc->realize = aspeed_soc_ast1030_realize;
- sc->name = "ast1030-a1";
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST1030_A1_SILICON_REV;
sc->sram_size = 0xc0000;
diff --git a/hw/arm/aspeed_ast2400.c b/hw/arm/aspeed_ast2400.c
index d125886..c7b0f21 100644
--- a/hw/arm/aspeed_ast2400.c
+++ b/hw/arm/aspeed_ast2400.c
@@ -15,12 +15,12 @@
#include "qapi/error.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "hw/i2c/aspeed_i2c.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "target/arm/cpu-qom.h"
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
@@ -151,7 +151,7 @@ static void aspeed_ast2400_soc_init(Object *obj)
char socname[8];
char typename[64];
- if (sscanf(sc->name, "%7s", socname) != 1) {
+ if (sscanf(object_get_typename(obj), "%7s", socname) != 1) {
g_assert_not_reached();
}
@@ -224,7 +224,8 @@ static void aspeed_ast2400_soc_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
- object_initialize_child(obj, "sdc", &s->sdhci, TYPE_ASPEED_SDHCI);
+ snprintf(typename, sizeof(typename), "aspeed.sdhci-%s", socname);
+ object_initialize_child(obj, "sdc", &s->sdhci, typename);
object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort);
@@ -501,7 +502,7 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp)
aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
}
-static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data)
+static void aspeed_soc_ast2400_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("arm926"),
@@ -514,7 +515,6 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data)
/* Reason: Uses serial_hds and nd_table in realize() directly */
dc->user_creatable = false;
- sc->name = "ast2400-a1";
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST2400_A1_SILICON_REV;
sc->sram_size = 0x8000;
@@ -530,7 +530,7 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data)
sc->get_irq = aspeed_soc_ast2400_get_irq;
}
-static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data)
+static void aspeed_soc_ast2500_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("arm1176"),
@@ -543,7 +543,6 @@ static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data)
/* Reason: Uses serial_hds and nd_table in realize() directly */
dc->user_creatable = false;
- sc->name = "ast2500-a1";
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST2500_A1_SILICON_REV;
sc->sram_size = 0x9000;
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index be3eb70..d12707f 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -15,7 +15,7 @@
#include "qemu/error-report.h"
#include "hw/i2c/aspeed_i2c.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "target/arm/cpu-qom.h"
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
@@ -157,7 +157,7 @@ static void aspeed_soc_ast2600_init(Object *obj)
char socname[8];
char typename[64];
- if (sscanf(sc->name, "%7s", socname) != 1) {
+ if (sscanf(object_get_typename(obj), "%7s", socname) != 1) {
g_assert_not_reached();
}
@@ -236,8 +236,8 @@ static void aspeed_soc_ast2600_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.gpio-%s-1_8v", socname);
object_initialize_child(obj, "gpio_1_8v", &s->gpio_1_8v, typename);
- object_initialize_child(obj, "sd-controller", &s->sdhci,
- TYPE_ASPEED_SDHCI);
+ snprintf(typename, sizeof(typename), "aspeed.sdhci-%s", socname);
+ object_initialize_child(obj, "sd-controller", &s->sdhci, typename);
object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort);
@@ -247,8 +247,7 @@ static void aspeed_soc_ast2600_init(Object *obj)
&s->sdhci.slots[i], TYPE_SYSBUS_SDHCI);
}
- object_initialize_child(obj, "emmc-controller", &s->emmc,
- TYPE_ASPEED_SDHCI);
+ object_initialize_child(obj, "emmc-controller", &s->emmc, typename);
object_property_set_int(OBJECT(&s->emmc), "num-slots", 1, &error_abort);
@@ -541,7 +540,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
- aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]);
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+ sc->memmap[ASPEED_DEV_GPIO]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
@@ -653,7 +653,7 @@ static bool aspeed_soc_ast2600_boot_from_emmc(AspeedSoCState *s)
return !!(hw_strap1 & SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC);
}
-static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
+static void aspeed_soc_ast2600_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a7"),
@@ -666,7 +666,6 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
/* Reason: The Aspeed SoC can only be instantiated from a board */
dc->user_creatable = false;
- sc->name = "ast2600-a3";
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST2600_A3_SILICON_REV;
sc->sram_size = 0x16400;
diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c
new file mode 100644
index 0000000..7087be4
--- /dev/null
+++ b/hw/arm/aspeed_ast27x0-fc.c
@@ -0,0 +1,200 @@
+/*
+ * ASPEED SoC 2700 family
+ *
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "system/block-backend.h"
+#include "system/system.h"
+#include "hw/arm/aspeed.h"
+#include "hw/boards.h"
+#include "hw/qdev-clock.h"
+#include "hw/arm/aspeed_soc.h"
+#include "hw/loader.h"
+#include "hw/arm/boot.h"
+#include "hw/block/flash.h"
+
+
+#define TYPE_AST2700A1FC MACHINE_TYPE_NAME("ast2700fc")
+OBJECT_DECLARE_SIMPLE_TYPE(Ast2700FCState, AST2700A1FC);
+
+static struct arm_boot_info ast2700fc_board_info = {
+ .board_id = -1, /* device-tree-only board */
+};
+
+struct Ast2700FCState {
+ MachineState parent_obj;
+
+ MemoryRegion ca35_memory;
+ MemoryRegion ca35_dram;
+ MemoryRegion ssp_memory;
+ MemoryRegion tsp_memory;
+
+ Clock *ssp_sysclk;
+ Clock *tsp_sysclk;
+
+ Aspeed27x0SoCState ca35;
+ Aspeed27x0SSPSoCState ssp;
+ Aspeed27x0TSPSoCState tsp;
+
+ bool mmio_exec;
+};
+
+#define AST2700FC_BMC_RAM_SIZE (1 * GiB)
+#define AST2700FC_CM4_DRAM_SIZE (32 * MiB)
+
+#define AST2700FC_HW_STRAP1 0x000000C0
+#define AST2700FC_HW_STRAP2 0x00000003
+#define AST2700FC_FMC_MODEL "w25q01jvq"
+#define AST2700FC_SPI_MODEL "w25q512jv"
+
+static void ast2700fc_ca35_init(MachineState *machine)
+{
+ Ast2700FCState *s = AST2700A1FC(machine);
+ AspeedSoCState *soc;
+ AspeedSoCClass *sc;
+
+ object_initialize_child(OBJECT(s), "ca35", &s->ca35, "ast2700-a1");
+ soc = ASPEED_SOC(&s->ca35);
+ sc = ASPEED_SOC_GET_CLASS(soc);
+
+ memory_region_init(&s->ca35_memory, OBJECT(&s->ca35), "ca35-memory",
+ UINT64_MAX);
+ memory_region_add_subregion(get_system_memory(), 0, &s->ca35_memory);
+
+ if (!memory_region_init_ram(&s->ca35_dram, OBJECT(&s->ca35), "ca35-dram",
+ AST2700FC_BMC_RAM_SIZE, &error_abort)) {
+ return;
+ }
+ if (!object_property_set_link(OBJECT(&s->ca35), "memory",
+ OBJECT(&s->ca35_memory),
+ &error_abort)) {
+ return;
+ };
+ if (!object_property_set_link(OBJECT(&s->ca35), "dram",
+ OBJECT(&s->ca35_dram), &error_abort)) {
+ return;
+ }
+ if (!object_property_set_int(OBJECT(&s->ca35), "ram-size",
+ AST2700FC_BMC_RAM_SIZE, &error_abort)) {
+ return;
+ }
+
+ for (int i = 0; i < sc->macs_num; i++) {
+ if (!qemu_configure_nic_device(DEVICE(&soc->ftgmac100[i]),
+ true, NULL)) {
+ break;
+ }
+ }
+ if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap1",
+ AST2700FC_HW_STRAP1, &error_abort)) {
+ return;
+ }
+ if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap2",
+ AST2700FC_HW_STRAP2, &error_abort)) {
+ return;
+ }
+ aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART12, serial_hd(0));
+ if (!qdev_realize(DEVICE(&s->ca35), NULL, &error_abort)) {
+ return;
+ }
+
+ /*
+ * AST2700 EVB has a LM75 temperature sensor on I2C bus 0 at address 0x4d.
+ */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0), "tmp105", 0x4d);
+
+ aspeed_board_init_flashes(&soc->fmc, AST2700FC_FMC_MODEL, 2, 0);
+ aspeed_board_init_flashes(&soc->spi[0], AST2700FC_SPI_MODEL, 1, 2);
+
+ ast2700fc_board_info.ram_size = machine->ram_size;
+ ast2700fc_board_info.loader_start = sc->memmap[ASPEED_DEV_SDRAM];
+
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &ast2700fc_board_info);
+}
+
+static void ast2700fc_ssp_init(MachineState *machine)
+{
+ AspeedSoCState *soc;
+ Ast2700FCState *s = AST2700A1FC(machine);
+ s->ssp_sysclk = clock_new(OBJECT(s), "SSP_SYSCLK");
+ clock_set_hz(s->ssp_sysclk, 200000000ULL);
+
+ object_initialize_child(OBJECT(s), "ssp", &s->ssp, TYPE_ASPEED27X0SSP_SOC);
+ memory_region_init(&s->ssp_memory, OBJECT(&s->ssp), "ssp-memory",
+ UINT64_MAX);
+
+ qdev_connect_clock_in(DEVICE(&s->ssp), "sysclk", s->ssp_sysclk);
+ if (!object_property_set_link(OBJECT(&s->ssp), "memory",
+ OBJECT(&s->ssp_memory), &error_abort)) {
+ return;
+ }
+
+ soc = ASPEED_SOC(&s->ssp);
+ aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART4, serial_hd(1));
+ if (!qdev_realize(DEVICE(&s->ssp), NULL, &error_abort)) {
+ return;
+ }
+}
+
+static void ast2700fc_tsp_init(MachineState *machine)
+{
+ AspeedSoCState *soc;
+ Ast2700FCState *s = AST2700A1FC(machine);
+ s->tsp_sysclk = clock_new(OBJECT(s), "TSP_SYSCLK");
+ clock_set_hz(s->tsp_sysclk, 200000000ULL);
+
+ object_initialize_child(OBJECT(s), "tsp", &s->tsp, TYPE_ASPEED27X0TSP_SOC);
+ memory_region_init(&s->tsp_memory, OBJECT(&s->tsp), "tsp-memory",
+ UINT64_MAX);
+
+ qdev_connect_clock_in(DEVICE(&s->tsp), "sysclk", s->tsp_sysclk);
+ if (!object_property_set_link(OBJECT(&s->tsp), "memory",
+ OBJECT(&s->tsp_memory), &error_abort)) {
+ return;
+ }
+
+ soc = ASPEED_SOC(&s->tsp);
+ aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART7, serial_hd(2));
+ if (!qdev_realize(DEVICE(&s->tsp), NULL, &error_abort)) {
+ return;
+ }
+}
+
+static void ast2700fc_init(MachineState *machine)
+{
+ ast2700fc_ca35_init(machine);
+ ast2700fc_ssp_init(machine);
+ ast2700fc_tsp_init(machine);
+}
+
+static void ast2700fc_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->alias = "ast2700fc";
+ mc->desc = "ast2700 full core support";
+ mc->init = ast2700fc_init;
+ mc->no_floppy = 1;
+ mc->no_cdrom = 1;
+ mc->min_cpus = mc->max_cpus = mc->default_cpus = 6;
+}
+
+static const TypeInfo ast2700fc_types[] = {
+ {
+ .name = MACHINE_TYPE_NAME("ast2700fc"),
+ .parent = TYPE_MACHINE,
+ .class_init = ast2700fc_class_init,
+ .instance_size = sizeof(Ast2700FCState),
+ },
+};
+
+DEFINE_TYPES(ast2700fc_types)
diff --git a/hw/arm/aspeed_ast27x0-ssp.c b/hw/arm/aspeed_ast27x0-ssp.c
new file mode 100644
index 0000000..80ec599
--- /dev/null
+++ b/hw/arm/aspeed_ast27x0-ssp.c
@@ -0,0 +1,294 @@
+/*
+ * ASPEED Ast27x0 SSP SoC
+ *
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-clock.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/aspeed_soc.h"
+
+#define AST2700_SSP_RAM_SIZE (32 * MiB)
+
+static const hwaddr aspeed_soc_ast27x0ssp_memmap[] = {
+ [ASPEED_DEV_SRAM] = 0x00000000,
+ [ASPEED_DEV_INTC] = 0x72100000,
+ [ASPEED_DEV_SCU] = 0x72C02000,
+ [ASPEED_DEV_SCUIO] = 0x74C02000,
+ [ASPEED_DEV_UART0] = 0x74C33000,
+ [ASPEED_DEV_UART1] = 0x74C33100,
+ [ASPEED_DEV_UART2] = 0x74C33200,
+ [ASPEED_DEV_UART3] = 0x74C33300,
+ [ASPEED_DEV_UART4] = 0x72C1A000,
+ [ASPEED_DEV_INTCIO] = 0x74C18000,
+ [ASPEED_DEV_IPC0] = 0x72C1C000,
+ [ASPEED_DEV_IPC1] = 0x74C39000,
+ [ASPEED_DEV_UART5] = 0x74C33400,
+ [ASPEED_DEV_UART6] = 0x74C33500,
+ [ASPEED_DEV_UART7] = 0x74C33600,
+ [ASPEED_DEV_UART8] = 0x74C33700,
+ [ASPEED_DEV_UART9] = 0x74C33800,
+ [ASPEED_DEV_UART10] = 0x74C33900,
+ [ASPEED_DEV_UART11] = 0x74C33A00,
+ [ASPEED_DEV_UART12] = 0x74C33B00,
+ [ASPEED_DEV_TIMER1] = 0x72C10000,
+};
+
+static const int aspeed_soc_ast27x0ssp_irqmap[] = {
+ [ASPEED_DEV_SCU] = 12,
+ [ASPEED_DEV_UART0] = 164,
+ [ASPEED_DEV_UART1] = 164,
+ [ASPEED_DEV_UART2] = 164,
+ [ASPEED_DEV_UART3] = 164,
+ [ASPEED_DEV_UART4] = 8,
+ [ASPEED_DEV_UART5] = 164,
+ [ASPEED_DEV_UART6] = 164,
+ [ASPEED_DEV_UART7] = 164,
+ [ASPEED_DEV_UART8] = 164,
+ [ASPEED_DEV_UART9] = 164,
+ [ASPEED_DEV_UART10] = 164,
+ [ASPEED_DEV_UART11] = 164,
+ [ASPEED_DEV_UART12] = 164,
+ [ASPEED_DEV_TIMER1] = 16,
+};
+
+/* SSPINT 164 */
+static const int ast2700_ssp132_ssp164_intcmap[] = {
+ [ASPEED_DEV_UART0] = 7,
+ [ASPEED_DEV_UART1] = 8,
+ [ASPEED_DEV_UART2] = 9,
+ [ASPEED_DEV_UART3] = 10,
+ [ASPEED_DEV_UART5] = 11,
+ [ASPEED_DEV_UART6] = 12,
+ [ASPEED_DEV_UART7] = 13,
+ [ASPEED_DEV_UART8] = 14,
+ [ASPEED_DEV_UART9] = 15,
+ [ASPEED_DEV_UART10] = 16,
+ [ASPEED_DEV_UART11] = 17,
+ [ASPEED_DEV_UART12] = 18,
+};
+
+struct nvic_intc_irq_info {
+ int irq;
+ int intc_idx;
+ int orgate_idx;
+ const int *ptr;
+};
+
+static struct nvic_intc_irq_info ast2700_ssp_intcmap[] = {
+ {160, 1, 0, NULL},
+ {161, 1, 1, NULL},
+ {162, 1, 2, NULL},
+ {163, 1, 3, NULL},
+ {164, 1, 4, ast2700_ssp132_ssp164_intcmap},
+ {165, 1, 5, NULL},
+ {166, 1, 6, NULL},
+ {167, 1, 7, NULL},
+ {168, 1, 8, NULL},
+ {169, 1, 9, NULL},
+ {128, 0, 1, NULL},
+ {129, 0, 2, NULL},
+ {130, 0, 3, NULL},
+ {131, 0, 4, NULL},
+ {132, 0, 5, ast2700_ssp132_ssp164_intcmap},
+ {133, 0, 6, NULL},
+ {134, 0, 7, NULL},
+ {135, 0, 8, NULL},
+ {136, 0, 9, NULL},
+};
+
+static qemu_irq aspeed_soc_ast27x0ssp_get_irq(AspeedSoCState *s, int dev)
+{
+ Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(s);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ int or_idx;
+ int idx;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ast2700_ssp_intcmap); i++) {
+ if (sc->irqmap[dev] == ast2700_ssp_intcmap[i].irq) {
+ assert(ast2700_ssp_intcmap[i].ptr);
+ or_idx = ast2700_ssp_intcmap[i].orgate_idx;
+ idx = ast2700_ssp_intcmap[i].intc_idx;
+ return qdev_get_gpio_in(DEVICE(&a->intc[idx].orgates[or_idx]),
+ ast2700_ssp_intcmap[i].ptr[dev]);
+ }
+ }
+
+ return qdev_get_gpio_in(DEVICE(&a->armv7m), sc->irqmap[dev]);
+}
+
+static void aspeed_soc_ast27x0ssp_init(Object *obj)
+{
+ Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(obj);
+ AspeedSoCState *s = ASPEED_SOC(obj);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int i;
+
+ object_initialize_child(obj, "armv7m", &a->armv7m, TYPE_ARMV7M);
+ object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU);
+ s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
+ qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev);
+
+ for (i = 0; i < sc->uarts_num; i++) {
+ object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
+ }
+
+ object_initialize_child(obj, "intc0", &a->intc[0],
+ TYPE_ASPEED_2700SSP_INTC);
+ object_initialize_child(obj, "intc1", &a->intc[1],
+ TYPE_ASPEED_2700SSP_INTCIO);
+
+ object_initialize_child(obj, "timerctrl", &s->timerctrl,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "ipc0", &a->ipc[0],
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "ipc1", &a->ipc[1],
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "scuio", &a->scuio,
+ TYPE_UNIMPLEMENTED_DEVICE);
+}
+
+static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp)
+{
+ Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(dev_soc);
+ AspeedSoCState *s = ASPEED_SOC(dev_soc);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ DeviceState *armv7m;
+ g_autofree char *sram_name = NULL;
+ int i;
+
+ if (!clock_has_source(s->sysclk)) {
+ error_setg(errp, "sysclk clock must be wired up by the board code");
+ return;
+ }
+
+ /* AST27X0 SSP Core */
+ armv7m = DEVICE(&a->armv7m);
+ qdev_prop_set_uint32(armv7m, "num-irq", 256);
+ qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc));
+ qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
+ object_property_set_link(OBJECT(&a->armv7m), "memory",
+ OBJECT(s->memory), &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&a->armv7m), &error_abort);
+
+ sram_name = g_strdup_printf("aspeed.dram.%d",
+ CPU(a->armv7m.cpu)->cpu_index);
+
+ if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size,
+ errp)) {
+ return;
+ }
+ memory_region_add_subregion(s->memory,
+ sc->memmap[ASPEED_DEV_SRAM],
+ &s->sram);
+
+ /* SCU */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
+
+ /* INTC */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) {
+ return;
+ }
+
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0,
+ sc->memmap[ASPEED_DEV_INTC]);
+
+ /* INTCIO */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[1]), errp)) {
+ return;
+ }
+
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0,
+ sc->memmap[ASPEED_DEV_INTCIO]);
+
+ /* irq source orgates -> INTC0 */
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_inpins; i++) {
+ qdev_connect_gpio_out(DEVICE(&a->intc[0].orgates[i]), 0,
+ qdev_get_gpio_in(DEVICE(&a->intc[0]), i));
+ }
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_outpins; i++) {
+ assert(i < ARRAY_SIZE(ast2700_ssp_intcmap));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[0]), i,
+ qdev_get_gpio_in(DEVICE(&a->armv7m),
+ ast2700_ssp_intcmap[i].irq));
+ }
+ /* irq source orgates -> INTCIO */
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_inpins; i++) {
+ qdev_connect_gpio_out(DEVICE(&a->intc[1].orgates[i]), 0,
+ qdev_get_gpio_in(DEVICE(&a->intc[1]), i));
+ }
+ /* INTCIO -> INTC */
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_outpins; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[1]), i,
+ qdev_get_gpio_in(DEVICE(&a->intc[0].orgates[0]), i));
+ }
+ /* UART */
+ if (!aspeed_soc_uart_realize(s, errp)) {
+ return;
+ }
+
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->timerctrl),
+ "aspeed.timerctrl",
+ sc->memmap[ASPEED_DEV_TIMER1], 0x200);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[0]),
+ "aspeed.ipc0",
+ sc->memmap[ASPEED_DEV_IPC0], 0x1000);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[1]),
+ "aspeed.ipc1",
+ sc->memmap[ASPEED_DEV_IPC1], 0x1000);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->scuio),
+ "aspeed.scuio",
+ sc->memmap[ASPEED_DEV_SCUIO], 0x1000);
+}
+
+static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, const void *data)
+{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO: cortex-m4f */
+ NULL
+ };
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc);
+
+ /* Reason: The Aspeed SoC can only be instantiated from a board */
+ dc->user_creatable = false;
+ dc->realize = aspeed_soc_ast27x0ssp_realize;
+
+ sc->valid_cpu_types = valid_cpu_types;
+ sc->silicon_rev = AST2700_A1_SILICON_REV;
+ sc->sram_size = AST2700_SSP_RAM_SIZE;
+ sc->spis_num = 0;
+ sc->ehcis_num = 0;
+ sc->wdts_num = 0;
+ sc->macs_num = 0;
+ sc->uarts_num = 13;
+ sc->uarts_base = ASPEED_DEV_UART0;
+ sc->irqmap = aspeed_soc_ast27x0ssp_irqmap;
+ sc->memmap = aspeed_soc_ast27x0ssp_memmap;
+ sc->num_cpus = 1;
+ sc->get_irq = aspeed_soc_ast27x0ssp_get_irq;
+}
+
+static const TypeInfo aspeed_soc_ast27x0ssp_types[] = {
+ {
+ .name = TYPE_ASPEED27X0SSP_SOC,
+ .parent = TYPE_ASPEED_SOC,
+ .instance_size = sizeof(Aspeed27x0SSPSoCState),
+ .instance_init = aspeed_soc_ast27x0ssp_init,
+ .class_init = aspeed_soc_ast27x0ssp_class_init,
+ },
+};
+
+DEFINE_TYPES(aspeed_soc_ast27x0ssp_types)
diff --git a/hw/arm/aspeed_ast27x0-tsp.c b/hw/arm/aspeed_ast27x0-tsp.c
new file mode 100644
index 0000000..4e0efae
--- /dev/null
+++ b/hw/arm/aspeed_ast27x0-tsp.c
@@ -0,0 +1,294 @@
+/*
+ * ASPEED Ast27x0 TSP SoC
+ *
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-clock.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/aspeed_soc.h"
+
+#define AST2700_TSP_RAM_SIZE (32 * MiB)
+
+static const hwaddr aspeed_soc_ast27x0tsp_memmap[] = {
+ [ASPEED_DEV_SRAM] = 0x00000000,
+ [ASPEED_DEV_INTC] = 0x72100000,
+ [ASPEED_DEV_SCU] = 0x72C02000,
+ [ASPEED_DEV_SCUIO] = 0x74C02000,
+ [ASPEED_DEV_UART0] = 0x74C33000,
+ [ASPEED_DEV_UART1] = 0x74C33100,
+ [ASPEED_DEV_UART2] = 0x74C33200,
+ [ASPEED_DEV_UART3] = 0x74C33300,
+ [ASPEED_DEV_UART4] = 0x72C1A000,
+ [ASPEED_DEV_INTCIO] = 0x74C18000,
+ [ASPEED_DEV_IPC0] = 0x72C1C000,
+ [ASPEED_DEV_IPC1] = 0x74C39000,
+ [ASPEED_DEV_UART5] = 0x74C33400,
+ [ASPEED_DEV_UART6] = 0x74C33500,
+ [ASPEED_DEV_UART7] = 0x74C33600,
+ [ASPEED_DEV_UART8] = 0x74C33700,
+ [ASPEED_DEV_UART9] = 0x74C33800,
+ [ASPEED_DEV_UART10] = 0x74C33900,
+ [ASPEED_DEV_UART11] = 0x74C33A00,
+ [ASPEED_DEV_UART12] = 0x74C33B00,
+ [ASPEED_DEV_TIMER1] = 0x72C10000,
+};
+
+static const int aspeed_soc_ast27x0tsp_irqmap[] = {
+ [ASPEED_DEV_SCU] = 12,
+ [ASPEED_DEV_UART0] = 164,
+ [ASPEED_DEV_UART1] = 164,
+ [ASPEED_DEV_UART2] = 164,
+ [ASPEED_DEV_UART3] = 164,
+ [ASPEED_DEV_UART4] = 8,
+ [ASPEED_DEV_UART5] = 164,
+ [ASPEED_DEV_UART6] = 164,
+ [ASPEED_DEV_UART7] = 164,
+ [ASPEED_DEV_UART8] = 164,
+ [ASPEED_DEV_UART9] = 164,
+ [ASPEED_DEV_UART10] = 164,
+ [ASPEED_DEV_UART11] = 164,
+ [ASPEED_DEV_UART12] = 164,
+ [ASPEED_DEV_TIMER1] = 16,
+};
+
+/* TSPINT 164 */
+static const int ast2700_tsp132_tsp164_intcmap[] = {
+ [ASPEED_DEV_UART0] = 7,
+ [ASPEED_DEV_UART1] = 8,
+ [ASPEED_DEV_UART2] = 9,
+ [ASPEED_DEV_UART3] = 10,
+ [ASPEED_DEV_UART5] = 11,
+ [ASPEED_DEV_UART6] = 12,
+ [ASPEED_DEV_UART7] = 13,
+ [ASPEED_DEV_UART8] = 14,
+ [ASPEED_DEV_UART9] = 15,
+ [ASPEED_DEV_UART10] = 16,
+ [ASPEED_DEV_UART11] = 17,
+ [ASPEED_DEV_UART12] = 18,
+};
+
+struct nvic_intc_irq_info {
+ int irq;
+ int intc_idx;
+ int orgate_idx;
+ const int *ptr;
+};
+
+static struct nvic_intc_irq_info ast2700_tsp_intcmap[] = {
+ {160, 1, 0, NULL},
+ {161, 1, 1, NULL},
+ {162, 1, 2, NULL},
+ {163, 1, 3, NULL},
+ {164, 1, 4, ast2700_tsp132_tsp164_intcmap},
+ {165, 1, 5, NULL},
+ {166, 1, 6, NULL},
+ {167, 1, 7, NULL},
+ {168, 1, 8, NULL},
+ {169, 1, 9, NULL},
+ {128, 0, 1, NULL},
+ {129, 0, 2, NULL},
+ {130, 0, 3, NULL},
+ {131, 0, 4, NULL},
+ {132, 0, 5, ast2700_tsp132_tsp164_intcmap},
+ {133, 0, 6, NULL},
+ {134, 0, 7, NULL},
+ {135, 0, 8, NULL},
+ {136, 0, 9, NULL},
+};
+
+static qemu_irq aspeed_soc_ast27x0tsp_get_irq(AspeedSoCState *s, int dev)
+{
+ Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(s);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ int or_idx;
+ int idx;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ast2700_tsp_intcmap); i++) {
+ if (sc->irqmap[dev] == ast2700_tsp_intcmap[i].irq) {
+ assert(ast2700_tsp_intcmap[i].ptr);
+ or_idx = ast2700_tsp_intcmap[i].orgate_idx;
+ idx = ast2700_tsp_intcmap[i].intc_idx;
+ return qdev_get_gpio_in(DEVICE(&a->intc[idx].orgates[or_idx]),
+ ast2700_tsp_intcmap[i].ptr[dev]);
+ }
+ }
+
+ return qdev_get_gpio_in(DEVICE(&a->armv7m), sc->irqmap[dev]);
+}
+
+static void aspeed_soc_ast27x0tsp_init(Object *obj)
+{
+ Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(obj);
+ AspeedSoCState *s = ASPEED_SOC(obj);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int i;
+
+ object_initialize_child(obj, "armv7m", &a->armv7m, TYPE_ARMV7M);
+ object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU);
+ s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
+ qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev);
+
+ for (i = 0; i < sc->uarts_num; i++) {
+ object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
+ }
+
+ object_initialize_child(obj, "intc0", &a->intc[0],
+ TYPE_ASPEED_2700TSP_INTC);
+ object_initialize_child(obj, "intc1", &a->intc[1],
+ TYPE_ASPEED_2700TSP_INTCIO);
+
+ object_initialize_child(obj, "timerctrl", &s->timerctrl,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "ipc0", &a->ipc[0],
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "ipc1", &a->ipc[1],
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "scuio", &a->scuio,
+ TYPE_UNIMPLEMENTED_DEVICE);
+}
+
+static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp)
+{
+ Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(dev_soc);
+ AspeedSoCState *s = ASPEED_SOC(dev_soc);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ DeviceState *armv7m;
+ g_autofree char *sram_name = NULL;
+ int i;
+
+ if (!clock_has_source(s->sysclk)) {
+ error_setg(errp, "sysclk clock must be wired up by the board code");
+ return;
+ }
+
+ /* AST27X0 TSP Core */
+ armv7m = DEVICE(&a->armv7m);
+ qdev_prop_set_uint32(armv7m, "num-irq", 256);
+ qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc));
+ qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
+ object_property_set_link(OBJECT(&a->armv7m), "memory",
+ OBJECT(s->memory), &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&a->armv7m), &error_abort);
+
+ sram_name = g_strdup_printf("aspeed.dram.%d",
+ CPU(a->armv7m.cpu)->cpu_index);
+
+ if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size,
+ errp)) {
+ return;
+ }
+ memory_region_add_subregion(s->memory,
+ sc->memmap[ASPEED_DEV_SRAM],
+ &s->sram);
+
+ /* SCU */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
+
+ /* INTC */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) {
+ return;
+ }
+
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0,
+ sc->memmap[ASPEED_DEV_INTC]);
+
+ /* INTCIO */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[1]), errp)) {
+ return;
+ }
+
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0,
+ sc->memmap[ASPEED_DEV_INTCIO]);
+
+ /* irq source orgates -> INTC */
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_inpins; i++) {
+ qdev_connect_gpio_out(DEVICE(&a->intc[0].orgates[i]), 0,
+ qdev_get_gpio_in(DEVICE(&a->intc[0]), i));
+ }
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_outpins; i++) {
+ assert(i < ARRAY_SIZE(ast2700_tsp_intcmap));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[0]), i,
+ qdev_get_gpio_in(DEVICE(&a->armv7m),
+ ast2700_tsp_intcmap[i].irq));
+ }
+ /* irq source orgates -> INTC */
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_inpins; i++) {
+ qdev_connect_gpio_out(DEVICE(&a->intc[1].orgates[i]), 0,
+ qdev_get_gpio_in(DEVICE(&a->intc[1]), i));
+ }
+ /* INTCIO -> INTC */
+ for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_outpins; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[1]), i,
+ qdev_get_gpio_in(DEVICE(&a->intc[0].orgates[0]), i));
+ }
+ /* UART */
+ if (!aspeed_soc_uart_realize(s, errp)) {
+ return;
+ }
+
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->timerctrl),
+ "aspeed.timerctrl",
+ sc->memmap[ASPEED_DEV_TIMER1], 0x200);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[0]),
+ "aspeed.ipc0",
+ sc->memmap[ASPEED_DEV_IPC0], 0x1000);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[1]),
+ "aspeed.ipc1",
+ sc->memmap[ASPEED_DEV_IPC1], 0x1000);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->scuio),
+ "aspeed.scuio",
+ sc->memmap[ASPEED_DEV_SCUIO], 0x1000);
+}
+
+static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, const void *data)
+{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO cortex-m4f */
+ NULL
+ };
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc);
+
+ /* Reason: The Aspeed SoC can only be instantiated from a board */
+ dc->user_creatable = false;
+ dc->realize = aspeed_soc_ast27x0tsp_realize;
+
+ sc->valid_cpu_types = valid_cpu_types;
+ sc->silicon_rev = AST2700_A1_SILICON_REV;
+ sc->sram_size = AST2700_TSP_RAM_SIZE;
+ sc->spis_num = 0;
+ sc->ehcis_num = 0;
+ sc->wdts_num = 0;
+ sc->macs_num = 0;
+ sc->uarts_num = 13;
+ sc->uarts_base = ASPEED_DEV_UART0;
+ sc->irqmap = aspeed_soc_ast27x0tsp_irqmap;
+ sc->memmap = aspeed_soc_ast27x0tsp_memmap;
+ sc->num_cpus = 1;
+ sc->get_irq = aspeed_soc_ast27x0tsp_get_irq;
+}
+
+static const TypeInfo aspeed_soc_ast27x0tsp_types[] = {
+ {
+ .name = TYPE_ASPEED27X0TSP_SOC,
+ .parent = TYPE_ASPEED_SOC,
+ .instance_size = sizeof(Aspeed27x0TSPSoCState),
+ .instance_init = aspeed_soc_ast27x0tsp_init,
+ .class_init = aspeed_soc_ast27x0tsp_class_init,
+ },
+};
+
+DEFINE_TYPES(aspeed_soc_ast27x0tsp_types)
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 4257b5e..6aa3841 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -13,65 +13,115 @@
#include "qapi/error.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
+#include "hw/arm/bsa.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "hw/i2c/aspeed_i2c.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/intc/arm_gicv3.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qemu/log.h"
+#define AST2700_SOC_IO_SIZE 0x00FE0000
+#define AST2700_SOC_IOMEM_SIZE 0x01000000
+#define AST2700_SOC_DPMCU_SIZE 0x00040000
+#define AST2700_SOC_LTPI_SIZE 0x01000000
+
static const hwaddr aspeed_soc_ast2700_memmap[] = {
- [ASPEED_DEV_SPI_BOOT] = 0x400000000,
+ [ASPEED_DEV_VBOOTROM] = 0x00000000,
+ [ASPEED_DEV_IOMEM] = 0x00020000,
[ASPEED_DEV_SRAM] = 0x10000000,
+ [ASPEED_DEV_DPMCU] = 0x11000000,
+ [ASPEED_DEV_IOMEM0] = 0x12000000,
+ [ASPEED_DEV_EHCI1] = 0x12061000,
+ [ASPEED_DEV_EHCI2] = 0x12063000,
+ [ASPEED_DEV_HACE] = 0x12070000,
+ [ASPEED_DEV_EMMC] = 0x12090000,
+ [ASPEED_DEV_INTC] = 0x12100000,
+ [ASPEED_GIC_DIST] = 0x12200000,
+ [ASPEED_GIC_REDIST] = 0x12280000,
[ASPEED_DEV_SDMC] = 0x12C00000,
[ASPEED_DEV_SCU] = 0x12C02000,
- [ASPEED_DEV_SCUIO] = 0x14C02000,
- [ASPEED_DEV_UART0] = 0X14C33000,
- [ASPEED_DEV_UART1] = 0X14C33100,
- [ASPEED_DEV_UART2] = 0X14C33200,
- [ASPEED_DEV_UART3] = 0X14C33300,
- [ASPEED_DEV_UART4] = 0X12C1A000,
- [ASPEED_DEV_UART5] = 0X14C33400,
- [ASPEED_DEV_UART6] = 0X14C33500,
- [ASPEED_DEV_UART7] = 0X14C33600,
- [ASPEED_DEV_UART8] = 0X14C33700,
- [ASPEED_DEV_UART9] = 0X14C33800,
- [ASPEED_DEV_UART10] = 0X14C33900,
- [ASPEED_DEV_UART11] = 0X14C33A00,
- [ASPEED_DEV_UART12] = 0X14C33B00,
- [ASPEED_DEV_WDT] = 0x14C37000,
- [ASPEED_DEV_VUART] = 0X14C30000,
+ [ASPEED_DEV_RTC] = 0x12C0F000,
+ [ASPEED_DEV_TIMER1] = 0x12C10000,
+ [ASPEED_DEV_SLI] = 0x12C17000,
+ [ASPEED_DEV_UART4] = 0x12C1A000,
+ [ASPEED_DEV_IOMEM1] = 0x14000000,
[ASPEED_DEV_FMC] = 0x14000000,
[ASPEED_DEV_SPI0] = 0x14010000,
[ASPEED_DEV_SPI1] = 0x14020000,
[ASPEED_DEV_SPI2] = 0x14030000,
- [ASPEED_DEV_SDRAM] = 0x400000000,
[ASPEED_DEV_MII1] = 0x14040000,
[ASPEED_DEV_MII2] = 0x14040008,
[ASPEED_DEV_MII3] = 0x14040010,
[ASPEED_DEV_ETH1] = 0x14050000,
[ASPEED_DEV_ETH2] = 0x14060000,
[ASPEED_DEV_ETH3] = 0x14070000,
- [ASPEED_DEV_EMMC] = 0x12090000,
- [ASPEED_DEV_INTC] = 0x12100000,
- [ASPEED_DEV_SLI] = 0x12C17000,
- [ASPEED_DEV_SLIIO] = 0x14C1E000,
- [ASPEED_GIC_DIST] = 0x12200000,
- [ASPEED_GIC_REDIST] = 0x12280000,
+ [ASPEED_DEV_SDHCI] = 0x14080000,
+ [ASPEED_DEV_EHCI3] = 0x14121000,
+ [ASPEED_DEV_EHCI4] = 0x14123000,
[ASPEED_DEV_ADC] = 0x14C00000,
+ [ASPEED_DEV_SCUIO] = 0x14C02000,
+ [ASPEED_DEV_GPIO] = 0x14C0B000,
+ [ASPEED_DEV_I2C] = 0x14C0F000,
+ [ASPEED_DEV_INTCIO] = 0x14C18000,
+ [ASPEED_DEV_SLIIO] = 0x14C1E000,
+ [ASPEED_DEV_VUART] = 0x14C30000,
+ [ASPEED_DEV_UART0] = 0x14C33000,
+ [ASPEED_DEV_UART1] = 0x14C33100,
+ [ASPEED_DEV_UART2] = 0x14C33200,
+ [ASPEED_DEV_UART3] = 0x14C33300,
+ [ASPEED_DEV_UART5] = 0x14C33400,
+ [ASPEED_DEV_UART6] = 0x14C33500,
+ [ASPEED_DEV_UART7] = 0x14C33600,
+ [ASPEED_DEV_UART8] = 0x14C33700,
+ [ASPEED_DEV_UART9] = 0x14C33800,
+ [ASPEED_DEV_UART10] = 0x14C33900,
+ [ASPEED_DEV_UART11] = 0x14C33A00,
+ [ASPEED_DEV_UART12] = 0x14C33B00,
+ [ASPEED_DEV_WDT] = 0x14C37000,
+ [ASPEED_DEV_SPI_BOOT] = 0x100000000,
+ [ASPEED_DEV_LTPI] = 0x300000000,
+ [ASPEED_DEV_SDRAM] = 0x400000000,
};
-#define AST2700_MAX_IRQ 288
+#define AST2700_MAX_IRQ 256
/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
-static const int aspeed_soc_ast2700_irqmap[] = {
+static const int aspeed_soc_ast2700a0_irqmap[] = {
+ [ASPEED_DEV_SDMC] = 0,
+ [ASPEED_DEV_HACE] = 4,
+ [ASPEED_DEV_XDMA] = 5,
+ [ASPEED_DEV_UART4] = 8,
+ [ASPEED_DEV_SCU] = 12,
+ [ASPEED_DEV_RTC] = 13,
+ [ASPEED_DEV_EMMC] = 15,
+ [ASPEED_DEV_TIMER1] = 16,
+ [ASPEED_DEV_TIMER2] = 17,
+ [ASPEED_DEV_TIMER3] = 18,
+ [ASPEED_DEV_TIMER4] = 19,
+ [ASPEED_DEV_TIMER5] = 20,
+ [ASPEED_DEV_TIMER6] = 21,
+ [ASPEED_DEV_TIMER7] = 22,
+ [ASPEED_DEV_TIMER8] = 23,
+ [ASPEED_DEV_DP] = 28,
+ [ASPEED_DEV_EHCI1] = 33,
+ [ASPEED_DEV_EHCI2] = 37,
+ [ASPEED_DEV_LPC] = 128,
+ [ASPEED_DEV_IBT] = 128,
+ [ASPEED_DEV_KCS] = 128,
+ [ASPEED_DEV_ADC] = 130,
+ [ASPEED_DEV_GPIO] = 130,
+ [ASPEED_DEV_I2C] = 130,
+ [ASPEED_DEV_FMC] = 131,
+ [ASPEED_DEV_WDT] = 131,
+ [ASPEED_DEV_PWM] = 131,
+ [ASPEED_DEV_I3C] = 131,
[ASPEED_DEV_UART0] = 132,
[ASPEED_DEV_UART1] = 132,
[ASPEED_DEV_UART2] = 132,
[ASPEED_DEV_UART3] = 132,
- [ASPEED_DEV_UART4] = 8,
[ASPEED_DEV_UART5] = 132,
[ASPEED_DEV_UART6] = 132,
[ASPEED_DEV_UART7] = 132,
@@ -80,15 +130,21 @@ static const int aspeed_soc_ast2700_irqmap[] = {
[ASPEED_DEV_UART10] = 132,
[ASPEED_DEV_UART11] = 132,
[ASPEED_DEV_UART12] = 132,
- [ASPEED_DEV_FMC] = 131,
+ [ASPEED_DEV_ETH1] = 132,
+ [ASPEED_DEV_ETH2] = 132,
+ [ASPEED_DEV_ETH3] = 132,
+ [ASPEED_DEV_PECI] = 133,
+ [ASPEED_DEV_SDHCI] = 133,
+};
+
+static const int aspeed_soc_ast2700a1_irqmap[] = {
[ASPEED_DEV_SDMC] = 0,
- [ASPEED_DEV_SCU] = 12,
- [ASPEED_DEV_ADC] = 130,
+ [ASPEED_DEV_HACE] = 4,
[ASPEED_DEV_XDMA] = 5,
- [ASPEED_DEV_EMMC] = 15,
- [ASPEED_DEV_GPIO] = 11,
- [ASPEED_DEV_GPIO_1_8V] = 130,
+ [ASPEED_DEV_UART4] = 8,
+ [ASPEED_DEV_SCU] = 12,
[ASPEED_DEV_RTC] = 13,
+ [ASPEED_DEV_EMMC] = 15,
[ASPEED_DEV_TIMER1] = 16,
[ASPEED_DEV_TIMER2] = 17,
[ASPEED_DEV_TIMER3] = 18,
@@ -97,37 +153,60 @@ static const int aspeed_soc_ast2700_irqmap[] = {
[ASPEED_DEV_TIMER6] = 21,
[ASPEED_DEV_TIMER7] = 22,
[ASPEED_DEV_TIMER8] = 23,
- [ASPEED_DEV_WDT] = 131,
- [ASPEED_DEV_PWM] = 131,
- [ASPEED_DEV_LPC] = 128,
- [ASPEED_DEV_IBT] = 128,
- [ASPEED_DEV_I2C] = 130,
- [ASPEED_DEV_PECI] = 133,
- [ASPEED_DEV_ETH1] = 132,
- [ASPEED_DEV_ETH2] = 132,
- [ASPEED_DEV_ETH3] = 132,
- [ASPEED_DEV_HACE] = 4,
- [ASPEED_DEV_KCS] = 128,
[ASPEED_DEV_DP] = 28,
- [ASPEED_DEV_I3C] = 131,
+ [ASPEED_DEV_EHCI1] = 33,
+ [ASPEED_DEV_EHCI2] = 37,
+ [ASPEED_DEV_LPC] = 192,
+ [ASPEED_DEV_IBT] = 192,
+ [ASPEED_DEV_KCS] = 192,
+ [ASPEED_DEV_I2C] = 194,
+ [ASPEED_DEV_ADC] = 194,
+ [ASPEED_DEV_GPIO] = 194,
+ [ASPEED_DEV_FMC] = 195,
+ [ASPEED_DEV_WDT] = 195,
+ [ASPEED_DEV_PWM] = 195,
+ [ASPEED_DEV_I3C] = 195,
+ [ASPEED_DEV_UART0] = 196,
+ [ASPEED_DEV_UART1] = 196,
+ [ASPEED_DEV_UART2] = 196,
+ [ASPEED_DEV_UART3] = 196,
+ [ASPEED_DEV_UART5] = 196,
+ [ASPEED_DEV_UART6] = 196,
+ [ASPEED_DEV_UART7] = 196,
+ [ASPEED_DEV_UART8] = 196,
+ [ASPEED_DEV_UART9] = 196,
+ [ASPEED_DEV_UART10] = 196,
+ [ASPEED_DEV_UART11] = 196,
+ [ASPEED_DEV_UART12] = 196,
+ [ASPEED_DEV_ETH1] = 196,
+ [ASPEED_DEV_ETH2] = 196,
+ [ASPEED_DEV_ETH3] = 196,
+ [ASPEED_DEV_PECI] = 197,
+ [ASPEED_DEV_SDHCI] = 197,
};
/* GICINT 128 */
-static const int aspeed_soc_ast2700_gic128_intcmap[] = {
+/* GICINT 192 */
+static const int ast2700_gic128_gic192_intcmap[] = {
[ASPEED_DEV_LPC] = 0,
[ASPEED_DEV_IBT] = 2,
[ASPEED_DEV_KCS] = 4,
};
+/* GICINT 129 */
+/* GICINT 193 */
+
/* GICINT 130 */
-static const int aspeed_soc_ast2700_gic130_intcmap[] = {
+/* GICINT 194 */
+static const int ast2700_gic130_gic194_intcmap[] = {
[ASPEED_DEV_I2C] = 0,
[ASPEED_DEV_ADC] = 16,
- [ASPEED_DEV_GPIO_1_8V] = 18,
+ [ASPEED_DEV_GPIO] = 18,
};
/* GICINT 131 */
-static const int aspeed_soc_ast2700_gic131_intcmap[] = {
+/* GICINT 195 */
+static const int ast2700_gic131_gic195_intcmap[] = {
[ASPEED_DEV_I3C] = 0,
[ASPEED_DEV_WDT] = 16,
[ASPEED_DEV_FMC] = 25,
@@ -135,7 +214,8 @@ static const int aspeed_soc_ast2700_gic131_intcmap[] = {
};
/* GICINT 132 */
-static const int aspeed_soc_ast2700_gic132_intcmap[] = {
+/* GICINT 196 */
+static const int ast2700_gic132_gic196_intcmap[] = {
[ASPEED_DEV_ETH1] = 0,
[ASPEED_DEV_ETH2] = 1,
[ASPEED_DEV_ETH3] = 2,
@@ -151,48 +231,95 @@ static const int aspeed_soc_ast2700_gic132_intcmap[] = {
[ASPEED_DEV_UART10] = 16,
[ASPEED_DEV_UART11] = 17,
[ASPEED_DEV_UART12] = 18,
+ [ASPEED_DEV_EHCI3] = 28,
+ [ASPEED_DEV_EHCI4] = 29,
};
/* GICINT 133 */
-static const int aspeed_soc_ast2700_gic133_intcmap[] = {
+/* GICINT 197 */
+static const int ast2700_gic133_gic197_intcmap[] = {
+ [ASPEED_DEV_SDHCI] = 1,
[ASPEED_DEV_PECI] = 4,
};
/* GICINT 128 ~ 136 */
+/* GICINT 192 ~ 201 */
struct gic_intc_irq_info {
int irq;
+ int intc_idx;
+ int orgate_idx;
const int *ptr;
};
-static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
- {128, aspeed_soc_ast2700_gic128_intcmap},
- {129, NULL},
- {130, aspeed_soc_ast2700_gic130_intcmap},
- {131, aspeed_soc_ast2700_gic131_intcmap},
- {132, aspeed_soc_ast2700_gic132_intcmap},
- {133, aspeed_soc_ast2700_gic133_intcmap},
- {134, NULL},
- {135, NULL},
- {136, NULL},
+static const struct gic_intc_irq_info ast2700_gic_intcmap[] = {
+ {192, 1, 0, ast2700_gic128_gic192_intcmap},
+ {193, 1, 1, NULL},
+ {194, 1, 2, ast2700_gic130_gic194_intcmap},
+ {195, 1, 3, ast2700_gic131_gic195_intcmap},
+ {196, 1, 4, ast2700_gic132_gic196_intcmap},
+ {197, 1, 5, ast2700_gic133_gic197_intcmap},
+ {198, 1, 6, NULL},
+ {199, 1, 7, NULL},
+ {200, 1, 8, NULL},
+ {201, 1, 9, NULL},
+ {128, 0, 1, ast2700_gic128_gic192_intcmap},
+ {129, 0, 2, NULL},
+ {130, 0, 3, ast2700_gic130_gic194_intcmap},
+ {131, 0, 4, ast2700_gic131_gic195_intcmap},
+ {132, 0, 5, ast2700_gic132_gic196_intcmap},
+ {133, 0, 6, ast2700_gic133_gic197_intcmap},
+ {134, 0, 7, NULL},
+ {135, 0, 8, NULL},
+ {136, 0, 9, NULL},
};
static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
{
Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int or_idx;
+ int idx;
int i;
- for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
- if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
- assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
- return qdev_get_gpio_in(DEVICE(&a->intc.orgates[i]),
- aspeed_soc_ast2700_gic_intcmap[i].ptr[dev]);
+ for (i = 0; i < ARRAY_SIZE(ast2700_gic_intcmap); i++) {
+ if (sc->irqmap[dev] == ast2700_gic_intcmap[i].irq) {
+ assert(ast2700_gic_intcmap[i].ptr);
+ or_idx = ast2700_gic_intcmap[i].orgate_idx;
+ idx = ast2700_gic_intcmap[i].intc_idx;
+ return qdev_get_gpio_in(DEVICE(&a->intc[idx].orgates[or_idx]),
+ ast2700_gic_intcmap[i].ptr[dev]);
}
}
return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
}
+static qemu_irq aspeed_soc_ast2700_get_irq_index(AspeedSoCState *s, int dev,
+ int index)
+{
+ Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int or_idx;
+ int idx;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ast2700_gic_intcmap); i++) {
+ if (sc->irqmap[dev] == ast2700_gic_intcmap[i].irq) {
+ assert(ast2700_gic_intcmap[i].ptr);
+ or_idx = ast2700_gic_intcmap[i].orgate_idx;
+ idx = ast2700_gic_intcmap[i].intc_idx;
+ return qdev_get_gpio_in(DEVICE(&a->intc[idx].orgates[or_idx]),
+ ast2700_gic_intcmap[i].ptr[dev] + index);
+ }
+ }
+
+ /*
+ * Invalid OR gate index, device IRQ should be between 128 to 136
+ * and 192 to 201.
+ */
+ g_assert_not_reached();
+}
+
static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
unsigned int size)
{
@@ -219,8 +346,9 @@ static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data,
* If writes the data to the address which is beyond the ram size,
* it would write the data to the "address % ram_size".
*/
- result = address_space_write(&s->dram_as, addr % ram_size,
- MEMTXATTRS_UNSPECIFIED, &data, 4);
+ address_space_stl_le(&s->dram_as, addr % ram_size, data,
+ MEMTXATTRS_UNSPECIFIED, &result);
+
if (result != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: DRAM write failed, addr:0x%" HWADDR_PRIx
@@ -233,9 +361,10 @@ static const MemoryRegionOps aspeed_ram_capacity_ops = {
.read = aspeed_ram_capacity_read,
.write = aspeed_ram_capacity_write,
.endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
.valid = {
- .min_access_size = 1,
- .max_access_size = 8,
+ .min_access_size = 4,
+ .max_access_size = 4,
},
};
@@ -288,7 +417,7 @@ static void aspeed_soc_ast2700_init(Object *obj)
char socname[8];
char typename[64];
- if (sscanf(sc->name, "%7s", socname) != 1) {
+ if (sscanf(object_get_typename(obj), "%7s", socname) != 1) {
g_assert_not_reached();
}
@@ -304,14 +433,21 @@ static void aspeed_soc_ast2700_init(Object *obj)
sc->silicon_rev);
object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
"hw-strap1");
- object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
- "hw-strap2");
object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
"hw-prot-key");
object_initialize_child(obj, "scuio", &s->scuio, TYPE_ASPEED_2700_SCUIO);
qdev_prop_set_uint32(DEVICE(&s->scuio), "silicon-rev",
sc->silicon_rev);
+ /*
+ * There is one hw-strap1 register in the SCU (CPU DIE) and another
+ * hw-strap1 register in the SCUIO (IO DIE). To reuse the current design
+ * of hw-strap, hw-strap1 is assigned to the SCU and sets the value in the
+ * SCU hw-strap1 register, while hw-strap2 is assigned to the SCUIO and
+ * sets the value in the SCUIO hw-strap1 register.
+ */
+ object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scuio),
+ "hw-strap1");
snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
object_initialize_child(obj, "fmc", &s->fmc, typename);
@@ -321,6 +457,11 @@ static void aspeed_soc_ast2700_init(Object *obj)
object_initialize_child(obj, "spi[*]", &s->spi[i], typename);
}
+ for (i = 0; i < sc->ehcis_num; i++) {
+ object_initialize_child(obj, "ehci[*]", &s->ehci[i],
+ TYPE_PLATFORM_EHCI);
+ }
+
snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
object_initialize_child(obj, "sdmc", &s->sdmc, typename);
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
@@ -344,10 +485,50 @@ static void aspeed_soc_ast2700_init(Object *obj)
object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
object_initialize_child(obj, "sliio", &s->sliio, TYPE_ASPEED_2700_SLIIO);
- object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_2700_INTC);
+ object_initialize_child(obj, "intc", &a->intc[0], TYPE_ASPEED_2700_INTC);
+ object_initialize_child(obj, "intcio", &a->intc[1],
+ TYPE_ASPEED_2700_INTCIO);
snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
object_initialize_child(obj, "adc", &s->adc, typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+ object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+ object_initialize_child(obj, "gpio", &s->gpio, typename);
+
+ object_initialize_child(obj, "rtc", &s->rtc, TYPE_ASPEED_RTC);
+
+ snprintf(typename, sizeof(typename), "aspeed.sdhci-%s", socname);
+ object_initialize_child(obj, "sd-controller", &s->sdhci, typename);
+ object_property_set_int(OBJECT(&s->sdhci), "num-slots", 1, &error_abort);
+
+ /* Init sd card slot class here so that they're under the correct parent */
+ object_initialize_child(obj, "sd-controller.sdhci",
+ &s->sdhci.slots[0], TYPE_SYSBUS_SDHCI);
+
+ object_initialize_child(obj, "emmc-controller", &s->emmc, typename);
+ object_property_set_int(OBJECT(&s->emmc), "num-slots", 1, &error_abort);
+
+ object_initialize_child(obj, "emmc-controller.sdhci", &s->emmc.slots[0],
+ TYPE_SYSBUS_SDHCI);
+
+ snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
+ object_initialize_child(obj, "timerctrl", &s->timerctrl, typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
+ object_initialize_child(obj, "hace", &s->hace, typename);
+ object_initialize_child(obj, "dpmcu", &s->dpmcu,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "ltpi", &s->ltpi,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "iomem", &s->iomem,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "iomem0", &s->iomem0,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize_child(obj, "iomem1", &s->iomem1,
+ TYPE_UNIMPLEMENTED_DEVICE);
}
/*
@@ -374,7 +555,7 @@ static bool aspeed_soc_ast2700_gic_realize(DeviceState *dev, Error **errp)
gicdev = DEVICE(&a->gic);
qdev_prop_set_uint32(gicdev, "revision", 3);
qdev_prop_set_uint32(gicdev, "num-cpu", sc->num_cpus);
- qdev_prop_set_uint32(gicdev, "num-irq", AST2700_MAX_IRQ);
+ qdev_prop_set_uint32(gicdev, "num-irq", AST2700_MAX_IRQ + GIC_INTERNAL);
redist_region_count = qlist_new();
qlist_append_int(redist_region_count, sc->num_cpus);
@@ -383,33 +564,35 @@ static bool aspeed_soc_ast2700_gic_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(gicbusdev, errp)) {
return false;
}
- sysbus_mmio_map(gicbusdev, 0, sc->memmap[ASPEED_GIC_DIST]);
- sysbus_mmio_map(gicbusdev, 1, sc->memmap[ASPEED_GIC_REDIST]);
+
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->gic), 0,
+ sc->memmap[ASPEED_GIC_DIST]);
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->gic), 1,
+ sc->memmap[ASPEED_GIC_REDIST]);
for (i = 0; i < sc->num_cpus; i++) {
DeviceState *cpudev = DEVICE(&a->cpu[i]);
- int NUM_IRQS = 256, ARCH_GIC_MAINT_IRQ = 9, VIRTUAL_PMU_IRQ = 7;
- int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
+ int intidbase = AST2700_MAX_IRQ + i * GIC_INTERNAL;
const int timer_irq[] = {
- [GTIMER_PHYS] = 14,
- [GTIMER_VIRT] = 11,
- [GTIMER_HYP] = 10,
- [GTIMER_SEC] = 13,
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
};
int j;
for (j = 0; j < ARRAY_SIZE(timer_irq); j++) {
qdev_connect_gpio_out(cpudev, j,
- qdev_get_gpio_in(gicdev, ppibase + timer_irq[j]));
+ qdev_get_gpio_in(gicdev, intidbase + timer_irq[j]));
}
qemu_irq irq = qdev_get_gpio_in(gicdev,
- ppibase + ARCH_GIC_MAINT_IRQ);
+ intidbase + ARCH_GIC_MAINT_IRQ);
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
0, irq);
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
- qdev_get_gpio_in(gicdev, ppibase + VIRTUAL_PMU_IRQ));
+ qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ));
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(gicbusdev, i + sc->num_cpus,
@@ -418,6 +601,10 @@ static bool aspeed_soc_ast2700_gic_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(gicbusdev, i + 3 * sc->num_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+ sysbus_connect_irq(gicbusdev, i + 4 * sc->num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_NMI));
+ sysbus_connect_irq(gicbusdev, i + 5 * sc->num_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VINMI));
}
return true;
@@ -429,8 +616,10 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
- AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc);
- g_autofree char *sram_name = NULL;
+ AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc[0]);
+ AspeedINTCClass *icio = ASPEED_INTC_GET_CLASS(&a->intc[1]);
+ g_autofree char *name = NULL;
+ qemu_irq irq;
/* Default boot region (SPI memory or ROMs) */
memory_region_init(&s->spi_boot_container, OBJECT(s),
@@ -459,31 +648,64 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
}
/* INTC */
- if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc), errp)) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) {
return;
}
- aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc), 0,
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0,
sc->memmap[ASPEED_DEV_INTC]);
- /* GICINT orgates -> INTC -> GIC */
- for (i = 0; i < ic->num_ints; i++) {
- qdev_connect_gpio_out(DEVICE(&a->intc.orgates[i]), 0,
- qdev_get_gpio_in(DEVICE(&a->intc), i));
- sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc), i,
+ /* INTCIO */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[1]), errp)) {
+ return;
+ }
+
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0,
+ sc->memmap[ASPEED_DEV_INTCIO]);
+
+ /* irq sources -> orgates -> INTC */
+ for (i = 0; i < ic->num_inpins; i++) {
+ qdev_connect_gpio_out(DEVICE(&a->intc[0].orgates[i]), 0,
+ qdev_get_gpio_in(DEVICE(&a->intc[0]), i));
+ }
+
+ /* INTC -> GIC192 - GIC201 */
+ /* INTC -> GIC128 - GIC136 */
+ for (i = 0; i < ic->num_outpins; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[0]), i,
qdev_get_gpio_in(DEVICE(&a->gic),
- aspeed_soc_ast2700_gic_intcmap[i].irq));
+ ast2700_gic_intcmap[i].irq));
+ }
+
+ /* irq source -> orgates -> INTCIO */
+ for (i = 0; i < icio->num_inpins; i++) {
+ qdev_connect_gpio_out(DEVICE(&a->intc[1].orgates[i]), 0,
+ qdev_get_gpio_in(DEVICE(&a->intc[1]), i));
+ }
+
+ /* INTCIO -> INTC */
+ for (i = 0; i < icio->num_outpins; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[1]), i,
+ qdev_get_gpio_in(DEVICE(&a->intc[0].orgates[0]), i));
}
/* SRAM */
- sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index);
- if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size,
- errp)) {
+ name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index);
+ if (!memory_region_init_ram(&s->sram, OBJECT(s), name, sc->sram_size,
+ errp)) {
return;
}
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SRAM], &s->sram);
+ /* VBOOTROM */
+ if (!memory_region_init_ram(&s->vbootrom, OBJECT(s), "aspeed.vbootrom",
+ 0x20000, errp)) {
+ return;
+ }
+ memory_region_add_subregion(s->memory,
+ sc->memmap[ASPEED_DEV_VBOOTROM], &s->vbootrom);
+
/* SCU */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
return;
@@ -536,6 +758,17 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
}
+ /* EHCI */
+ for (i = 0; i < sc->ehcis_num; i++) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0,
+ sc->memmap[ASPEED_DEV_EHCI1 + i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i));
+ }
+
/*
* SDMC - SDRAM Memory Controller
* The SDMC controller is unlocked at SPL stage.
@@ -613,14 +846,119 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
- create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
- create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
- create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
- create_unimplemented_device("ast2700.ltpi", 0x30000000, 0x1000000);
- create_unimplemented_device("ast2700.io", 0x0, 0x4000000);
+ /* I2C */
+ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
+ for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+ /*
+ * The AST2700 I2C controller has one source INTC per bus.
+ *
+ * For AST2700 A0:
+ * I2C bus interrupts are connected to the OR gate from bit 0 to bit
+ * 15, and the OR gate output pin is connected to the input pin of
+ * GICINT130 of INTC (CPU Die). Then, the output pin is connected to
+ * the GIC.
+ *
+ * For AST2700 A1:
+ * I2C bus interrupts are connected to the OR gate from bit 0 to bit
+ * 15, and the OR gate output pin is connected to the input pin of
+ * GICINT194 of INTCIO (IO Die). Then, the output pin is connected
+ * to the INTC (CPU Die) input pin, and its output pin is connected
+ * to the GIC.
+ *
+ * I2C bus 0 is connected to the OR gate at bit 0.
+ * I2C bus 15 is connected to the OR gate at bit 15.
+ */
+ irq = aspeed_soc_ast2700_get_irq_index(s, ASPEED_DEV_I2C, i);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
+ }
+
+ /* GPIO */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+ sc->memmap[ASPEED_DEV_GPIO]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
+ /* RTC */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_RTC));
+
+ /* SDHCI */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0,
+ sc->memmap[ASPEED_DEV_SDHCI]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
+
+ /* eMMC */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->emmc), 0,
+ sc->memmap[ASPEED_DEV_EMMC]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_EMMC));
+
+ /* Timer */
+ object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0,
+ sc->memmap[ASPEED_DEV_TIMER1]);
+ for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
+ irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
+ }
+
+ /* HACE */
+ object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0,
+ sc->memmap[ASPEED_DEV_HACE]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
+
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu),
+ "aspeed.dpmcu",
+ sc->memmap[ASPEED_DEV_DPMCU],
+ AST2700_SOC_DPMCU_SIZE);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->ltpi),
+ "aspeed.ltpi",
+ sc->memmap[ASPEED_DEV_LTPI],
+ AST2700_SOC_LTPI_SIZE);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem),
+ "aspeed.io",
+ sc->memmap[ASPEED_DEV_IOMEM],
+ AST2700_SOC_IO_SIZE);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem0),
+ "aspeed.iomem0",
+ sc->memmap[ASPEED_DEV_IOMEM0],
+ AST2700_SOC_IOMEM_SIZE);
+ aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem1),
+ "aspeed.iomem1",
+ sc->memmap[ASPEED_DEV_IOMEM1],
+ AST2700_SOC_IOMEM_SIZE);
}
-static void aspeed_soc_ast2700_class_init(ObjectClass *oc, void *data)
+static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a35"),
@@ -633,17 +971,45 @@ static void aspeed_soc_ast2700_class_init(ObjectClass *oc, void *data)
dc->user_creatable = false;
dc->realize = aspeed_soc_ast2700_realize;
- sc->name = "ast2700-a0";
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST2700_A0_SILICON_REV;
sc->sram_size = 0x20000;
sc->spis_num = 3;
+ sc->ehcis_num = 2;
sc->wdts_num = 8;
sc->macs_num = 1;
sc->uarts_num = 13;
sc->num_cpus = 4;
sc->uarts_base = ASPEED_DEV_UART0;
- sc->irqmap = aspeed_soc_ast2700_irqmap;
+ sc->irqmap = aspeed_soc_ast2700a0_irqmap;
+ sc->memmap = aspeed_soc_ast2700_memmap;
+ sc->get_irq = aspeed_soc_ast2700_get_irq;
+}
+
+static void aspeed_soc_ast2700a1_class_init(ObjectClass *oc, const void *data)
+{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a35"),
+ NULL
+ };
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
+
+ /* Reason: The Aspeed SoC can only be instantiated from a board */
+ dc->user_creatable = false;
+ dc->realize = aspeed_soc_ast2700_realize;
+
+ sc->valid_cpu_types = valid_cpu_types;
+ sc->silicon_rev = AST2700_A1_SILICON_REV;
+ sc->sram_size = 0x20000;
+ sc->spis_num = 3;
+ sc->ehcis_num = 4;
+ sc->wdts_num = 8;
+ sc->macs_num = 3;
+ sc->uarts_num = 13;
+ sc->num_cpus = 4;
+ sc->uarts_base = ASPEED_DEV_UART0;
+ sc->irqmap = aspeed_soc_ast2700a1_irqmap;
sc->memmap = aspeed_soc_ast2700_memmap;
sc->get_irq = aspeed_soc_ast2700_get_irq;
}
@@ -658,7 +1024,13 @@ static const TypeInfo aspeed_soc_ast27x0_types[] = {
.name = "ast2700-a0",
.parent = TYPE_ASPEED27X0_SOC,
.instance_init = aspeed_soc_ast2700_init,
- .class_init = aspeed_soc_ast2700_class_init,
+ .class_init = aspeed_soc_ast2700a0_class_init,
+ },
+ {
+ .name = "ast2700-a1",
+ .parent = TYPE_ASPEED27X0_SOC,
+ .instance_init = aspeed_soc_ast2700_init,
+ .class_init = aspeed_soc_ast2700a1_class_init,
},
};
diff --git a/hw/arm/aspeed_soc_common.c b/hw/arm/aspeed_soc_common.c
index 0555146..1c4ac93 100644
--- a/hw/arm/aspeed_soc_common.c
+++ b/hw/arm/aspeed_soc_common.c
@@ -15,7 +15,7 @@
#include "hw/qdev-properties.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
const char *aspeed_soc_cpu_type(AspeedSoCClass *sc)
@@ -139,15 +139,14 @@ static bool aspeed_soc_boot_from_emmc(AspeedSoCState *s)
return false;
}
-static Property aspeed_soc_properties[] = {
+static const Property aspeed_soc_properties[] = {
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_LINK("memory", AspeedSoCState, memory, TYPE_MEMORY_REGION,
MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_soc_class_init(ObjectClass *oc, void *data)
+static void aspeed_soc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
diff --git a/hw/arm/b-l475e-iot01a.c b/hw/arm/b-l475e-iot01a.c
index 5002a40..34ed2e0 100644
--- a/hw/arm/b-l475e-iot01a.c
+++ b/hw/arm/b-l475e-iot01a.c
@@ -82,7 +82,7 @@ static void bl475e_init(MachineState *machine)
sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
sc = STM32L4X5_SOC_GET_CLASS(&s->soc);
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0,
+ armv7m_load_kernel(s->soc.armv7m.cpu, machine->kernel_filename, 0,
sc->flash_size);
if (object_class_by_name(TYPE_DM163)) {
@@ -110,7 +110,7 @@ static void bl475e_init(MachineState *machine)
}
}
-static void bl475e_machine_init(ObjectClass *oc, void *data)
+static void bl475e_machine_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static const char *machine_valid_cpu_types[] = {
diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
index 0a4b6f2..b750a57 100644
--- a/hw/arm/bananapi_m2u.c
+++ b/hw/arm/bananapi_m2u.c
@@ -19,7 +19,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/boards.h"
@@ -141,6 +141,7 @@ static void bpim2u_machine_init(MachineClass *mc)
mc->valid_cpu_types = valid_cpu_types;
mc->default_ram_size = 1 * GiB;
mc->default_ram_id = "bpim2u.ram";
+ mc->auto_create_sdcard = true;
}
DEFINE_MACHINE("bpim2u", bpim2u_machine_init)
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index ac153a9..8a1e72d 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -15,7 +15,7 @@
#include "hw/arm/bcm2835_peripherals.h"
#include "hw/misc/bcm2835_mbox_defs.h"
#include "hw/arm/raspi_platform.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
/* Peripheral base address on the VC (GPU) system bus */
#define BCM2835_VC_PERI_BASE 0x7e000000
@@ -520,7 +520,7 @@ void bcm_soc_peripherals_common_realize(DeviceState *dev, Error **errp)
create_unimp(s, &s->sdramc, "bcm2835-sdramc", SDRAMC_OFFSET, 0x100);
}
-static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
+static void bcm2835_peripherals_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCMSocPeripheralBaseClass *bc = BCM_SOC_PERIPHERALS_BASE_CLASS(oc);
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 40a379b..cd61ba1 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -18,7 +18,7 @@
#include "target/arm/cpu-qom.h"
#include "target/arm/gtimer.h"
-static Property bcm2836_enabled_cores_property =
+static const Property bcm2836_enabled_cores_property =
DEFINE_PROP_UINT32("enabled-cpus", BCM283XBaseState, enabled_cpus, 0);
static void bcm283x_base_init(Object *obj)
@@ -163,7 +163,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
}
}
-static void bcm283x_base_class_init(ObjectClass *oc, void *data)
+static void bcm283x_base_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -171,7 +171,7 @@ static void bcm283x_base_class_init(ObjectClass *oc, void *data)
dc->user_creatable = false;
}
-static void bcm2835_class_init(ObjectClass *oc, void *data)
+static void bcm2835_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
@@ -182,7 +182,7 @@ static void bcm2835_class_init(ObjectClass *oc, void *data)
dc->realize = bcm2835_realize;
};
-static void bcm2836_class_init(ObjectClass *oc, void *data)
+static void bcm2836_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
@@ -196,7 +196,7 @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
};
#ifdef TARGET_AARCH64
-static void bcm2837_class_init(ObjectClass *oc, void *data)
+static void bcm2837_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c
index ddb7c5f..22aa754 100644
--- a/hw/arm/bcm2838.c
+++ b/hw/arm/bcm2838.c
@@ -233,7 +233,7 @@ static void bcm2838_realize(DeviceState *dev, Error **errp)
qdev_pass_gpios(DEVICE(&s->gic), DEVICE(&s->peripherals), NULL);
}
-static void bcm2838_class_init(ObjectClass *oc, void *data)
+static void bcm2838_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XBaseClass *bc_base = BCM283X_BASE_CLASS(oc);
diff --git a/hw/arm/bcm2838_peripherals.c b/hw/arm/bcm2838_peripherals.c
index e28bef4..812b5b8 100644
--- a/hw/arm/bcm2838_peripherals.c
+++ b/hw/arm/bcm2838_peripherals.c
@@ -196,7 +196,7 @@ static void bcm2838_peripherals_realize(DeviceState *dev, Error **errp)
create_unimp(s_base, &s->asb, "bcm2838-asb", BRDG_OFFSET, 0x24);
}
-static void bcm2838_peripherals_class_init(ObjectClass *oc, void *data)
+static void bcm2838_peripherals_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM2838PeripheralClass *bc = BCM2838_PERIPHERALS_CLASS(oc);
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index d480a7d..becd827 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -14,15 +14,18 @@
#include <libfdt.h>
#include "hw/arm/boot.h"
#include "hw/arm/linux-boot-if.h"
-#include "sysemu/kvm.h"
-#include "sysemu/tcg.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/numa.h"
+#include "cpu.h"
+#include "exec/target_page.h"
+#include "system/kvm.h"
+#include "system/tcg.h"
+#include "system/system.h"
+#include "system/memory.h"
+#include "system/numa.h"
#include "hw/boards.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/loader.h"
#include "elf.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/units.h"
@@ -432,13 +435,12 @@ out:
return ret;
}
-static void fdt_add_psci_node(void *fdt)
+static void fdt_add_psci_node(void *fdt, ARMCPU *armcpu)
{
uint32_t cpu_suspend_fn;
uint32_t cpu_off_fn;
uint32_t cpu_on_fn;
uint32_t migrate_fn;
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0));
const char *psci_method;
int64_t psci_conduit;
int rc;
@@ -512,7 +514,8 @@ static void fdt_add_psci_node(void *fdt)
}
int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
- hwaddr addr_limit, AddressSpace *as, MachineState *ms)
+ hwaddr addr_limit, AddressSpace *as, MachineState *ms,
+ ARMCPU *cpu)
{
void *fdt = NULL;
int size, rc, n = 0;
@@ -524,7 +527,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
if (binfo->dtb_filename) {
char *filename;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename);
+ filename = qemu_find_file(QEMU_FILE_TYPE_DTB, binfo->dtb_filename);
if (!filename) {
fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename);
goto fail;
@@ -655,14 +658,12 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
}
}
- fdt_add_psci_node(fdt);
+ fdt_add_psci_node(fdt, cpu);
if (binfo->modify_dtb) {
binfo->modify_dtb(binfo, fdt);
}
- qemu_fdt_dumpdtb(fdt, size);
-
/* Put the DTB into the memory map as a ROM image: this will ensure
* the DTB is copied again upon reset, even if addr points into RAM.
*/
@@ -743,7 +744,7 @@ static void do_cpu_reset(void *opaque)
} else {
if (arm_feature(env, ARM_FEATURE_EL3) &&
(info->secure_boot ||
- (info->secure_board_setup && cs == first_cpu))) {
+ (info->secure_board_setup && cpu == info->primary_cpu))) {
/* Start this CPU in Secure SVC */
target_el = 3;
}
@@ -751,7 +752,7 @@ static void do_cpu_reset(void *opaque)
arm_emulate_firmware_reset(cs, target_el);
- if (cs == first_cpu) {
+ if (cpu == info->primary_cpu) {
AddressSpace *as = arm_boot_address_space(cpu, info);
cpu_set_pc(cs, info->loader_start);
@@ -798,24 +799,28 @@ static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
Elf64_Ehdr h64;
} elf_header;
int data_swab = 0;
- bool big_endian;
- ssize_t ret = -1;
+ int elf_data_order;
+ ssize_t ret;
Error *err = NULL;
load_elf_hdr(info->kernel_filename, &elf_header, &elf_is64, &err);
if (err) {
+ /*
+ * If the file is not an ELF file we silently return.
+ * The caller will fall back to try other formats.
+ */
error_free(err);
- return ret;
+ return -1;
}
if (elf_is64) {
- big_endian = elf_header.h64.e_ident[EI_DATA] == ELFDATA2MSB;
- info->endianness = big_endian ? ARM_ENDIANNESS_BE8
- : ARM_ENDIANNESS_LE;
+ elf_data_order = elf_header.h64.e_ident[EI_DATA];
+ info->endianness = elf_data_order == ELFDATA2MSB ? ARM_ENDIANNESS_BE8
+ : ARM_ENDIANNESS_LE;
} else {
- big_endian = elf_header.h32.e_ident[EI_DATA] == ELFDATA2MSB;
- if (big_endian) {
+ elf_data_order = elf_header.h32.e_ident[EI_DATA];
+ if (elf_data_order == ELFDATA2MSB) {
if (bswap32(elf_header.h32.e_flags) & EF_ARM_BE8) {
info->endianness = ARM_ENDIANNESS_BE8;
} else {
@@ -835,10 +840,12 @@ static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
}
ret = load_elf_as(info->kernel_filename, NULL, NULL, NULL,
- pentry, lowaddr, highaddr, NULL, big_endian, elf_machine,
- 1, data_swab, as);
+ pentry, lowaddr, highaddr, NULL, elf_data_order,
+ elf_machine, 1, data_swab, as);
if (ret <= 0) {
/* The header loaded but the image didn't */
+ error_report("Couldn't load elf '%s': %s",
+ info->kernel_filename, load_elf_strerror(ret));
exit(1);
}
@@ -851,7 +858,7 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR;
uint64_t kernel_size = 0;
uint8_t *buffer;
- int size;
+ ssize_t size;
/* On aarch64, it's the bootloader's job to uncompress the kernel. */
size = load_image_gzipped_buffer(filename, LOAD_IMAGE_MAX_GUNZIP_BYTES,
@@ -1232,6 +1239,9 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
info->dtb_filename = ms->dtb;
info->dtb_limit = 0;
+ /* We assume the CPU passed as argument is the primary CPU. */
+ info->primary_cpu = cpu;
+
/* Load the kernel. */
if (!info->kernel_filename || info->firmware_loaded) {
arm_setup_firmware_boot(cpu, info);
@@ -1281,12 +1291,8 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
object_property_set_int(cpuobj, "psci-conduit", info->psci_conduit,
&error_abort);
- /*
- * Secondary CPUs start in PSCI powered-down state. Like the
- * code in do_cpu_reset(), we assume first_cpu is the primary
- * CPU.
- */
- if (cs != first_cpu) {
+ /* Secondary CPUs start in PSCI powered-down state. */
+ if (ARM_CPU(cs) != info->primary_cpu) {
object_property_set_bool(cpuobj, "start-powered-off", true,
&error_abort);
}
@@ -1321,7 +1327,8 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
* decided whether to enable PSCI and set the psci-conduit CPU properties.
*/
if (!info->skip_dtb_autoload && have_dtb(info)) {
- if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) {
+ if (arm_load_dtb(info->dtb_start, info, info->dtb_limit,
+ as, ms, cpu) < 0) {
exit(1);
}
}
diff --git a/hw/arm/collie.c b/hw/arm/collie.c
index eaa5c52..93bb190 100644
--- a/hw/arm/collie.c
+++ b/hw/arm/collie.c
@@ -16,7 +16,7 @@
#include "strongarm.h"
#include "hw/arm/boot.h"
#include "hw/block/flash.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qom/object.h"
#include "qemu/error-report.h"
@@ -69,7 +69,7 @@ static void collie_init(MachineState *machine)
arm_load_kernel(cms->sa1110->cpu, machine, &collie_binfo);
}
-static void collie_machine_class_init(ObjectClass *oc, void *data)
+static void collie_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c
index b976727..d665d4e 100644
--- a/hw/arm/cubieboard.c
+++ b/hw/arm/cubieboard.c
@@ -122,6 +122,7 @@ static void cubieboard_machine_init(MachineClass *mc)
mc->units_per_default_bus = 1;
mc->ignore_memory_transaction_failures = true;
mc->default_ram_id = "cubieboard.ram";
+ mc->auto_create_sdcard = true;
}
DEFINE_MACHINE("cubieboard", cubieboard_machine_init)
diff --git a/hw/arm/digic.c b/hw/arm/digic.c
index 6df5547..d831bc9 100644
--- a/hw/arm/digic.c
+++ b/hw/arm/digic.c
@@ -25,7 +25,7 @@
#include "qemu/module.h"
#include "hw/arm/digic.h"
#include "hw/qdev-properties.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100)
@@ -79,7 +79,7 @@ static void digic_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE);
}
-static void digic_class_init(ObjectClass *oc, void *data)
+static void digic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c
index 4093af0..466b8b8 100644
--- a/hw/arm/digic_boards.c
+++ b/hw/arm/digic_boards.c
@@ -31,7 +31,7 @@
#include "hw/arm/digic.h"
#include "hw/block/flash.h"
#include "hw/loader.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
@@ -80,7 +80,7 @@ static void digic4_board_init(MachineState *machine, DigicBoard *board)
static void digic_load_rom(DigicState *s, hwaddr addr,
hwaddr max_size, const char *filename)
{
- target_long rom_size;
+ ssize_t rom_size;
if (qtest_enabled()) {
/* qtest runs no code so don't attempt a ROM load which
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index e3f1de2..76001ff 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -27,8 +27,8 @@
#include "cpu.h"
#include "hw/cpu/a9mpcore.h"
#include "hw/irq.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
+#include "system/blockdev.h"
+#include "system/system.h"
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "hw/loader.h"
@@ -103,6 +103,8 @@
#define EXYNOS4210_PL330_BASE1_ADDR 0x12690000
#define EXYNOS4210_PL330_BASE2_ADDR 0x12850000
+#define GIC_EXT_IRQS 64 /* FIXME: verify for this SoC */
+
enum ExtGicId {
EXT_GIC_ID_MDMA_LCD0 = 66,
EXT_GIC_ID_PDMA0,
@@ -394,7 +396,8 @@ static void exynos4210_init_board_irqs(Exynos4210State *s)
}
if (irq_id) {
qdev_connect_gpio_out(splitter, splitin,
- qdev_get_gpio_in(extgicdev, irq_id - 32));
+ qdev_get_gpio_in(extgicdev,
+ irq_id - GIC_INTERNAL));
}
}
for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
@@ -421,7 +424,8 @@ static void exynos4210_init_board_irqs(Exynos4210State *s)
s->irq_table[n] = qdev_get_gpio_in(splitter, 0);
qdev_connect_gpio_out(splitter, 0, qdev_get_gpio_in(intcdev, n));
qdev_connect_gpio_out(splitter, 1,
- qdev_get_gpio_in(extgicdev, irq_id - 32));
+ qdev_get_gpio_in(extgicdev,
+ irq_id - GIC_INTERNAL));
} else {
s->irq_table[n] = qdev_get_gpio_in(intcdev, n);
}
@@ -458,7 +462,6 @@ static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset,
static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
- return;
}
static const MemoryRegionOps exynos4210_chipid_and_omr_ops = {
@@ -586,6 +589,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
/* Private memory region and Internal GIC */
qdev_prop_set_uint32(DEVICE(&s->a9mpcore), "num-cpu", EXYNOS4210_NCPUS);
+ qdev_prop_set_uint32(DEVICE(&s->a9mpcore), "num-irq",
+ GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(&s->a9mpcore);
sysbus_realize(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
@@ -837,7 +842,7 @@ static void exynos4210_init(Object *obj)
TYPE_EXYNOS4210_COMBINER);
}
-static void exynos4210_class_init(ObjectClass *klass, void *data)
+static void exynos4210_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
index 2410e2a..7304974 100644
--- a/hw/arm/exynos4_boards.c
+++ b/hw/arm/exynos4_boards.c
@@ -28,7 +28,7 @@
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/arm/boot.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/arm/exynos4210.h"
#include "hw/net/lan9118.h"
#include "hw/qdev-properties.h"
@@ -154,7 +154,7 @@ static const char * const valid_cpu_types[] = {
NULL
};
-static void nuri_class_init(ObjectClass *oc, void *data)
+static void nuri_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -165,6 +165,7 @@ static void nuri_class_init(ObjectClass *oc, void *data)
mc->min_cpus = EXYNOS4210_NCPUS;
mc->default_cpus = EXYNOS4210_NCPUS;
mc->ignore_memory_transaction_failures = true;
+ mc->auto_create_sdcard = true;
}
static const TypeInfo nuri_type = {
@@ -173,7 +174,7 @@ static const TypeInfo nuri_type = {
.class_init = nuri_class_init,
};
-static void smdkc210_class_init(ObjectClass *oc, void *data)
+static void smdkc210_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -184,6 +185,7 @@ static void smdkc210_class_init(ObjectClass *oc, void *data)
mc->min_cpus = EXYNOS4210_NCPUS;
mc->default_cpus = EXYNOS4210_NCPUS;
mc->ignore_memory_transaction_failures = true;
+ mc->auto_create_sdcard = true;
}
static const TypeInfo smdkc210_type = {
diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c
index c9964bd..c14fc2e 100644
--- a/hw/arm/fby35.c
+++ b/hw/arm/fby35.c
@@ -8,8 +8,8 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
+#include "system/system.h"
+#include "system/block-backend.h"
#include "hw/boards.h"
#include "hw/qdev-clock.h"
#include "hw/arm/aspeed_soc.h"
@@ -77,6 +77,7 @@ static void fby35_bmc_init(Fby35State *s)
memory_region_init(&s->bmc_memory, OBJECT(&s->bmc), "bmc-memory",
UINT64_MAX);
+ memory_region_add_subregion(get_system_memory(), 0, &s->bmc_memory);
memory_region_init_ram(&s->bmc_dram, OBJECT(&s->bmc), "bmc-dram",
FBY35_BMC_RAM_SIZE, &error_abort);
@@ -162,7 +163,7 @@ static void fby35_instance_init(Object *obj)
FBY35(obj)->mmio_exec = false;
}
-static void fby35_class_init(ObjectClass *oc, void *data)
+static void fby35_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -170,6 +171,7 @@ static void fby35_class_init(ObjectClass *oc, void *data)
mc->init = fby35_init;
mc->no_floppy = 1;
mc->no_cdrom = 1;
+ mc->auto_create_sdcard = true;
mc->min_cpus = mc->max_cpus = mc->default_cpus = 3;
object_class_property_add_bool(oc, "execute-in-place",
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 5ed87ed..7aad635 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/arm/fsl-imx25.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/qdev-properties.h"
#include "chardev/char.h"
#include "target/arm/cpu-qom.h"
@@ -243,8 +243,6 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
&error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), "capareg",
IMX25_ESDHC_CAPABILITIES, &error_abort);
- object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor",
- SDHCI_VENDOR_IMX, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), errp)) {
return;
}
@@ -309,12 +307,11 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
&s->iram_alias);
}
-static Property fsl_imx25_properties[] = {
+static const Property fsl_imx25_properties[] = {
DEFINE_PROP_UINT32("fec-phy-num", FslIMX25State, phy_num, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void fsl_imx25_class_init(ObjectClass *oc, void *data)
+static void fsl_imx25_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index 4b8d9b8..e9f70ad 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -22,8 +22,8 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/arm/fsl-imx31.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
+#include "system/system.h"
+#include "system/address-spaces.h"
#include "hw/qdev-properties.h"
#include "chardev/char.h"
#include "target/arm/cpu-qom.h"
@@ -218,7 +218,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
&s->iram_alias);
}
-static void fsl_imx31_class_init(ObjectClass *oc, void *data)
+static void fsl_imx31_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 85748cb..f3a6002 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -26,7 +26,7 @@
#include "hw/usb/imx-usb-phy.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "chardev/char.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
@@ -106,6 +106,8 @@ static void fsl_imx6_init(Object *obj)
object_initialize_child(obj, "eth", &s->eth, TYPE_IMX_ENET);
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
+ object_initialize_child(obj, "pcie4-msi-irq", &s->pcie4_msi_irq,
+ TYPE_OR_IRQ);
}
static void fsl_imx6_realize(DeviceState *dev, Error **errp)
@@ -115,6 +117,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
uint16_t i;
qemu_irq irq;
unsigned int smp_cpus = ms->smp.cpus;
+ DeviceState *mpcore = DEVICE(&s->a9mpcore);
+ DeviceState *gic;
if (smp_cpus > FSL_IMX6_NUM_CPUS) {
error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
@@ -141,21 +145,21 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
}
}
- object_property_set_int(OBJECT(&s->a9mpcore), "num-cpu", smp_cpus,
- &error_abort);
+ object_property_set_int(OBJECT(mpcore), "num-cpu", smp_cpus, &error_abort);
- object_property_set_int(OBJECT(&s->a9mpcore), "num-irq",
+ object_property_set_int(OBJECT(mpcore), "num-irq",
FSL_IMX6_MAX_IRQ + GIC_INTERNAL, &error_abort);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->a9mpcore), errp)) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(mpcore), errp)) {
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, FSL_IMX6_A9MPCORE_ADDR);
+ sysbus_mmio_map(SYS_BUS_DEVICE(mpcore), 0, FSL_IMX6_A9MPCORE_ADDR);
+ gic = mpcore;
for (i = 0; i < smp_cpus; i++) {
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
+ sysbus_connect_irq(SYS_BUS_DEVICE(gic), i,
qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + smp_cpus,
+ sysbus_connect_irq(SYS_BUS_DEVICE(gic), i + smp_cpus,
qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
}
@@ -193,8 +197,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- serial_table[i].irq));
+ qdev_get_gpio_in(gic, serial_table[i].irq));
}
s->gpt.ccm = IMX_CCM(&s->ccm);
@@ -205,8 +208,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX6_GPT_ADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- FSL_IMX6_GPT_IRQ));
+ qdev_get_gpio_in(gic, FSL_IMX6_GPT_IRQ));
/* Initialize all EPIT timers */
for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
@@ -226,8 +228,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- epit_table[i].irq));
+ qdev_get_gpio_in(gic, epit_table[i].irq));
}
/* Initialize all I2C */
@@ -247,8 +248,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- i2c_table[i].irq));
+ qdev_get_gpio_in(gic, i2c_table[i].irq));
}
/* Initialize all GPIOs */
@@ -305,11 +305,9 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- gpio_table[i].irq_low));
+ qdev_get_gpio_in(gic, gpio_table[i].irq_low));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- gpio_table[i].irq_high));
+ qdev_get_gpio_in(gic, gpio_table[i].irq_high));
}
/* Initialize all SDHC */
@@ -329,15 +327,12 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
&error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), "capareg",
IMX6_ESDHC_CAPABILITIES, &error_abort);
- object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor",
- SDHCI_VENDOR_IMX, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->esdhc[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- esdhc_table[i].irq));
+ qdev_get_gpio_in(gic, esdhc_table[i].irq));
}
/* USB */
@@ -358,8 +353,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0,
FSL_IMX6_USBOH3_USB_ADDR + i * 0x200);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- FSL_IMX6_USBn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6_USBn_IRQ[i]));
}
/* Initialize all ECSPI */
@@ -382,8 +376,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- spi_table[i].irq));
+ qdev_get_gpio_in(gic, spi_table[i].irq));
}
object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num,
@@ -394,11 +387,9 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth), 0, FSL_IMX6_ENET_ADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- FSL_IMX6_ENET_MAC_IRQ));
+ qdev_get_gpio_in(gic, FSL_IMX6_ENET_MAC_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 1,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- FSL_IMX6_ENET_MAC_1588_IRQ));
+ qdev_get_gpio_in(gic, FSL_IMX6_ENET_MAC_1588_IRQ));
/*
* SNVS
@@ -425,8 +416,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6_WDOGn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a9mpcore),
- FSL_IMX6_WDOGn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6_WDOGn_IRQ[i]));
}
/*
@@ -435,14 +425,23 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(&s->pcie), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0, FSL_IMX6_PCIe_REG_ADDR);
+ object_property_set_int(OBJECT(&s->pcie4_msi_irq), "num-lines", 2,
+ &error_abort);
+ qdev_realize(DEVICE(&s->pcie4_msi_irq), NULL, &error_abort);
+
+ irq = qdev_get_gpio_in(DEVICE(&s->a9mpcore), FSL_IMX6_PCIE4_MSI_IRQ);
+ qdev_connect_gpio_out(DEVICE(&s->pcie4_msi_irq), 0, irq);
+
irq = qdev_get_gpio_in(DEVICE(&s->a9mpcore), FSL_IMX6_PCIE1_IRQ);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0, irq);
irq = qdev_get_gpio_in(DEVICE(&s->a9mpcore), FSL_IMX6_PCIE2_IRQ);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1, irq);
irq = qdev_get_gpio_in(DEVICE(&s->a9mpcore), FSL_IMX6_PCIE3_IRQ);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2, irq);
- irq = qdev_get_gpio_in(DEVICE(&s->a9mpcore), FSL_IMX6_PCIE4_IRQ);
+ irq = qdev_get_gpio_in(DEVICE(&s->pcie4_msi_irq), 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3, irq);
+ irq = qdev_get_gpio_in(DEVICE(&s->pcie4_msi_irq), 1);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4, irq);
/*
* PCIe PHY
@@ -481,12 +480,11 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
&s->ocram_alias);
}
-static Property fsl_imx6_properties[] = {
+static const Property fsl_imx6_properties[] = {
DEFINE_PROP_UINT32("fec-phy-num", FslIMX6State, phy_num, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void fsl_imx6_class_init(ObjectClass *oc, void *data)
+static void fsl_imx6_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c
index 19f4435..883c7fc 100644
--- a/hw/arm/fsl-imx6ul.c
+++ b/hw/arm/fsl-imx6ul.c
@@ -22,7 +22,7 @@
#include "hw/misc/unimp.h"
#include "hw/usb/imx-usb-phy.h"
#include "hw/boards.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "target/arm/cpu-qom.h"
@@ -157,10 +157,12 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
FslIMX6ULState *s = FSL_IMX6UL(dev);
+ DeviceState *mpcore = DEVICE(&s->a7mpcore);
int i;
char name[NAME_SIZE];
- SysBusDevice *sbd;
- DeviceState *d;
+ DeviceState *gic;
+ SysBusDevice *gicsbd;
+ DeviceState *cpu;
if (ms->smp.cpus > 1) {
error_setg(errp, "%s: Only a single CPU is supported (%d requested)",
@@ -173,19 +175,19 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
/*
* A7MPCORE
*/
- object_property_set_int(OBJECT(&s->a7mpcore), "num-cpu", 1, &error_abort);
- object_property_set_int(OBJECT(&s->a7mpcore), "num-irq",
+ object_property_set_int(OBJECT(mpcore), "num-cpu", 1, &error_abort);
+ object_property_set_int(OBJECT(mpcore), "num-irq",
FSL_IMX6UL_MAX_IRQ + GIC_INTERNAL, &error_abort);
- sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort);
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, FSL_IMX6UL_A7MPCORE_ADDR);
+ sysbus_realize(SYS_BUS_DEVICE(mpcore), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(mpcore), 0, FSL_IMX6UL_A7MPCORE_ADDR);
- sbd = SYS_BUS_DEVICE(&s->a7mpcore);
- d = DEVICE(&s->cpu);
-
- sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(d, ARM_CPU_IRQ));
- sysbus_connect_irq(sbd, 1, qdev_get_gpio_in(d, ARM_CPU_FIQ));
- sysbus_connect_irq(sbd, 2, qdev_get_gpio_in(d, ARM_CPU_VIRQ));
- sysbus_connect_irq(sbd, 3, qdev_get_gpio_in(d, ARM_CPU_VFIQ));
+ gic = mpcore;
+ gicsbd = SYS_BUS_DEVICE(gic);
+ cpu = DEVICE(&s->cpu);
+ sysbus_connect_irq(gicsbd, 0, qdev_get_gpio_in(cpu, ARM_CPU_IRQ));
+ sysbus_connect_irq(gicsbd, 1, qdev_get_gpio_in(cpu, ARM_CPU_FIQ));
+ sysbus_connect_irq(gicsbd, 2, qdev_get_gpio_in(cpu, ARM_CPU_VIRQ));
+ sysbus_connect_irq(gicsbd, 3, qdev_get_gpio_in(cpu, ARM_CPU_VFIQ));
/*
* A7MPCORE DAP
@@ -244,8 +246,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_GPTn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_GPTn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_GPTn_IRQ[i]));
}
/*
@@ -269,8 +270,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_EPITn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_EPITn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_EPITn_IRQ[i]));
}
/*
@@ -307,12 +307,10 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_GPIOn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_GPIOn_LOW_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_GPIOn_LOW_IRQ[i]));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_GPIOn_HIGH_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_GPIOn_HIGH_IRQ[i]));
}
/*
@@ -366,8 +364,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_SPIn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_SPIn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_SPIn_IRQ[i]));
}
/*
@@ -392,8 +389,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, FSL_IMX6UL_I2Cn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_I2Cn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_I2Cn_IRQ[i]));
}
/*
@@ -430,8 +426,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_UARTn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_UARTn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_UARTn_IRQ[i]));
}
/*
@@ -480,12 +475,10 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_ENETn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_ENETn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_ENETn_IRQ[i]));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth[i]), 1,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_ENETn_TIMER_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_ENETn_TIMER_IRQ[i]));
}
/*
@@ -521,8 +514,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0,
FSL_IMX6UL_USB02_USBn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_USBn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_USBn_IRQ[i]));
}
/*
@@ -539,16 +531,13 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_USDHC2_IRQ,
};
- object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
- SDHCI_VENDOR_IMX, &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
FSL_IMX6UL_USDHCn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_USDHCn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_USDHCn_IRQ[i]));
}
/*
@@ -580,8 +569,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
FSL_IMX6UL_WDOGn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX6UL_WDOGn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX6UL_WDOGn_IRQ[i]));
}
/*
@@ -718,17 +706,16 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_OCRAM_ALIAS_ADDR, &s->ocram_alias);
}
-static Property fsl_imx6ul_properties[] = {
+static const Property fsl_imx6ul_properties[] = {
DEFINE_PROP_UINT32("fec1-phy-num", FslIMX6ULState, phy_num[0], 0),
DEFINE_PROP_UINT32("fec2-phy-num", FslIMX6ULState, phy_num[1], 1),
DEFINE_PROP_BOOL("fec1-phy-connected", FslIMX6ULState, phy_connected[0],
true),
DEFINE_PROP_BOOL("fec2-phy-connected", FslIMX6ULState, phy_connected[1],
true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void fsl_imx6ul_class_init(ObjectClass *oc, void *data)
+static void fsl_imx6ul_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
index 9f2ef34..02f7602 100644
--- a/hw/arm/fsl-imx7.c
+++ b/hw/arm/fsl-imx7.c
@@ -23,7 +23,7 @@
#include "hw/arm/fsl-imx7.h"
#include "hw/misc/unimp.h"
#include "hw/boards.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "target/arm/cpu-qom.h"
@@ -150,6 +150,8 @@ static void fsl_imx7_init(Object *obj)
* PCIE
*/
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
+ object_initialize_child(obj, "pcie4-msi-irq", &s->pcie4_msi_irq,
+ TYPE_OR_IRQ);
/*
* USBs
@@ -164,7 +166,8 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
FslIMX7State *s = FSL_IMX7(dev);
- Object *o;
+ DeviceState *mpcore = DEVICE(&s->a7mpcore);
+ DeviceState *gic;
int i;
qemu_irq irq;
char name[NAME_SIZE];
@@ -180,7 +183,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
* CPUs
*/
for (i = 0; i < smp_cpus; i++) {
- o = OBJECT(&s->cpu[i]);
+ Object *o = OBJECT(&s->cpu[i]);
/* On uniprocessor, the CBAR is set to 0 */
if (smp_cpus > 1) {
@@ -203,16 +206,15 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
/*
* A7MPCORE
*/
- object_property_set_int(OBJECT(&s->a7mpcore), "num-cpu", smp_cpus,
- &error_abort);
- object_property_set_int(OBJECT(&s->a7mpcore), "num-irq",
+ object_property_set_int(OBJECT(mpcore), "num-cpu", smp_cpus, &error_abort);
+ object_property_set_int(OBJECT(mpcore), "num-irq",
FSL_IMX7_MAX_IRQ + GIC_INTERNAL, &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(mpcore), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(mpcore), 0, FSL_IMX7_A7MPCORE_ADDR);
- sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort);
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->a7mpcore), 0, FSL_IMX7_A7MPCORE_ADDR);
-
+ gic = mpcore;
for (i = 0; i < smp_cpus; i++) {
- SysBusDevice *sbd = SYS_BUS_DEVICE(&s->a7mpcore);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(gic);
DeviceState *d = DEVICE(qemu_get_cpu(i));
irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
@@ -253,8 +255,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX7_GPTn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX7_GPTn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX7_GPTn_IRQ[i]));
}
/*
@@ -296,12 +297,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_GPIOn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX7_GPIOn_LOW_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX7_GPIOn_LOW_IRQ[i]));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX7_GPIOn_HIGH_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX7_GPIOn_HIGH_IRQ[i]));
}
/*
@@ -353,8 +352,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
FSL_IMX7_SPIn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX7_SPIn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX7_SPIn_IRQ[i]));
}
/*
@@ -379,8 +377,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, FSL_IMX7_I2Cn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX7_I2Cn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX7_I2Cn_IRQ[i]));
}
/*
@@ -414,7 +411,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, FSL_IMX7_UARTn_ADDR[i]);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_UARTn_IRQ[i]);
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_UARTn_IRQ[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, irq);
}
@@ -452,9 +449,9 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth[i]), 0, FSL_IMX7_ENETn_ADDR[i]);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_ENET_IRQ(i, 0));
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_ENET_IRQ(i, 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth[i]), 0, irq);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_ENET_IRQ(i, 3));
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_ENET_IRQ(i, 3));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth[i]), 1, irq);
}
@@ -474,14 +471,12 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_USDHC3_IRQ,
};
- object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
- SDHCI_VENDOR_IMX, &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
FSL_IMX7_USDHCn_ADDR[i]);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_USDHCn_IRQ[i]);
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_USDHCn_IRQ[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0, irq);
}
@@ -520,8 +515,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX7_WDOGn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->a7mpcore),
- FSL_IMX7_WDOGn_IRQ[i]));
+ qdev_get_gpio_in(gic, FSL_IMX7_WDOGn_IRQ[i]));
}
/*
@@ -597,14 +591,23 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(&s->pcie), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0, FSL_IMX7_PCIE_REG_ADDR);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_PCI_INTA_IRQ);
+ object_property_set_int(OBJECT(&s->pcie4_msi_irq), "num-lines", 2,
+ &error_abort);
+ qdev_realize(DEVICE(&s->pcie4_msi_irq), NULL, &error_abort);
+
+ irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_PCI_INTD_MSI_IRQ);
+ qdev_connect_gpio_out(DEVICE(&s->pcie4_msi_irq), 0, irq);
+
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_PCI_INTA_IRQ);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0, irq);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_PCI_INTB_IRQ);
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_PCI_INTB_IRQ);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1, irq);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_PCI_INTC_IRQ);
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_PCI_INTC_IRQ);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2, irq);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_PCI_INTD_IRQ);
+ irq = qdev_get_gpio_in(DEVICE(&s->pcie4_msi_irq), 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3, irq);
+ irq = qdev_get_gpio_in(DEVICE(&s->pcie4_msi_irq), 1);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4, irq);
/*
* USBs
@@ -632,7 +635,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0,
FSL_IMX7_USBn_ADDR[i]);
- irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_USBn_IRQ[i]);
+ irq = qdev_get_gpio_in(gic, FSL_IMX7_USBn_IRQ[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0, irq);
snprintf(name, NAME_SIZE, "usbmisc%d", i);
@@ -736,17 +739,16 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
&s->caam);
}
-static Property fsl_imx7_properties[] = {
+static const Property fsl_imx7_properties[] = {
DEFINE_PROP_UINT32("fec1-phy-num", FslIMX7State, phy_num[0], 0),
DEFINE_PROP_UINT32("fec2-phy-num", FslIMX7State, phy_num[1], 1),
DEFINE_PROP_BOOL("fec1-phy-connected", FslIMX7State, phy_connected[0],
true),
DEFINE_PROP_BOOL("fec2-phy-connected", FslIMX7State, phy_connected[1],
true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void fsl_imx7_class_init(ObjectClass *oc, void *data)
+static void fsl_imx7_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
new file mode 100644
index 0000000..23e662c
--- /dev/null
+++ b/hw/arm/fsl-imx8mp.c
@@ -0,0 +1,712 @@
+/*
+ * i.MX 8M Plus SoC Implementation
+ *
+ * Based on hw/arm/fsl-imx6.c
+ *
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/address-spaces.h"
+#include "hw/arm/bsa.h"
+#include "hw/arm/fsl-imx8mp.h"
+#include "hw/intc/arm_gicv3.h"
+#include "hw/misc/unimp.h"
+#include "hw/boards.h"
+#include "system/system.h"
+#include "target/arm/cpu-qom.h"
+#include "qapi/error.h"
+#include "qobject/qlist.h"
+
+static const struct {
+ hwaddr addr;
+ size_t size;
+ const char *name;
+} fsl_imx8mp_memmap[] = {
+ [FSL_IMX8MP_RAM] = { FSL_IMX8MP_RAM_START, FSL_IMX8MP_RAM_SIZE_MAX, "ram" },
+ [FSL_IMX8MP_DDR_PHY_BROADCAST] = { 0x3dc00000, 4 * MiB, "ddr_phy_broadcast" },
+ [FSL_IMX8MP_DDR_PERF_MON] = { 0x3d800000, 4 * MiB, "ddr_perf_mon" },
+ [FSL_IMX8MP_DDR_CTL] = { 0x3d400000, 4 * MiB, "ddr_ctl" },
+ [FSL_IMX8MP_DDR_BLK_CTRL] = { 0x3d000000, 1 * MiB, "ddr_blk_ctrl" },
+ [FSL_IMX8MP_DDR_PHY] = { 0x3c000000, 16 * MiB, "ddr_phy" },
+ [FSL_IMX8MP_AUDIO_DSP] = { 0x3b000000, 16 * MiB, "audio_dsp" },
+ [FSL_IMX8MP_GIC_DIST] = { 0x38800000, 512 * KiB, "gic_dist" },
+ [FSL_IMX8MP_GIC_REDIST] = { 0x38880000, 512 * KiB, "gic_redist" },
+ [FSL_IMX8MP_NPU] = { 0x38500000, 2 * MiB, "npu" },
+ [FSL_IMX8MP_VPU] = { 0x38340000, 2 * MiB, "vpu" },
+ [FSL_IMX8MP_VPU_BLK_CTRL] = { 0x38330000, 2 * MiB, "vpu_blk_ctrl" },
+ [FSL_IMX8MP_VPU_VC8000E_ENCODER] = { 0x38320000, 2 * MiB, "vpu_vc8000e_encoder" },
+ [FSL_IMX8MP_VPU_G2_DECODER] = { 0x38310000, 2 * MiB, "vpu_g2_decoder" },
+ [FSL_IMX8MP_VPU_G1_DECODER] = { 0x38300000, 2 * MiB, "vpu_g1_decoder" },
+ [FSL_IMX8MP_USB2_GLUE] = { 0x382f0000, 0x100, "usb2_glue" },
+ [FSL_IMX8MP_USB2_OTG] = { 0x3820cc00, 0x100, "usb2_otg" },
+ [FSL_IMX8MP_USB2_DEV] = { 0x3820c700, 0x500, "usb2_dev" },
+ [FSL_IMX8MP_USB2] = { 0x38200000, 0xc700, "usb2" },
+ [FSL_IMX8MP_USB1_GLUE] = { 0x381f0000, 0x100, "usb1_glue" },
+ [FSL_IMX8MP_USB1_OTG] = { 0x3810cc00, 0x100, "usb1_otg" },
+ [FSL_IMX8MP_USB1_DEV] = { 0x3810c700, 0x500, "usb1_dev" },
+ [FSL_IMX8MP_USB1] = { 0x38100000, 0xc700, "usb1" },
+ [FSL_IMX8MP_GPU2D] = { 0x38008000, 32 * KiB, "gpu2d" },
+ [FSL_IMX8MP_GPU3D] = { 0x38000000, 32 * KiB, "gpu3d" },
+ [FSL_IMX8MP_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" },
+ [FSL_IMX8MP_PCIE1] = { 0x33800000, 4 * MiB, "pcie1" },
+ [FSL_IMX8MP_QSPI1_TX_BUFFER] = { 0x33008000, 32 * KiB, "qspi1_tx_buffer" },
+ [FSL_IMX8MP_APBH_DMA] = { 0x33000000, 32 * KiB, "apbh_dma" },
+
+ /* AIPS-5 Begin */
+ [FSL_IMX8MP_MU_3_B] = { 0x30e90000, 64 * KiB, "mu_3_b" },
+ [FSL_IMX8MP_MU_3_A] = { 0x30e80000, 64 * KiB, "mu_3_a" },
+ [FSL_IMX8MP_MU_2_B] = { 0x30e70000, 64 * KiB, "mu_2_b" },
+ [FSL_IMX8MP_MU_2_A] = { 0x30e60000, 64 * KiB, "mu_2_a" },
+ [FSL_IMX8MP_EDMA_CHANNELS] = { 0x30e40000, 128 * KiB, "edma_channels" },
+ [FSL_IMX8MP_EDMA_MANAGEMENT_PAGE] = { 0x30e30000, 64 * KiB, "edma_management_page" },
+ [FSL_IMX8MP_AUDIO_BLK_CTRL] = { 0x30e20000, 64 * KiB, "audio_blk_ctrl" },
+ [FSL_IMX8MP_SDMA2] = { 0x30e10000, 64 * KiB, "sdma2" },
+ [FSL_IMX8MP_SDMA3] = { 0x30e00000, 64 * KiB, "sdma3" },
+ [FSL_IMX8MP_AIPS5_CONFIGURATION] = { 0x30df0000, 64 * KiB, "aips5_configuration" },
+ [FSL_IMX8MP_SPBA2] = { 0x30cf0000, 64 * KiB, "spba2" },
+ [FSL_IMX8MP_AUDIO_XCVR_RX] = { 0x30cc0000, 64 * KiB, "audio_xcvr_rx" },
+ [FSL_IMX8MP_HDMI_TX_AUDLNK_MSTR] = { 0x30cb0000, 64 * KiB, "hdmi_tx_audlnk_mstr" },
+ [FSL_IMX8MP_PDM] = { 0x30ca0000, 64 * KiB, "pdm" },
+ [FSL_IMX8MP_ASRC] = { 0x30c90000, 64 * KiB, "asrc" },
+ [FSL_IMX8MP_SAI7] = { 0x30c80000, 64 * KiB, "sai7" },
+ [FSL_IMX8MP_SAI6] = { 0x30c60000, 64 * KiB, "sai6" },
+ [FSL_IMX8MP_SAI5] = { 0x30c50000, 64 * KiB, "sai5" },
+ [FSL_IMX8MP_SAI3] = { 0x30c30000, 64 * KiB, "sai3" },
+ [FSL_IMX8MP_SAI2] = { 0x30c20000, 64 * KiB, "sai2" },
+ [FSL_IMX8MP_SAI1] = { 0x30c10000, 64 * KiB, "sai1" },
+ /* AIPS-5 End */
+
+ /* AIPS-4 Begin */
+ [FSL_IMX8MP_HDMI_TX] = { 0x32fc0000, 128 * KiB, "hdmi_tx" },
+ [FSL_IMX8MP_TZASC] = { 0x32f80000, 64 * KiB, "tzasc" },
+ [FSL_IMX8MP_HSIO_BLK_CTL] = { 0x32f10000, 64 * KiB, "hsio_blk_ctl" },
+ [FSL_IMX8MP_PCIE_PHY1] = { 0x32f00000, 64 * KiB, "pcie_phy1" },
+ [FSL_IMX8MP_MEDIA_BLK_CTL] = { 0x32ec0000, 64 * KiB, "media_blk_ctl" },
+ [FSL_IMX8MP_LCDIF2] = { 0x32e90000, 64 * KiB, "lcdif2" },
+ [FSL_IMX8MP_LCDIF1] = { 0x32e80000, 64 * KiB, "lcdif1" },
+ [FSL_IMX8MP_MIPI_DSI1] = { 0x32e60000, 64 * KiB, "mipi_dsi1" },
+ [FSL_IMX8MP_MIPI_CSI2] = { 0x32e50000, 64 * KiB, "mipi_csi2" },
+ [FSL_IMX8MP_MIPI_CSI1] = { 0x32e40000, 64 * KiB, "mipi_csi1" },
+ [FSL_IMX8MP_IPS_DEWARP] = { 0x32e30000, 64 * KiB, "ips_dewarp" },
+ [FSL_IMX8MP_ISP2] = { 0x32e20000, 64 * KiB, "isp2" },
+ [FSL_IMX8MP_ISP1] = { 0x32e10000, 64 * KiB, "isp1" },
+ [FSL_IMX8MP_ISI] = { 0x32e00000, 64 * KiB, "isi" },
+ [FSL_IMX8MP_AIPS4_CONFIGURATION] = { 0x32df0000, 64 * KiB, "aips4_configuration" },
+ /* AIPS-4 End */
+
+ [FSL_IMX8MP_INTERCONNECT] = { 0x32700000, 1 * MiB, "interconnect" },
+
+ /* AIPS-3 Begin */
+ [FSL_IMX8MP_ENET2_TSN] = { 0x30bf0000, 64 * KiB, "enet2_tsn" },
+ [FSL_IMX8MP_ENET1] = { 0x30be0000, 64 * KiB, "enet1" },
+ [FSL_IMX8MP_SDMA1] = { 0x30bd0000, 64 * KiB, "sdma1" },
+ [FSL_IMX8MP_QSPI] = { 0x30bb0000, 64 * KiB, "qspi" },
+ [FSL_IMX8MP_USDHC3] = { 0x30b60000, 64 * KiB, "usdhc3" },
+ [FSL_IMX8MP_USDHC2] = { 0x30b50000, 64 * KiB, "usdhc2" },
+ [FSL_IMX8MP_USDHC1] = { 0x30b40000, 64 * KiB, "usdhc1" },
+ [FSL_IMX8MP_I2C6] = { 0x30ae0000, 64 * KiB, "i2c6" },
+ [FSL_IMX8MP_I2C5] = { 0x30ad0000, 64 * KiB, "i2c5" },
+ [FSL_IMX8MP_SEMAPHORE_HS] = { 0x30ac0000, 64 * KiB, "semaphore_hs" },
+ [FSL_IMX8MP_MU_1_B] = { 0x30ab0000, 64 * KiB, "mu_1_b" },
+ [FSL_IMX8MP_MU_1_A] = { 0x30aa0000, 64 * KiB, "mu_1_a" },
+ [FSL_IMX8MP_AUD_IRQ_STEER] = { 0x30a80000, 64 * KiB, "aud_irq_steer" },
+ [FSL_IMX8MP_UART4] = { 0x30a60000, 64 * KiB, "uart4" },
+ [FSL_IMX8MP_I2C4] = { 0x30a50000, 64 * KiB, "i2c4" },
+ [FSL_IMX8MP_I2C3] = { 0x30a40000, 64 * KiB, "i2c3" },
+ [FSL_IMX8MP_I2C2] = { 0x30a30000, 64 * KiB, "i2c2" },
+ [FSL_IMX8MP_I2C1] = { 0x30a20000, 64 * KiB, "i2c1" },
+ [FSL_IMX8MP_AIPS3_CONFIGURATION] = { 0x309f0000, 64 * KiB, "aips3_configuration" },
+ [FSL_IMX8MP_CAAM] = { 0x30900000, 256 * KiB, "caam" },
+ [FSL_IMX8MP_SPBA1] = { 0x308f0000, 64 * KiB, "spba1" },
+ [FSL_IMX8MP_FLEXCAN2] = { 0x308d0000, 64 * KiB, "flexcan2" },
+ [FSL_IMX8MP_FLEXCAN1] = { 0x308c0000, 64 * KiB, "flexcan1" },
+ [FSL_IMX8MP_UART2] = { 0x30890000, 64 * KiB, "uart2" },
+ [FSL_IMX8MP_UART3] = { 0x30880000, 64 * KiB, "uart3" },
+ [FSL_IMX8MP_UART1] = { 0x30860000, 64 * KiB, "uart1" },
+ [FSL_IMX8MP_ECSPI3] = { 0x30840000, 64 * KiB, "ecspi3" },
+ [FSL_IMX8MP_ECSPI2] = { 0x30830000, 64 * KiB, "ecspi2" },
+ [FSL_IMX8MP_ECSPI1] = { 0x30820000, 64 * KiB, "ecspi1" },
+ /* AIPS-3 End */
+
+ /* AIPS-2 Begin */
+ [FSL_IMX8MP_QOSC] = { 0x307f0000, 64 * KiB, "qosc" },
+ [FSL_IMX8MP_PERFMON2] = { 0x307d0000, 64 * KiB, "perfmon2" },
+ [FSL_IMX8MP_PERFMON1] = { 0x307c0000, 64 * KiB, "perfmon1" },
+ [FSL_IMX8MP_GPT4] = { 0x30700000, 64 * KiB, "gpt4" },
+ [FSL_IMX8MP_GPT5] = { 0x306f0000, 64 * KiB, "gpt5" },
+ [FSL_IMX8MP_GPT6] = { 0x306e0000, 64 * KiB, "gpt6" },
+ [FSL_IMX8MP_SYSCNT_CTRL] = { 0x306c0000, 64 * KiB, "syscnt_ctrl" },
+ [FSL_IMX8MP_SYSCNT_CMP] = { 0x306b0000, 64 * KiB, "syscnt_cmp" },
+ [FSL_IMX8MP_SYSCNT_RD] = { 0x306a0000, 64 * KiB, "syscnt_rd" },
+ [FSL_IMX8MP_PWM4] = { 0x30690000, 64 * KiB, "pwm4" },
+ [FSL_IMX8MP_PWM3] = { 0x30680000, 64 * KiB, "pwm3" },
+ [FSL_IMX8MP_PWM2] = { 0x30670000, 64 * KiB, "pwm2" },
+ [FSL_IMX8MP_PWM1] = { 0x30660000, 64 * KiB, "pwm1" },
+ [FSL_IMX8MP_AIPS2_CONFIGURATION] = { 0x305f0000, 64 * KiB, "aips2_configuration" },
+ /* AIPS-2 End */
+
+ /* AIPS-1 Begin */
+ [FSL_IMX8MP_CSU] = { 0x303e0000, 64 * KiB, "csu" },
+ [FSL_IMX8MP_RDC] = { 0x303d0000, 64 * KiB, "rdc" },
+ [FSL_IMX8MP_SEMAPHORE2] = { 0x303c0000, 64 * KiB, "semaphore2" },
+ [FSL_IMX8MP_SEMAPHORE1] = { 0x303b0000, 64 * KiB, "semaphore1" },
+ [FSL_IMX8MP_GPC] = { 0x303a0000, 64 * KiB, "gpc" },
+ [FSL_IMX8MP_SRC] = { 0x30390000, 64 * KiB, "src" },
+ [FSL_IMX8MP_CCM] = { 0x30380000, 64 * KiB, "ccm" },
+ [FSL_IMX8MP_SNVS_HP] = { 0x30370000, 64 * KiB, "snvs_hp" },
+ [FSL_IMX8MP_ANA_PLL] = { 0x30360000, 64 * KiB, "ana_pll" },
+ [FSL_IMX8MP_OCOTP_CTRL] = { 0x30350000, 64 * KiB, "ocotp_ctrl" },
+ [FSL_IMX8MP_IOMUXC_GPR] = { 0x30340000, 64 * KiB, "iomuxc_gpr" },
+ [FSL_IMX8MP_IOMUXC] = { 0x30330000, 64 * KiB, "iomuxc" },
+ [FSL_IMX8MP_GPT3] = { 0x302f0000, 64 * KiB, "gpt3" },
+ [FSL_IMX8MP_GPT2] = { 0x302e0000, 64 * KiB, "gpt2" },
+ [FSL_IMX8MP_GPT1] = { 0x302d0000, 64 * KiB, "gpt1" },
+ [FSL_IMX8MP_WDOG3] = { 0x302a0000, 64 * KiB, "wdog3" },
+ [FSL_IMX8MP_WDOG2] = { 0x30290000, 64 * KiB, "wdog2" },
+ [FSL_IMX8MP_WDOG1] = { 0x30280000, 64 * KiB, "wdog1" },
+ [FSL_IMX8MP_ANA_OSC] = { 0x30270000, 64 * KiB, "ana_osc" },
+ [FSL_IMX8MP_ANA_TSENSOR] = { 0x30260000, 64 * KiB, "ana_tsensor" },
+ [FSL_IMX8MP_GPIO5] = { 0x30240000, 64 * KiB, "gpio5" },
+ [FSL_IMX8MP_GPIO4] = { 0x30230000, 64 * KiB, "gpio4" },
+ [FSL_IMX8MP_GPIO3] = { 0x30220000, 64 * KiB, "gpio3" },
+ [FSL_IMX8MP_GPIO2] = { 0x30210000, 64 * KiB, "gpio2" },
+ [FSL_IMX8MP_GPIO1] = { 0x30200000, 64 * KiB, "gpio1" },
+ [FSL_IMX8MP_AIPS1_CONFIGURATION] = { 0x301f0000, 64 * KiB, "aips1_configuration" },
+ /* AIPS-1 End */
+
+ [FSL_IMX8MP_A53_DAP] = { 0x28000000, 16 * MiB, "a53_dap" },
+ [FSL_IMX8MP_PCIE1_MEM] = { 0x18000000, 128 * MiB, "pcie1_mem" },
+ [FSL_IMX8MP_QSPI_MEM] = { 0x08000000, 256 * MiB, "qspi_mem" },
+ [FSL_IMX8MP_OCRAM] = { 0x00900000, 576 * KiB, "ocram" },
+ [FSL_IMX8MP_TCM_DTCM] = { 0x00800000, 128 * KiB, "tcm_dtcm" },
+ [FSL_IMX8MP_TCM_ITCM] = { 0x007e0000, 128 * KiB, "tcm_itcm" },
+ [FSL_IMX8MP_OCRAM_S] = { 0x00180000, 36 * KiB, "ocram_s" },
+ [FSL_IMX8MP_CAAM_MEM] = { 0x00100000, 32 * KiB, "caam_mem" },
+ [FSL_IMX8MP_BOOT_ROM_PROTECTED] = { 0x0003f000, 4 * KiB, "boot_rom_protected" },
+ [FSL_IMX8MP_BOOT_ROM] = { 0x00000000, 252 * KiB, "boot_rom" },
+};
+
+static void fsl_imx8mp_init(Object *obj)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ FslImx8mpState *s = FSL_IMX8MP(obj);
+ int i;
+
+ for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MP_NUM_CPUS); i++) {
+ g_autofree char *name = g_strdup_printf("cpu%d", i);
+ object_initialize_child(obj, name, &s->cpu[i],
+ ARM_CPU_TYPE_NAME("cortex-a53"));
+ }
+
+ object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3);
+
+ object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM);
+
+ object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG);
+
+ object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS);
+
+ for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
+ g_autofree char *name = g_strdup_printf("uart%d", i + 1);
+ object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
+ }
+
+ for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
+ g_autofree char *name = g_strdup_printf("gpt%d", i + 1);
+ object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MP_GPT);
+ }
+ object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq,
+ TYPE_OR_IRQ);
+
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
+ g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
+ object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
+ }
+
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
+ g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
+ object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO);
+ }
+
+ for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
+ g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
+ object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
+ }
+
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
+ g_autofree char *name = g_strdup_printf("usb%d", i);
+ object_initialize_child(obj, name, &s->usb[i], TYPE_USB_DWC3);
+ }
+
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
+ g_autofree char *name = g_strdup_printf("spi%d", i + 1);
+ object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
+ }
+
+ for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
+ g_autofree char *name = g_strdup_printf("wdt%d", i);
+ object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
+ }
+
+ object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET);
+
+ object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
+ object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
+ TYPE_FSL_IMX8M_PCIE_PHY);
+}
+
+static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ FslImx8mpState *s = FSL_IMX8MP(dev);
+ DeviceState *gicdev = DEVICE(&s->gic);
+ int i;
+
+ if (ms->smp.cpus > FSL_IMX8MP_NUM_CPUS) {
+ error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
+ TYPE_FSL_IMX8MP, FSL_IMX8MP_NUM_CPUS, ms->smp.cpus);
+ return;
+ }
+
+ /* CPUs */
+ for (i = 0; i < ms->smp.cpus; i++) {
+ /* On uniprocessor, the CBAR is set to 0 */
+ if (ms->smp.cpus > 1) {
+ object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
+ fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr,
+ &error_abort);
+ }
+
+ /*
+ * CNTFID0 base frequency in Hz of system counter
+ */
+ object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000,
+ &error_abort);
+
+ if (i) {
+ /*
+ * Secondary CPUs start in powered-down state (and can be
+ * powered up via the SRC system reset controller)
+ */
+ object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off",
+ true, &error_abort);
+ }
+
+ if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
+ return;
+ }
+ }
+
+ /* GIC */
+ {
+ SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic);
+ QList *redist_region_count;
+
+ qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus);
+ qdev_prop_set_uint32(gicdev, "num-irq",
+ FSL_IMX8MP_NUM_IRQS + GIC_INTERNAL);
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, ms->smp.cpus);
+ qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
+ object_property_set_link(OBJECT(&s->gic), "sysmem",
+ OBJECT(get_system_memory()), &error_fatal);
+ if (!sysbus_realize(gicsbd, errp)) {
+ return;
+ }
+ sysbus_mmio_map(gicsbd, 0, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr);
+ sysbus_mmio_map(gicsbd, 1, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_REDIST].addr);
+
+ /*
+ * 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 interrupt outputs to the CPU's inputs.
+ */
+ for (i = 0; i < ms->smp.cpus; i++) {
+ DeviceState *cpudev = DEVICE(&s->cpu[i]);
+ int intidbase = FSL_IMX8MP_NUM_IRQS + i * GIC_INTERNAL;
+ qemu_irq irq;
+
+ /*
+ * Mapping from the output timer irq lines from the CPU to the
+ * GIC PPI inputs.
+ */
+ static const int timer_irqs[] = {
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
+ };
+
+ for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) {
+ irq = qdev_get_gpio_in(gicdev, intidbase + timer_irqs[j]);
+ qdev_connect_gpio_out(cpudev, j, irq);
+ }
+
+ irq = qdev_get_gpio_in(gicdev, intidbase + ARCH_GIC_MAINT_IRQ);
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
+ 0, irq);
+
+ irq = qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ);
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, irq);
+
+ sysbus_connect_irq(gicsbd, i,
+ qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+ sysbus_connect_irq(gicsbd, i + ms->smp.cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ }
+ }
+
+ /* CCM */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_CCM].addr);
+
+ /* Analog */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->analog), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_ANA_PLL].addr);
+
+ /* UARTs */
+ for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq;
+ } serial_table[FSL_IMX8MP_NUM_UARTS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART3].addr, FSL_IMX8MP_UART3_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART4].addr, FSL_IMX8MP_UART4_IRQ },
+ };
+
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
+ qdev_get_gpio_in(gicdev, serial_table[i].irq));
+ }
+
+ /* GPTs */
+ object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2,
+ &error_abort);
+ if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) {
+ return;
+ }
+
+ qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_GPT5_GPT6_IRQ));
+
+ for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
+ hwaddr gpt_addrs[FSL_IMX8MP_NUM_GPTS] = {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT1].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT2].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT3].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT4].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT5].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT6].addr,
+ };
+
+ s->gpt[i].ccm = IMX_CCM(&s->ccm);
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_addrs[i]);
+
+ if (i < FSL_IMX8MP_NUM_GPTS - 2) {
+ static const unsigned int gpt_irqs[FSL_IMX8MP_NUM_GPTS - 2] = {
+ FSL_IMX8MP_GPT1_IRQ,
+ FSL_IMX8MP_GPT2_IRQ,
+ FSL_IMX8MP_GPT3_IRQ,
+ FSL_IMX8MP_GPT4_IRQ,
+ };
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
+ qdev_get_gpio_in(gicdev, gpt_irqs[i]));
+ } else {
+ int irq = i - FSL_IMX8MP_NUM_GPTS + 2;
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->gpt5_gpt6_irq), irq));
+ }
+ }
+
+ /* I2Cs */
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq;
+ } i2c_table[FSL_IMX8MP_NUM_I2CS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C1].addr, FSL_IMX8MP_I2C1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C2].addr, FSL_IMX8MP_I2C2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C3].addr, FSL_IMX8MP_I2C3_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C4].addr, FSL_IMX8MP_I2C4_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C5].addr, FSL_IMX8MP_I2C5_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C6].addr, FSL_IMX8MP_I2C6_IRQ },
+ };
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
+ qdev_get_gpio_in(gicdev, i2c_table[i].irq));
+ }
+
+ /* GPIOs */
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq_low;
+ unsigned int irq_high;
+ } gpio_table[FSL_IMX8MP_NUM_GPIOS] = {
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO1].addr,
+ FSL_IMX8MP_GPIO1_LOW_IRQ,
+ FSL_IMX8MP_GPIO1_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO2].addr,
+ FSL_IMX8MP_GPIO2_LOW_IRQ,
+ FSL_IMX8MP_GPIO2_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO3].addr,
+ FSL_IMX8MP_GPIO3_LOW_IRQ,
+ FSL_IMX8MP_GPIO3_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO4].addr,
+ FSL_IMX8MP_GPIO4_LOW_IRQ,
+ FSL_IMX8MP_GPIO4_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO5].addr,
+ FSL_IMX8MP_GPIO5_LOW_IRQ,
+ FSL_IMX8MP_GPIO5_HIGH_IRQ
+ },
+ };
+
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true,
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq",
+ true, &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_low));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_high));
+ }
+
+ /* USDHCs */
+ for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq;
+ } usdhc_table[FSL_IMX8MP_NUM_USDHCS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC1].addr, FSL_IMX8MP_USDHC1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC2].addr, FSL_IMX8MP_USDHC2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC3].addr, FSL_IMX8MP_USDHC3_IRQ },
+ };
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
+ qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
+ }
+
+ /* USBs */
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq;
+ } usb_table[FSL_IMX8MP_NUM_USBS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USB1].addr, FSL_IMX8MP_USB1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USB2].addr, FSL_IMX8MP_USB2_IRQ },
+ };
+
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p2", 1);
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p3", 1);
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 0,
+ qdev_get_gpio_in(gicdev, usb_table[i].irq));
+ }
+
+ /* ECSPIs */
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq;
+ } spi_table[FSL_IMX8MP_NUM_ECSPIS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI1].addr, FSL_IMX8MP_ECSPI1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI2].addr, FSL_IMX8MP_ECSPI2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI3].addr, FSL_IMX8MP_ECSPI3_IRQ },
+ };
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
+ qdev_get_gpio_in(gicdev, spi_table[i].irq));
+ }
+
+ /* ENET1 */
+ object_property_set_uint(OBJECT(&s->enet), "phy-num", s->phy_num,
+ &error_abort);
+ object_property_set_uint(OBJECT(&s->enet), "tx-ring-num", 3, &error_abort);
+ qemu_configure_nic_device(DEVICE(&s->enet), true, NULL);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->enet), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->enet), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_ENET1].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 0,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_ENET1_MAC_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 1,
+ qdev_get_gpio_in(gicdev, FSL_IMX6_ENET1_MAC_1588_IRQ));
+
+ /* SNVS */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
+
+ /* Watchdogs */
+ for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
+ struct {
+ hwaddr addr;
+ unsigned int irq;
+ } wdog_table[FSL_IMX8MP_NUM_WDTS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG1].addr, FSL_IMX8MP_WDOG1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG2].addr, FSL_IMX8MP_WDOG2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG3].addr, FSL_IMX8MP_WDOG3_IRQ },
+ };
+
+ object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support",
+ true, &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, wdog_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
+ qdev_get_gpio_in(gicdev, wdog_table[i].irq));
+ }
+
+ /* PCIe */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_PCIE1].addr);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTA_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTB_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTC_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTD_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_MSI_IRQ));
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
+
+ /* On-Chip RAM */
+ if (!memory_region_init_ram(&s->ocram, NULL, "imx8mp.ocram",
+ fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
+ errp)) {
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(),
+ fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].addr,
+ &s->ocram);
+
+ /* Unimplemented devices */
+ for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
+ switch (i) {
+ case FSL_IMX8MP_ANA_PLL:
+ case FSL_IMX8MP_CCM:
+ case FSL_IMX8MP_GIC_DIST:
+ case FSL_IMX8MP_GIC_REDIST:
+ case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
+ case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
+ case FSL_IMX8MP_ENET1:
+ case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
+ case FSL_IMX8MP_OCRAM:
+ case FSL_IMX8MP_PCIE1:
+ case FSL_IMX8MP_PCIE_PHY1:
+ case FSL_IMX8MP_RAM:
+ case FSL_IMX8MP_SNVS_HP:
+ case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
+ case FSL_IMX8MP_USB1 ... FSL_IMX8MP_USB2:
+ case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
+ case FSL_IMX8MP_WDOG1 ... FSL_IMX8MP_WDOG3:
+ /* device implemented and treated above */
+ break;
+
+ default:
+ create_unimplemented_device(fsl_imx8mp_memmap[i].name,
+ fsl_imx8mp_memmap[i].addr,
+ fsl_imx8mp_memmap[i].size);
+ break;
+ }
+ }
+}
+
+static const Property fsl_imx8mp_properties[] = {
+ DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mpState, phy_num, 0),
+ DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true),
+};
+
+static void fsl_imx8mp_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ device_class_set_props(dc, fsl_imx8mp_properties);
+ dc->realize = fsl_imx8mp_realize;
+
+ dc->desc = "i.MX 8M Plus SoC";
+}
+
+static const TypeInfo fsl_imx8mp_types[] = {
+ {
+ .name = TYPE_FSL_IMX8MP,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FslImx8mpState),
+ .instance_init = fsl_imx8mp_init,
+ .class_init = fsl_imx8mp_class_init,
+ },
+};
+
+DEFINE_TYPES(fsl_imx8mp_types)
diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c
deleted file mode 100644
index 9146269..0000000
--- a/hw/arm/gumstix.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Gumstix Platforms
- *
- * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * Example usage:
- *
- * connex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=16k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * start it:
- * # qemu-system-arm -M connex -pflash flash -monitor null -nographic
- *
- * verdex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=32k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage
- * start it:
- * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "qemu/error-report.h"
-#include "hw/arm/pxa.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "hw/net/smc91c111.h"
-#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-#define CONNEX_FLASH_SIZE (16 * MiB)
-#define CONNEX_RAM_SIZE (64 * MiB)
-
-#define VERDEX_FLASH_SIZE (32 * MiB)
-#define VERDEX_RAM_SIZE (256 * MiB)
-
-#define FLASH_SECTOR_SIZE (128 * KiB)
-
-static void connex_init(MachineState *machine)
-{
- PXA2xxState *cpu;
- DriveInfo *dinfo;
-
- cpu = pxa255_init(CONNEX_RAM_SIZE);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- error_report("A flash image must be given with the "
- "'pflash' parameter");
- exit(1);
- }
-
- /* Numonyx RC28F128J3F75 */
- pflash_cfi01_register(0x00000000, "connext.rom", CONNEX_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0);
-
- /* Interrupt line of NIC is connected to GPIO line 36 */
- smc91c111_init(0x04000300, qdev_get_gpio_in(cpu->gpio, 36));
-}
-
-static void verdex_init(MachineState *machine)
-{
- PXA2xxState *cpu;
- DriveInfo *dinfo;
-
- cpu = pxa270_init(VERDEX_RAM_SIZE, machine->cpu_type);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- error_report("A flash image must be given with the "
- "'pflash' parameter");
- exit(1);
- }
-
- /* Micron RC28F256P30TFA */
- pflash_cfi01_register(0x00000000, "verdex.rom", VERDEX_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0);
-
- /* Interrupt line of NIC is connected to GPIO line 99 */
- smc91c111_init(0x04000300, qdev_get_gpio_in(cpu->gpio, 99));
-}
-
-static void connex_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Gumstix Connex (PXA255)";
- mc->init = connex_init;
- mc->ignore_memory_transaction_failures = true;
- mc->deprecation_reason = "machine is old and unmaintained";
-}
-
-static const TypeInfo connex_type = {
- .name = MACHINE_TYPE_NAME("connex"),
- .parent = TYPE_MACHINE,
- .class_init = connex_class_init,
-};
-
-static void verdex_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Gumstix Verdex Pro XL6P COMs (PXA270)";
- mc->init = verdex_init;
- mc->ignore_memory_transaction_failures = true;
- mc->deprecation_reason = "machine is old and unmaintained";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
-}
-
-static const TypeInfo verdex_type = {
- .name = MACHINE_TYPE_NAME("verdex"),
- .parent = TYPE_MACHINE,
- .class_init = verdex_class_init,
-};
-
-static void gumstix_machine_init(void)
-{
- type_register_static(&connex_type);
- type_register_static(&verdex_type);
-}
-
-type_init(gumstix_machine_init)
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index c71b1a8..3ae26eb 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -25,8 +25,8 @@
#include "hw/arm/boot.h"
#include "hw/loader.h"
#include "net/net.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "hw/char/pl011.h"
@@ -45,7 +45,7 @@
#define MVBAR_ADDR 0x200
#define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t))
-#define NIRQ_GIC 160
+#define GIC_EXT_IRQS 128 /* EnergyCore ECX-1000 & ECX-2000 */
/* Board init. */
@@ -139,13 +139,13 @@ static void highbank_regs_init(Object *obj)
sysbus_init_mmio(dev, &s->iomem);
}
-static void highbank_regs_class_init(ObjectClass *klass, void *data)
+static void highbank_regs_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "Calxeda Highbank registers";
dc->vmsd = &vmstate_highbank_regs;
- dc->reset = highbank_regs_reset;
+ device_class_set_legacy_reset(dc, highbank_regs_reset);
}
static const TypeInfo highbank_regs_info = {
@@ -180,7 +180,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
{
DeviceState *dev = NULL;
SysBusDevice *busdev;
- qemu_irq pic[128];
+ qemu_irq pic[GIC_EXT_IRQS];
int n;
unsigned int smp_cpus = machine->smp.cpus;
qemu_irq cpu_irq[4];
@@ -199,7 +199,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
machine->cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
break;
default:
- assert(0);
+ g_assert_not_reached();
}
for (n = 0; n < smp_cpus; n++) {
@@ -260,7 +260,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
break;
}
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
- qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
+ qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
@@ -271,7 +271,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
sysbus_connect_irq(busdev, n + 3 * smp_cpus, cpu_vfiq[n]);
}
- for (n = 0; n < 128; n++) {
+ for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
@@ -341,7 +341,7 @@ static void midway_init(MachineState *machine)
calxeda_init(machine, CALXEDA_MIDWAY);
}
-static void highbank_class_init(ObjectClass *oc, void *data)
+static void highbank_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
@@ -365,7 +365,7 @@ static const TypeInfo highbank_type = {
.class_init = highbank_class_init,
};
-static void midway_class_init(ObjectClass *oc, void *data)
+static void midway_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a15"),
diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
index 7dfddd4..e95ea5e 100644
--- a/hw/arm/imx25_pdk.c
+++ b/hw/arm/imx25_pdk.c
@@ -30,7 +30,7 @@
#include "hw/arm/boot.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#include "hw/i2c/i2c.h"
#include "qemu/cutils.h"
@@ -147,6 +147,7 @@ static void imx25_pdk_machine_init(MachineClass *mc)
mc->init = imx25_pdk_init;
mc->ignore_memory_transaction_failures = true;
mc->default_ram_id = "imx25.ram";
+ mc->auto_create_sdcard = true;
}
DEFINE_MACHINE("imx25-pdk", imx25_pdk_machine_init)
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
new file mode 100644
index 0000000..b3082fa
--- /dev/null
+++ b/hw/arm/imx8mp-evk.c
@@ -0,0 +1,103 @@
+/*
+ * NXP i.MX 8M Plus Evaluation Kit System Emulation
+ *
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/address-spaces.h"
+#include "hw/arm/boot.h"
+#include "hw/arm/fsl-imx8mp.h"
+#include "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "system/qtest.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include <libfdt.h>
+
+static void imx8mp_evk_modify_dtb(const struct arm_boot_info *info, void *fdt)
+{
+ int i, offset;
+
+ /* Temporarily disable following nodes until they are implemented */
+ const char *nodes_to_remove[] = {
+ "nxp,imx8mp-fspi",
+ };
+
+ for (i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) {
+ const char *dev_str = nodes_to_remove[i];
+
+ offset = fdt_node_offset_by_compatible(fdt, -1, dev_str);
+ while (offset >= 0) {
+ fdt_nop_node(fdt, offset);
+ offset = fdt_node_offset_by_compatible(fdt, offset, dev_str);
+ }
+ }
+
+ /* Remove cpu-idle-states property from CPU nodes */
+ offset = fdt_node_offset_by_compatible(fdt, -1, "arm,cortex-a53");
+ while (offset >= 0) {
+ fdt_nop_property(fdt, offset, "cpu-idle-states");
+ offset = fdt_node_offset_by_compatible(fdt, offset, "arm,cortex-a53");
+ }
+}
+
+static void imx8mp_evk_init(MachineState *machine)
+{
+ static struct arm_boot_info boot_info;
+ FslImx8mpState *s;
+
+ if (machine->ram_size > FSL_IMX8MP_RAM_SIZE_MAX) {
+ error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")",
+ machine->ram_size, FSL_IMX8MP_RAM_SIZE_MAX);
+ exit(1);
+ }
+
+ boot_info = (struct arm_boot_info) {
+ .loader_start = FSL_IMX8MP_RAM_START,
+ .board_id = -1,
+ .ram_size = machine->ram_size,
+ .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
+ .modify_dtb = imx8mp_evk_modify_dtb,
+ };
+
+ s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
+ object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal);
+
+ memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
+ machine->ram);
+
+ for (int i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
+ BusState *bus;
+ DeviceState *carddev;
+ BlockBackend *blk;
+ DriveInfo *di = drive_get(IF_SD, i, 0);
+
+ if (!di) {
+ continue;
+ }
+
+ blk = blk_by_legacy_dinfo(di);
+ bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
+ carddev = qdev_new(TYPE_SD_CARD);
+ qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
+ qdev_realize_and_unref(carddev, bus, &error_fatal);
+ }
+
+ if (!qtest_enabled()) {
+ arm_load_kernel(&s->cpu[0], machine, &boot_info);
+ }
+}
+
+static void imx8mp_evk_machine_init(MachineClass *mc)
+{
+ mc->desc = "NXP i.MX 8M Plus EVK Board";
+ mc->init = imx8mp_evk_init;
+ mc->max_cpus = FSL_IMX8MP_NUM_CPUS;
+ mc->default_ram_id = "imx8mp-evk.ram";
+}
+DEFINE_MACHINE("imx8mp-evk", imx8mp_evk_machine_init)
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index feb0dd6..b1d8fbd 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -16,9 +16,9 @@
#include "hw/misc/arm_integrator_debug.h"
#include "hw/net/smc91c111.h"
#include "net/net.h"
-#include "exec/address-spaces.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/char/pl011.h"
@@ -688,18 +688,18 @@ static void integratorcp_machine_init(MachineClass *mc)
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
mc->default_ram_id = "integrator.ram";
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
}
DEFINE_MACHINE("integratorcp", integratorcp_machine_init)
-static Property core_properties[] = {
+static const Property core_properties[] = {
DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void core_class_init(ObjectClass *klass, void *data)
+static void core_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -708,14 +708,14 @@ static void core_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_integratorcm;
}
-static void icp_pic_class_init(ObjectClass *klass, void *data)
+static void icp_pic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_icp_pic;
}
-static void icp_control_class_init(ObjectClass *klass, void *data)
+static void icp_control_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
index 2ccd6f8..362c145 100644
--- a/hw/arm/kzm.c
+++ b/hw/arm/kzm.c
@@ -19,12 +19,12 @@
#include "hw/arm/boot.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "net/net.h"
#include "hw/net/lan9118.h"
-#include "hw/char/serial.h"
-#include "sysemu/qtest.h"
-#include "sysemu/sysemu.h"
+#include "hw/char/serial-mm.h"
+#include "system/qtest.h"
+#include "system/system.h"
#include "qemu/cutils.h"
/* Memory map for Kzm Emulation Baseboard:
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
deleted file mode 100644
index 3a6c22f..0000000
--- a/hw/arm/mainstone.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- * <akuster@mvista.com>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "qemu/error-report.h"
-#include "qapi/error.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "net/net.h"
-#include "hw/net/smc91c111.h"
-#include "hw/boards.h"
-#include "hw/block/flash.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-/* Device addresses */
-#define MST_FPGA_PHYS 0x08000000
-#define MST_ETH_PHYS 0x10000300
-#define MST_FLASH_0 0x00000000
-#define MST_FLASH_1 0x04000000
-
-/* IRQ definitions */
-#define MMC_IRQ 0
-#define USIM_IRQ 1
-#define USBC_IRQ 2
-#define ETHERNET_IRQ 3
-#define AC97_IRQ 4
-#define PEN_IRQ 5
-#define MSINS_IRQ 6
-#define EXBRD_IRQ 7
-#define S0_CD_IRQ 9
-#define S0_STSCHG_IRQ 10
-#define S0_IRQ 11
-#define S1_CD_IRQ 13
-#define S1_STSCHG_IRQ 14
-#define S1_IRQ 15
-
-static const struct keymap map[0xE0] = {
- [0 ... 0xDF] = { -1, -1 },
- [0x1e] = {0,0}, /* a */
- [0x30] = {0,1}, /* b */
- [0x2e] = {0,2}, /* c */
- [0x20] = {0,3}, /* d */
- [0x12] = {0,4}, /* e */
- [0x21] = {0,5}, /* f */
- [0x22] = {1,0}, /* g */
- [0x23] = {1,1}, /* h */
- [0x17] = {1,2}, /* i */
- [0x24] = {1,3}, /* j */
- [0x25] = {1,4}, /* k */
- [0x26] = {1,5}, /* l */
- [0x32] = {2,0}, /* m */
- [0x31] = {2,1}, /* n */
- [0x18] = {2,2}, /* o */
- [0x19] = {2,3}, /* p */
- [0x10] = {2,4}, /* q */
- [0x13] = {2,5}, /* r */
- [0x1f] = {3,0}, /* s */
- [0x14] = {3,1}, /* t */
- [0x16] = {3,2}, /* u */
- [0x2f] = {3,3}, /* v */
- [0x11] = {3,4}, /* w */
- [0x2d] = {3,5}, /* x */
- [0x34] = {4,0}, /* . */
- [0x15] = {4,2}, /* y */
- [0x2c] = {4,3}, /* z */
- [0x35] = {4,4}, /* / */
- [0xc7] = {5,0}, /* Home */
- [0x2a] = {5,1}, /* shift */
- /*
- * There are two matrix positions which map to space,
- * but QEMU can only use one of them for the reverse
- * mapping, so simply use the second one.
- */
- /* [0x39] = {5,2}, space */
- [0x39] = {5,3}, /* space */
- /*
- * Matrix position {5,4} and other keys are missing here.
- * TODO: Compare with Linux code and test real hardware.
- */
- [0x1c] = {5,4}, /* enter */
- [0x0e] = {5,5}, /* backspace */
- [0xc8] = {6,0}, /* up */
- [0xd0] = {6,1}, /* down */
- [0xcb] = {6,2}, /* left */
- [0xcd] = {6,3}, /* right */
-};
-
-enum mainstone_model_e { mainstone };
-
-#define MAINSTONE_RAM_SIZE (64 * MiB)
-#define MAINSTONE_ROM_SIZE (8 * MiB)
-#define MAINSTONE_FLASH_SIZE (32 * MiB)
-
-static struct arm_boot_info mainstone_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = MAINSTONE_RAM_SIZE,
-};
-
-#define FLASH_SECTOR_SIZE (256 * KiB)
-
-static void mainstone_common_init(MachineState *machine,
- enum mainstone_model_e model, int arm_id)
-{
- hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
- PXA2xxState *mpu;
- DeviceState *mst_irq;
- DriveInfo *dinfo;
- int i;
- MemoryRegion *rom = g_new(MemoryRegion, 1);
-
- /* Setup CPU & memory */
- mpu = pxa270_init(mainstone_binfo.ram_size, machine->cpu_type);
- memory_region_init_rom(rom, NULL, "mainstone.rom", MAINSTONE_ROM_SIZE,
- &error_fatal);
- memory_region_add_subregion(get_system_memory(), 0x00000000, rom);
-
- /* There are two 32MiB flash devices on the board */
- for (i = 0; i < 2; i ++) {
- dinfo = drive_get(IF_PFLASH, 0, i);
- pflash_cfi01_register(mainstone_flash_base[i],
- i ? "mainstone.flash1" : "mainstone.flash0",
- MAINSTONE_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0);
- }
-
- mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
- qdev_get_gpio_in(mpu->gpio, 0));
-
- /* setup keypad */
- pxa27x_register_keypad(mpu->kp, map, 0xe0);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
-
- pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0],
- qdev_get_gpio_in(mst_irq, S0_IRQ),
- qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
- pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1],
- qdev_get_gpio_in(mst_irq, S1_IRQ),
- qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
-
- smc91c111_init(MST_ETH_PHYS, qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
-
- mainstone_binfo.board_id = arm_id;
- arm_load_kernel(mpu->cpu, machine, &mainstone_binfo);
-}
-
-static void mainstone_init(MachineState *machine)
-{
- mainstone_common_init(machine, mainstone, 0x196);
-}
-
-static void mainstone2_machine_init(MachineClass *mc)
-{
- mc->desc = "Mainstone II (PXA27x)";
- mc->init = mainstone_init;
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
- mc->deprecation_reason = "machine is old and unmaintained";
-}
-
-DEFINE_MACHINE("mainstone", mainstone2_machine_init)
diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c
index 500427e..86982cb 100644
--- a/hw/arm/mcimx6ul-evk.c
+++ b/hw/arm/mcimx6ul-evk.c
@@ -17,7 +17,7 @@
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
static void mcimx6ul_evk_init(MachineState *machine)
{
@@ -74,5 +74,6 @@ static void mcimx6ul_evk_machine_init(MachineClass *mc)
mc->init = mcimx6ul_evk_init;
mc->max_cpus = FSL_IMX6UL_NUM_CPUS;
mc->default_ram_id = "mcimx6ul-evk.ram";
+ mc->auto_create_sdcard = true;
}
DEFINE_MACHINE("mcimx6ul-evk", mcimx6ul_evk_machine_init)
diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c
index 693a102..3311961 100644
--- a/hw/arm/mcimx7d-sabre.c
+++ b/hw/arm/mcimx7d-sabre.c
@@ -19,7 +19,7 @@
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
static void mcimx7d_sabre_init(MachineState *machine)
{
@@ -74,5 +74,6 @@ static void mcimx7d_sabre_machine_init(MachineClass *mc)
mc->init = mcimx7d_sabre_init;
mc->max_cpus = FSL_IMX7_NUM_CPUS;
mc->default_ram_id = "mcimx7d-sabre.ram";
+ mc->auto_create_sdcard = true;
}
DEFINE_MACHINE("mcimx7d-sabre", mcimx7d_sabre_machine_init)
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index 0c07ab5..d90be8f 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -1,81 +1,85 @@
arm_ss = ss.source_set()
-arm_ss.add(files('boot.c'))
+arm_common_ss = ss.source_set()
arm_ss.add(when: 'CONFIG_ARM_VIRT', if_true: files('virt.c'))
arm_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
-arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c'))
-arm_ss.add(when: 'CONFIG_EMCRAFT_SF2', if_true: files('msf2-som.c'))
-arm_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c'))
-arm_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c'))
-arm_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mainstone.c'))
-arm_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c'))
-arm_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c'))
-arm_ss.add(when: 'CONFIG_MUSICPAL', if_true: files('musicpal.c'))
-arm_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c'))
-arm_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c'))
-arm_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
-arm_ss.add(when: 'CONFIG_NSERIES', if_true: files('nseries.c'))
-arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
+arm_common_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c'))
+arm_common_ss.add(when: 'CONFIG_EMCRAFT_SF2', if_true: files('msf2-som.c'))
+arm_common_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c'))
+arm_common_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c'))
+arm_common_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c'))
+arm_common_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c'))
+arm_common_ss.add(when: 'CONFIG_MUSICPAL', if_true: [files('musicpal.c')])
+arm_common_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c'))
+arm_common_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c'))
+arm_common_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
+arm_common_ss.add(when: 'CONFIG_NPCM8XX', if_true: files('npcm8xx.c', 'npcm8xx_boards.c'))
+arm_common_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
-arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
-arm_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c'))
-arm_ss.add(when: 'CONFIG_ZYNQ', if_true: files('xilinx_zynq.c'))
-arm_ss.add(when: 'CONFIG_SABRELITE', if_true: files('sabrelite.c'))
+arm_common_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
+arm_common_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c'))
+arm_common_ss.add(when: 'CONFIG_ZYNQ', if_true: files('xilinx_zynq.c'))
+arm_common_ss.add(when: 'CONFIG_SABRELITE', if_true: files('sabrelite.c'))
-arm_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m.c'))
-arm_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210.c'))
-arm_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c', 'pxa2xx_gpio.c', 'pxa2xx_pic.c'))
-arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic.c'))
-arm_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c'))
-arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
-arm_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
-arm_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c'))
+arm_common_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m.c'))
+arm_common_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210.c'))
+arm_common_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic.c'))
+arm_common_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c'))
+arm_common_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
+arm_common_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
+arm_common_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c'))
arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c'))
-arm_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', 'raspi4b.c'))
-arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
-arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c'))
-arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c'))
-arm_ss.add(when: 'CONFIG_B_L475E_IOT01A', if_true: files('b-l475e-iot01a.c'))
-arm_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_soc.c'))
-arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c'))
-arm_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c'))
-arm_ss.add(when: 'CONFIG_FSL_IMX25', if_true: files('fsl-imx25.c', 'imx25_pdk.c'))
-arm_ss.add(when: 'CONFIG_FSL_IMX31', if_true: files('fsl-imx31.c', 'kzm.c'))
-arm_ss.add(when: 'CONFIG_FSL_IMX6', if_true: files('fsl-imx6.c'))
+arm_common_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', 'raspi4b.c'))
+arm_common_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
+arm_common_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c'))
+arm_common_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c'))
+arm_common_ss.add(when: 'CONFIG_B_L475E_IOT01A', if_true: files('b-l475e-iot01a.c'))
+arm_common_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_soc.c'))
+arm_common_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c'))
+arm_common_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c'))
+arm_common_ss.add(when: 'CONFIG_FSL_IMX25', if_true: files('fsl-imx25.c', 'imx25_pdk.c'))
+arm_common_ss.add(when: 'CONFIG_FSL_IMX31', if_true: files('fsl-imx31.c', 'kzm.c'))
+arm_common_ss.add(when: 'CONFIG_FSL_IMX6', if_true: files('fsl-imx6.c'))
arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed.c',
'aspeed_soc_common.c',
'aspeed_ast2400.c',
'aspeed_ast2600.c',
+ 'aspeed_ast27x0-ssp.c',
+ 'aspeed_ast27x0-tsp.c',
'aspeed_ast10x0.c',
'aspeed_eeprom.c',
'fby35.c'))
-arm_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files('aspeed_ast27x0.c'))
-arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c'))
-arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c'))
-arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))
-arm_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c'))
-arm_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c'))
-arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c'))
-arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
-arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
-arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
-arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c'))
+arm_common_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files(
+ 'aspeed_ast27x0.c',
+ 'aspeed_ast27x0-fc.c',))
+arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c'))
+arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c'))
+arm_common_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))
+arm_common_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c'))
+arm_common_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c'))
+arm_common_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c'))
+arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c'))
+arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c'))
+arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
+arm_common_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
+arm_common_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
+arm_ss.add(when: 'CONFIG_XEN', if_true: files(
+ 'xen-stubs.c',
+ 'xen-pvh.c',
+))
-system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
-system_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c'))
-system_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
-system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
-system_ss.add(when: 'CONFIG_GUMSTIX', if_true: files('gumstix.c'))
-system_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap2.c'))
-system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
-system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c'))
-system_ss.add(when: 'CONFIG_SPITZ', if_true: files('spitz.c'))
-system_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
-system_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c'))
-system_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c'))
-system_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
-system_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
-system_ss.add(when: 'CONFIG_Z2', if_true: files('z2.c'))
+arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
+arm_common_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
+arm_common_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
+arm_common_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
+arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
+arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c'))
+arm_common_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
+arm_common_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c'))
+arm_common_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
+arm_common_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
+
+arm_common_ss.add(files('boot.c'))
hw_arch += {'arm': arm_ss}
+hw_common_arch += {'arm': arm_common_ss}
diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c
index 50df362..525443f 100644
--- a/hw/arm/microbit.c
+++ b/hw/arm/microbit.c
@@ -12,8 +12,8 @@
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/arm/boot.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
+#include "system/system.h"
+#include "system/address-spaces.h"
#include "hw/arm/nrf51_soc.h"
#include "hw/i2c/microbit_i2c.h"
@@ -56,11 +56,11 @@ static void microbit_init(MachineState *machine)
memory_region_add_subregion_overlap(&s->nrf51.container, NRF51_TWI_BASE,
mr, -1);
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ armv7m_load_kernel(s->nrf51.armv7m.cpu, machine->kernel_filename,
0, s->nrf51.flash_size);
}
-static void microbit_machine_class_init(ObjectClass *oc, void *data)
+static void microbit_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index aec57c0..5dd87cc 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -48,15 +48,15 @@
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qemu/error-report.h"
#include "hw/arm/boot.h"
#include "hw/arm/armv7m.h"
#include "hw/or-irq.h"
#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/reset.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
+#include "system/reset.h"
#include "hw/misc/unimp.h"
#include "hw/char/cmsdk-apb-uart.h"
#include "hw/timer/cmsdk-apb-timer.h"
@@ -1211,7 +1211,7 @@ static void mps2tz_common_init(MachineState *machine)
mms->remap_irq);
}
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ armv7m_load_kernel(mms->iotkit.armv7m[0].cpu, machine->kernel_filename,
0, boot_ram_size(mms));
}
@@ -1254,7 +1254,7 @@ static void mps2_set_remap(Object *obj, const char *value, Error **errp)
}
}
-static void mps2_machine_reset(MachineState *machine, ShutdownCause reason)
+static void mps2_machine_reset(MachineState *machine, ResetType type)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@@ -1264,10 +1264,10 @@ static void mps2_machine_reset(MachineState *machine, ShutdownCause reason)
* reset see the correct mapping.
*/
remap_memory(mms, mms->remap);
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
}
-static void mps2tz_class_init(ObjectClass *oc, void *data)
+static void mps2tz_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
@@ -1304,7 +1304,7 @@ static void mps2tz_set_default_ram_info(MPS2TZMachineClass *mmc)
g_assert_not_reached();
}
-static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
+static void mps2tz_an505_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc);
@@ -1338,7 +1338,7 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
mps2tz_set_default_ram_info(mmc);
}
-static void mps2tz_an521_class_init(ObjectClass *oc, void *data)
+static void mps2tz_an521_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc);
@@ -1372,7 +1372,7 @@ static void mps2tz_an521_class_init(ObjectClass *oc, void *data)
mps2tz_set_default_ram_info(mmc);
}
-static void mps3tz_an524_class_init(ObjectClass *oc, void *data)
+static void mps3tz_an524_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc);
@@ -1411,7 +1411,7 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data)
"are BRAM (default) and QSPI.");
}
-static void mps3tz_an547_class_init(ObjectClass *oc, void *data)
+static void mps3tz_an547_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc);
@@ -1453,7 +1453,7 @@ static const TypeInfo mps2tz_info = {
.instance_size = sizeof(MPS2TZMachineState),
.class_size = sizeof(MPS2TZMachineClass),
.class_init = mps2tz_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_IDAU_INTERFACE },
{ }
},
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index 50919ee..bd378e3 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -33,8 +33,8 @@
#include "hw/arm/armv7m.h"
#include "hw/or-irq.h"
#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
#include "hw/qdev-properties.h"
#include "hw/misc/unimp.h"
#include "hw/char/cmsdk-apb-uart.h"
@@ -48,7 +48,7 @@
#include "net/net.h"
#include "hw/watchdog/cmsdk-apb-watchdog.h"
#include "hw/qdev-clock.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qom/object.h"
typedef enum MPS2FPGAType {
@@ -224,7 +224,11 @@ static void mps2_common_init(MachineState *machine)
switch (mmc->fpga_type) {
case FPGA_AN385:
case FPGA_AN386:
+ qdev_prop_set_uint32(armv7m, "num-irq", 32);
+ break;
case FPGA_AN500:
+ /* The AN500 configures its Cortex-M7 with 16 MPU regions */
+ qdev_prop_set_uint32(armv7m, "mpu-ns-regions", 16);
qdev_prop_set_uint32(armv7m, "num-irq", 32);
break;
case FPGA_AN511:
@@ -460,11 +464,11 @@ static void mps2_common_init(MachineState *machine)
qdev_get_gpio_in(armv7m,
mmc->fpga_type == FPGA_AN511 ? 47 : 13));
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ armv7m_load_kernel(mms->armv7m.cpu, machine->kernel_filename,
0, 0x400000);
}
-static void mps2_class_init(ObjectClass *oc, void *data)
+static void mps2_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -474,7 +478,7 @@ static void mps2_class_init(ObjectClass *oc, void *data)
mc->default_ram_id = "mps.ram";
}
-static void mps2_an385_class_init(ObjectClass *oc, void *data)
+static void mps2_an385_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
@@ -493,7 +497,7 @@ static void mps2_an385_class_init(ObjectClass *oc, void *data)
mmc->has_block_ram = true;
}
-static void mps2_an386_class_init(ObjectClass *oc, void *data)
+static void mps2_an386_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
@@ -512,7 +516,7 @@ static void mps2_an386_class_init(ObjectClass *oc, void *data)
mmc->has_block_ram = true;
}
-static void mps2_an500_class_init(ObjectClass *oc, void *data)
+static void mps2_an500_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
@@ -531,7 +535,7 @@ static void mps2_an500_class_init(ObjectClass *oc, void *data)
mmc->has_block_ram = false;
}
-static void mps2_an511_class_init(ObjectClass *oc, void *data)
+static void mps2_an511_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
diff --git a/hw/arm/mps3r.c b/hw/arm/mps3r.c
index 4d55a65..48c73ac 100644
--- a/hw/arm/mps3r.c
+++ b/hw/arm/mps3r.c
@@ -27,10 +27,10 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "qapi/qmp/qlist.h"
-#include "exec/address-spaces.h"
+#include "qobject/qlist.h"
+#include "system/address-spaces.h"
#include "cpu.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/or-irq.h"
#include "hw/qdev-clock.h"
@@ -583,14 +583,14 @@ static void mps3r_set_default_ram_info(MPS3RMachineClass *mmc)
g_assert_not_reached();
}
-static void mps3r_class_init(ObjectClass *oc, void *data)
+static void mps3r_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->init = mps3r_common_init;
}
-static void mps3r_an536_class_init(ObjectClass *oc, void *data)
+static void mps3r_an536_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MPS3RMachineClass *mmc = MPS3R_MACHINE_CLASS(oc);
diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c
index a94a10a..c5e9c717 100644
--- a/hw/arm/msf2-soc.c
+++ b/hw/arm/msf2-soc.c
@@ -25,12 +25,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "hw/char/serial.h"
+#include "system/address-spaces.h"
+#include "hw/char/serial-mm.h"
#include "hw/arm/msf2-soc.h"
#include "hw/misc/unimp.h"
#include "hw/qdev-clock.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#define MSF2_TIMER_BASE 0x40004000
#define MSF2_SYSREG_BASE 0x40038000
@@ -222,7 +222,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("usb", 0x40043000, 0x1000);
}
-static Property m2sxxx_soc_properties[] = {
+static const Property m2sxxx_soc_properties[] = {
/*
* part name specifies the type of SmartFusion2 device variant(this
* property is for information purpose only.
@@ -234,10 +234,9 @@ static Property m2sxxx_soc_properties[] = {
/* default divisors in Libero GUI */
DEFINE_PROP_UINT8("apb0div", MSF2State, apb0div, 2),
DEFINE_PROP_UINT8("apb1div", MSF2State, apb1div, 2),
- DEFINE_PROP_END_OF_LIST(),
};
-static void m2sxxx_soc_class_init(ObjectClass *klass, void *data)
+static void m2sxxx_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c
index 5c415ab..29c76c6 100644
--- a/hw/arm/msf2-som.c
+++ b/hw/arm/msf2-som.c
@@ -33,7 +33,7 @@
#include "hw/qdev-properties.h"
#include "hw/arm/boot.h"
#include "hw/qdev-clock.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/arm/msf2-soc.h"
#define DDR_BASE_ADDRESS 0xA0000000
@@ -92,7 +92,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
cs_line = qdev_get_gpio_in_named(spi_flash, SSI_GPIO_CS, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&soc->spi[0]), 1, cs_line);
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ armv7m_load_kernel(soc->armv7m.cpu, machine->kernel_filename,
0, soc->envm_size);
}
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
index e2c9d49..250b3b5 100644
--- a/hw/arm/musca.c
+++ b/hw/arm/musca.c
@@ -22,8 +22,8 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
#include "hw/arm/boot.h"
#include "hw/arm/armsse.h"
#include "hw/boards.h"
@@ -590,11 +590,11 @@ static void musca_init(MachineState *machine)
"cfg_sec_resp", 0));
}
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ armv7m_load_kernel(mms->sse.armv7m[0].cpu, machine->kernel_filename,
0, 0x2000000);
}
-static void musca_class_init(ObjectClass *oc, void *data)
+static void musca_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static const char * const valid_cpu_types[] = {
@@ -609,7 +609,7 @@ static void musca_class_init(ObjectClass *oc, void *data)
mc->init = musca_init;
}
-static void musca_a_class_init(ObjectClass *oc, void *data)
+static void musca_a_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc);
@@ -623,7 +623,7 @@ static void musca_a_class_init(ObjectClass *oc, void *data)
mmc->num_mpcs = ARRAY_SIZE(a_mpc_info);
}
-static void musca_b1_class_init(ObjectClass *oc, void *data)
+static void musca_b1_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc);
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 2020f73..329b162 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -16,9 +16,9 @@
#include "migration/vmstate.h"
#include "hw/arm/boot.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
@@ -29,9 +29,9 @@
#include "hw/irq.h"
#include "hw/or-irq.h"
#include "hw/audio/wm8750.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/runstate.h"
-#include "sysemu/dma.h"
+#include "system/block-backend.h"
+#include "system/runstate.h"
+#include "system/dma.h"
#include "ui/pixel_ops.h"
#include "qemu/cutils.h"
#include "qom/object.h"
@@ -286,7 +286,7 @@ static const VMStateDescription musicpal_lcd_vmsd = {
}
};
-static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
+static void musicpal_lcd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -407,11 +407,11 @@ static const VMStateDescription mv88w8618_pic_vmsd = {
}
};
-static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
+static void mv88w8618_pic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = mv88w8618_pic_reset;
+ device_class_set_legacy_reset(dc, mv88w8618_pic_reset);
dc->vmsd = &mv88w8618_pic_vmsd;
}
@@ -601,11 +601,11 @@ static const VMStateDescription mv88w8618_pit_vmsd = {
}
};
-static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
+static void mv88w8618_pit_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = mv88w8618_pit_reset;
+ device_class_set_legacy_reset(dc, mv88w8618_pit_reset);
dc->vmsd = &mv88w8618_pit_vmsd;
}
@@ -687,7 +687,7 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = {
}
};
-static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
+static void mv88w8618_flashcfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1026,11 +1026,11 @@ static const VMStateDescription musicpal_gpio_vmsd = {
}
};
-static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
+static void musicpal_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = musicpal_gpio_reset;
+ device_class_set_legacy_reset(dc, musicpal_gpio_reset);
dc->vmsd = &musicpal_gpio_vmsd;
}
@@ -1171,7 +1171,7 @@ static const VMStateDescription musicpal_key_vmsd = {
}
};
-static void musicpal_key_class_init(ObjectClass *klass, void *data)
+static void musicpal_key_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1238,7 +1238,7 @@ static void musicpal_init(MachineState *machine)
qdev_get_gpio_in(pic, MP_TIMER4_IRQ), NULL);
/* Logically OR both UART IRQs together */
- uart_orgate = DEVICE(object_new(TYPE_OR_IRQ));
+ uart_orgate = qdev_new(TYPE_OR_IRQ);
object_property_set_int(OBJECT(uart_orgate), "num-lines", 2, &error_fatal);
qdev_realize_and_unref(uart_orgate, NULL, &error_fatal);
qdev_connect_gpio_out(uart_orgate, 0,
@@ -1348,7 +1348,7 @@ static void musicpal_machine_init(MachineClass *mc)
DEFINE_MACHINE("musicpal", musicpal_machine_init)
-static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
+static void mv88w8618_wlan_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c
index 8b1a9a2..df793c7 100644
--- a/hw/arm/netduino2.c
+++ b/hw/arm/netduino2.c
@@ -48,7 +48,7 @@ static void netduino2_init(MachineState *machine)
qdev_connect_clock_in(dev, "sysclk", sysclk);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ armv7m_load_kernel(STM32F205_SOC(dev)->armv7m.cpu, machine->kernel_filename,
0, FLASH_SIZE);
}
diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c
index bccd100..81b6334 100644
--- a/hw/arm/netduinoplus2.c
+++ b/hw/arm/netduinoplus2.c
@@ -48,7 +48,7 @@ static void netduinoplus2_init(MachineState *machine)
qdev_connect_clock_in(dev, "sysclk", sysclk);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- armv7m_load_kernel(ARM_CPU(first_cpu),
+ armv7m_load_kernel(STM32F405_SOC(dev)->armv7m.cpu,
machine->kernel_filename,
0, FLASH_SIZE);
}
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index cb77913..2f30c49 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -18,7 +18,7 @@
#include "hw/arm/boot.h"
#include "hw/arm/npcm7xx.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/loader.h"
#include "hw/misc/unimp.h"
#include "hw/qdev-clock.h"
@@ -26,7 +26,7 @@
#include "qapi/error.h"
#include "qemu/bswap.h"
#include "qemu/units.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "target/arm/cpu-qom.h"
/*
@@ -292,17 +292,21 @@ static const struct {
hwaddr regs_addr;
int cs_count;
const hwaddr *flash_addr;
+ size_t flash_size;
} npcm7xx_fiu[] = {
{
.name = "fiu0",
.regs_addr = 0xfb000000,
.cs_count = ARRAY_SIZE(npcm7xx_fiu0_flash_addr),
.flash_addr = npcm7xx_fiu0_flash_addr,
+ .flash_size = 128 * MiB,
+
}, {
.name = "fiu3",
.regs_addr = 0xc0000000,
.cs_count = ARRAY_SIZE(npcm7xx_fiu3_flash_addr),
.flash_addr = npcm7xx_fiu3_flash_addr,
+ .flash_size = 128 * MiB,
},
};
@@ -735,6 +739,8 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
object_property_set_int(OBJECT(sbd), "cs-count",
npcm7xx_fiu[i].cs_count, &error_abort);
+ object_property_set_int(OBJECT(sbd), "flash-size",
+ npcm7xx_fiu[i].flash_size, &error_abort);
sysbus_realize(sbd, &error_abort);
sysbus_mmio_map(sbd, 0, npcm7xx_fiu[i].regs_addr);
@@ -810,13 +816,12 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm7xx.spix", 0xfb001000, 4 * KiB);
}
-static Property npcm7xx_properties[] = {
+static const Property npcm7xx_properties[] = {
DEFINE_PROP_LINK("dram-mr", NPCM7xxState, dram, TYPE_MEMORY_REGION,
MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void npcm7xx_class_init(ObjectClass *oc, void *data)
+static void npcm7xx_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -825,7 +830,7 @@ static void npcm7xx_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, npcm7xx_properties);
}
-static void npcm730_class_init(ObjectClass *oc, void *data)
+static void npcm730_class_init(ObjectClass *oc, const void *data)
{
NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
@@ -834,7 +839,7 @@ static void npcm730_class_init(ObjectClass *oc, void *data)
nc->num_cpus = 2;
}
-static void npcm750_class_init(ObjectClass *oc, void *data)
+static void npcm750_class_init(ObjectClass *oc, const void *data)
{
NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
index e229efb..465a0e5 100644
--- a/hw/arm/npcm7xx_boards.c
+++ b/hw/arm/npcm7xx_boards.c
@@ -27,9 +27,9 @@
#include "qapi/error.h"
#include "qemu/datadir.h"
#include "qemu/units.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
+#include "system/blockdev.h"
+#include "system/system.h"
+#include "system/block-backend.h"
#include "qemu/error-report.h"
@@ -453,7 +453,7 @@ static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type)
mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus;
}
-static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
+static void npcm7xx_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static const char * const valid_cpu_types[] = {
@@ -472,7 +472,7 @@ static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
* Schematics:
* https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf
*/
-static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data)
+static void npcm750_evb_machine_class_init(ObjectClass *oc, const void *data)
{
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
@@ -481,10 +481,11 @@ static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data)
mc->desc = "Nuvoton NPCM750 Evaluation Board (Cortex-A9)";
mc->init = npcm750_evb_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
};
-static void gsj_machine_class_init(ObjectClass *oc, void *data)
+static void gsj_machine_class_init(ObjectClass *oc, const void *data)
{
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
@@ -493,10 +494,11 @@ static void gsj_machine_class_init(ObjectClass *oc, void *data)
mc->desc = "Quanta GSJ (Cortex-A9)";
mc->init = quanta_gsj_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 512 * MiB;
};
-static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data)
+static void gbs_bmc_machine_class_init(ObjectClass *oc, const void *data)
{
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
@@ -505,10 +507,11 @@ static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data)
mc->desc = "Quanta GBS (Cortex-A9)";
mc->init = quanta_gbs_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
}
-static void kudo_bmc_machine_class_init(ObjectClass *oc, void *data)
+static void kudo_bmc_machine_class_init(ObjectClass *oc, const void *data)
{
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
@@ -517,10 +520,11 @@ static void kudo_bmc_machine_class_init(ObjectClass *oc, void *data)
mc->desc = "Kudo BMC (Cortex-A9)";
mc->init = kudo_bmc_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
};
-static void mori_bmc_machine_class_init(ObjectClass *oc, void *data)
+static void mori_bmc_machine_class_init(ObjectClass *oc, const void *data)
{
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
@@ -529,6 +533,7 @@ static void mori_bmc_machine_class_init(ObjectClass *oc, void *data)
mc->desc = "Mori BMC (Cortex-A9)";
mc->init = mori_bmc_init;
+ mc->auto_create_sdcard = true;
mc->default_ram_size = 1 * GiB;
}
diff --git a/hw/arm/npcm8xx.c b/hw/arm/npcm8xx.c
new file mode 100644
index 0000000..a276fea
--- /dev/null
+++ b/hw/arm/npcm8xx.c
@@ -0,0 +1,859 @@
+/*
+ * Nuvoton NPCM8xx SoC family.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/boards.h"
+#include "hw/arm/boot.h"
+#include "hw/arm/bsa.h"
+#include "hw/arm/npcm8xx.h"
+#include "hw/char/serial-mm.h"
+#include "hw/intc/arm_gic.h"
+#include "hw/loader.h"
+#include "hw/misc/unimp.h"
+#include "hw/qdev-clock.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "qemu/units.h"
+#include "system/system.h"
+
+/*
+ * This covers the whole MMIO space. We'll use this to catch any MMIO accesses
+ * that aren't handled by a device.
+ */
+#define NPCM8XX_MMIO_BA 0x80000000
+#define NPCM8XX_MMIO_SZ 0x7ffd0000
+
+/* OTP fuse array */
+#define NPCM8XX_OTP_BA 0xf0189000
+
+/* GIC Distributor */
+#define NPCM8XX_GICD_BA 0xdfff9000
+#define NPCM8XX_GICC_BA 0xdfffa000
+
+/* Core system modules. */
+#define NPCM8XX_CPUP_BA 0xf03fe000
+#define NPCM8XX_GCR_BA 0xf0800000
+#define NPCM8XX_CLK_BA 0xf0801000
+#define NPCM8XX_MC_BA 0xf0824000
+#define NPCM8XX_RNG_BA 0xf000b000
+
+/* ADC Module */
+#define NPCM8XX_ADC_BA 0xf000c000
+
+/* Internal AHB SRAM */
+#define NPCM8XX_RAM3_BA 0xc0008000
+#define NPCM8XX_RAM3_SZ (4 * KiB)
+
+/* Memory blocks at the end of the address space */
+#define NPCM8XX_RAM2_BA 0xfffb0000
+#define NPCM8XX_RAM2_SZ (256 * KiB)
+#define NPCM8XX_ROM_BA 0xffff0100
+#define NPCM8XX_ROM_SZ (64 * KiB)
+
+/* SDHCI Modules */
+#define NPCM8XX_MMC_BA 0xf0842000
+
+/* PCS Module */
+#define NPCM8XX_PCS_BA 0xf0780000
+
+/* PSPI Modules */
+#define NPCM8XX_PSPI_BA 0xf0201000
+
+/* Run PLL1 at 1600 MHz */
+#define NPCM8XX_PLLCON1_FIXUP_VAL 0x00402101
+/* Run the CPU from PLL1 and UART from PLL2 */
+#define NPCM8XX_CLKSEL_FIXUP_VAL 0x004aaba9
+
+/* Clock configuration values to be fixed up when bypassing bootloader */
+
+/*
+ * Interrupt lines going into the GIC. This does not include internal Cortex-A35
+ * interrupts.
+ */
+enum NPCM8xxInterrupt {
+ NPCM8XX_ADC_IRQ = 0,
+ NPCM8XX_PECI_IRQ = 6,
+ NPCM8XX_KCS_HIB_IRQ = 9,
+ NPCM8XX_GMAC1_IRQ = 14,
+ NPCM8XX_GMAC2_IRQ,
+ NPCM8XX_GMAC3_IRQ,
+ NPCM8XX_GMAC4_IRQ,
+ NPCM8XX_MMC_IRQ = 26,
+ NPCM8XX_PSPI_IRQ = 28,
+ NPCM8XX_TIMER0_IRQ = 32, /* Timer Module 0 */
+ NPCM8XX_TIMER1_IRQ,
+ NPCM8XX_TIMER2_IRQ,
+ NPCM8XX_TIMER3_IRQ,
+ NPCM8XX_TIMER4_IRQ,
+ NPCM8XX_TIMER5_IRQ, /* Timer Module 1 */
+ NPCM8XX_TIMER6_IRQ,
+ NPCM8XX_TIMER7_IRQ,
+ NPCM8XX_TIMER8_IRQ,
+ NPCM8XX_TIMER9_IRQ,
+ NPCM8XX_TIMER10_IRQ, /* Timer Module 2 */
+ NPCM8XX_TIMER11_IRQ,
+ NPCM8XX_TIMER12_IRQ,
+ NPCM8XX_TIMER13_IRQ,
+ NPCM8XX_TIMER14_IRQ,
+ NPCM8XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
+ NPCM8XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
+ NPCM8XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
+ NPCM8XX_EHCI1_IRQ = 61,
+ NPCM8XX_OHCI1_IRQ,
+ NPCM8XX_EHCI2_IRQ,
+ NPCM8XX_OHCI2_IRQ,
+ NPCM8XX_PWM0_IRQ = 93, /* PWM module 0 */
+ NPCM8XX_PWM1_IRQ, /* PWM module 1 */
+ NPCM8XX_MFT0_IRQ = 96, /* MFT module 0 */
+ NPCM8XX_MFT1_IRQ, /* MFT module 1 */
+ NPCM8XX_MFT2_IRQ, /* MFT module 2 */
+ NPCM8XX_MFT3_IRQ, /* MFT module 3 */
+ NPCM8XX_MFT4_IRQ, /* MFT module 4 */
+ NPCM8XX_MFT5_IRQ, /* MFT module 5 */
+ NPCM8XX_MFT6_IRQ, /* MFT module 6 */
+ NPCM8XX_MFT7_IRQ, /* MFT module 7 */
+ NPCM8XX_PCI_MBOX1_IRQ = 105,
+ NPCM8XX_PCI_MBOX2_IRQ,
+ NPCM8XX_GPIO0_IRQ = 116,
+ NPCM8XX_GPIO1_IRQ,
+ NPCM8XX_GPIO2_IRQ,
+ NPCM8XX_GPIO3_IRQ,
+ NPCM8XX_GPIO4_IRQ,
+ NPCM8XX_GPIO5_IRQ,
+ NPCM8XX_GPIO6_IRQ,
+ NPCM8XX_GPIO7_IRQ,
+ NPCM8XX_SMBUS0_IRQ = 128,
+ NPCM8XX_SMBUS1_IRQ,
+ NPCM8XX_SMBUS2_IRQ,
+ NPCM8XX_SMBUS3_IRQ,
+ NPCM8XX_SMBUS4_IRQ,
+ NPCM8XX_SMBUS5_IRQ,
+ NPCM8XX_SMBUS6_IRQ,
+ NPCM8XX_SMBUS7_IRQ,
+ NPCM8XX_SMBUS8_IRQ,
+ NPCM8XX_SMBUS9_IRQ,
+ NPCM8XX_SMBUS10_IRQ,
+ NPCM8XX_SMBUS11_IRQ,
+ NPCM8XX_SMBUS12_IRQ,
+ NPCM8XX_SMBUS13_IRQ,
+ NPCM8XX_SMBUS14_IRQ,
+ NPCM8XX_SMBUS15_IRQ,
+ NPCM8XX_SMBUS16_IRQ,
+ NPCM8XX_SMBUS17_IRQ,
+ NPCM8XX_SMBUS18_IRQ,
+ NPCM8XX_SMBUS19_IRQ,
+ NPCM8XX_SMBUS20_IRQ,
+ NPCM8XX_SMBUS21_IRQ,
+ NPCM8XX_SMBUS22_IRQ,
+ NPCM8XX_SMBUS23_IRQ,
+ NPCM8XX_SMBUS24_IRQ,
+ NPCM8XX_SMBUS25_IRQ,
+ NPCM8XX_SMBUS26_IRQ,
+ NPCM8XX_UART0_IRQ = 192,
+ NPCM8XX_UART1_IRQ,
+ NPCM8XX_UART2_IRQ,
+ NPCM8XX_UART3_IRQ,
+ NPCM8XX_UART4_IRQ,
+ NPCM8XX_UART5_IRQ,
+ NPCM8XX_UART6_IRQ,
+};
+
+/* Total number of GIC interrupts, including internal Cortex-A35 interrupts. */
+#define NPCM8XX_NUM_IRQ (288)
+#define NPCM8XX_PPI_BASE(cpu) \
+ ((NPCM8XX_NUM_IRQ - GIC_INTERNAL) + (cpu) * GIC_INTERNAL)
+
+/* Register base address for each Timer Module */
+static const hwaddr npcm8xx_tim_addr[] = {
+ 0xf0008000,
+ 0xf0009000,
+ 0xf000a000,
+};
+
+/* Register base address for each 16550 UART */
+static const hwaddr npcm8xx_uart_addr[] = {
+ 0xf0000000,
+ 0xf0001000,
+ 0xf0002000,
+ 0xf0003000,
+ 0xf0004000,
+ 0xf0005000,
+ 0xf0006000,
+};
+
+/* Direct memory-mapped access to SPI0 CS0-1. */
+static const hwaddr npcm8xx_fiu0_flash_addr[] = {
+ 0x80000000, /* CS0 */
+ 0x88000000, /* CS1 */
+};
+
+/* Direct memory-mapped access to SPI1 CS0-3. */
+static const hwaddr npcm8xx_fiu1_flash_addr[] = {
+ 0x90000000, /* CS0 */
+ 0x91000000, /* CS1 */
+ 0x92000000, /* CS2 */
+ 0x93000000, /* CS3 */
+};
+
+/* Direct memory-mapped access to SPI3 CS0-3. */
+static const hwaddr npcm8xx_fiu3_flash_addr[] = {
+ 0xa0000000, /* CS0 */
+ 0xa8000000, /* CS1 */
+ 0xb0000000, /* CS2 */
+ 0xb8000000, /* CS3 */
+};
+
+/* Register base address for each PWM Module */
+static const hwaddr npcm8xx_pwm_addr[] = {
+ 0xf0103000,
+ 0xf0104000,
+ 0xf0105000,
+};
+
+/* Register base address for each MFT Module */
+static const hwaddr npcm8xx_mft_addr[] = {
+ 0xf0180000,
+ 0xf0181000,
+ 0xf0182000,
+ 0xf0183000,
+ 0xf0184000,
+ 0xf0185000,
+ 0xf0186000,
+ 0xf0187000,
+};
+
+/* Direct memory-mapped access to each SMBus Module. */
+static const hwaddr npcm8xx_smbus_addr[] = {
+ 0xf0080000,
+ 0xf0081000,
+ 0xf0082000,
+ 0xf0083000,
+ 0xf0084000,
+ 0xf0085000,
+ 0xf0086000,
+ 0xf0087000,
+ 0xf0088000,
+ 0xf0089000,
+ 0xf008a000,
+ 0xf008b000,
+ 0xf008c000,
+ 0xf008d000,
+ 0xf008e000,
+ 0xf008f000,
+ 0xfff00000,
+ 0xfff01000,
+ 0xfff02000,
+ 0xfff03000,
+ 0xfff04000,
+ 0xfff05000,
+ 0xfff06000,
+ 0xfff07000,
+ 0xfff08000,
+ 0xfff09000,
+ 0xfff0a000,
+};
+
+/* Register base address for each GMAC Module */
+static const hwaddr npcm8xx_gmac_addr[] = {
+ 0xf0802000,
+ 0xf0804000,
+ 0xf0806000,
+ 0xf0808000,
+};
+
+/* Register base address for each USB host EHCI registers */
+static const hwaddr npcm8xx_ehci_addr[] = {
+ 0xf0828100,
+ 0xf082a100,
+};
+
+/* Register base address for each USB host OHCI registers */
+static const hwaddr npcm8xx_ohci_addr[] = {
+ 0xf0829000,
+ 0xf082b000,
+};
+
+static const struct {
+ hwaddr regs_addr;
+ uint32_t reset_pu;
+ uint32_t reset_pd;
+ uint32_t reset_osrc;
+ uint32_t reset_odsc;
+} npcm8xx_gpio[] = {
+ {
+ .regs_addr = 0xf0010000,
+ .reset_pu = 0x00000300,
+ .reset_pd = 0x000f0000,
+ }, {
+ .regs_addr = 0xf0011000,
+ .reset_pu = 0xe0fefe01,
+ .reset_pd = 0x07000000,
+ }, {
+ .regs_addr = 0xf0012000,
+ .reset_pu = 0xc00fffff,
+ .reset_pd = 0x3ff00000,
+ }, {
+ .regs_addr = 0xf0013000,
+ .reset_pd = 0x00003000,
+ }, {
+ .regs_addr = 0xf0014000,
+ .reset_pu = 0xffff0000,
+ }, {
+ .regs_addr = 0xf0015000,
+ .reset_pu = 0xff8387fe,
+ .reset_pd = 0x007c0001,
+ .reset_osrc = 0x08000000,
+ }, {
+ .regs_addr = 0xf0016000,
+ .reset_pu = 0x00000801,
+ .reset_pd = 0x00000302,
+ }, {
+ .regs_addr = 0xf0017000,
+ .reset_pu = 0x000002ff,
+ .reset_pd = 0x00000c00,
+ },
+};
+
+static const struct {
+ const char *name;
+ hwaddr regs_addr;
+ int cs_count;
+ const hwaddr *flash_addr;
+ size_t flash_size;
+} npcm8xx_fiu[] = {
+ {
+ .name = "fiu0",
+ .regs_addr = 0xfb000000,
+ .cs_count = ARRAY_SIZE(npcm8xx_fiu0_flash_addr),
+ .flash_addr = npcm8xx_fiu0_flash_addr,
+ .flash_size = 128 * MiB,
+ },
+ {
+ .name = "fiu1",
+ .regs_addr = 0xfb002000,
+ .cs_count = ARRAY_SIZE(npcm8xx_fiu1_flash_addr),
+ .flash_addr = npcm8xx_fiu1_flash_addr,
+ .flash_size = 16 * MiB,
+ }, {
+ .name = "fiu3",
+ .regs_addr = 0xc0000000,
+ .cs_count = ARRAY_SIZE(npcm8xx_fiu3_flash_addr),
+ .flash_addr = npcm8xx_fiu3_flash_addr,
+ .flash_size = 128 * MiB,
+ },
+};
+
+static struct arm_boot_info npcm8xx_binfo = {
+ .loader_start = NPCM8XX_LOADER_START,
+ .smp_loader_start = NPCM8XX_SMP_LOADER_START,
+ .smp_bootreg_addr = NPCM8XX_SMP_BOOTREG_ADDR,
+ .gic_cpu_if_addr = NPCM8XX_GICC_BA,
+ .secure_boot = false,
+ .board_id = -1,
+ .board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR,
+ .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
+};
+
+void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc)
+{
+ npcm8xx_binfo.ram_size = machine->ram_size;
+
+ arm_load_kernel(&soc->cpu[0], machine, &npcm8xx_binfo);
+}
+
+static void npcm8xx_init_fuses(NPCM8xxState *s)
+{
+ NPCM8xxClass *nc = NPCM8XX_GET_CLASS(s);
+ uint32_t value;
+
+ /*
+ * The initial mask of disabled modules indicates the chip derivative (e.g.
+ * NPCM750 or NPCM730).
+ */
+ value = cpu_to_le32(nc->disabled_modules);
+ npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE,
+ sizeof(value));
+}
+
+static void npcm8xx_write_adc_calibration(NPCM8xxState *s)
+{
+ /* Both ADC and the fuse array must have realized. */
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
+}
+
+static qemu_irq npcm8xx_irq(NPCM8xxState *s, int n)
+{
+ return qdev_get_gpio_in(DEVICE(&s->gic), n);
+}
+
+static void npcm8xx_init(Object *obj)
+{
+ NPCM8xxState *s = NPCM8XX(obj);
+ int i;
+
+ object_initialize_child(obj, "cpu-cluster", &s->cpu_cluster,
+ TYPE_CPU_CLUSTER);
+ for (i = 0; i < NPCM8XX_MAX_NUM_CPUS; i++) {
+ object_initialize_child(OBJECT(&s->cpu_cluster), "cpu[*]", &s->cpu[i],
+ ARM_CPU_TYPE_NAME("cortex-a35"));
+ }
+ object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC);
+ object_initialize_child(obj, "gcr", &s->gcr, TYPE_NPCM8XX_GCR);
+ object_property_add_alias(obj, "power-on-straps", OBJECT(&s->gcr),
+ "power-on-straps");
+ object_initialize_child(obj, "clk", &s->clk, TYPE_NPCM8XX_CLK);
+ object_initialize_child(obj, "otp", &s->fuse_array,
+ TYPE_NPCM7XX_FUSE_ARRAY);
+ object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
+ object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
+
+ for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
+ object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
+ object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
+ }
+
+
+ for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
+ object_initialize_child(obj, "smbus[*]", &s->smbus[i],
+ TYPE_NPCM7XX_SMBUS);
+ DEVICE(&s->smbus[i])->id = g_strdup_printf("smbus[%d]", i);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->ehci); i++) {
+ object_initialize_child(obj, "ehci[*]", &s->ehci[i], TYPE_NPCM7XX_EHCI);
+ }
+ for (i = 0; i < ARRAY_SIZE(s->ohci); i++) {
+ object_initialize_child(obj, "ohci[*]", &s->ohci[i], TYPE_SYSBUS_OHCI);
+ }
+
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_fiu) != ARRAY_SIZE(s->fiu));
+ for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
+ object_initialize_child(obj, npcm8xx_fiu[i].name, &s->fiu[i],
+ TYPE_NPCM7XX_FIU);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
+ object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
+ object_initialize_child(obj, "gmac[*]", &s->gmac[i], TYPE_NPCM_GMAC);
+ }
+ object_initialize_child(obj, "pcs", &s->pcs, TYPE_NPCM_PCS);
+
+ object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
+ object_initialize_child(obj, "pspi", &s->pspi, TYPE_NPCM_PSPI);
+}
+
+static void npcm8xx_realize(DeviceState *dev, Error **errp)
+{
+ NPCM8xxState *s = NPCM8XX(dev);
+ NPCM8xxClass *nc = NPCM8XX_GET_CLASS(s);
+ int i;
+
+ if (memory_region_size(s->dram) > NPCM8XX_DRAM_SZ) {
+ error_setg(errp, "%s: NPCM8xx cannot address more than %" PRIu64
+ " MiB of DRAM", __func__, NPCM8XX_DRAM_SZ / MiB);
+ return;
+ }
+
+ /* CPUs */
+ for (i = 0; i < nc->num_cpus; i++) {
+ object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity",
+ arm_build_mp_affinity(i, NPCM8XX_MAX_NUM_CPUS),
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true,
+ &error_abort);
+ object_property_set_int(OBJECT(&s->cpu[i]), "core-count",
+ nc->num_cpus, &error_abort);
+
+ /* Disable security extensions. */
+ object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false,
+ &error_abort);
+
+ if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
+ return;
+ }
+ }
+
+ /* ARM GIC for Cortex A35. Can only fail if we pass bad parameters here. */
+ object_property_set_uint(OBJECT(&s->gic), "num-cpu", nc->num_cpus, errp);
+ object_property_set_uint(OBJECT(&s->gic), "num-irq", NPCM8XX_NUM_IRQ, errp);
+ object_property_set_uint(OBJECT(&s->gic), "revision", 2, errp);
+ object_property_set_bool(OBJECT(&s->gic), "has-security-extensions", true,
+ errp);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) {
+ return;
+ }
+ for (i = 0; i < nc->num_cpus; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
+ qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + nc->num_cpus,
+ qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + nc->num_cpus * 2,
+ qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_VIRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + nc->num_cpus * 3,
+ qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_VFIQ));
+
+ qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_PHYS,
+ qdev_get_gpio_in(DEVICE(&s->gic),
+ NPCM8XX_PPI_BASE(i) + ARCH_TIMER_NS_EL1_IRQ));
+ qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_VIRT,
+ qdev_get_gpio_in(DEVICE(&s->gic),
+ NPCM8XX_PPI_BASE(i) + ARCH_TIMER_VIRT_IRQ));
+ qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_HYP,
+ qdev_get_gpio_in(DEVICE(&s->gic),
+ NPCM8XX_PPI_BASE(i) + ARCH_TIMER_NS_EL2_IRQ));
+ qdev_connect_gpio_out(DEVICE(&s->cpu[i]), GTIMER_SEC,
+ qdev_get_gpio_in(DEVICE(&s->gic),
+ NPCM8XX_PPI_BASE(i) + ARCH_TIMER_S_EL1_IRQ));
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0, NPCM8XX_GICD_BA);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1, NPCM8XX_GICC_BA);
+
+ /* CPU cluster */
+ qdev_prop_set_uint32(DEVICE(&s->cpu_cluster), "cluster-id", 0);
+ qdev_realize(DEVICE(&s->cpu_cluster), NULL, &error_fatal);
+
+ /* System Global Control Registers (GCR). Can fail due to user input. */
+ object_property_set_int(OBJECT(&s->gcr), "disabled-modules",
+ nc->disabled_modules, &error_abort);
+ object_property_add_const_link(OBJECT(&s->gcr), "dram-mr", OBJECT(s->dram));
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM8XX_GCR_BA);
+
+ /* Clock Control Registers (CLK). Cannot fail. */
+ sysbus_realize(SYS_BUS_DEVICE(&s->clk), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM8XX_CLK_BA);
+
+ /* OTP fuse strap array. Cannot fail. */
+ sysbus_realize(SYS_BUS_DEVICE(&s->fuse_array), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->fuse_array), 0, NPCM8XX_OTP_BA);
+ npcm8xx_init_fuses(s);
+
+ /* Fake Memory Controller (MC). Cannot fail. */
+ sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM8XX_MC_BA);
+
+ /* ADC Modules. Cannot fail. */
+ qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
+ DEVICE(&s->clk), "adc-clock"));
+ sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM8XX_ADC_BA);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
+ npcm8xx_irq(s, NPCM8XX_ADC_IRQ));
+ npcm8xx_write_adc_calibration(s);
+
+ /* Timer Modules (TIM). Cannot fail. */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_tim_addr) != ARRAY_SIZE(s->tim));
+ for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->tim[i]);
+ int first_irq;
+ int j;
+
+ /* Connect the timer clock. */
+ qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
+ DEVICE(&s->clk), "timer-clock"));
+
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm8xx_tim_addr[i]);
+
+ first_irq = NPCM8XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL;
+ for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) {
+ qemu_irq irq = npcm8xx_irq(s, first_irq + j);
+ sysbus_connect_irq(sbd, j, irq);
+ }
+
+ /* IRQ for watchdogs */
+ sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL,
+ npcm8xx_irq(s, NPCM8XX_WDG0_IRQ + i));
+ /* GPIO that connects clk module with watchdog */
+ qdev_connect_gpio_out_named(DEVICE(&s->tim[i]),
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0,
+ qdev_get_gpio_in_named(DEVICE(&s->clk),
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, i));
+ }
+
+ /* UART0..6 (16550 compatible) */
+ for (i = 0; i < ARRAY_SIZE(npcm8xx_uart_addr); i++) {
+ serial_mm_init(get_system_memory(), npcm8xx_uart_addr[i], 2,
+ npcm8xx_irq(s, NPCM8XX_UART0_IRQ + i), 115200,
+ serial_hd(i), DEVICE_LITTLE_ENDIAN);
+ }
+
+ /* Random Number Generator. Cannot fail. */
+ sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM8XX_RNG_BA);
+
+ /* GPIO modules. Cannot fail. */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_gpio) != ARRAY_SIZE(s->gpio));
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
+ Object *obj = OBJECT(&s->gpio[i]);
+
+ object_property_set_uint(obj, "reset-pullup",
+ npcm8xx_gpio[i].reset_pu, &error_abort);
+ object_property_set_uint(obj, "reset-pulldown",
+ npcm8xx_gpio[i].reset_pd, &error_abort);
+ object_property_set_uint(obj, "reset-osrc",
+ npcm8xx_gpio[i].reset_osrc, &error_abort);
+ object_property_set_uint(obj, "reset-odsc",
+ npcm8xx_gpio[i].reset_odsc, &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm8xx_gpio[i].regs_addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
+ npcm8xx_irq(s, NPCM8XX_GPIO0_IRQ + i));
+ }
+
+ /* SMBus modules. Cannot fail. */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_smbus_addr) != ARRAY_SIZE(s->smbus));
+ for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
+ Object *obj = OBJECT(&s->smbus[i]);
+
+ sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm8xx_smbus_addr[i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
+ npcm8xx_irq(s, NPCM8XX_SMBUS0_IRQ + i));
+ }
+
+ /* USB Host */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->ohci) != ARRAY_SIZE(s->ehci));
+ for (i = 0; i < ARRAY_SIZE(s->ehci); i++) {
+ object_property_set_bool(OBJECT(&s->ehci[i]), "companion-enable", true,
+ &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0, npcm8xx_ehci_addr[i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
+ npcm8xx_irq(s, NPCM8XX_EHCI1_IRQ + 2 * i));
+ }
+ for (i = 0; i < ARRAY_SIZE(s->ohci); i++) {
+ object_property_set_str(OBJECT(&s->ohci[i]), "masterbus", "usb-bus.0",
+ &error_abort);
+ object_property_set_uint(OBJECT(&s->ohci[i]), "num-ports", 1,
+ &error_abort);
+ object_property_set_uint(OBJECT(&s->ohci[i]), "firstport", i,
+ &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->ohci[i]), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci[i]), 0, npcm8xx_ohci_addr[i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci[i]), 0,
+ npcm8xx_irq(s, NPCM8XX_OHCI1_IRQ + 2 * i));
+ }
+
+ /* PWM Modules. Cannot fail. */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_pwm_addr) != ARRAY_SIZE(s->pwm));
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
+
+ qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
+ DEVICE(&s->clk), "apb3-clock"));
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm8xx_pwm_addr[i]);
+ sysbus_connect_irq(sbd, i, npcm8xx_irq(s, NPCM8XX_PWM0_IRQ + i));
+ }
+
+ /* MFT Modules. Cannot fail. */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_mft_addr) != ARRAY_SIZE(s->mft));
+ for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->mft[i]);
+
+ qdev_connect_clock_in(DEVICE(&s->mft[i]), "clock-in",
+ qdev_get_clock_out(DEVICE(&s->clk),
+ "apb4-clock"));
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm8xx_mft_addr[i]);
+ sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_MFT0_IRQ + i));
+ }
+
+ /*
+ * GMAC Modules. Cannot fail.
+ */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_gmac_addr) != ARRAY_SIZE(s->gmac));
+ for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->gmac[i]);
+
+ /* This is used to make sure that the NIC can create the device */
+ qemu_configure_nic_device(DEVICE(sbd), false, NULL);
+
+ /*
+ * The device exists regardless of whether it's connected to a QEMU
+ * netdev backend. So always instantiate it even if there is no
+ * backend.
+ */
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm8xx_gmac_addr[i]);
+ /*
+ * N.B. The values for the second argument sysbus_connect_irq are
+ * chosen to match the registration order in npcm7xx_emc_realize.
+ */
+ sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_GMAC1_IRQ + i));
+ }
+ /*
+ * GMAC Physical Coding Sublayer(PCS) Module. Cannot fail.
+ */
+ sysbus_realize(SYS_BUS_DEVICE(&s->pcs), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcs), 0, NPCM8XX_PCS_BA);
+
+ /*
+ * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
+ * specified, but this is a programming error.
+ */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_fiu) != ARRAY_SIZE(s->fiu));
+ for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->fiu[i]);
+ int j;
+
+ object_property_set_int(OBJECT(sbd), "cs-count",
+ npcm8xx_fiu[i].cs_count, &error_abort);
+ object_property_set_int(OBJECT(sbd), "flash-size",
+ npcm8xx_fiu[i].flash_size, &error_abort);
+ sysbus_realize(sbd, &error_abort);
+
+ sysbus_mmio_map(sbd, 0, npcm8xx_fiu[i].regs_addr);
+ for (j = 0; j < npcm8xx_fiu[i].cs_count; j++) {
+ sysbus_mmio_map(sbd, j + 1, npcm8xx_fiu[i].flash_addr[j]);
+ }
+ }
+
+ /* RAM2 (SRAM) */
+ memory_region_init_ram(&s->sram, OBJECT(dev), "ram2",
+ NPCM8XX_RAM2_SZ, &error_abort);
+ memory_region_add_subregion(get_system_memory(), NPCM8XX_RAM2_BA, &s->sram);
+
+ /* RAM3 (SRAM) */
+ memory_region_init_ram(&s->ram3, OBJECT(dev), "ram3",
+ NPCM8XX_RAM3_SZ, &error_abort);
+ memory_region_add_subregion(get_system_memory(), NPCM8XX_RAM3_BA, &s->ram3);
+
+ /* Internal ROM */
+ memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM8XX_ROM_SZ,
+ &error_abort);
+ memory_region_add_subregion(get_system_memory(), NPCM8XX_ROM_BA, &s->irom);
+
+ /* SDHCI */
+ sysbus_realize(SYS_BUS_DEVICE(&s->mmc), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc), 0, NPCM8XX_MMC_BA);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
+ npcm8xx_irq(s, NPCM8XX_MMC_IRQ));
+
+ /* PSPI */
+ sysbus_realize(SYS_BUS_DEVICE(&s->pspi), &error_abort);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pspi), 0, NPCM8XX_PSPI_BA);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pspi), 0,
+ npcm8xx_irq(s, NPCM8XX_PSPI_IRQ));
+
+ create_unimplemented_device("npcm8xx.shm", 0xc0001000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.gicextra", 0xdfffa000, 24 * KiB);
+ create_unimplemented_device("npcm8xx.vdmx", 0xe0800000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.pcierc", 0xe1000000, 64 * KiB);
+ create_unimplemented_device("npcm8xx.rootc", 0xe8000000, 128 * MiB);
+ create_unimplemented_device("npcm8xx.kcs", 0xf0007000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.gfxi", 0xf000e000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.fsw", 0xf000f000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.bt", 0xf0030000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.espi", 0xf009f000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.peci", 0xf0100000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.siox[1]", 0xf0101000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.siox[2]", 0xf0102000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.tmps", 0xf0188000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.viru1", 0xf0204000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.viru2", 0xf0205000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.jtm1", 0xf0208000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.jtm2", 0xf0209000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.flm0", 0xf0210000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.flm1", 0xf0211000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.flm2", 0xf0212000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.flm3", 0xf0213000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.ahbpci", 0xf0400000, 1 * MiB);
+ create_unimplemented_device("npcm8xx.dap", 0xf0500000, 960 * KiB);
+ create_unimplemented_device("npcm8xx.mcphy", 0xf05f0000, 64 * KiB);
+ create_unimplemented_device("npcm8xx.tsgen", 0xf07fc000, 8 * KiB);
+ create_unimplemented_device("npcm8xx.copctl", 0xf080c000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.tipctl", 0xf080d000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.rst", 0xf080e000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.vcd", 0xf0810000, 64 * KiB);
+ create_unimplemented_device("npcm8xx.ece", 0xf0820000, 8 * KiB);
+ create_unimplemented_device("npcm8xx.vdma", 0xf0822000, 8 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[0]", 0xf0830000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[1]", 0xf0831000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[2]", 0xf0832000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[3]", 0xf0833000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[4]", 0xf0834000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[5]", 0xf0835000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[6]", 0xf0836000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[7]", 0xf0837000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[8]", 0xf0838000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.usbd[9]", 0xf0839000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.pci_mbox1", 0xf0848000, 64 * KiB);
+ create_unimplemented_device("npcm8xx.gdma0", 0xf0850000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.gdma1", 0xf0851000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.gdma2", 0xf0852000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.aes", 0xf0858000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.des", 0xf0859000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.sha", 0xf085a000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.pci_mbox2", 0xf0868000, 64 * KiB);
+ create_unimplemented_device("npcm8xx.i3c0", 0xfff10000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.i3c1", 0xfff11000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.i3c2", 0xfff12000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.i3c3", 0xfff13000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.i3c4", 0xfff14000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.i3c5", 0xfff15000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.spixcs0", 0xf8000000, 16 * MiB);
+ create_unimplemented_device("npcm8xx.spixcs1", 0xf9000000, 16 * MiB);
+ create_unimplemented_device("npcm8xx.spix", 0xfb001000, 4 * KiB);
+ create_unimplemented_device("npcm8xx.vect", 0xffff0000, 256);
+}
+
+static const Property npcm8xx_properties[] = {
+ DEFINE_PROP_LINK("dram-mr", NPCM8xxState, dram, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+};
+
+static void npcm8xx_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ NPCM8xxClass *nc = NPCM8XX_CLASS(oc);
+
+ dc->realize = npcm8xx_realize;
+ dc->user_creatable = false;
+ nc->disabled_modules = 0x00000000;
+ nc->num_cpus = NPCM8XX_MAX_NUM_CPUS;
+ device_class_set_props(dc, npcm8xx_properties);
+}
+
+static const TypeInfo npcm8xx_soc_types[] = {
+ {
+ .name = TYPE_NPCM8XX,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(NPCM8xxState),
+ .instance_init = npcm8xx_init,
+ .class_size = sizeof(NPCM8xxClass),
+ .class_init = npcm8xx_class_init,
+ },
+};
+
+DEFINE_TYPES(npcm8xx_soc_types);
diff --git a/hw/arm/npcm8xx_boards.c b/hw/arm/npcm8xx_boards.c
new file mode 100644
index 0000000..3bf3e1f
--- /dev/null
+++ b/hw/arm/npcm8xx_boards.c
@@ -0,0 +1,254 @@
+/*
+ * Machine definitions for boards featuring an NPCM8xx SoC.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+
+#include "chardev/char.h"
+#include "hw/boards.h"
+#include "hw/arm/npcm8xx.h"
+#include "hw/core/cpu.h"
+#include "hw/loader.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/datadir.h"
+#include "qemu/units.h"
+
+#define NPCM845_EVB_POWER_ON_STRAPS 0x000017ff
+
+static const char npcm8xx_default_bootrom[] = "npcm8xx_bootrom.bin";
+
+static void npcm8xx_load_bootrom(MachineState *machine, NPCM8xxState *soc)
+{
+ const char *bios_name = machine->firmware ?: npcm8xx_default_bootrom;
+ g_autofree char *filename = NULL;
+ int ret;
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (!filename) {
+ error_report("Could not find ROM image '%s'", bios_name);
+ if (!machine->kernel_filename) {
+ /* We can't boot without a bootrom or a kernel image. */
+ exit(1);
+ }
+ return;
+ }
+ ret = load_image_mr(filename, machine->ram);
+ if (ret < 0) {
+ error_report("Failed to load ROM image '%s'", filename);
+ exit(1);
+ }
+}
+
+static void npcm8xx_connect_flash(NPCM7xxFIUState *fiu, int cs_no,
+ const char *flash_type, DriveInfo *dinfo)
+{
+ DeviceState *flash;
+ qemu_irq flash_cs;
+
+ flash = qdev_new(flash_type);
+ if (dinfo) {
+ qdev_prop_set_drive(flash, "drive", blk_by_legacy_dinfo(dinfo));
+ }
+ qdev_realize_and_unref(flash, BUS(fiu->spi), &error_fatal);
+
+ flash_cs = qdev_get_gpio_in_named(flash, SSI_GPIO_CS, 0);
+ qdev_connect_gpio_out_named(DEVICE(fiu), "cs", cs_no, flash_cs);
+}
+
+static void npcm8xx_connect_dram(NPCM8xxState *soc, MemoryRegion *dram)
+{
+ memory_region_add_subregion(get_system_memory(), NPCM8XX_DRAM_BA, dram);
+
+ object_property_set_link(OBJECT(soc), "dram-mr", OBJECT(dram),
+ &error_abort);
+}
+
+static NPCM8xxState *npcm8xx_create_soc(MachineState *machine,
+ uint32_t hw_straps)
+{
+ NPCM8xxMachineClass *nmc = NPCM8XX_MACHINE_GET_CLASS(machine);
+ Object *obj;
+
+ obj = object_new_with_props(nmc->soc_type, OBJECT(machine), "soc",
+ &error_abort, NULL);
+ object_property_set_uint(obj, "power-on-straps", hw_straps, &error_abort);
+
+ return NPCM8XX(obj);
+}
+
+static I2CBus *npcm8xx_i2c_get_bus(NPCM8xxState *soc, uint32_t num)
+{
+ g_assert(num < ARRAY_SIZE(soc->smbus));
+ return I2C_BUS(qdev_get_child_bus(DEVICE(&soc->smbus[num]), "i2c-bus"));
+}
+
+static void npcm8xx_init_pwm_splitter(NPCM8xxMachine *machine,
+ NPCM8xxState *soc, const int *fan_counts)
+{
+ SplitIRQ *splitters = machine->fan_splitter;
+
+ /*
+ * PWM 0~3 belong to module 0 output 0~3.
+ * PWM 4~7 belong to module 1 output 0~3.
+ */
+ for (int i = 0; i < NPCM8XX_NR_PWM_MODULES; ++i) {
+ for (int j = 0; j < NPCM7XX_PWM_PER_MODULE; ++j) {
+ int splitter_no = i * NPCM7XX_PWM_PER_MODULE + j;
+ DeviceState *splitter;
+
+ if (fan_counts[splitter_no] < 1) {
+ continue;
+ }
+ object_initialize_child(OBJECT(machine), "fan-splitter[*]",
+ &splitters[splitter_no], TYPE_SPLIT_IRQ);
+ splitter = DEVICE(&splitters[splitter_no]);
+ qdev_prop_set_uint16(splitter, "num-lines",
+ fan_counts[splitter_no]);
+ qdev_realize(splitter, NULL, &error_abort);
+ qdev_connect_gpio_out_named(DEVICE(&soc->pwm[i]), "duty-gpio-out",
+ j, qdev_get_gpio_in(splitter, 0));
+ }
+ }
+}
+
+static void npcm8xx_connect_pwm_fan(NPCM8xxState *soc, SplitIRQ *splitter,
+ int fan_no, int output_no)
+{
+ DeviceState *fan;
+ int fan_input;
+ qemu_irq fan_duty_gpio;
+
+ g_assert(fan_no >= 0 && fan_no <= NPCM7XX_MFT_MAX_FAN_INPUT);
+ /*
+ * Fan 0~1 belong to module 0 input 0~1.
+ * Fan 2~3 belong to module 1 input 0~1.
+ * ...
+ * Fan 14~15 belong to module 7 input 0~1.
+ * Fan 16~17 belong to module 0 input 2~3.
+ * Fan 18~19 belong to module 1 input 2~3.
+ */
+ if (fan_no < 16) {
+ fan = DEVICE(&soc->mft[fan_no / 2]);
+ fan_input = fan_no % 2;
+ } else {
+ fan = DEVICE(&soc->mft[(fan_no - 16) / 2]);
+ fan_input = fan_no % 2 + 2;
+ }
+
+ /* Connect the Fan to PWM module */
+ fan_duty_gpio = qdev_get_gpio_in_named(fan, "duty", fan_input);
+ qdev_connect_gpio_out(DEVICE(splitter), output_no, fan_duty_gpio);
+}
+
+static void npcm845_evb_i2c_init(NPCM8xxState *soc)
+{
+ /* tmp100 temperature sensor on SVB, tmp105 is compatible */
+ i2c_slave_create_simple(npcm8xx_i2c_get_bus(soc, 6), "tmp105", 0x48);
+}
+
+static void npcm845_evb_fan_init(NPCM8xxMachine *machine, NPCM8xxState *soc)
+{
+ SplitIRQ *splitter = machine->fan_splitter;
+ static const int fan_counts[] = {2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0};
+
+ npcm8xx_init_pwm_splitter(machine, soc, fan_counts);
+ npcm8xx_connect_pwm_fan(soc, &splitter[0], 0x00, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[0], 0x01, 1);
+ npcm8xx_connect_pwm_fan(soc, &splitter[1], 0x02, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[1], 0x03, 1);
+ npcm8xx_connect_pwm_fan(soc, &splitter[2], 0x04, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
+ npcm8xx_connect_pwm_fan(soc, &splitter[3], 0x06, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[3], 0x07, 1);
+ npcm8xx_connect_pwm_fan(soc, &splitter[4], 0x08, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[4], 0x09, 1);
+ npcm8xx_connect_pwm_fan(soc, &splitter[5], 0x0a, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[5], 0x0b, 1);
+ npcm8xx_connect_pwm_fan(soc, &splitter[6], 0x0c, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[6], 0x0d, 1);
+ npcm8xx_connect_pwm_fan(soc, &splitter[7], 0x0e, 0);
+ npcm8xx_connect_pwm_fan(soc, &splitter[7], 0x0f, 1);
+}
+
+static void npcm845_evb_init(MachineState *machine)
+{
+ NPCM8xxState *soc;
+
+ soc = npcm8xx_create_soc(machine, NPCM845_EVB_POWER_ON_STRAPS);
+ npcm8xx_connect_dram(soc, machine->ram);
+ qdev_realize(DEVICE(soc), NULL, &error_fatal);
+
+ npcm8xx_load_bootrom(machine, soc);
+ npcm8xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0));
+ npcm845_evb_i2c_init(soc);
+ npcm845_evb_fan_init(NPCM8XX_MACHINE(machine), soc);
+ npcm8xx_load_kernel(machine, soc);
+}
+
+static void npcm8xx_set_soc_type(NPCM8xxMachineClass *nmc, const char *type)
+{
+ NPCM8xxClass *sc = NPCM8XX_CLASS(object_class_by_name(type));
+ MachineClass *mc = MACHINE_CLASS(nmc);
+
+ nmc->soc_type = type;
+ mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus;
+}
+
+static void npcm8xx_machine_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-a35"),
+ NULL
+ };
+
+ mc->no_floppy = 1;
+ mc->no_cdrom = 1;
+ mc->no_parallel = 1;
+ mc->default_ram_id = "ram";
+ mc->valid_cpu_types = valid_cpu_types;
+}
+
+static void npcm845_evb_machine_class_init(ObjectClass *oc, const void *data)
+{
+ NPCM8xxMachineClass *nmc = NPCM8XX_MACHINE_CLASS(oc);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ npcm8xx_set_soc_type(nmc, TYPE_NPCM8XX);
+
+ mc->desc = "Nuvoton NPCM845 Evaluation Board (Cortex-A35)";
+ mc->init = npcm845_evb_init;
+ mc->default_ram_size = 1 * GiB;
+};
+
+static const TypeInfo npcm8xx_machine_types[] = {
+ {
+ .name = TYPE_NPCM8XX_MACHINE,
+ .parent = TYPE_MACHINE,
+ .instance_size = sizeof(NPCM8xxMachine),
+ .class_size = sizeof(NPCM8xxMachineClass),
+ .class_init = npcm8xx_machine_class_init,
+ .abstract = true,
+ }, {
+ .name = MACHINE_TYPE_NAME("npcm845-evb"),
+ .parent = TYPE_NPCM8XX_MACHINE,
+ .class_init = npcm845_evb_machine_class_init,
+ },
+};
+
+DEFINE_TYPES(npcm8xx_machine_types)
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index ac53441..d8cc321 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -76,16 +76,16 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
}
/* This clock doesn't need migration because it is fixed-frequency */
clock_set_hz(s->sysclk, HCLK_FRQ);
- qdev_connect_clock_in(DEVICE(&s->cpu), "cpuclk", s->sysclk);
+ qdev_connect_clock_in(DEVICE(&s->armv7m), "cpuclk", s->sysclk);
/*
* This SoC has no systick device, so don't connect refclk.
* TODO: model the lack of systick (currently the armv7m object
* will always provide one).
*/
- object_property_set_link(OBJECT(&s->cpu), "memory", OBJECT(&s->container),
+ object_property_set_link(OBJECT(&s->armv7m), "memory", OBJECT(&s->container),
&error_abort);
- if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpu), errp)) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
return;
}
@@ -104,7 +104,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0);
memory_region_add_subregion_overlap(&s->container, NRF51_UART_BASE, mr, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0,
- qdev_get_gpio_in(DEVICE(&s->cpu),
+ qdev_get_gpio_in(DEVICE(&s->armv7m),
BASE_TO_IRQ(NRF51_UART_BASE)));
/* RNG */
@@ -115,7 +115,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0);
memory_region_add_subregion_overlap(&s->container, NRF51_RNG_BASE, mr, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rng), 0,
- qdev_get_gpio_in(DEVICE(&s->cpu),
+ qdev_get_gpio_in(DEVICE(&s->armv7m),
BASE_TO_IRQ(NRF51_RNG_BASE)));
/* UICR, FICR, NVMC, FLASH */
@@ -161,7 +161,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer[i]), 0, base_addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer[i]), 0,
- qdev_get_gpio_in(DEVICE(&s->cpu),
+ qdev_get_gpio_in(DEVICE(&s->armv7m),
BASE_TO_IRQ(base_addr)));
}
@@ -185,10 +185,10 @@ static void nrf51_soc_init(Object *obj)
memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX);
- object_initialize_child(OBJECT(s), "armv6m", &s->cpu, TYPE_ARMV7M);
- qdev_prop_set_string(DEVICE(&s->cpu), "cpu-type",
+ object_initialize_child(OBJECT(s), "armv6m", &s->armv7m, TYPE_ARMV7M);
+ qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type",
ARM_CPU_TYPE_NAME("cortex-m0"));
- qdev_prop_set_uint32(DEVICE(&s->cpu), "num-irq", 32);
+ qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq", 32);
object_initialize_child(obj, "uart", &s->uart, TYPE_NRF51_UART);
object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev");
@@ -208,16 +208,15 @@ static void nrf51_soc_init(Object *obj)
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
}
-static Property nrf51_soc_properties[] = {
+static const Property nrf51_soc_properties[] = {
DEFINE_PROP_LINK("memory", NRF51State, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("sram-size", NRF51State, sram_size, NRF51822_SRAM_SIZE),
DEFINE_PROP_UINT32("flash-size", NRF51State, flash_size,
NRF51822_FLASH_SIZE),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nrf51_soc_class_init(ObjectClass *klass, void *data)
+static void nrf51_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
deleted file mode 100644
index 3536431..0000000
--- a/hw/arm/nseries.c
+++ /dev/null
@@ -1,1473 +0,0 @@
-/*
- * Nokia N-series internet tablets.
- *
- * Copyright (C) 2007 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "chardev/char.h"
-#include "qemu/cutils.h"
-#include "qemu/bswap.h"
-#include "qemu/hw-version.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
-#include "hw/arm/omap.h"
-#include "hw/arm/boot.h"
-#include "hw/irq.h"
-#include "ui/console.h"
-#include "hw/boards.h"
-#include "hw/i2c/i2c.h"
-#include "hw/display/blizzard.h"
-#include "hw/input/lm832x.h"
-#include "hw/input/tsc2xxx.h"
-#include "hw/misc/cbus.h"
-#include "hw/sensor/tmp105.h"
-#include "hw/qdev-properties.h"
-#include "hw/block/flash.h"
-#include "hw/hw.h"
-#include "hw/loader.h"
-#include "hw/sysbus.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-
-
-/* Nokia N8x0 support */
-struct n800_s {
- struct omap_mpu_state_s *mpu;
-
- struct rfbi_chip_s blizzard;
- struct {
- void *opaque;
- uint32_t (*txrx)(void *opaque, uint32_t value, int len);
- uWireSlave *chip;
- } ts;
-
- int keymap[0x80];
- DeviceState *kbd;
-
- DeviceState *usb;
- void *retu;
- void *tahvo;
- DeviceState *nand;
-};
-
-/* GPIO pins */
-#define N8X0_TUSB_ENABLE_GPIO 0
-#define N800_MMC2_WP_GPIO 8
-#define N800_UNKNOWN_GPIO0 9 /* out */
-#define N810_MMC2_VIOSD_GPIO 9
-#define N810_HEADSET_AMP_GPIO 10
-#define N800_CAM_TURN_GPIO 12
-#define N810_GPS_RESET_GPIO 12
-#define N800_BLIZZARD_POWERDOWN_GPIO 15
-#define N800_MMC1_WP_GPIO 23
-#define N810_MMC2_VSD_GPIO 23
-#define N8X0_ONENAND_GPIO 26
-#define N810_BLIZZARD_RESET_GPIO 30
-#define N800_UNKNOWN_GPIO2 53 /* out */
-#define N8X0_TUSB_INT_GPIO 58
-#define N8X0_BT_WKUP_GPIO 61
-#define N8X0_STI_GPIO 62
-#define N8X0_CBUS_SEL_GPIO 64
-#define N8X0_CBUS_DAT_GPIO 65
-#define N8X0_CBUS_CLK_GPIO 66
-#define N8X0_WLAN_IRQ_GPIO 87
-#define N8X0_BT_RESET_GPIO 92
-#define N8X0_TEA5761_CS_GPIO 93
-#define N800_UNKNOWN_GPIO 94
-#define N810_TSC_RESET_GPIO 94
-#define N800_CAM_ACT_GPIO 95
-#define N810_GPS_WAKEUP_GPIO 95
-#define N8X0_MMC_CS_GPIO 96
-#define N8X0_WLAN_PWR_GPIO 97
-#define N8X0_BT_HOST_WKUP_GPIO 98
-#define N810_SPEAKER_AMP_GPIO 101
-#define N810_KB_LOCK_GPIO 102
-#define N800_TSC_TS_GPIO 103
-#define N810_TSC_TS_GPIO 106
-#define N8X0_HEADPHONE_GPIO 107
-#define N8X0_RETU_GPIO 108
-#define N800_TSC_KP_IRQ_GPIO 109
-#define N810_KEYBOARD_GPIO 109
-#define N800_BAT_COVER_GPIO 110
-#define N810_SLIDE_GPIO 110
-#define N8X0_TAHVO_GPIO 111
-#define N800_UNKNOWN_GPIO4 112 /* out */
-#define N810_SLEEPX_LED_GPIO 112
-#define N800_TSC_RESET_GPIO 118 /* ? */
-#define N810_AIC33_RESET_GPIO 118
-#define N800_TSC_UNKNOWN_GPIO 119 /* out */
-#define N8X0_TMP105_GPIO 125
-
-/* Config */
-#define BT_UART 0
-#define XLDR_LL_UART 1
-
-/* Addresses on the I2C bus 0 */
-#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */
-#define N8X0_TCM825x_ADDR 0x29 /* Camera */
-#define N810_LP5521_ADDR 0x32 /* LEDs */
-#define N810_TSL2563_ADDR 0x3d /* Light sensor */
-#define N810_LM8323_ADDR 0x45 /* Keyboard */
-/* Addresses on the I2C bus 1 */
-#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */
-#define N8X0_MENELAUS_ADDR 0x72 /* Power management */
-
-/* Chipselects on GPMC NOR interface */
-#define N8X0_ONENAND_CS 0
-#define N8X0_USB_ASYNC_CS 1
-#define N8X0_USB_SYNC_CS 4
-
-#define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
-
-static void n800_mmc_cs_cb(void *opaque, int line, int level)
-{
- /* TODO: this seems to actually be connected to the menelaus, to
- * which also both MMC slots connect. */
- omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
-}
-
-static void n8x0_gpio_setup(struct n800_s *s)
-{
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO,
- qemu_allocate_irq(n800_mmc_cs_cb, s->mpu->mmc, 0));
- qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
-}
-
-#define MAEMO_CAL_HEADER(...) \
- 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \
- __VA_ARGS__, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-static const uint8_t n8x0_cal_wlan_mac[] = {
- MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c')
- 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3,
- 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
- 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
- 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
-};
-
-static const uint8_t n8x0_cal_bt_id[] = {
- MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0)
- 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96,
- 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00,
- N8X0_BD_ADDR,
-};
-
-static void n8x0_nand_setup(struct n800_s *s)
-{
- char *otp_region;
- DriveInfo *dinfo;
-
- s->nand = qdev_new("onenand");
- qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG);
- /* Either 0x40 or 0x48 are OK for the device ID */
- qdev_prop_set_uint16(s->nand, "device_id", 0x48);
- qdev_prop_set_uint16(s->nand, "version_id", 0);
- qdev_prop_set_int32(s->nand, "shift", 1);
- dinfo = drive_get(IF_MTD, 0, 0);
- if (dinfo) {
- qdev_prop_set_drive_err(s->nand, "drive", blk_by_legacy_dinfo(dinfo),
- &error_fatal);
- }
- sysbus_realize_and_unref(SYS_BUS_DEVICE(s->nand), &error_fatal);
- sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,
- qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO));
- omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0));
- otp_region = onenand_raw_otp(s->nand);
-
- memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
- memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id));
- /* XXX: in theory should also update the OOB for both pages */
-}
-
-static qemu_irq n8x0_system_powerdown;
-
-static void n8x0_powerdown_req(Notifier *n, void *opaque)
-{
- qemu_irq_raise(n8x0_system_powerdown);
-}
-
-static Notifier n8x0_system_powerdown_notifier = {
- .notify = n8x0_powerdown_req
-};
-
-static void n8x0_i2c_setup(struct n800_s *s)
-{
- DeviceState *dev;
- qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
- I2CBus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
-
- /* Attach a menelaus PM chip */
- dev = DEVICE(i2c_slave_create_simple(i2c, "twl92230", N8X0_MENELAUS_ADDR));
- qdev_connect_gpio_out(dev, 3,
- qdev_get_gpio_in(s->mpu->ih[0],
- OMAP_INT_24XX_SYS_NIRQ));
-
- n8x0_system_powerdown = qdev_get_gpio_in(dev, 3);
- qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
-
- /* Attach a TMP105 PM chip (A0 wired to ground) */
- dev = DEVICE(i2c_slave_create_simple(i2c, TYPE_TMP105, N8X0_TMP105_ADDR));
- qdev_connect_gpio_out(dev, 0, tmp_irq);
-}
-
-/* Touchscreen and keypad controller */
-static const MouseTransformInfo n800_pointercal = {
- .x = 800,
- .y = 480,
- .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
-};
-
-static const MouseTransformInfo n810_pointercal = {
- .x = 800,
- .y = 480,
- .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
-};
-
-#define RETU_KEYCODE 61 /* F3 */
-
-static void n800_key_event(void *opaque, int keycode)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- int code = s->keymap[keycode & 0x7f];
-
- if (code == -1) {
- if ((keycode & 0x7f) == RETU_KEYCODE) {
- retu_key_event(s->retu, !(keycode & 0x80));
- }
- return;
- }
-
- tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80));
-}
-
-static const int n800_keys[16] = {
- -1,
- 72, /* Up */
- 63, /* Home (F5) */
- -1,
- 75, /* Left */
- 28, /* Enter */
- 77, /* Right */
- -1,
- 1, /* Cycle (ESC) */
- 80, /* Down */
- 62, /* Menu (F4) */
- -1,
- 66, /* Zoom- (F8) */
- 64, /* FullScreen (F6) */
- 65, /* Zoom+ (F7) */
- -1,
-};
-
-static void n800_tsc_kbd_setup(struct n800_s *s)
-{
- int i;
-
- /* XXX: are the three pins inverted inside the chip between the
- * tsc and the cpu (N4111)? */
- qemu_irq penirq = NULL; /* NC */
- qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO);
- qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO);
-
- s->ts.chip = tsc2301_init(penirq, kbirq, dav);
- s->ts.opaque = s->ts.chip->opaque;
- s->ts.txrx = tsc210x_txrx;
-
- for (i = 0; i < 0x80; i++) {
- s->keymap[i] = -1;
- }
- for (i = 0; i < 0x10; i++) {
- if (n800_keys[i] >= 0) {
- s->keymap[n800_keys[i]] = i;
- }
- }
-
- qemu_add_kbd_event_handler(n800_key_event, s);
-
- tsc210x_set_transform(s->ts.chip, &n800_pointercal);
-}
-
-static void n810_tsc_setup(struct n800_s *s)
-{
- qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO);
-
- s->ts.opaque = tsc2005_init(pintdav);
- s->ts.txrx = tsc2005_txrx;
-
- tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
-}
-
-/* N810 Keyboard controller */
-static void n810_key_event(void *opaque, int keycode)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- int code = s->keymap[keycode & 0x7f];
-
- if (code == -1) {
- if ((keycode & 0x7f) == RETU_KEYCODE) {
- retu_key_event(s->retu, !(keycode & 0x80));
- }
- return;
- }
-
- lm832x_key_event(s->kbd, code, !(keycode & 0x80));
-}
-
-#define M 0
-
-static const int n810_keys[0x80] = {
- [0x01] = 16, /* Q */
- [0x02] = 37, /* K */
- [0x03] = 24, /* O */
- [0x04] = 25, /* P */
- [0x05] = 14, /* Backspace */
- [0x06] = 30, /* A */
- [0x07] = 31, /* S */
- [0x08] = 32, /* D */
- [0x09] = 33, /* F */
- [0x0a] = 34, /* G */
- [0x0b] = 35, /* H */
- [0x0c] = 36, /* J */
-
- [0x11] = 17, /* W */
- [0x12] = 62, /* Menu (F4) */
- [0x13] = 38, /* L */
- [0x14] = 40, /* ' (Apostrophe) */
- [0x16] = 44, /* Z */
- [0x17] = 45, /* X */
- [0x18] = 46, /* C */
- [0x19] = 47, /* V */
- [0x1a] = 48, /* B */
- [0x1b] = 49, /* N */
- [0x1c] = 42, /* Shift (Left shift) */
- [0x1f] = 65, /* Zoom+ (F7) */
-
- [0x21] = 18, /* E */
- [0x22] = 39, /* ; (Semicolon) */
- [0x23] = 12, /* - (Minus) */
- [0x24] = 13, /* = (Equal) */
- [0x2b] = 56, /* Fn (Left Alt) */
- [0x2c] = 50, /* M */
- [0x2f] = 66, /* Zoom- (F8) */
-
- [0x31] = 19, /* R */
- [0x32] = 29 | M, /* Right Ctrl */
- [0x34] = 57, /* Space */
- [0x35] = 51, /* , (Comma) */
- [0x37] = 72 | M, /* Up */
- [0x3c] = 82 | M, /* Compose (Insert) */
- [0x3f] = 64, /* FullScreen (F6) */
-
- [0x41] = 20, /* T */
- [0x44] = 52, /* . (Dot) */
- [0x46] = 77 | M, /* Right */
- [0x4f] = 63, /* Home (F5) */
- [0x51] = 21, /* Y */
- [0x53] = 80 | M, /* Down */
- [0x55] = 28, /* Enter */
- [0x5f] = 1, /* Cycle (ESC) */
-
- [0x61] = 22, /* U */
- [0x64] = 75 | M, /* Left */
-
- [0x71] = 23, /* I */
-#if 0
- [0x75] = 28 | M, /* KP Enter (KP Enter) */
-#else
- [0x75] = 15, /* KP Enter (Tab) */
-#endif
-};
-
-#undef M
-
-static void n810_kbd_setup(struct n800_s *s)
-{
- qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO);
- int i;
-
- for (i = 0; i < 0x80; i++) {
- s->keymap[i] = -1;
- }
- for (i = 0; i < 0x80; i++) {
- if (n810_keys[i] > 0) {
- s->keymap[n810_keys[i]] = i;
- }
- }
-
- qemu_add_kbd_event_handler(n810_key_event, s);
-
- /* Attach the LM8322 keyboard to the I2C bus,
- * should happen in n8x0_i2c_setup and s->kbd be initialised here. */
- s->kbd = DEVICE(i2c_slave_create_simple(omap_i2c_bus(s->mpu->i2c[0]),
- TYPE_LM8323, N810_LM8323_ADDR));
- qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
-}
-
-/* LCD MIPI DBI-C controller (URAL) */
-struct mipid_s {
- int resp[4];
- int param[4];
- int p;
- int pm;
- int cmd;
-
- int sleep;
- int booster;
- int te;
- int selfcheck;
- int partial;
- int normal;
- int vscr;
- int invert;
- int onoff;
- int gamma;
- uint32_t id;
-};
-
-static void mipid_reset(struct mipid_s *s)
-{
- s->pm = 0;
- s->cmd = 0;
-
- s->sleep = 1;
- s->booster = 0;
- s->selfcheck =
- (1 << 7) | /* Register loading OK. */
- (1 << 5) | /* The chip is attached. */
- (1 << 4); /* Display glass still in one piece. */
- s->te = 0;
- s->partial = 0;
- s->normal = 1;
- s->vscr = 0;
- s->invert = 0;
- s->onoff = 1;
- s->gamma = 0;
-}
-
-static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
-{
- struct mipid_s *s = (struct mipid_s *) opaque;
- uint8_t ret;
-
- if (len > 9) {
- hw_error("%s: FIXME: bad SPI word width %i\n", __func__, len);
- }
-
- if (s->p >= ARRAY_SIZE(s->resp)) {
- ret = 0;
- } else {
- ret = s->resp[s->p++];
- }
- if (s->pm-- > 0) {
- s->param[s->pm] = cmd;
- } else {
- s->cmd = cmd;
- }
-
- switch (s->cmd) {
- case 0x00: /* NOP */
- break;
-
- case 0x01: /* SWRESET */
- mipid_reset(s);
- break;
-
- case 0x02: /* BSTROFF */
- s->booster = 0;
- break;
- case 0x03: /* BSTRON */
- s->booster = 1;
- break;
-
- case 0x04: /* RDDID */
- s->p = 0;
- s->resp[0] = (s->id >> 16) & 0xff;
- s->resp[1] = (s->id >> 8) & 0xff;
- s->resp[2] = (s->id >> 0) & 0xff;
- break;
-
- case 0x06: /* RD_RED */
- case 0x07: /* RD_GREEN */
- /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
- * for the bootloader one needs to change this. */
- case 0x08: /* RD_BLUE */
- s->p = 0;
- /* TODO: return first pixel components */
- s->resp[0] = 0x01;
- break;
-
- case 0x09: /* RDDST */
- s->p = 0;
- s->resp[0] = s->booster << 7;
- s->resp[1] = (5 << 4) | (s->partial << 2) |
- (s->sleep << 1) | s->normal;
- s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
- (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
- s->resp[3] = s->gamma << 6;
- break;
-
- case 0x0a: /* RDDPM */
- s->p = 0;
- s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
- (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
- break;
- case 0x0b: /* RDDMADCTR */
- s->p = 0;
- s->resp[0] = 0;
- break;
- case 0x0c: /* RDDCOLMOD */
- s->p = 0;
- s->resp[0] = 5; /* 65K colours */
- break;
- case 0x0d: /* RDDIM */
- s->p = 0;
- s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
- break;
- case 0x0e: /* RDDSM */
- s->p = 0;
- s->resp[0] = s->te << 7;
- break;
- case 0x0f: /* RDDSDR */
- s->p = 0;
- s->resp[0] = s->selfcheck;
- break;
-
- case 0x10: /* SLPIN */
- s->sleep = 1;
- break;
- case 0x11: /* SLPOUT */
- s->sleep = 0;
- s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */
- break;
-
- case 0x12: /* PTLON */
- s->partial = 1;
- s->normal = 0;
- s->vscr = 0;
- break;
- case 0x13: /* NORON */
- s->partial = 0;
- s->normal = 1;
- s->vscr = 0;
- break;
-
- case 0x20: /* INVOFF */
- s->invert = 0;
- break;
- case 0x21: /* INVON */
- s->invert = 1;
- break;
-
- case 0x22: /* APOFF */
- case 0x23: /* APON */
- goto bad_cmd;
-
- case 0x25: /* WRCNTR */
- if (s->pm < 0) {
- s->pm = 1;
- }
- goto bad_cmd;
-
- case 0x26: /* GAMSET */
- if (!s->pm) {
- s->gamma = ctz32(s->param[0] & 0xf);
- if (s->gamma == 32) {
- s->gamma = -1; /* XXX: should this be 0? */
- }
- } else if (s->pm < 0) {
- s->pm = 1;
- }
- break;
-
- case 0x28: /* DISPOFF */
- s->onoff = 0;
- break;
- case 0x29: /* DISPON */
- s->onoff = 1;
- break;
-
- case 0x2a: /* CASET */
- case 0x2b: /* RASET */
- case 0x2c: /* RAMWR */
- case 0x2d: /* RGBSET */
- case 0x2e: /* RAMRD */
- case 0x30: /* PTLAR */
- case 0x33: /* SCRLAR */
- goto bad_cmd;
-
- case 0x34: /* TEOFF */
- s->te = 0;
- break;
- case 0x35: /* TEON */
- if (!s->pm) {
- s->te = 1;
- } else if (s->pm < 0) {
- s->pm = 1;
- }
- break;
-
- case 0x36: /* MADCTR */
- goto bad_cmd;
-
- case 0x37: /* VSCSAD */
- s->partial = 0;
- s->normal = 0;
- s->vscr = 1;
- break;
-
- case 0x38: /* IDMOFF */
- case 0x39: /* IDMON */
- case 0x3a: /* COLMOD */
- goto bad_cmd;
-
- case 0xb0: /* CLKINT / DISCTL */
- case 0xb1: /* CLKEXT */
- if (s->pm < 0) {
- s->pm = 2;
- }
- break;
-
- case 0xb4: /* FRMSEL */
- break;
-
- case 0xb5: /* FRM8SEL */
- case 0xb6: /* TMPRNG / INIESC */
- case 0xb7: /* TMPHIS / NOP2 */
- case 0xb8: /* TMPREAD / MADCTL */
- case 0xba: /* DISTCTR */
- case 0xbb: /* EPVOL */
- goto bad_cmd;
-
- case 0xbd: /* Unknown */
- s->p = 0;
- s->resp[0] = 0;
- s->resp[1] = 1;
- break;
-
- case 0xc2: /* IFMOD */
- if (s->pm < 0) {
- s->pm = 2;
- }
- break;
-
- case 0xc6: /* PWRCTL */
- case 0xc7: /* PPWRCTL */
- case 0xd0: /* EPWROUT */
- case 0xd1: /* EPWRIN */
- case 0xd4: /* RDEV */
- case 0xd5: /* RDRR */
- goto bad_cmd;
-
- case 0xda: /* RDID1 */
- s->p = 0;
- s->resp[0] = (s->id >> 16) & 0xff;
- break;
- case 0xdb: /* RDID2 */
- s->p = 0;
- s->resp[0] = (s->id >> 8) & 0xff;
- break;
- case 0xdc: /* RDID3 */
- s->p = 0;
- s->resp[0] = (s->id >> 0) & 0xff;
- break;
-
- default:
- bad_cmd:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: unknown command 0x%02x\n", __func__, s->cmd);
- break;
- }
-
- return ret;
-}
-
-static void *mipid_init(void)
-{
- struct mipid_s *s = g_malloc0(sizeof(*s));
-
- s->id = 0x838f03;
- mipid_reset(s);
-
- return s;
-}
-
-static void n8x0_spi_setup(struct n800_s *s)
-{
- void *tsc = s->ts.opaque;
- void *mipid = mipid_init();
-
- omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0);
- omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1);
-}
-
-/* This task is normally performed by the bootloader. If we're loading
- * a kernel directly, we need to enable the Blizzard ourselves. */
-static void n800_dss_init(struct rfbi_chip_s *chip)
-{
- uint8_t *fb_blank;
-
- chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */
- chip->write(chip->opaque, 1, 0x64);
- chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */
- chip->write(chip->opaque, 1, 0x1e);
- chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */
- chip->write(chip->opaque, 1, 0xe0);
- chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */
- chip->write(chip->opaque, 1, 0x01);
- chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */
- chip->write(chip->opaque, 1, 0x06);
- chip->write(chip->opaque, 0, 0x68); /* Display Mode register */
- chip->write(chip->opaque, 1, 1); /* Enable bit */
-
- chip->write(chip->opaque, 0, 0x6c);
- chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
- chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */
- chip->write(chip->opaque, 1, 0x03); /* Input X End Position */
- chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */
- chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
- chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */
- chip->write(chip->opaque, 1, 0x03); /* Output X End Position */
- chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Input Data Format */
- chip->write(chip->opaque, 1, 0x01); /* Data Source Select */
-
- fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
- /* Display Memory Data Port */
- chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
- g_free(fb_blank);
-}
-
-static void n8x0_dss_setup(struct n800_s *s)
-{
- s->blizzard.opaque = s1d13745_init(NULL);
- s->blizzard.block = s1d13745_write_block;
- s->blizzard.write = s1d13745_write;
- s->blizzard.read = s1d13745_read;
-
- omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard);
-}
-
-static void n8x0_cbus_setup(struct n800_s *s)
-{
- qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO);
- qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO);
- qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO);
-
- CBus *cbus = cbus_init(dat_out);
-
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
-
- cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
- cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
-}
-
-static void n8x0_usb_setup(struct n800_s *s)
-{
- SysBusDevice *dev;
- s->usb = qdev_new("tusb6010");
- dev = SYS_BUS_DEVICE(s->usb);
- sysbus_realize_and_unref(dev, &error_fatal);
- sysbus_connect_irq(dev, 0,
- qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO));
- /* Using the NOR interface */
- omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS,
- sysbus_mmio_get_region(dev, 0));
- omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS,
- sysbus_mmio_get_region(dev, 1));
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO,
- qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */
-}
-
-/* Setup done before the main bootloader starts by some early setup code
- * - used when we want to run the main bootloader in emulation. This
- * isn't documented. */
-static const uint32_t n800_pinout[104] = {
- 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
- 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
- 0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
- 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128,
- 0x01241800, 0x18181818, 0x000000f0, 0x01300000,
- 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b,
- 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080,
- 0x007c0000, 0x00000000, 0x00000088, 0x00840000,
- 0x00000000, 0x00000094, 0x00980300, 0x0f180003,
- 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c,
- 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008,
- 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f,
- 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc,
- 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008,
- 0x00000000, 0x00000038, 0x00340000, 0x00000000,
- 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060,
- 0x005c0808, 0x08080808, 0x08080058, 0x00540808,
- 0x08080808, 0x0808006c, 0x00680808, 0x08080808,
- 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0,
- 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808,
- 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff,
- 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100,
- 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a,
- 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00,
- 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118,
- 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b,
-};
-
-static void n800_setup_nolo_tags(void *sram_base)
-{
- int i;
- uint32_t *p = sram_base + 0x8000;
- uint32_t *v = sram_base + 0xa000;
-
- memset(p, 0, 0x3000);
-
- strcpy((void *) (p + 0), "QEMU N800");
-
- strcpy((void *) (p + 8), "F5");
-
- stl_p(p + 10, 0x04f70000);
- strcpy((void *) (p + 9), "RX-34");
-
- /* RAM size in MB? */
- stl_p(p + 12, 0x80);
-
- /* Pointer to the list of tags */
- stl_p(p + 13, OMAP2_SRAM_BASE + 0x9000);
-
- /* The NOLO tags start here */
- p = sram_base + 0x9000;
-#define ADD_TAG(tag, len) \
- stw_p((uint16_t *) p + 0, tag); \
- stw_p((uint16_t *) p + 1, len); p++; \
- stl_p(p++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff));
-
- /* OMAP STI console? Pin out settings? */
- ADD_TAG(0x6e01, 414);
- for (i = 0; i < ARRAY_SIZE(n800_pinout); i++) {
- stl_p(v++, n800_pinout[i]);
- }
-
- /* Kernel memsize? */
- ADD_TAG(0x6e05, 1);
- stl_p(v++, 2);
-
- /* NOLO serial console */
- ADD_TAG(0x6e02, 4);
- stl_p(v++, XLDR_LL_UART); /* UART number (1 - 3) */
-
-#if 0
- /* CBUS settings (Retu/AVilma) */
- ADD_TAG(0x6e03, 6);
- stw_p((uint16_t *) v + 0, 65); /* CBUS GPIO0 */
- stw_p((uint16_t *) v + 1, 66); /* CBUS GPIO1 */
- stw_p((uint16_t *) v + 2, 64); /* CBUS GPIO2 */
- v += 2;
-#endif
-
- /* Nokia ASIC BB5 (Retu/Tahvo) */
- ADD_TAG(0x6e0a, 4);
- stw_p((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */
- stw_p((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */
- v++;
-
- /* LCD console? */
- ADD_TAG(0x6e04, 4);
- stw_p((uint16_t *) v + 0, 30); /* ??? */
- stw_p((uint16_t *) v + 1, 24); /* ??? */
- v++;
-
-#if 0
- /* LCD settings */
- ADD_TAG(0x6e06, 2);
- stw_p((uint16_t *) (v++), 15); /* ??? */
-#endif
-
- /* I^2C (Menelaus) */
- ADD_TAG(0x6e07, 4);
- stl_p(v++, 0x00720000); /* ??? */
-
- /* Unknown */
- ADD_TAG(0x6e0b, 6);
- stw_p((uint16_t *) v + 0, 94); /* ??? */
- stw_p((uint16_t *) v + 1, 23); /* ??? */
- stw_p((uint16_t *) v + 2, 0); /* ??? */
- v += 2;
-
- /* OMAP gpio switch info */
- ADD_TAG(0x6e0c, 80);
- strcpy((void *) v, "bat_cover"); v += 3;
- stw_p((uint16_t *) v + 0, 110); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 1); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "cam_act"); v += 3;
- stw_p((uint16_t *) v + 0, 95); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 32); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "cam_turn"); v += 3;
- stw_p((uint16_t *) v + 0, 12); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 33); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "headphone"); v += 3;
- stw_p((uint16_t *) v + 0, 107); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 17); /* GPIO num ??? */
- v += 2;
-
- /* Bluetooth */
- ADD_TAG(0x6e0e, 12);
- stl_p(v++, 0x5c623d01); /* ??? */
- stl_p(v++, 0x00000201); /* ??? */
- stl_p(v++, 0x00000000); /* ??? */
-
- /* CX3110x WLAN settings */
- ADD_TAG(0x6e0f, 8);
- stl_p(v++, 0x00610025); /* ??? */
- stl_p(v++, 0xffff0057); /* ??? */
-
- /* MMC host settings */
- ADD_TAG(0x6e10, 12);
- stl_p(v++, 0xffff000f); /* ??? */
- stl_p(v++, 0xffffffff); /* ??? */
- stl_p(v++, 0x00000060); /* ??? */
-
- /* OneNAND chip select */
- ADD_TAG(0x6e11, 10);
- stl_p(v++, 0x00000401); /* ??? */
- stl_p(v++, 0x0002003a); /* ??? */
- stl_p(v++, 0x00000002); /* ??? */
-
- /* TEA5761 sensor settings */
- ADD_TAG(0x6e12, 2);
- stl_p(v++, 93); /* GPIO num ??? */
-
-#if 0
- /* Unknown tag */
- ADD_TAG(6e09, 0);
-
- /* Kernel UART / console */
- ADD_TAG(6e12, 0);
-#endif
-
- /* End of the list */
- stl_p(p++, 0x00000000);
- stl_p(p++, 0x00000000);
-}
-
-/* This task is normally performed by the bootloader. If we're loading
- * a kernel directly, we need to set up GPMC mappings ourselves. */
-static void n800_gpmc_init(struct n800_s *s)
-{
- uint32_t config7 =
- (0xf << 8) | /* MASKADDRESS */
- (1 << 6) | /* CSVALID */
- (4 << 0); /* BASEADDRESS */
-
- cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */
- &config7, sizeof(config7));
-}
-
-/* Setup sequence done by the bootloader */
-static void n8x0_boot_init(void *opaque)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- uint32_t buf;
-
- /* PRCM setup */
-#define omap_writel(addr, val) \
- buf = (val); \
- cpu_physical_memory_write(addr, &buf, sizeof(buf))
-
- omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */
- omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */
- omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */
- omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */
- omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */
- omap_writel(0x48008098, 0); /* PRCM_POLCTRL */
- omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */
- omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */
- omap_writel(0x48008158, 1); /* RM_RSTST_MPU */
- omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */
- omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */
- omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */
- omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */
- omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */
- omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */
- omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */
- omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */
- omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */
- omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */
- omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */
- omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */
- omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */
- omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */
- omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */
- omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */
- omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */
- omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */
- omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */
- omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */
- omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */
- omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */
- omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */
- omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */
- omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */
- omap_writel(0x48008540, /* CM_CLKSEL1_PLL */
- (0x78 << 12) | (6 << 8));
- omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */
-
- /* GPMC setup */
- n800_gpmc_init(s);
-
- /* Video setup */
- n800_dss_init(&s->blizzard);
-
- /* CPU setup */
- s->mpu->cpu->env.GE = 0x5;
-
- /* If the machine has a slided keyboard, open it */
- if (s->kbd) {
- qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO));
- }
-}
-
-#define OMAP_TAG_NOKIA_BT 0x4e01
-#define OMAP_TAG_WLAN_CX3110X 0x4e02
-#define OMAP_TAG_CBUS 0x4e03
-#define OMAP_TAG_EM_ASIC_BB5 0x4e04
-
-static const struct omap_gpiosw_info_s {
- const char *name;
- int line;
- int type;
-} n800_gpiosw_info[] = {
- {
- "bat_cover", N800_BAT_COVER_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- }, {
- "cam_act", N800_CAM_ACT_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY,
- }, {
- "cam_turn", N800_CAM_TURN_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED,
- }, {
- "headphone", N8X0_HEADPHONE_GPIO,
- OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
- },
- { /* end of list */ }
-}, n810_gpiosw_info[] = {
- {
- "gps_reset", N810_GPS_RESET_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
- }, {
- "gps_wakeup", N810_GPS_WAKEUP_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
- }, {
- "headphone", N8X0_HEADPHONE_GPIO,
- OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
- }, {
- "kb_lock", N810_KB_LOCK_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- }, {
- "sleepx_led", N810_SLEEPX_LED_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT,
- }, {
- "slide", N810_SLIDE_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- },
- { /* end of list */ }
-};
-
-static const struct omap_partition_info_s {
- uint32_t offset;
- uint32_t size;
- int mask;
- const char *name;
-} n800_part_info[] = {
- { 0x00000000, 0x00020000, 0x3, "bootloader" },
- { 0x00020000, 0x00060000, 0x0, "config" },
- { 0x00080000, 0x00200000, 0x0, "kernel" },
- { 0x00280000, 0x00200000, 0x3, "initfs" },
- { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
- { /* end of list */ }
-}, n810_part_info[] = {
- { 0x00000000, 0x00020000, 0x3, "bootloader" },
- { 0x00020000, 0x00060000, 0x0, "config" },
- { 0x00080000, 0x00220000, 0x0, "kernel" },
- { 0x002a0000, 0x00400000, 0x0, "initfs" },
- { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
- { /* end of list */ }
-};
-
-static const uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
-
-static int n8x0_atag_setup(void *p, int model)
-{
- uint8_t *b;
- uint16_t *w;
- uint32_t *l;
- const struct omap_gpiosw_info_s *gpiosw;
- const struct omap_partition_info_s *partition;
- const char *tag;
-
- w = p;
-
- stw_p(w++, OMAP_TAG_UART); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
- w++;
-
-#if 0
- stw_p(w++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, XLDR_LL_UART + 1); /* u8 console_uart */
- stw_p(w++, 115200); /* u32 console_speed */
-#endif
-
- stw_p(w++, OMAP_TAG_LCD); /* u16 tag */
- stw_p(w++, 36); /* u16 len */
- strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */
- w += 8;
- strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */
- w += 8;
- stw_p(w++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */
- stw_p(w++, 24); /* u8 data_lines */
-
- stw_p(w++, OMAP_TAG_CBUS); /* u16 tag */
- stw_p(w++, 8); /* u16 len */
- stw_p(w++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */
- stw_p(w++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */
- stw_p(w++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */
- w++;
-
- stw_p(w++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */
- stw_p(w++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */
-
- gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info;
- for (; gpiosw->name; gpiosw++) {
- stw_p(w++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */
- stw_p(w++, 20); /* u16 len */
- strcpy((void *) w, gpiosw->name); /* char name[12] */
- w += 6;
- stw_p(w++, gpiosw->line); /* u16 gpio */
- stw_p(w++, gpiosw->type);
- stw_p(w++, 0);
- stw_p(w++, 0);
- }
-
- stw_p(w++, OMAP_TAG_NOKIA_BT); /* u16 tag */
- stw_p(w++, 12); /* u16 len */
- b = (void *) w;
- stb_p(b++, 0x01); /* u8 chip_type (CSR) */
- stb_p(b++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */
- stb_p(b++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */
- stb_p(b++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */
- stb_p(b++, BT_UART + 1); /* u8 bt_uart */
- memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */
- b += 6;
- stb_p(b++, 0x02); /* u8 bt_sysclk (38.4) */
- w = (void *) b;
-
- stw_p(w++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */
- stw_p(w++, 8); /* u16 len */
- stw_p(w++, 0x25); /* u8 chip_type */
- stw_p(w++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */
- stw_p(w++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */
- stw_p(w++, -1); /* s16 spi_cs_gpio */
-
- stw_p(w++, OMAP_TAG_MMC); /* u16 tag */
- stw_p(w++, 16); /* u16 len */
- if (model == 810) {
- stw_p(w++, 0x23f); /* unsigned flags */
- stw_p(w++, -1); /* s16 power_pin */
- stw_p(w++, -1); /* s16 switch_pin */
- stw_p(w++, -1); /* s16 wp_pin */
- stw_p(w++, 0x240); /* unsigned flags */
- stw_p(w++, 0xc000); /* s16 power_pin */
- stw_p(w++, 0x0248); /* s16 switch_pin */
- stw_p(w++, 0xc000); /* s16 wp_pin */
- } else {
- stw_p(w++, 0xf); /* unsigned flags */
- stw_p(w++, -1); /* s16 power_pin */
- stw_p(w++, -1); /* s16 switch_pin */
- stw_p(w++, -1); /* s16 wp_pin */
- stw_p(w++, 0); /* unsigned flags */
- stw_p(w++, 0); /* s16 power_pin */
- stw_p(w++, 0); /* s16 switch_pin */
- stw_p(w++, 0); /* s16 wp_pin */
- }
-
- stw_p(w++, OMAP_TAG_TEA5761); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */
- w++;
-
- partition = (model == 810) ? n810_part_info : n800_part_info;
- for (; partition->name; partition++) {
- stw_p(w++, OMAP_TAG_PARTITION); /* u16 tag */
- stw_p(w++, 28); /* u16 len */
- strcpy((void *) w, partition->name); /* char name[16] */
- l = (void *) (w + 8);
- stl_p(l++, partition->size); /* unsigned int size */
- stl_p(l++, partition->offset); /* unsigned int offset */
- stl_p(l++, partition->mask); /* unsigned int mask_flags */
- w = (void *) l;
- }
-
- stw_p(w++, OMAP_TAG_BOOT_REASON); /* u16 tag */
- stw_p(w++, 12); /* u16 len */
-#if 0
- strcpy((void *) w, "por"); /* char reason_str[12] */
- strcpy((void *) w, "charger"); /* char reason_str[12] */
- strcpy((void *) w, "32wd_to"); /* char reason_str[12] */
- strcpy((void *) w, "sw_rst"); /* char reason_str[12] */
- strcpy((void *) w, "mbus"); /* char reason_str[12] */
- strcpy((void *) w, "unknown"); /* char reason_str[12] */
- strcpy((void *) w, "swdg_to"); /* char reason_str[12] */
- strcpy((void *) w, "sec_vio"); /* char reason_str[12] */
- strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
- strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */
-#else
- strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
-#endif
- w += 6;
-
- tag = (model == 810) ? "RX-44" : "RX-34";
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "product"); /* char component[12] */
- w += 6;
- strcpy((void *) w, tag); /* char version[12] */
- w += 6;
-
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "hw-build"); /* char component[12] */
- w += 6;
- strcpy((void *) w, "QEMU ");
- pstrcat((void *) w, 12, qemu_hw_version()); /* char version[12] */
- w += 6;
-
- tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "nolo"); /* char component[12] */
- w += 6;
- strcpy((void *) w, tag); /* char version[12] */
- w += 6;
-
- return (void *) w - p;
-}
-
-static int n800_atag_setup(const struct arm_boot_info *info, void *p)
-{
- return n8x0_atag_setup(p, 800);
-}
-
-static int n810_atag_setup(const struct arm_boot_info *info, void *p)
-{
- return n8x0_atag_setup(p, 810);
-}
-
-static void n8x0_init(MachineState *machine,
- struct arm_boot_info *binfo, int model)
-{
- struct n800_s *s = g_malloc0(sizeof(*s));
- MachineClass *mc = MACHINE_GET_CLASS(machine);
-
- if (machine->ram_size != mc->default_ram_size) {
- char *sz = size_to_str(mc->default_ram_size);
- error_report("Invalid RAM size, should be %s", sz);
- g_free(sz);
- exit(EXIT_FAILURE);
- }
- binfo->ram_size = machine->ram_size;
-
- memory_region_add_subregion(get_system_memory(), OMAP2_Q2_BASE,
- machine->ram);
-
- s->mpu = omap2420_mpu_init(machine->ram, machine->cpu_type);
-
- /* Setup peripherals
- *
- * Believed external peripherals layout in the N810:
- * (spi bus 1)
- * tsc2005
- * lcd_mipid
- * (spi bus 2)
- * Conexant cx3110x (WLAN)
- * optional: pc2400m (WiMAX)
- * (i2c bus 0)
- * TLV320AIC33 (audio codec)
- * TCM825x (camera by Toshiba)
- * lp5521 (clever LEDs)
- * tsl2563 (light sensor, hwmon, model 7, rev. 0)
- * lm8323 (keypad, manf 00, rev 04)
- * (i2c bus 1)
- * tmp105 (temperature sensor, hwmon)
- * menelaus (pm)
- * (somewhere on i2c - maybe N800-only)
- * tea5761 (FM tuner)
- * (serial 0)
- * GPS
- * (some serial port)
- * csr41814 (Bluetooth)
- */
- n8x0_gpio_setup(s);
- n8x0_nand_setup(s);
- n8x0_i2c_setup(s);
- if (model == 800) {
- n800_tsc_kbd_setup(s);
- } else if (model == 810) {
- n810_tsc_setup(s);
- n810_kbd_setup(s);
- }
- n8x0_spi_setup(s);
- n8x0_dss_setup(s);
- n8x0_cbus_setup(s);
- n8x0_usb_setup(s);
-
- if (machine->kernel_filename) {
- /* Or at the linux loader. */
- arm_load_kernel(s->mpu->cpu, machine, binfo);
-
- qemu_register_reset(n8x0_boot_init, s);
- }
-
- if (option_rom[0].name &&
- (machine->boot_config.order[0] == 'n' || !machine->kernel_filename)) {
- uint8_t *nolo_tags = g_new(uint8_t, 0x10000);
- /* No, wait, better start at the ROM. */
- s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
-
- /*
- * This is intended for loading the `secondary.bin' program from
- * Nokia images (the NOLO bootloader). The entry point seems
- * to be at OMAP2_Q2_BASE + 0x400000.
- *
- * The `2nd.bin' files contain some kind of earlier boot code and
- * for them the entry point needs to be set to OMAP2_SRAM_BASE.
- *
- * The code above is for loading the `zImage' file from Nokia
- * images.
- */
- if (load_image_targphys(option_rom[0].name,
- OMAP2_Q2_BASE + 0x400000,
- machine->ram_size - 0x400000) < 0) {
- error_report("Failed to load secondary bootloader %s",
- option_rom[0].name);
- exit(EXIT_FAILURE);
- }
-
- n800_setup_nolo_tags(nolo_tags);
- cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
- g_free(nolo_tags);
- }
-}
-
-static struct arm_boot_info n800_binfo = {
- .loader_start = OMAP2_Q2_BASE,
- .board_id = 0x4f7,
- .atag_board = n800_atag_setup,
-};
-
-static struct arm_boot_info n810_binfo = {
- .loader_start = OMAP2_Q2_BASE,
- /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not
- * used by some older versions of the bootloader and 5555 is used
- * instead (including versions that shipped with many devices). */
- .board_id = 0x60c,
- .atag_board = n810_atag_setup,
-};
-
-static void n800_init(MachineState *machine)
-{
- n8x0_init(machine, &n800_binfo, 800);
-}
-
-static void n810_init(MachineState *machine)
-{
- n8x0_init(machine, &n810_binfo, 810);
-}
-
-static void n800_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)";
- mc->init = n800_init;
- mc->default_boot_order = "";
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm1136-r2");
- /* Actually two chips of 0x4000000 bytes each */
- mc->default_ram_size = 0x08000000;
- mc->default_ram_id = "omap2.dram";
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-static const TypeInfo n800_type = {
- .name = MACHINE_TYPE_NAME("n800"),
- .parent = TYPE_MACHINE,
- .class_init = n800_class_init,
-};
-
-static void n810_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)";
- mc->init = n810_init;
- mc->default_boot_order = "";
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm1136-r2");
- /* Actually two chips of 0x4000000 bytes each */
- mc->default_ram_size = 0x08000000;
- mc->default_ram_id = "omap2.dram";
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-static const TypeInfo n810_type = {
- .name = MACHINE_TYPE_NAME("n810"),
- .parent = TYPE_MACHINE,
- .class_init = n810_class_init,
-};
-
-static void nseries_machine_init(void)
-{
- type_register_static(&n800_type);
- type_register_static(&n810_type);
-}
-
-type_init(nseries_machine_init)
diff --git a/hw/arm/olimex-stm32-h405.c b/hw/arm/olimex-stm32-h405.c
index 4ad7b04..1f15620 100644
--- a/hw/arm/olimex-stm32-h405.c
+++ b/hw/arm/olimex-stm32-h405.c
@@ -51,7 +51,7 @@ static void olimex_stm32_h405_init(MachineState *machine)
qdev_connect_clock_in(dev, "sysclk", sysclk);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- armv7m_load_kernel(ARM_CPU(first_cpu),
+ armv7m_load_kernel(STM32F405_SOC(dev)->armv7m.cpu,
machine->kernel_filename,
0, FLASH_SIZE);
}
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 86ee336..74458fb 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -23,24 +23,26 @@
#include "qemu/main-loop.h"
#include "qapi/error.h"
#include "cpu.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/hw.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/arm/boot.h"
#include "hw/arm/omap.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
+#include "hw/sd/sd.h"
+#include "system/blockdev.h"
+#include "system/system.h"
#include "hw/arm/soc_dma.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/rtc.h"
+#include "system/qtest.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/rtc.h"
#include "qemu/range.h"
#include "hw/sysbus.h"
#include "qemu/cutils.h"
#include "qemu/bcd.h"
#include "target/arm/cpu-qom.h"
+#include "trace.h"
static inline void omap_log_badwidth(const char *funcname, hwaddr addr, int sz)
{
@@ -142,7 +144,7 @@ static inline void omap_timer_update(struct omap_mpu_timer_s *timer)
int64_t expires;
if (timer->enable && timer->st && timer->rate) {
- timer->val = timer->reset_val; /* Should skip this on clk enable */
+ timer->val = timer->reset_val; /* Should skip this on clk enable */
expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1),
NANOSECONDS_PER_SECOND, timer->rate);
@@ -210,13 +212,13 @@ static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* CNTL_TIMER */
+ case 0x00: /* CNTL_TIMER */
return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st;
- case 0x04: /* LOAD_TIM */
+ case 0x04: /* LOAD_TIM */
break;
- case 0x08: /* READ_TIM */
+ case 0x08: /* READ_TIM */
return omap_timer_read(s);
}
@@ -235,7 +237,7 @@ static void omap_mpu_timer_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* CNTL_TIMER */
+ case 0x00: /* CNTL_TIMER */
omap_timer_sync(s);
s->enable = (value >> 5) & 1;
s->ptv = (value >> 2) & 7;
@@ -244,11 +246,11 @@ static void omap_mpu_timer_write(void *opaque, hwaddr addr,
omap_timer_update(s);
return;
- case 0x04: /* LOAD_TIM */
+ case 0x04: /* LOAD_TIM */
s->reset_val = value;
return;
- case 0x08: /* READ_TIM */
+ case 0x08: /* READ_TIM */
OMAP_RO_REG(addr);
break;
@@ -316,14 +318,14 @@ static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* CNTL_TIMER */
+ case 0x00: /* CNTL_TIMER */
return (s->timer.ptv << 9) | (s->timer.ar << 8) |
(s->timer.st << 7) | (s->free << 1);
- case 0x04: /* READ_TIMER */
+ case 0x04: /* READ_TIMER */
return omap_timer_read(&s->timer);
- case 0x08: /* TIMER_MODE */
+ case 0x08: /* TIMER_MODE */
return s->mode << 15;
}
@@ -342,7 +344,7 @@ static void omap_wd_timer_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* CNTL_TIMER */
+ case 0x00: /* CNTL_TIMER */
omap_timer_sync(&s->timer);
s->timer.ptv = (value >> 9) & 7;
s->timer.ar = (value >> 8) & 1;
@@ -351,11 +353,11 @@ static void omap_wd_timer_write(void *opaque, hwaddr addr,
omap_timer_update(&s->timer);
break;
- case 0x04: /* LOAD_TIMER */
+ case 0x04: /* LOAD_TIMER */
s->timer.reset_val = value & 0xffff;
break;
- case 0x08: /* TIMER_MODE */
+ case 0x08: /* TIMER_MODE */
if (!s->mode && ((value >> 15) & 1))
omap_clk_get(s->timer.clk);
s->mode |= (value >> 15) & 1;
@@ -440,13 +442,13 @@ static uint64_t omap_os_timer_read(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* TVR */
+ case 0x00: /* TVR */
return s->timer.reset_val;
- case 0x04: /* TCR */
+ case 0x04: /* TCR */
return omap_timer_read(&s->timer);
- case 0x08: /* CR */
+ case 0x08: /* CR */
return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st;
default:
@@ -468,15 +470,15 @@ static void omap_os_timer_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* TVR */
+ case 0x00: /* TVR */
s->timer.reset_val = value & 0x00ffffff;
break;
- case 0x04: /* TCR */
+ case 0x04: /* TCR */
OMAP_RO_REG(addr);
break;
- case 0x08: /* CR */
+ case 0x08: /* CR */
s->timer.ar = (value >> 3) & 1;
s->timer.it_ena = (value >> 2) & 1;
if (s->timer.st != (value & 1) || (value & 2)) {
@@ -541,34 +543,34 @@ static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x14: /* IT_STATUS */
+ case 0x14: /* IT_STATUS */
ret = s->ulpd_pm_regs[addr >> 2];
s->ulpd_pm_regs[addr >> 2] = 0;
qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
return ret;
- case 0x18: /* Reserved */
- case 0x1c: /* Reserved */
- case 0x20: /* Reserved */
- case 0x28: /* Reserved */
- case 0x2c: /* Reserved */
+ case 0x18: /* Reserved */
+ case 0x1c: /* Reserved */
+ case 0x20: /* Reserved */
+ case 0x28: /* Reserved */
+ case 0x2c: /* Reserved */
OMAP_BAD_REG(addr);
/* fall through */
- case 0x00: /* COUNTER_32_LSB */
- case 0x04: /* COUNTER_32_MSB */
- case 0x08: /* COUNTER_HIGH_FREQ_LSB */
- case 0x0c: /* COUNTER_HIGH_FREQ_MSB */
- case 0x10: /* GAUGING_CTRL */
- case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */
- case 0x30: /* CLOCK_CTRL */
- case 0x34: /* SOFT_REQ */
- case 0x38: /* COUNTER_32_FIQ */
- case 0x3c: /* DPLL_CTRL */
- case 0x40: /* STATUS_REQ */
+ case 0x00: /* COUNTER_32_LSB */
+ case 0x04: /* COUNTER_32_MSB */
+ case 0x08: /* COUNTER_HIGH_FREQ_LSB */
+ case 0x0c: /* COUNTER_HIGH_FREQ_MSB */
+ case 0x10: /* GAUGING_CTRL */
+ case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */
+ case 0x30: /* CLOCK_CTRL */
+ case 0x34: /* SOFT_REQ */
+ case 0x38: /* COUNTER_32_FIQ */
+ case 0x3c: /* DPLL_CTRL */
+ case 0x40: /* STATUS_REQ */
/* XXX: check clk::usecount state for every clock */
- case 0x48: /* LOCL_TIME */
- case 0x4c: /* APLL_CTRL */
- case 0x50: /* POWER_CTRL */
+ case 0x48: /* LOCL_TIME */
+ case 0x4c: /* APLL_CTRL */
+ case 0x50: /* POWER_CTRL */
return s->ulpd_pm_regs[addr >> 2];
}
@@ -579,22 +581,22 @@ static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr,
static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s,
uint16_t diff, uint16_t value)
{
- if (diff & (1 << 4)) /* USB_MCLK_EN */
+ if (diff & (1 << 4)) /* USB_MCLK_EN */
omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1);
- if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */
+ if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */
omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1);
}
static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s,
uint16_t diff, uint16_t value)
{
- if (diff & (1 << 0)) /* SOFT_DPLL_REQ */
+ if (diff & (1 << 0)) /* SOFT_DPLL_REQ */
omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1);
- if (diff & (1 << 1)) /* SOFT_COM_REQ */
+ if (diff & (1 << 1)) /* SOFT_COM_REQ */
omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1);
- if (diff & (1 << 2)) /* SOFT_SDW_REQ */
+ if (diff & (1 << 2)) /* SOFT_SDW_REQ */
omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1);
- if (diff & (1 << 3)) /* SOFT_USB_REQ */
+ if (diff & (1 << 3)) /* SOFT_USB_REQ */
omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1);
}
@@ -613,16 +615,16 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* COUNTER_32_LSB */
- case 0x04: /* COUNTER_32_MSB */
- case 0x08: /* COUNTER_HIGH_FREQ_LSB */
- case 0x0c: /* COUNTER_HIGH_FREQ_MSB */
- case 0x14: /* IT_STATUS */
- case 0x40: /* STATUS_REQ */
+ case 0x00: /* COUNTER_32_LSB */
+ case 0x04: /* COUNTER_32_MSB */
+ case 0x08: /* COUNTER_HIGH_FREQ_LSB */
+ case 0x0c: /* COUNTER_HIGH_FREQ_MSB */
+ case 0x14: /* IT_STATUS */
+ case 0x40: /* STATUS_REQ */
OMAP_RO_REG(addr);
break;
- case 0x10: /* GAUGING_CTRL */
+ case 0x10: /* GAUGING_CTRL */
/* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */
if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) {
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -636,50 +638,50 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr,
ticks = muldiv64(now, 32768, NANOSECONDS_PER_SECOND);
s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff;
s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff;
- if (ticks >> 32) /* OVERFLOW_32K */
+ if (ticks >> 32) /* OVERFLOW_32K */
s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2;
/* High frequency ticks */
ticks = muldiv64(now, 12000000, NANOSECONDS_PER_SECOND);
s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff;
s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff;
- if (ticks >> 32) /* OVERFLOW_HI_FREQ */
+ if (ticks >> 32) /* OVERFLOW_HI_FREQ */
s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
- s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */
+ s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */
qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
}
}
s->ulpd_pm_regs[addr >> 2] = value;
break;
- case 0x18: /* Reserved */
- case 0x1c: /* Reserved */
- case 0x20: /* Reserved */
- case 0x28: /* Reserved */
- case 0x2c: /* Reserved */
+ case 0x18: /* Reserved */
+ case 0x1c: /* Reserved */
+ case 0x20: /* Reserved */
+ case 0x28: /* Reserved */
+ case 0x2c: /* Reserved */
OMAP_BAD_REG(addr);
/* fall through */
- case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */
- case 0x38: /* COUNTER_32_FIQ */
- case 0x48: /* LOCL_TIME */
- case 0x50: /* POWER_CTRL */
+ case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */
+ case 0x38: /* COUNTER_32_FIQ */
+ case 0x48: /* LOCL_TIME */
+ case 0x50: /* POWER_CTRL */
s->ulpd_pm_regs[addr >> 2] = value;
break;
- case 0x30: /* CLOCK_CTRL */
+ case 0x30: /* CLOCK_CTRL */
diff = s->ulpd_pm_regs[addr >> 2] ^ value;
s->ulpd_pm_regs[addr >> 2] = value & 0x3f;
omap_ulpd_clk_update(s, diff, value);
break;
- case 0x34: /* SOFT_REQ */
+ case 0x34: /* SOFT_REQ */
diff = s->ulpd_pm_regs[addr >> 2] ^ value;
s->ulpd_pm_regs[addr >> 2] = value & 0x1f;
omap_ulpd_req_update(s, diff, value);
break;
- case 0x3c: /* DPLL_CTRL */
+ case 0x3c: /* DPLL_CTRL */
/* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is
* omitted altogether, probably a typo. */
/* This register has identical semantics with DPLL(1:3) control
@@ -687,11 +689,11 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr,
diff = s->ulpd_pm_regs[addr >> 2] & value;
s->ulpd_pm_regs[addr >> 2] = value & 0x2fff;
if (diff & (0x3ff << 2)) {
- if (value & (1 << 4)) { /* PLL_ENABLE */
- div = ((value >> 5) & 3) + 1; /* PLL_DIV */
- mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */
+ if (value & (1 << 4)) { /* PLL_ENABLE */
+ div = ((value >> 5) & 3) + 1; /* PLL_DIV */
+ mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */
} else {
- div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */
+ div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */
mult = 1;
}
omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult);
@@ -706,10 +708,10 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr,
s->ulpd_pm_regs[addr >> 2] |= 2;
break;
- case 0x4c: /* APLL_CTRL */
+ case 0x4c: /* APLL_CTRL */
diff = s->ulpd_pm_regs[addr >> 2] & value;
s->ulpd_pm_regs[addr >> 2] = value & 0xf;
- if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */
+ if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */
omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s,
(value & (1 << 0)) ? "apll" : "dpll4"));
break;
@@ -773,43 +775,43 @@ static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* FUNC_MUX_CTRL_0 */
- case 0x04: /* FUNC_MUX_CTRL_1 */
- case 0x08: /* FUNC_MUX_CTRL_2 */
+ case 0x00: /* FUNC_MUX_CTRL_0 */
+ case 0x04: /* FUNC_MUX_CTRL_1 */
+ case 0x08: /* FUNC_MUX_CTRL_2 */
return s->func_mux_ctrl[addr >> 2];
- case 0x0c: /* COMP_MODE_CTRL_0 */
+ case 0x0c: /* COMP_MODE_CTRL_0 */
return s->comp_mode_ctrl[0];
- case 0x10: /* FUNC_MUX_CTRL_3 */
- case 0x14: /* FUNC_MUX_CTRL_4 */
- case 0x18: /* FUNC_MUX_CTRL_5 */
- case 0x1c: /* FUNC_MUX_CTRL_6 */
- case 0x20: /* FUNC_MUX_CTRL_7 */
- case 0x24: /* FUNC_MUX_CTRL_8 */
- case 0x28: /* FUNC_MUX_CTRL_9 */
- case 0x2c: /* FUNC_MUX_CTRL_A */
- case 0x30: /* FUNC_MUX_CTRL_B */
- case 0x34: /* FUNC_MUX_CTRL_C */
- case 0x38: /* FUNC_MUX_CTRL_D */
+ case 0x10: /* FUNC_MUX_CTRL_3 */
+ case 0x14: /* FUNC_MUX_CTRL_4 */
+ case 0x18: /* FUNC_MUX_CTRL_5 */
+ case 0x1c: /* FUNC_MUX_CTRL_6 */
+ case 0x20: /* FUNC_MUX_CTRL_7 */
+ case 0x24: /* FUNC_MUX_CTRL_8 */
+ case 0x28: /* FUNC_MUX_CTRL_9 */
+ case 0x2c: /* FUNC_MUX_CTRL_A */
+ case 0x30: /* FUNC_MUX_CTRL_B */
+ case 0x34: /* FUNC_MUX_CTRL_C */
+ case 0x38: /* FUNC_MUX_CTRL_D */
return s->func_mux_ctrl[(addr >> 2) - 1];
- case 0x40: /* PULL_DWN_CTRL_0 */
- case 0x44: /* PULL_DWN_CTRL_1 */
- case 0x48: /* PULL_DWN_CTRL_2 */
- case 0x4c: /* PULL_DWN_CTRL_3 */
+ case 0x40: /* PULL_DWN_CTRL_0 */
+ case 0x44: /* PULL_DWN_CTRL_1 */
+ case 0x48: /* PULL_DWN_CTRL_2 */
+ case 0x4c: /* PULL_DWN_CTRL_3 */
return s->pull_dwn_ctrl[(addr & 0xf) >> 2];
- case 0x50: /* GATE_INH_CTRL_0 */
+ case 0x50: /* GATE_INH_CTRL_0 */
return s->gate_inh_ctrl[0];
- case 0x60: /* VOLTAGE_CTRL_0 */
+ case 0x60: /* VOLTAGE_CTRL_0 */
return s->voltage_ctrl[0];
- case 0x70: /* TEST_DBG_CTRL_0 */
+ case 0x70: /* TEST_DBG_CTRL_0 */
return s->test_dbg_ctrl[0];
- case 0x80: /* MOD_CONF_CTRL_0 */
+ case 0x80: /* MOD_CONF_CTRL_0 */
return s->mod_conf_ctrl[0];
}
@@ -821,10 +823,10 @@ static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s,
uint32_t diff, uint32_t value)
{
if (s->compat1509) {
- if (diff & (1 << 9)) /* BLUETOOTH */
+ if (diff & (1 << 9)) /* BLUETOOTH */
omap_clk_onoff(omap_findclk(s, "bt_mclk_out"),
(~value >> 9) & 1);
- if (diff & (1 << 7)) /* USB.CLKO */
+ if (diff & (1 << 7)) /* USB.CLKO */
omap_clk_onoff(omap_findclk(s, "usb.clko"),
(value >> 7) & 1);
}
@@ -854,23 +856,23 @@ static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
omap_findclk(s, ((value >> 31) & 1) ?
"ck_48m" : "armper_ck"));
}
- if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */
+ if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */
omap_clk_reparent(omap_findclk(s, "uart2_ck"),
omap_findclk(s, ((value >> 30) & 1) ?
"ck_48m" : "armper_ck"));
- if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */
+ if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */
omap_clk_reparent(omap_findclk(s, "uart1_ck"),
omap_findclk(s, ((value >> 29) & 1) ?
"ck_48m" : "armper_ck"));
- if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */
+ if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */
omap_clk_reparent(omap_findclk(s, "mmc_ck"),
omap_findclk(s, ((value >> 23) & 1) ?
"ck_48m" : "armper_ck"));
- if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */
+ if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */
omap_clk_reparent(omap_findclk(s, "com_mclk_out"),
omap_findclk(s, ((value >> 12) & 1) ?
"ck_48m" : "armper_ck"));
- if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */
+ if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */
omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1);
}
@@ -886,63 +888,63 @@ static void omap_pin_cfg_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* FUNC_MUX_CTRL_0 */
+ case 0x00: /* FUNC_MUX_CTRL_0 */
diff = s->func_mux_ctrl[addr >> 2] ^ value;
s->func_mux_ctrl[addr >> 2] = value;
omap_pin_funcmux0_update(s, diff, value);
return;
- case 0x04: /* FUNC_MUX_CTRL_1 */
+ case 0x04: /* FUNC_MUX_CTRL_1 */
diff = s->func_mux_ctrl[addr >> 2] ^ value;
s->func_mux_ctrl[addr >> 2] = value;
omap_pin_funcmux1_update(s, diff, value);
return;
- case 0x08: /* FUNC_MUX_CTRL_2 */
+ case 0x08: /* FUNC_MUX_CTRL_2 */
s->func_mux_ctrl[addr >> 2] = value;
return;
- case 0x0c: /* COMP_MODE_CTRL_0 */
+ case 0x0c: /* COMP_MODE_CTRL_0 */
s->comp_mode_ctrl[0] = value;
s->compat1509 = (value != 0x0000eaef);
omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]);
omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]);
return;
- case 0x10: /* FUNC_MUX_CTRL_3 */
- case 0x14: /* FUNC_MUX_CTRL_4 */
- case 0x18: /* FUNC_MUX_CTRL_5 */
- case 0x1c: /* FUNC_MUX_CTRL_6 */
- case 0x20: /* FUNC_MUX_CTRL_7 */
- case 0x24: /* FUNC_MUX_CTRL_8 */
- case 0x28: /* FUNC_MUX_CTRL_9 */
- case 0x2c: /* FUNC_MUX_CTRL_A */
- case 0x30: /* FUNC_MUX_CTRL_B */
- case 0x34: /* FUNC_MUX_CTRL_C */
- case 0x38: /* FUNC_MUX_CTRL_D */
+ case 0x10: /* FUNC_MUX_CTRL_3 */
+ case 0x14: /* FUNC_MUX_CTRL_4 */
+ case 0x18: /* FUNC_MUX_CTRL_5 */
+ case 0x1c: /* FUNC_MUX_CTRL_6 */
+ case 0x20: /* FUNC_MUX_CTRL_7 */
+ case 0x24: /* FUNC_MUX_CTRL_8 */
+ case 0x28: /* FUNC_MUX_CTRL_9 */
+ case 0x2c: /* FUNC_MUX_CTRL_A */
+ case 0x30: /* FUNC_MUX_CTRL_B */
+ case 0x34: /* FUNC_MUX_CTRL_C */
+ case 0x38: /* FUNC_MUX_CTRL_D */
s->func_mux_ctrl[(addr >> 2) - 1] = value;
return;
- case 0x40: /* PULL_DWN_CTRL_0 */
- case 0x44: /* PULL_DWN_CTRL_1 */
- case 0x48: /* PULL_DWN_CTRL_2 */
- case 0x4c: /* PULL_DWN_CTRL_3 */
+ case 0x40: /* PULL_DWN_CTRL_0 */
+ case 0x44: /* PULL_DWN_CTRL_1 */
+ case 0x48: /* PULL_DWN_CTRL_2 */
+ case 0x4c: /* PULL_DWN_CTRL_3 */
s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value;
return;
- case 0x50: /* GATE_INH_CTRL_0 */
+ case 0x50: /* GATE_INH_CTRL_0 */
s->gate_inh_ctrl[0] = value;
return;
- case 0x60: /* VOLTAGE_CTRL_0 */
+ case 0x60: /* VOLTAGE_CTRL_0 */
s->voltage_ctrl[0] = value;
return;
- case 0x70: /* TEST_DBG_CTRL_0 */
+ case 0x70: /* TEST_DBG_CTRL_0 */
s->test_dbg_ctrl[0] = value;
return;
- case 0x80: /* MOD_CONF_CTRL_0 */
+ case 0x80: /* MOD_CONF_CTRL_0 */
diff = s->mod_conf_ctrl[0] ^ value;
s->mod_conf_ctrl[0] = value;
omap_pin_modconf1_update(s, diff, value);
@@ -996,17 +998,17 @@ static uint64_t omap_id_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0xfffe1800: /* DIE_ID_LSB */
+ case 0xfffe1800: /* DIE_ID_LSB */
return 0xc9581f0e;
- case 0xfffe1804: /* DIE_ID_MSB */
+ case 0xfffe1804: /* DIE_ID_MSB */
return 0xa8858bfa;
- case 0xfffe2000: /* PRODUCT_ID_LSB */
+ case 0xfffe2000: /* PRODUCT_ID_LSB */
return 0x00aaaafc;
- case 0xfffe2004: /* PRODUCT_ID_MSB */
+ case 0xfffe2004: /* PRODUCT_ID_MSB */
return 0xcafeb574;
- case 0xfffed400: /* JTAG_ID_LSB */
+ case 0xfffed400: /* JTAG_ID_LSB */
switch (s->mpu_model) {
case omap310:
return 0x03310315;
@@ -1017,7 +1019,7 @@ static uint64_t omap_id_read(void *opaque, hwaddr addr,
}
break;
- case 0xfffed404: /* JTAG_ID_MSB */
+ case 0xfffed404: /* JTAG_ID_MSB */
switch (s->mpu_model) {
case omap310:
return 0xfb57402f;
@@ -1078,22 +1080,22 @@ static uint64_t omap_mpui_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* CTRL */
+ case 0x00: /* CTRL */
return s->mpui_ctrl;
- case 0x04: /* DEBUG_ADDR */
+ case 0x04: /* DEBUG_ADDR */
return 0x01ffffff;
- case 0x08: /* DEBUG_DATA */
+ case 0x08: /* DEBUG_DATA */
return 0xffffffff;
- case 0x0c: /* DEBUG_FLAG */
+ case 0x0c: /* DEBUG_FLAG */
return 0x00000800;
- case 0x10: /* STATUS */
+ case 0x10: /* STATUS */
return 0x00000000;
/* Not in OMAP310 */
- case 0x14: /* DSP_STATUS */
- case 0x18: /* DSP_BOOT_CONFIG */
+ case 0x14: /* DSP_STATUS */
+ case 0x18: /* DSP_BOOT_CONFIG */
return 0x00000000;
- case 0x1c: /* DSP_MPUI_CONFIG */
+ case 0x1c: /* DSP_MPUI_CONFIG */
return 0x0000ffff;
}
@@ -1112,20 +1114,20 @@ static void omap_mpui_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* CTRL */
+ case 0x00: /* CTRL */
s->mpui_ctrl = value & 0x007fffff;
break;
- case 0x04: /* DEBUG_ADDR */
- case 0x08: /* DEBUG_DATA */
- case 0x0c: /* DEBUG_FLAG */
- case 0x10: /* STATUS */
+ case 0x04: /* DEBUG_ADDR */
+ case 0x08: /* DEBUG_DATA */
+ case 0x0c: /* DEBUG_FLAG */
+ case 0x10: /* STATUS */
/* Not in OMAP310 */
- case 0x14: /* DSP_STATUS */
+ case 0x14: /* DSP_STATUS */
OMAP_RO_REG(addr);
break;
- case 0x18: /* DSP_BOOT_CONFIG */
- case 0x1c: /* DSP_MPUI_CONFIG */
+ case 0x18: /* DSP_BOOT_CONFIG */
+ case 0x1c: /* DSP_MPUI_CONFIG */
break;
default:
@@ -1176,19 +1178,19 @@ static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* TIPB_CNTL */
+ case 0x00: /* TIPB_CNTL */
return s->control;
- case 0x04: /* TIPB_BUS_ALLOC */
+ case 0x04: /* TIPB_BUS_ALLOC */
return s->alloc;
- case 0x08: /* MPU_TIPB_CNTL */
+ case 0x08: /* MPU_TIPB_CNTL */
return s->buffer;
- case 0x0c: /* ENHANCED_TIPB_CNTL */
+ case 0x0c: /* ENHANCED_TIPB_CNTL */
return s->enh_control;
- case 0x10: /* ADDRESS_DBG */
- case 0x14: /* DATA_DEBUG_LOW */
- case 0x18: /* DATA_DEBUG_HIGH */
+ case 0x10: /* ADDRESS_DBG */
+ case 0x14: /* DATA_DEBUG_LOW */
+ case 0x18: /* DATA_DEBUG_HIGH */
return 0xffff;
- case 0x1c: /* DEBUG_CNTR_SIG */
+ case 0x1c: /* DEBUG_CNTR_SIG */
return 0x00f8;
}
@@ -1207,27 +1209,27 @@ static void omap_tipb_bridge_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* TIPB_CNTL */
+ case 0x00: /* TIPB_CNTL */
s->control = value & 0xffff;
break;
- case 0x04: /* TIPB_BUS_ALLOC */
+ case 0x04: /* TIPB_BUS_ALLOC */
s->alloc = value & 0x003f;
break;
- case 0x08: /* MPU_TIPB_CNTL */
+ case 0x08: /* MPU_TIPB_CNTL */
s->buffer = value & 0x0003;
break;
- case 0x0c: /* ENHANCED_TIPB_CNTL */
+ case 0x0c: /* ENHANCED_TIPB_CNTL */
s->width_intr = !(value & 2);
s->enh_control = value & 0x000f;
break;
- case 0x10: /* ADDRESS_DBG */
- case 0x14: /* DATA_DEBUG_LOW */
- case 0x18: /* DATA_DEBUG_HIGH */
- case 0x1c: /* DEBUG_CNTR_SIG */
+ case 0x10: /* ADDRESS_DBG */
+ case 0x14: /* DATA_DEBUG_LOW */
+ case 0x18: /* DATA_DEBUG_HIGH */
+ case 0x1c: /* DEBUG_CNTR_SIG */
OMAP_RO_REG(addr);
break;
@@ -1278,23 +1280,23 @@ static uint64_t omap_tcmi_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* IMIF_PRIO */
- case 0x04: /* EMIFS_PRIO */
- case 0x08: /* EMIFF_PRIO */
- case 0x0c: /* EMIFS_CONFIG */
- case 0x10: /* EMIFS_CS0_CONFIG */
- case 0x14: /* EMIFS_CS1_CONFIG */
- case 0x18: /* EMIFS_CS2_CONFIG */
- case 0x1c: /* EMIFS_CS3_CONFIG */
- case 0x24: /* EMIFF_MRS */
- case 0x28: /* TIMEOUT1 */
- case 0x2c: /* TIMEOUT2 */
- case 0x30: /* TIMEOUT3 */
- case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */
- case 0x40: /* EMIFS_CFG_DYN_WAIT */
+ case 0x00: /* IMIF_PRIO */
+ case 0x04: /* EMIFS_PRIO */
+ case 0x08: /* EMIFF_PRIO */
+ case 0x0c: /* EMIFS_CONFIG */
+ case 0x10: /* EMIFS_CS0_CONFIG */
+ case 0x14: /* EMIFS_CS1_CONFIG */
+ case 0x18: /* EMIFS_CS2_CONFIG */
+ case 0x1c: /* EMIFS_CS3_CONFIG */
+ case 0x24: /* EMIFF_MRS */
+ case 0x28: /* TIMEOUT1 */
+ case 0x2c: /* TIMEOUT2 */
+ case 0x30: /* TIMEOUT3 */
+ case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */
+ case 0x40: /* EMIFS_CFG_DYN_WAIT */
return s->tcmi_regs[addr >> 2];
- case 0x20: /* EMIFF_SDRAM_CONFIG */
+ case 0x20: /* EMIFF_SDRAM_CONFIG */
ret = s->tcmi_regs[addr >> 2];
s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */
/* XXX: We can try using the VGA_DIRTY flag for this */
@@ -1316,23 +1318,23 @@ static void omap_tcmi_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* IMIF_PRIO */
- case 0x04: /* EMIFS_PRIO */
- case 0x08: /* EMIFF_PRIO */
- case 0x10: /* EMIFS_CS0_CONFIG */
- case 0x14: /* EMIFS_CS1_CONFIG */
- case 0x18: /* EMIFS_CS2_CONFIG */
- case 0x1c: /* EMIFS_CS3_CONFIG */
- case 0x20: /* EMIFF_SDRAM_CONFIG */
- case 0x24: /* EMIFF_MRS */
- case 0x28: /* TIMEOUT1 */
- case 0x2c: /* TIMEOUT2 */
- case 0x30: /* TIMEOUT3 */
- case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */
- case 0x40: /* EMIFS_CFG_DYN_WAIT */
+ case 0x00: /* IMIF_PRIO */
+ case 0x04: /* EMIFS_PRIO */
+ case 0x08: /* EMIFF_PRIO */
+ case 0x10: /* EMIFS_CS0_CONFIG */
+ case 0x14: /* EMIFS_CS1_CONFIG */
+ case 0x18: /* EMIFS_CS2_CONFIG */
+ case 0x1c: /* EMIFS_CS3_CONFIG */
+ case 0x20: /* EMIFF_SDRAM_CONFIG */
+ case 0x24: /* EMIFF_MRS */
+ case 0x28: /* TIMEOUT1 */
+ case 0x2c: /* TIMEOUT2 */
+ case 0x30: /* TIMEOUT3 */
+ case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */
+ case 0x40: /* EMIFS_CFG_DYN_WAIT */
s->tcmi_regs[addr >> 2] = value;
break;
- case 0x0c: /* EMIFS_CONFIG */
+ case 0x0c: /* EMIFS_CONFIG */
s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4);
break;
@@ -1391,7 +1393,7 @@ static uint64_t omap_dpll_read(void *opaque, hwaddr addr,
return omap_badwidth_read16(opaque, addr);
}
- if (addr == 0x00) /* CTL_REG */
+ if (addr == 0x00) /* CTL_REG */
return s->mode;
OMAP_BAD_REG(addr);
@@ -1411,16 +1413,16 @@ static void omap_dpll_write(void *opaque, hwaddr addr,
return;
}
- if (addr == 0x00) { /* CTL_REG */
+ if (addr == 0x00) { /* CTL_REG */
/* See omap_ulpd_pm_write() too */
diff = s->mode & value;
s->mode = value & 0x2fff;
if (diff & (0x3ff << 2)) {
- if (value & (1 << 4)) { /* PLL_ENABLE */
- div = ((value >> 5) & 3) + 1; /* PLL_DIV */
- mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */
+ if (value & (1 << 4)) { /* PLL_ENABLE */
+ div = ((value >> 5) & 3) + 1; /* PLL_DIV */
+ mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */
} else {
- div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */
+ div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */
mult = 1;
}
omap_clk_setrate(s->dpll, div, mult);
@@ -1472,31 +1474,31 @@ static uint64_t omap_clkm_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* ARM_CKCTL */
+ case 0x00: /* ARM_CKCTL */
return s->clkm.arm_ckctl;
- case 0x04: /* ARM_IDLECT1 */
+ case 0x04: /* ARM_IDLECT1 */
return s->clkm.arm_idlect1;
- case 0x08: /* ARM_IDLECT2 */
+ case 0x08: /* ARM_IDLECT2 */
return s->clkm.arm_idlect2;
- case 0x0c: /* ARM_EWUPCT */
+ case 0x0c: /* ARM_EWUPCT */
return s->clkm.arm_ewupct;
- case 0x10: /* ARM_RSTCT1 */
+ case 0x10: /* ARM_RSTCT1 */
return s->clkm.arm_rstct1;
- case 0x14: /* ARM_RSTCT2 */
+ case 0x14: /* ARM_RSTCT2 */
return s->clkm.arm_rstct2;
- case 0x18: /* ARM_SYSST */
+ case 0x18: /* ARM_SYSST */
return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start;
- case 0x1c: /* ARM_CKOUT1 */
+ case 0x1c: /* ARM_CKOUT1 */
return s->clkm.arm_ckout1;
- case 0x20: /* ARM_CKOUT2 */
+ case 0x20: /* ARM_CKOUT2 */
break;
}
@@ -1509,7 +1511,7 @@ static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s,
{
omap_clk clk;
- if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */
+ if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */
if (value & (1 << 14))
/* Reserved */;
else {
@@ -1517,7 +1519,7 @@ static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s,
omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
}
}
- if (diff & (1 << 12)) { /* ARM_TIMXO */
+ if (diff & (1 << 12)) { /* ARM_TIMXO */
clk = omap_findclk(s, "armtim_ck");
if (value & (1 << 12))
omap_clk_reparent(clk, omap_findclk(s, "clkin"));
@@ -1525,27 +1527,27 @@ static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s,
omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
}
/* XXX: en_dspck */
- if (diff & (3 << 10)) { /* DSPMMUDIV */
+ if (diff & (3 << 10)) { /* DSPMMUDIV */
clk = omap_findclk(s, "dspmmu_ck");
omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1);
}
- if (diff & (3 << 8)) { /* TCDIV */
+ if (diff & (3 << 8)) { /* TCDIV */
clk = omap_findclk(s, "tc_ck");
omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1);
}
- if (diff & (3 << 6)) { /* DSPDIV */
+ if (diff & (3 << 6)) { /* DSPDIV */
clk = omap_findclk(s, "dsp_ck");
omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1);
}
- if (diff & (3 << 4)) { /* ARMDIV */
+ if (diff & (3 << 4)) { /* ARMDIV */
clk = omap_findclk(s, "arm_ck");
omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1);
}
- if (diff & (3 << 2)) { /* LCDDIV */
+ if (diff & (3 << 2)) { /* LCDDIV */
clk = omap_findclk(s, "lcd_ck");
omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1);
}
- if (diff & (3 << 0)) { /* PERDIV */
+ if (diff & (3 << 0)) { /* PERDIV */
clk = omap_findclk(s, "armper_ck");
omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1);
}
@@ -1564,25 +1566,25 @@ static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s,
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
-#define SET_CANIDLE(clock, bit) \
- if (diff & (1 << bit)) { \
- clk = omap_findclk(s, clock); \
- omap_clk_canidle(clk, (value >> bit) & 1); \
+#define SET_CANIDLE(clock, bit) \
+ if (diff & (1 << bit)) { \
+ clk = omap_findclk(s, clock); \
+ omap_clk_canidle(clk, (value >> bit) & 1); \
}
- SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */
- SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */
- SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */
- SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */
- SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */
- SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */
- SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */
- SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */
- SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */
- SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */
- SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */
- SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */
- SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */
- SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */
+ SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */
+ SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */
+ SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */
+ SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */
+ SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */
+ SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */
+ SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */
+ SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */
+ SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */
+ SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */
+ SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */
+ SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */
+ SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */
+ SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */
}
static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s,
@@ -1590,22 +1592,22 @@ static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s,
{
omap_clk clk;
-#define SET_ONOFF(clock, bit) \
- if (diff & (1 << bit)) { \
- clk = omap_findclk(s, clock); \
- omap_clk_onoff(clk, (value >> bit) & 1); \
+#define SET_ONOFF(clock, bit) \
+ if (diff & (1 << bit)) { \
+ clk = omap_findclk(s, clock); \
+ omap_clk_onoff(clk, (value >> bit) & 1); \
}
- SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */
- SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */
- SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */
- SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */
- SET_ONOFF("lb_ck", 4) /* EN_LBCK */
- SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */
- SET_ONOFF("mpui_ck", 6) /* EN_APICK */
- SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */
- SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */
- SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */
- SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */
+ SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */
+ SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */
+ SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */
+ SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */
+ SET_ONOFF("lb_ck", 4) /* EN_LBCK */
+ SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */
+ SET_ONOFF("mpui_ck", 6) /* EN_APICK */
+ SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */
+ SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */
+ SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */
+ SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */
}
static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
@@ -1613,7 +1615,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
{
omap_clk clk;
- if (diff & (3 << 4)) { /* TCLKOUT */
+ if (diff & (3 << 4)) { /* TCLKOUT */
clk = omap_findclk(s, "tclk_out");
switch ((value >> 4) & 3) {
case 1:
@@ -1628,7 +1630,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
omap_clk_onoff(clk, 0);
}
}
- if (diff & (3 << 2)) { /* DCLKOUT */
+ if (diff & (3 << 2)) { /* DCLKOUT */
clk = omap_findclk(s, "dclk_out");
switch ((value >> 2) & 3) {
case 0:
@@ -1645,7 +1647,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
break;
}
}
- if (diff & (3 << 0)) { /* ACLKOUT */
+ if (diff & (3 << 0)) { /* ACLKOUT */
clk = omap_findclk(s, "aclk_out");
switch ((value >> 0) & 3) {
case 1:
@@ -1683,66 +1685,66 @@ static void omap_clkm_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x00: /* ARM_CKCTL */
+ case 0x00: /* ARM_CKCTL */
diff = s->clkm.arm_ckctl ^ value;
s->clkm.arm_ckctl = value & 0x7fff;
omap_clkm_ckctl_update(s, diff, value);
return;
- case 0x04: /* ARM_IDLECT1 */
+ case 0x04: /* ARM_IDLECT1 */
diff = s->clkm.arm_idlect1 ^ value;
s->clkm.arm_idlect1 = value & 0x0fff;
omap_clkm_idlect1_update(s, diff, value);
return;
- case 0x08: /* ARM_IDLECT2 */
+ case 0x08: /* ARM_IDLECT2 */
diff = s->clkm.arm_idlect2 ^ value;
s->clkm.arm_idlect2 = value & 0x07ff;
omap_clkm_idlect2_update(s, diff, value);
return;
- case 0x0c: /* ARM_EWUPCT */
+ case 0x0c: /* ARM_EWUPCT */
s->clkm.arm_ewupct = value & 0x003f;
return;
- case 0x10: /* ARM_RSTCT1 */
+ case 0x10: /* ARM_RSTCT1 */
diff = s->clkm.arm_rstct1 ^ value;
s->clkm.arm_rstct1 = value & 0x0007;
if (value & 9) {
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
s->clkm.cold_start = 0xa;
}
- if (diff & ~value & 4) { /* DSP_RST */
+ if (diff & ~value & 4) { /* DSP_RST */
omap_mpui_reset(s);
omap_tipb_bridge_reset(s->private_tipb);
omap_tipb_bridge_reset(s->public_tipb);
}
- if (diff & 2) { /* DSP_EN */
+ if (diff & 2) { /* DSP_EN */
clk = omap_findclk(s, "dsp_ck");
omap_clk_canidle(clk, (~value >> 1) & 1);
}
return;
- case 0x14: /* ARM_RSTCT2 */
+ case 0x14: /* ARM_RSTCT2 */
s->clkm.arm_rstct2 = value & 0x0001;
return;
- case 0x18: /* ARM_SYSST */
+ case 0x18: /* ARM_SYSST */
if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) {
s->clkm.clocking_scheme = (value >> 11) & 7;
- printf("%s: clocking scheme set to %s\n", __func__,
+ trace_omap1_pwl_clocking_scheme(
clkschemename[s->clkm.clocking_scheme]);
}
s->clkm.cold_start &= value & 0x3f;
return;
- case 0x1c: /* ARM_CKOUT1 */
+ case 0x1c: /* ARM_CKOUT1 */
diff = s->clkm.arm_ckout1 ^ value;
s->clkm.arm_ckout1 = value & 0x003f;
omap_clkm_ckout1_update(s, diff, value);
return;
- case 0x20: /* ARM_CKOUT2 */
+ case 0x20: /* ARM_CKOUT2 */
default:
OMAP_BAD_REG(addr);
}
@@ -1765,16 +1767,16 @@ static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x04: /* DSP_IDLECT1 */
+ case 0x04: /* DSP_IDLECT1 */
return s->clkm.dsp_idlect1;
- case 0x08: /* DSP_IDLECT2 */
+ case 0x08: /* DSP_IDLECT2 */
return s->clkm.dsp_idlect2;
- case 0x14: /* DSP_RSTCT2 */
+ case 0x14: /* DSP_RSTCT2 */
return s->clkm.dsp_rstct2;
- case 0x18: /* DSP_SYSST */
+ case 0x18: /* DSP_SYSST */
return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start |
(cpu->halted << 6); /* Quite useless... */
}
@@ -1788,7 +1790,7 @@ static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s,
{
omap_clk clk;
- SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */
+ SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */
}
static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
@@ -1796,7 +1798,7 @@ static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
{
omap_clk clk;
- SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */
+ SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */
}
static void omap_clkdsp_write(void *opaque, hwaddr addr,
@@ -1811,23 +1813,23 @@ static void omap_clkdsp_write(void *opaque, hwaddr addr,
}
switch (addr) {
- case 0x04: /* DSP_IDLECT1 */
+ case 0x04: /* DSP_IDLECT1 */
diff = s->clkm.dsp_idlect1 ^ value;
s->clkm.dsp_idlect1 = value & 0x01f7;
omap_clkdsp_idlect1_update(s, diff, value);
break;
- case 0x08: /* DSP_IDLECT2 */
+ case 0x08: /* DSP_IDLECT2 */
s->clkm.dsp_idlect2 = value & 0x0037;
diff = s->clkm.dsp_idlect1 ^ value;
omap_clkdsp_idlect2_update(s, diff, value);
break;
- case 0x14: /* DSP_RSTCT2 */
+ case 0x14: /* DSP_RSTCT2 */
s->clkm.dsp_rstct2 = value & 0x0001;
break;
- case 0x18: /* DSP_SYSST */
+ case 0x18: /* DSP_SYSST */
s->clkm.cold_start &= value & 0x3f;
break;
@@ -1926,8 +1928,8 @@ static void omap_mpuio_set(void *opaque, int line, int level)
qemu_irq_raise(s->irq);
/* TODO: wakeup */
}
- if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */
- (s->event >> 1) == line) /* PIN_SELECT */
+ if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */
+ (s->event >> 1) == line) /* PIN_SELECT */
s->latch = s->inputs;
}
}
@@ -1957,47 +1959,47 @@ static uint64_t omap_mpuio_read(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* INPUT_LATCH */
+ case 0x00: /* INPUT_LATCH */
return s->inputs;
- case 0x04: /* OUTPUT_REG */
+ case 0x04: /* OUTPUT_REG */
return s->outputs;
- case 0x08: /* IO_CNTL */
+ case 0x08: /* IO_CNTL */
return s->dir;
- case 0x10: /* KBR_LATCH */
+ case 0x10: /* KBR_LATCH */
return s->row_latch;
- case 0x14: /* KBC_REG */
+ case 0x14: /* KBC_REG */
return s->cols;
- case 0x18: /* GPIO_EVENT_MODE_REG */
+ case 0x18: /* GPIO_EVENT_MODE_REG */
return s->event;
- case 0x1c: /* GPIO_INT_EDGE_REG */
+ case 0x1c: /* GPIO_INT_EDGE_REG */
return s->edge;
- case 0x20: /* KBD_INT */
+ case 0x20: /* KBD_INT */
return (~s->row_latch & 0x1f) && !s->kbd_mask;
- case 0x24: /* GPIO_INT */
+ case 0x24: /* GPIO_INT */
ret = s->ints;
s->ints &= s->mask;
if (ret)
qemu_irq_lower(s->irq);
return ret;
- case 0x28: /* KBD_MASKIT */
+ case 0x28: /* KBD_MASKIT */
return s->kbd_mask;
- case 0x2c: /* GPIO_MASKIT */
+ case 0x2c: /* GPIO_MASKIT */
return s->mask;
- case 0x30: /* GPIO_DEBOUNCING_REG */
+ case 0x30: /* GPIO_DEBOUNCING_REG */
return s->debounce;
- case 0x34: /* GPIO_LATCH_REG */
+ case 0x34: /* GPIO_LATCH_REG */
return s->latch;
}
@@ -2019,7 +2021,7 @@ static void omap_mpuio_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x04: /* OUTPUT_REG */
+ case 0x04: /* OUTPUT_REG */
diff = (s->outputs ^ value) & ~s->dir;
s->outputs = value;
while ((ln = ctz32(diff)) != 32) {
@@ -2029,7 +2031,7 @@ static void omap_mpuio_write(void *opaque, hwaddr addr,
}
break;
- case 0x08: /* IO_CNTL */
+ case 0x08: /* IO_CNTL */
diff = s->outputs & (s->dir ^ value);
s->dir = value;
@@ -2041,37 +2043,37 @@ static void omap_mpuio_write(void *opaque, hwaddr addr,
}
break;
- case 0x14: /* KBC_REG */
+ case 0x14: /* KBC_REG */
s->cols = value;
omap_mpuio_kbd_update(s);
break;
- case 0x18: /* GPIO_EVENT_MODE_REG */
+ case 0x18: /* GPIO_EVENT_MODE_REG */
s->event = value & 0x1f;
break;
- case 0x1c: /* GPIO_INT_EDGE_REG */
+ case 0x1c: /* GPIO_INT_EDGE_REG */
s->edge = value;
break;
- case 0x28: /* KBD_MASKIT */
+ case 0x28: /* KBD_MASKIT */
s->kbd_mask = value & 1;
omap_mpuio_kbd_update(s);
break;
- case 0x2c: /* GPIO_MASKIT */
+ case 0x2c: /* GPIO_MASKIT */
s->mask = value;
break;
- case 0x30: /* GPIO_DEBOUNCING_REG */
+ case 0x30: /* GPIO_DEBOUNCING_REG */
s->debounce = value & 0x1ff;
break;
- case 0x00: /* INPUT_LATCH */
- case 0x10: /* KBR_LATCH */
- case 0x20: /* KBD_INT */
- case 0x24: /* GPIO_INT */
- case 0x34: /* GPIO_LATCH_REG */
+ case 0x00: /* INPUT_LATCH */
+ case 0x10: /* KBR_LATCH */
+ case 0x20: /* KBD_INT */
+ case 0x24: /* GPIO_INT */
+ case 0x34: /* GPIO_LATCH_REG */
OMAP_RO_REG(addr);
return;
@@ -2170,30 +2172,28 @@ struct omap_uwire_s {
uint16_t rxbuf;
uint16_t control;
uint16_t setup[5];
-
- uWireSlave *chip[4];
};
static void omap_uwire_transfer_start(struct omap_uwire_s *s)
{
- int chipselect = (s->control >> 10) & 3; /* INDEX */
- uWireSlave *slave = s->chip[chipselect];
+ int chipselect = (s->control >> 10) & 3; /* INDEX */
- if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */
- if (s->control & (1 << 12)) /* CS_CMD */
- if (slave && slave->send)
- slave->send(slave->opaque,
- s->txbuf >> (16 - ((s->control >> 5) & 0x1f)));
- s->control &= ~(1 << 14); /* CSRB */
+ if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */
+ if (s->control & (1 << 12)) { /* CS_CMD */
+ qemu_log_mask(LOG_UNIMP, "uWireSlave TX CS:%d data:0x%04x\n",
+ chipselect,
+ s->txbuf >> (16 - ((s->control >> 5) & 0x1f)));
+ }
+ s->control &= ~(1 << 14); /* CSRB */
/* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
* a DRQ. When is the level IRQ supposed to be reset? */
}
- if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */
- if (s->control & (1 << 12)) /* CS_CMD */
- if (slave && slave->receive)
- s->rxbuf = slave->receive(slave->opaque);
- s->control |= 1 << 15; /* RDRB */
+ if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */
+ if (s->control & (1 << 12)) { /* CS_CMD */
+ qemu_log_mask(LOG_UNIMP, "uWireSlave RX CS:%d\n", chipselect);
+ }
+ s->control |= 1 << 15; /* RDRB */
/* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
* a DRQ. When is the level IRQ supposed to be reset? */
}
@@ -2209,22 +2209,22 @@ static uint64_t omap_uwire_read(void *opaque, hwaddr addr, unsigned size)
}
switch (offset) {
- case 0x00: /* RDR */
- s->control &= ~(1 << 15); /* RDRB */
+ case 0x00: /* RDR */
+ s->control &= ~(1 << 15); /* RDRB */
return s->rxbuf;
- case 0x04: /* CSR */
+ case 0x04: /* CSR */
return s->control;
- case 0x08: /* SR1 */
+ case 0x08: /* SR1 */
return s->setup[0];
- case 0x0c: /* SR2 */
+ case 0x0c: /* SR2 */
return s->setup[1];
- case 0x10: /* SR3 */
+ case 0x10: /* SR3 */
return s->setup[2];
- case 0x14: /* SR4 */
+ case 0x14: /* SR4 */
return s->setup[3];
- case 0x18: /* SR5 */
+ case 0x18: /* SR5 */
return s->setup[4];
}
@@ -2244,39 +2244,39 @@ static void omap_uwire_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* TDR */
- s->txbuf = value; /* TD */
- if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */
- ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */
- (s->control & (1 << 12)))) { /* CS_CMD */
- s->control |= 1 << 14; /* CSRB */
+ case 0x00: /* TDR */
+ s->txbuf = value; /* TD */
+ if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */
+ ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */
+ (s->control & (1 << 12)))) { /* CS_CMD */
+ s->control |= 1 << 14; /* CSRB */
omap_uwire_transfer_start(s);
}
break;
- case 0x04: /* CSR */
+ case 0x04: /* CSR */
s->control = value & 0x1fff;
- if (value & (1 << 13)) /* START */
+ if (value & (1 << 13)) /* START */
omap_uwire_transfer_start(s);
break;
- case 0x08: /* SR1 */
+ case 0x08: /* SR1 */
s->setup[0] = value & 0x003f;
break;
- case 0x0c: /* SR2 */
+ case 0x0c: /* SR2 */
s->setup[1] = value & 0x0fc0;
break;
- case 0x10: /* SR3 */
+ case 0x10: /* SR3 */
s->setup[2] = value & 0x0003;
break;
- case 0x14: /* SR4 */
+ case 0x14: /* SR4 */
s->setup[3] = value & 0x0001;
break;
- case 0x18: /* SR5 */
+ case 0x18: /* SR5 */
s->setup[4] = value & 0x000f;
break;
@@ -2321,17 +2321,6 @@ static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
return s;
}
-void omap_uwire_attach(struct omap_uwire_s *s,
- uWireSlave *slave, int chipselect)
-{
- if (chipselect < 0 || chipselect > 3) {
- error_report("%s: Bad chipselect %i", __func__, chipselect);
- exit(-1);
- }
-
- s->chip[chipselect] = slave;
-}
-
/* Pseudonoise Pulse-Width Light Modulator */
struct omap_pwl_s {
MemoryRegion iomem;
@@ -2347,7 +2336,7 @@ static void omap_pwl_update(struct omap_pwl_s *s)
if (output != s->output) {
s->output = output;
- printf("%s: Backlight now at %i/256\n", __func__, output);
+ trace_omap1_pwl_backlight(output);
}
}
@@ -2361,9 +2350,9 @@ static uint64_t omap_pwl_read(void *opaque, hwaddr addr, unsigned size)
}
switch (offset) {
- case 0x00: /* PWL_LEVEL */
+ case 0x00: /* PWL_LEVEL */
return s->level;
- case 0x04: /* PWL_CTRL */
+ case 0x04: /* PWL_CTRL */
return s->enable;
}
OMAP_BAD_REG(addr);
@@ -2382,11 +2371,11 @@ static void omap_pwl_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* PWL_LEVEL */
+ case 0x00: /* PWL_LEVEL */
s->level = value;
omap_pwl_update(s);
break;
- case 0x04: /* PWL_CTRL */
+ case 0x04: /* PWL_CTRL */
s->enable = value & 1;
omap_pwl_update(s);
break;
@@ -2454,11 +2443,11 @@ static uint64_t omap_pwt_read(void *opaque, hwaddr addr, unsigned size)
}
switch (offset) {
- case 0x00: /* FRC */
+ case 0x00: /* FRC */
return s->frc;
- case 0x04: /* VCR */
+ case 0x04: /* VCR */
return s->vrc;
- case 0x08: /* GCR */
+ case 0x08: /* GCR */
return s->gcr;
}
OMAP_BAD_REG(addr);
@@ -2477,13 +2466,13 @@ static void omap_pwt_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* FRC */
+ case 0x00: /* FRC */
s->frc = value & 0x3f;
break;
- case 0x04: /* VRC */
+ case 0x04: /* VRC */
if ((value ^ s->vrc) & 1) {
- if (value & 1)
- printf("%s: %iHz buzz on\n", __func__, (int)
+ if (value & 1) {
+ trace_omap1_pwt_buzz(
/* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */
((omap_clk_getrate(s->clk) >> 3) /
/* Pre-multiplexer divider */
@@ -2499,12 +2488,13 @@ static void omap_pwt_write(void *opaque, hwaddr addr,
/* 80/127 divider */
((value & (1 << 5)) ? 80 : 127) /
(107 * 55 * 63 * 127)));
- else
- printf("%s: silence!\n", __func__);
+ } else {
+ trace_omap1_pwt_silence();
+ }
}
s->vrc = value & 0x7f;
break;
- case 0x08: /* GCR */
+ case 0x08: /* GCR */
s->gcr = value & 3;
break;
default:
@@ -2571,8 +2561,9 @@ static void omap_rtc_interrupts_update(struct omap_rtc_s *s)
static void omap_rtc_alarm_update(struct omap_rtc_s *s)
{
s->alarm_ti = mktimegm(&s->alarm_tm);
- if (s->alarm_ti == -1)
- printf("%s: conversion failed\n", __func__);
+ if (s->alarm_ti == -1) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: conversion failed\n", __func__);
+ }
}
static uint64_t omap_rtc_read(void *opaque, hwaddr addr, unsigned size)
@@ -2586,69 +2577,69 @@ static uint64_t omap_rtc_read(void *opaque, hwaddr addr, unsigned size)
}
switch (offset) {
- case 0x00: /* SECONDS_REG */
+ case 0x00: /* SECONDS_REG */
return to_bcd(s->current_tm.tm_sec);
- case 0x04: /* MINUTES_REG */
+ case 0x04: /* MINUTES_REG */
return to_bcd(s->current_tm.tm_min);
- case 0x08: /* HOURS_REG */
+ case 0x08: /* HOURS_REG */
if (s->pm_am)
return ((s->current_tm.tm_hour > 11) << 7) |
to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1);
else
return to_bcd(s->current_tm.tm_hour);
- case 0x0c: /* DAYS_REG */
+ case 0x0c: /* DAYS_REG */
return to_bcd(s->current_tm.tm_mday);
- case 0x10: /* MONTHS_REG */
+ case 0x10: /* MONTHS_REG */
return to_bcd(s->current_tm.tm_mon + 1);
- case 0x14: /* YEARS_REG */
+ case 0x14: /* YEARS_REG */
return to_bcd(s->current_tm.tm_year % 100);
- case 0x18: /* WEEK_REG */
+ case 0x18: /* WEEK_REG */
return s->current_tm.tm_wday;
- case 0x20: /* ALARM_SECONDS_REG */
+ case 0x20: /* ALARM_SECONDS_REG */
return to_bcd(s->alarm_tm.tm_sec);
- case 0x24: /* ALARM_MINUTES_REG */
+ case 0x24: /* ALARM_MINUTES_REG */
return to_bcd(s->alarm_tm.tm_min);
- case 0x28: /* ALARM_HOURS_REG */
+ case 0x28: /* ALARM_HOURS_REG */
if (s->pm_am)
return ((s->alarm_tm.tm_hour > 11) << 7) |
to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1);
else
return to_bcd(s->alarm_tm.tm_hour);
- case 0x2c: /* ALARM_DAYS_REG */
+ case 0x2c: /* ALARM_DAYS_REG */
return to_bcd(s->alarm_tm.tm_mday);
- case 0x30: /* ALARM_MONTHS_REG */
+ case 0x30: /* ALARM_MONTHS_REG */
return to_bcd(s->alarm_tm.tm_mon + 1);
- case 0x34: /* ALARM_YEARS_REG */
+ case 0x34: /* ALARM_YEARS_REG */
return to_bcd(s->alarm_tm.tm_year % 100);
- case 0x40: /* RTC_CTRL_REG */
+ case 0x40: /* RTC_CTRL_REG */
return (s->pm_am << 3) | (s->auto_comp << 2) |
(s->round << 1) | s->running;
- case 0x44: /* RTC_STATUS_REG */
+ case 0x44: /* RTC_STATUS_REG */
i = s->status;
s->status &= ~0x3d;
return i;
- case 0x48: /* RTC_INTERRUPTS_REG */
+ case 0x48: /* RTC_INTERRUPTS_REG */
return s->interrupts;
- case 0x4c: /* RTC_COMP_LSB_REG */
+ case 0x4c: /* RTC_COMP_LSB_REG */
return ((uint16_t) s->comp_reg) & 0xff;
- case 0x50: /* RTC_COMP_MSB_REG */
+ case 0x50: /* RTC_COMP_MSB_REG */
return ((uint16_t) s->comp_reg) >> 8;
}
@@ -2670,26 +2661,17 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* SECONDS_REG */
-#ifdef ALMDEBUG
- printf("RTC SEC_REG <-- %02x\n", value);
-#endif
+ case 0x00: /* SECONDS_REG */
s->ti -= s->current_tm.tm_sec;
s->ti += from_bcd(value);
return;
- case 0x04: /* MINUTES_REG */
-#ifdef ALMDEBUG
- printf("RTC MIN_REG <-- %02x\n", value);
-#endif
+ case 0x04: /* MINUTES_REG */
s->ti -= s->current_tm.tm_min * 60;
s->ti += from_bcd(value) * 60;
return;
- case 0x08: /* HOURS_REG */
-#ifdef ALMDEBUG
- printf("RTC HRS_REG <-- %02x\n", value);
-#endif
+ case 0x08: /* HOURS_REG */
s->ti -= s->current_tm.tm_hour * 3600;
if (s->pm_am) {
s->ti += (from_bcd(value & 0x3f) & 12) * 3600;
@@ -2698,18 +2680,12 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
s->ti += from_bcd(value & 0x3f) * 3600;
return;
- case 0x0c: /* DAYS_REG */
-#ifdef ALMDEBUG
- printf("RTC DAY_REG <-- %02x\n", value);
-#endif
+ case 0x0c: /* DAYS_REG */
s->ti -= s->current_tm.tm_mday * 86400;
s->ti += from_bcd(value) * 86400;
return;
- case 0x10: /* MONTHS_REG */
-#ifdef ALMDEBUG
- printf("RTC MTH_REG <-- %02x\n", value);
-#endif
+ case 0x10: /* MONTHS_REG */
memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
new_tm.tm_mon = from_bcd(value);
ti[0] = mktimegm(&s->current_tm);
@@ -2725,10 +2701,7 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
}
return;
- case 0x14: /* YEARS_REG */
-#ifdef ALMDEBUG
- printf("RTC YRS_REG <-- %02x\n", value);
-#endif
+ case 0x14: /* YEARS_REG */
memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100);
ti[0] = mktimegm(&s->current_tm);
@@ -2744,29 +2717,20 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
}
return;
- case 0x18: /* WEEK_REG */
- return; /* Ignored */
+ case 0x18: /* WEEK_REG */
+ return; /* Ignored */
- case 0x20: /* ALARM_SECONDS_REG */
-#ifdef ALMDEBUG
- printf("ALM SEC_REG <-- %02x\n", value);
-#endif
+ case 0x20: /* ALARM_SECONDS_REG */
s->alarm_tm.tm_sec = from_bcd(value);
omap_rtc_alarm_update(s);
return;
- case 0x24: /* ALARM_MINUTES_REG */
-#ifdef ALMDEBUG
- printf("ALM MIN_REG <-- %02x\n", value);
-#endif
+ case 0x24: /* ALARM_MINUTES_REG */
s->alarm_tm.tm_min = from_bcd(value);
omap_rtc_alarm_update(s);
return;
- case 0x28: /* ALARM_HOURS_REG */
-#ifdef ALMDEBUG
- printf("ALM HRS_REG <-- %02x\n", value);
-#endif
+ case 0x28: /* ALARM_HOURS_REG */
if (s->pm_am)
s->alarm_tm.tm_hour =
((from_bcd(value & 0x3f)) % 12) +
@@ -2776,34 +2740,22 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
omap_rtc_alarm_update(s);
return;
- case 0x2c: /* ALARM_DAYS_REG */
-#ifdef ALMDEBUG
- printf("ALM DAY_REG <-- %02x\n", value);
-#endif
+ case 0x2c: /* ALARM_DAYS_REG */
s->alarm_tm.tm_mday = from_bcd(value);
omap_rtc_alarm_update(s);
return;
- case 0x30: /* ALARM_MONTHS_REG */
-#ifdef ALMDEBUG
- printf("ALM MON_REG <-- %02x\n", value);
-#endif
+ case 0x30: /* ALARM_MONTHS_REG */
s->alarm_tm.tm_mon = from_bcd(value);
omap_rtc_alarm_update(s);
return;
- case 0x34: /* ALARM_YEARS_REG */
-#ifdef ALMDEBUG
- printf("ALM YRS_REG <-- %02x\n", value);
-#endif
+ case 0x34: /* ALARM_YEARS_REG */
s->alarm_tm.tm_year = from_bcd(value);
omap_rtc_alarm_update(s);
return;
- case 0x40: /* RTC_CTRL_REG */
-#ifdef ALMDEBUG
- printf("RTC CONTROL <-- %02x\n", value);
-#endif
+ case 0x40: /* RTC_CTRL_REG */
s->pm_am = (value >> 3) & 1;
s->auto_comp = (value >> 2) & 1;
s->round = (value >> 1) & 1;
@@ -2812,33 +2764,21 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
s->status |= s->running << 1;
return;
- case 0x44: /* RTC_STATUS_REG */
-#ifdef ALMDEBUG
- printf("RTC STATUSL <-- %02x\n", value);
-#endif
+ case 0x44: /* RTC_STATUS_REG */
s->status &= ~((value & 0xc0) ^ 0x80);
omap_rtc_interrupts_update(s);
return;
- case 0x48: /* RTC_INTERRUPTS_REG */
-#ifdef ALMDEBUG
- printf("RTC INTRS <-- %02x\n", value);
-#endif
+ case 0x48: /* RTC_INTERRUPTS_REG */
s->interrupts = value;
return;
- case 0x4c: /* RTC_COMP_LSB_REG */
-#ifdef ALMDEBUG
- printf("RTC COMPLSB <-- %02x\n", value);
-#endif
+ case 0x4c: /* RTC_COMP_LSB_REG */
s->comp_reg &= 0xff00;
s->comp_reg |= 0x00ff & value;
return;
- case 0x50: /* RTC_COMP_MSB_REG */
-#ifdef ALMDEBUG
- printf("RTC COMPMSB <-- %02x\n", value);
-#endif
+ case 0x50: /* RTC_COMP_MSB_REG */
s->comp_reg &= 0x00ff;
s->comp_reg |= 0xff00 & (value << 8);
return;
@@ -2989,12 +2929,12 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
{
int irq;
- switch ((s->spcr[0] >> 4) & 3) { /* RINTM */
+ switch ((s->spcr[0] >> 4) & 3) { /* RINTM */
case 0:
- irq = (s->spcr[0] >> 1) & 1; /* RRDY */
+ irq = (s->spcr[0] >> 1) & 1; /* RRDY */
break;
case 3:
- irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */
+ irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */
break;
default:
irq = 0;
@@ -3004,12 +2944,12 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
if (irq)
qemu_irq_pulse(s->rxirq);
- switch ((s->spcr[1] >> 4) & 3) { /* XINTM */
+ switch ((s->spcr[1] >> 4) & 3) { /* XINTM */
case 0:
- irq = (s->spcr[1] >> 1) & 1; /* XRDY */
+ irq = (s->spcr[1] >> 1) & 1; /* XRDY */
break;
case 3:
- irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */
+ irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */
break;
default:
irq = 0;
@@ -3022,9 +2962,9 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s)
{
- if ((s->spcr[0] >> 1) & 1) /* RRDY */
- s->spcr[0] |= 1 << 2; /* RFULL */
- s->spcr[0] |= 1 << 1; /* RRDY */
+ if ((s->spcr[0] >> 1) & 1) /* RRDY */
+ s->spcr[0] |= 1 << 2; /* RFULL */
+ s->spcr[0] |= 1 << 1; /* RRDY */
qemu_irq_raise(s->rxdrq);
omap_mcbsp_intr_update(s);
}
@@ -3036,8 +2976,9 @@ static void omap_mcbsp_source_tick(void *opaque)
if (!s->rx_rate)
return;
- if (s->rx_req)
- printf("%s: Rx FIFO overrun\n", __func__);
+ if (s->rx_req) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Rx FIFO overrun\n", __func__);
+ }
s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7];
@@ -3063,14 +3004,14 @@ static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s)
static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s)
{
- s->spcr[0] &= ~(1 << 1); /* RRDY */
+ s->spcr[0] &= ~(1 << 1); /* RRDY */
qemu_irq_lower(s->rxdrq);
omap_mcbsp_intr_update(s);
}
static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s)
{
- s->spcr[1] |= 1 << 1; /* XRDY */
+ s->spcr[1] |= 1 << 1; /* XRDY */
qemu_irq_raise(s->txdrq);
omap_mcbsp_intr_update(s);
}
@@ -3082,8 +3023,9 @@ static void omap_mcbsp_sink_tick(void *opaque)
if (!s->tx_rate)
return;
- if (s->tx_req)
- printf("%s: Tx FIFO underrun\n", __func__);
+ if (s->tx_req) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Tx FIFO underrun\n", __func__);
+ }
s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7];
@@ -3104,7 +3046,7 @@ static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s)
static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s)
{
- s->spcr[1] &= ~(1 << 1); /* XRDY */
+ s->spcr[1] &= ~(1 << 1); /* XRDY */
qemu_irq_lower(s->txdrq);
omap_mcbsp_intr_update(s);
if (s->codec && s->codec->cts)
@@ -3122,27 +3064,27 @@ static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
{
int prev_rx_rate, prev_tx_rate;
int rx_rate = 0, tx_rate = 0;
- int cpu_rate = 1500000; /* XXX */
+ int cpu_rate = 1500000; /* XXX */
/* TODO: check CLKSTP bit */
- if (s->spcr[1] & (1 << 6)) { /* GRST */
- if (s->spcr[0] & (1 << 0)) { /* RRST */
- if ((s->srgr[1] & (1 << 13)) && /* CLKSM */
- (s->pcr & (1 << 8))) { /* CLKRM */
- if (~s->pcr & (1 << 7)) /* SCLKME */
+ if (s->spcr[1] & (1 << 6)) { /* GRST */
+ if (s->spcr[0] & (1 << 0)) { /* RRST */
+ if ((s->srgr[1] & (1 << 13)) && /* CLKSM */
+ (s->pcr & (1 << 8))) { /* CLKRM */
+ if (~s->pcr & (1 << 7)) /* SCLKME */
rx_rate = cpu_rate /
- ((s->srgr[0] & 0xff) + 1); /* CLKGDV */
+ ((s->srgr[0] & 0xff) + 1); /* CLKGDV */
} else
if (s->codec)
rx_rate = s->codec->rx_rate;
}
- if (s->spcr[1] & (1 << 0)) { /* XRST */
- if ((s->srgr[1] & (1 << 13)) && /* CLKSM */
- (s->pcr & (1 << 9))) { /* CLKXM */
- if (~s->pcr & (1 << 7)) /* SCLKME */
+ if (s->spcr[1] & (1 << 0)) { /* XRST */
+ if ((s->srgr[1] & (1 << 13)) && /* CLKSM */
+ (s->pcr & (1 << 9))) { /* CLKXM */
+ if (~s->pcr & (1 << 7)) /* SCLKME */
tx_rate = cpu_rate /
- ((s->srgr[0] & 0xff) + 1); /* CLKGDV */
+ ((s->srgr[0] & 0xff) + 1); /* CLKGDV */
} else
if (s->codec)
tx_rate = s->codec->tx_rate;
@@ -3179,13 +3121,13 @@ static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* DRR2 */
- if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */
+ case 0x00: /* DRR2 */
+ if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */
return 0x0000;
/* Fall through. */
- case 0x02: /* DRR1 */
+ case 0x02: /* DRR1 */
if (s->rx_req < 2) {
- printf("%s: Rx FIFO underrun\n", __func__);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Rx FIFO underrun\n", __func__);
omap_mcbsp_rx_done(s);
} else {
s->tx_req -= 2;
@@ -3201,63 +3143,63 @@ static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr,
}
return 0x0000;
- case 0x04: /* DXR2 */
- case 0x06: /* DXR1 */
+ case 0x04: /* DXR2 */
+ case 0x06: /* DXR1 */
return 0x0000;
- case 0x08: /* SPCR2 */
+ case 0x08: /* SPCR2 */
return s->spcr[1];
- case 0x0a: /* SPCR1 */
+ case 0x0a: /* SPCR1 */
return s->spcr[0];
- case 0x0c: /* RCR2 */
+ case 0x0c: /* RCR2 */
return s->rcr[1];
- case 0x0e: /* RCR1 */
+ case 0x0e: /* RCR1 */
return s->rcr[0];
- case 0x10: /* XCR2 */
+ case 0x10: /* XCR2 */
return s->xcr[1];
- case 0x12: /* XCR1 */
+ case 0x12: /* XCR1 */
return s->xcr[0];
- case 0x14: /* SRGR2 */
+ case 0x14: /* SRGR2 */
return s->srgr[1];
- case 0x16: /* SRGR1 */
+ case 0x16: /* SRGR1 */
return s->srgr[0];
- case 0x18: /* MCR2 */
+ case 0x18: /* MCR2 */
return s->mcr[1];
- case 0x1a: /* MCR1 */
+ case 0x1a: /* MCR1 */
return s->mcr[0];
- case 0x1c: /* RCERA */
+ case 0x1c: /* RCERA */
return s->rcer[0];
- case 0x1e: /* RCERB */
+ case 0x1e: /* RCERB */
return s->rcer[1];
- case 0x20: /* XCERA */
+ case 0x20: /* XCERA */
return s->xcer[0];
- case 0x22: /* XCERB */
+ case 0x22: /* XCERB */
return s->xcer[1];
- case 0x24: /* PCR0 */
+ case 0x24: /* PCR0 */
return s->pcr;
- case 0x26: /* RCERC */
+ case 0x26: /* RCERC */
return s->rcer[2];
- case 0x28: /* RCERD */
+ case 0x28: /* RCERD */
return s->rcer[3];
- case 0x2a: /* XCERC */
+ case 0x2a: /* XCERC */
return s->xcer[2];
- case 0x2c: /* XCERD */
+ case 0x2c: /* XCERD */
return s->xcer[3];
- case 0x2e: /* RCERE */
+ case 0x2e: /* RCERE */
return s->rcer[4];
- case 0x30: /* RCERF */
+ case 0x30: /* RCERF */
return s->rcer[5];
- case 0x32: /* XCERE */
+ case 0x32: /* XCERE */
return s->xcer[4];
- case 0x34: /* XCERF */
+ case 0x34: /* XCERF */
return s->xcer[5];
- case 0x36: /* RCERG */
+ case 0x36: /* RCERG */
return s->rcer[6];
- case 0x38: /* RCERH */
+ case 0x38: /* RCERH */
return s->rcer[7];
- case 0x3a: /* XCERG */
+ case 0x3a: /* XCERG */
return s->xcer[6];
- case 0x3c: /* XCERH */
+ case 0x3c: /* XCERH */
return s->xcer[7];
}
@@ -3272,16 +3214,16 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr,
int offset = addr & OMAP_MPUI_REG_MASK;
switch (offset) {
- case 0x00: /* DRR2 */
- case 0x02: /* DRR1 */
+ case 0x00: /* DRR2 */
+ case 0x02: /* DRR1 */
OMAP_RO_REG(addr);
return;
- case 0x04: /* DXR2 */
- if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */
+ case 0x04: /* DXR2 */
+ if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */
return;
/* Fall through. */
- case 0x06: /* DXR1 */
+ case 0x06: /* DXR1 */
if (s->tx_req > 1) {
s->tx_req -= 2;
if (s->codec && s->codec->cts) {
@@ -3290,24 +3232,28 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr,
}
if (s->tx_req < 2)
omap_mcbsp_tx_done(s);
- } else
- printf("%s: Tx FIFO overrun\n", __func__);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Tx FIFO overrun\n", __func__);
+ }
return;
- case 0x08: /* SPCR2 */
+ case 0x08: /* SPCR2 */
s->spcr[1] &= 0x0002;
s->spcr[1] |= 0x03f9 & value;
- s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */
- if (~value & 1) /* XRST */
+ s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */
+ if (~value & 1) /* XRST */
s->spcr[1] &= ~6;
omap_mcbsp_req_update(s);
return;
- case 0x0a: /* SPCR1 */
+ case 0x0a: /* SPCR1 */
s->spcr[0] &= 0x0006;
s->spcr[0] |= 0xf8f9 & value;
- if (value & (1 << 15)) /* DLB */
- printf("%s: Digital Loopback mode enable attempt\n", __func__);
- if (~value & 1) { /* RRST */
+ if (value & (1 << 15)) { /* DLB */
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Digital Loopback mode enable attempt\n",
+ __func__);
+ }
+ if (~value & 1) { /* RRST */
s->spcr[0] &= ~6;
s->rx_req = 0;
omap_mcbsp_rx_done(s);
@@ -3315,85 +3261,91 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr,
omap_mcbsp_req_update(s);
return;
- case 0x0c: /* RCR2 */
+ case 0x0c: /* RCR2 */
s->rcr[1] = value & 0xffff;
return;
- case 0x0e: /* RCR1 */
+ case 0x0e: /* RCR1 */
s->rcr[0] = value & 0x7fe0;
return;
- case 0x10: /* XCR2 */
+ case 0x10: /* XCR2 */
s->xcr[1] = value & 0xffff;
return;
- case 0x12: /* XCR1 */
+ case 0x12: /* XCR1 */
s->xcr[0] = value & 0x7fe0;
return;
- case 0x14: /* SRGR2 */
+ case 0x14: /* SRGR2 */
s->srgr[1] = value & 0xffff;
omap_mcbsp_req_update(s);
return;
- case 0x16: /* SRGR1 */
+ case 0x16: /* SRGR1 */
s->srgr[0] = value & 0xffff;
omap_mcbsp_req_update(s);
return;
- case 0x18: /* MCR2 */
+ case 0x18: /* MCR2 */
s->mcr[1] = value & 0x03e3;
- if (value & 3) /* XMCM */
- printf("%s: Tx channel selection mode enable attempt\n", __func__);
+ if (value & 3) { /* XMCM */
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Tx channel selection mode enable attempt\n",
+ __func__);
+ }
return;
- case 0x1a: /* MCR1 */
+ case 0x1a: /* MCR1 */
s->mcr[0] = value & 0x03e1;
- if (value & 1) /* RMCM */
- printf("%s: Rx channel selection mode enable attempt\n", __func__);
+ if (value & 1) { /* RMCM */
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Rx channel selection mode enable attempt\n",
+ __func__);
+ }
return;
- case 0x1c: /* RCERA */
+ case 0x1c: /* RCERA */
s->rcer[0] = value & 0xffff;
return;
- case 0x1e: /* RCERB */
+ case 0x1e: /* RCERB */
s->rcer[1] = value & 0xffff;
return;
- case 0x20: /* XCERA */
+ case 0x20: /* XCERA */
s->xcer[0] = value & 0xffff;
return;
- case 0x22: /* XCERB */
+ case 0x22: /* XCERB */
s->xcer[1] = value & 0xffff;
return;
- case 0x24: /* PCR0 */
+ case 0x24: /* PCR0 */
s->pcr = value & 0x7faf;
return;
- case 0x26: /* RCERC */
+ case 0x26: /* RCERC */
s->rcer[2] = value & 0xffff;
return;
- case 0x28: /* RCERD */
+ case 0x28: /* RCERD */
s->rcer[3] = value & 0xffff;
return;
- case 0x2a: /* XCERC */
+ case 0x2a: /* XCERC */
s->xcer[2] = value & 0xffff;
return;
- case 0x2c: /* XCERD */
+ case 0x2c: /* XCERD */
s->xcer[3] = value & 0xffff;
return;
- case 0x2e: /* RCERE */
+ case 0x2e: /* RCERE */
s->rcer[4] = value & 0xffff;
return;
- case 0x30: /* RCERF */
+ case 0x30: /* RCERF */
s->rcer[5] = value & 0xffff;
return;
- case 0x32: /* XCERE */
+ case 0x32: /* XCERE */
s->xcer[4] = value & 0xffff;
return;
- case 0x34: /* XCERF */
+ case 0x34: /* XCERF */
s->xcer[5] = value & 0xffff;
return;
- case 0x36: /* RCERG */
+ case 0x36: /* RCERG */
s->rcer[6] = value & 0xffff;
return;
- case 0x38: /* RCERH */
+ case 0x38: /* RCERH */
s->rcer[7] = value & 0xffff;
return;
- case 0x3a: /* XCERG */
+ case 0x3a: /* XCERG */
s->xcer[6] = value & 0xffff;
return;
- case 0x3c: /* XCERH */
+ case 0x3c: /* XCERH */
s->xcer[7] = value & 0xffff;
return;
}
@@ -3407,8 +3359,8 @@ static void omap_mcbsp_writew(void *opaque, hwaddr addr,
struct omap_mcbsp_s *s = opaque;
int offset = addr & OMAP_MPUI_REG_MASK;
- if (offset == 0x04) { /* DXR */
- if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */
+ if (offset == 0x04) { /* DXR */
+ if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */
return;
if (s->tx_req > 3) {
s->tx_req -= 4;
@@ -3424,8 +3376,9 @@ static void omap_mcbsp_writew(void *opaque, hwaddr addr,
}
if (s->tx_req < 4)
omap_mcbsp_tx_done(s);
- } else
- printf("%s: Tx FIFO overrun\n", __func__);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Tx FIFO overrun\n", __func__);
+ }
return;
}
@@ -3543,7 +3496,7 @@ static void omap_lpg_tick(void *opaque)
timer_mod(s->tm, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + s->on);
s->cycle = !s->cycle;
- printf("%s: LED is %s\n", __func__, s->cycle ? "on" : "off");
+ trace_omap1_lpg_led(s->cycle ? "on" : "off");
}
static void omap_lpg_update(struct omap_lpg_s *s)
@@ -3551,23 +3504,23 @@ static void omap_lpg_update(struct omap_lpg_s *s)
int64_t on, period = 1, ticks = 1000;
static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 };
- if (~s->control & (1 << 6)) /* LPGRES */
+ if (~s->control & (1 << 6)) /* LPGRES */
on = 0;
- else if (s->control & (1 << 7)) /* PERM_ON */
+ else if (s->control & (1 << 7)) /* PERM_ON */
on = period;
else {
- period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */
+ period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */
256 / 32);
on = (s->clk && s->power) ? muldiv64(ticks,
- per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */
+ per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */
}
timer_del(s->tm);
- if (on == period && s->on < s->period)
- printf("%s: LED is on\n", __func__);
- else if (on == 0 && s->on)
- printf("%s: LED is off\n", __func__);
- else if (on && (on != s->on || period != s->period)) {
+ if (on == period && s->on < s->period) {
+ trace_omap1_lpg_led("on");
+ } else if (on == 0 && s->on) {
+ trace_omap1_lpg_led("off");
+ } else if (on && (on != s->on || period != s->period)) {
s->cycle = 0;
s->on = on;
s->period = period;
@@ -3597,10 +3550,10 @@ static uint64_t omap_lpg_read(void *opaque, hwaddr addr, unsigned size)
}
switch (offset) {
- case 0x00: /* LCR */
+ case 0x00: /* LCR */
return s->control;
- case 0x04: /* PMR */
+ case 0x04: /* PMR */
return s->power;
}
@@ -3620,14 +3573,14 @@ static void omap_lpg_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* LCR */
- if (~value & (1 << 6)) /* LPGRES */
+ case 0x00: /* LCR */
+ if (~value & (1 << 6)) /* LPGRES */
omap_lpg_reset(s);
s->control = value & 0xff;
omap_lpg_update(s);
return;
- case 0x04: /* PMR */
+ case 0x04: /* PMR */
s->power = value & 0x01;
omap_lpg_update(s);
return;
@@ -3677,7 +3630,7 @@ static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr,
return omap_badwidth_read16(opaque, addr);
}
- if (addr == OMAP_MPUI_BASE) /* CMR */
+ if (addr == OMAP_MPUI_BASE) /* CMR */
return 0xfe4d;
OMAP_BAD_REG(addr);
@@ -3729,7 +3682,6 @@ static void omap1_mpu_reset(void *opaque)
omap_uart_reset(mpu->uart[0]);
omap_uart_reset(mpu->uart[1]);
omap_uart_reset(mpu->uart[2]);
- omap_mmc_reset(mpu->mmc);
omap_mpuio_reset(mpu->mpuio);
omap_uwire_reset(mpu->microwire);
omap_pwl_reset(mpu->pwl);
@@ -3751,25 +3703,25 @@ static const struct omap_map_s {
const char *name;
} omap15xx_dsp_mm[] = {
/* Strobe 0 */
- { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */
- { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */
- { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */
- { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */
- { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */
- { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */
- { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */
- { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */
- { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */
- { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */
- { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */
- { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */
- { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */
- { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */
- { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */
- { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */
- { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */
+ { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */
+ { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */
+ { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */
+ { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */
+ { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */
+ { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */
+ { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */
+ { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */
+ { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */
+ { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */
+ { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */
+ { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */
+ { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */
+ { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */
+ { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */
+ { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */
+ { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */
/* Strobe 1 */
- { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */
+ { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */
{ 0 }
};
@@ -3994,11 +3946,25 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram,
if (!dinfo && !qtest_enabled()) {
warn_report("missing SecureDigital device");
}
- s->mmc = omap_mmc_init(0xfffb7800, system_memory,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
- &s->drq[OMAP_DMA_MMC_TX],
- omap_findclk(s, "mmc_ck"));
+
+ s->mmc = qdev_new(TYPE_OMAP_MMC);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(s->mmc), &error_fatal);
+ omap_mmc_set_clk(s->mmc, omap_findclk(s, "mmc_ck"));
+
+ memory_region_add_subregion(system_memory, 0xfffb7800,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(s->mmc), 0));
+ qdev_connect_gpio_out_named(s->mmc, "dma-tx", 0, s->drq[OMAP_DMA_MMC_TX]);
+ qdev_connect_gpio_out_named(s->mmc, "dma-rx", 0, s->drq[OMAP_DMA_MMC_RX]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(s->mmc), 0,
+ qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN));
+
+ if (dinfo) {
+ DeviceState *card = qdev_new(TYPE_SD_CARD);
+ qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
+ &error_fatal);
+ qdev_realize_and_unref(card, qdev_get_child_bus(s->mmc, "sd-bus"),
+ &error_fatal);
+ }
s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000,
qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD),
@@ -4059,18 +4025,18 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram,
0xfffbd800, omap_findclk(s, "clk32-kHz"));
/* Register mappings not currently implemented:
- * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310)
- * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310)
- * USB W2FC fffb4000 - fffb47ff
- * Camera Interface fffb6800 - fffb6fff
- * USB Host fffba000 - fffba7ff
- * FAC fffba800 - fffbafff
- * HDQ/1-Wire fffbc000 - fffbc7ff
- * TIPB switches fffbc800 - fffbcfff
- * Mailbox fffcf000 - fffcf7ff
- * Local bus IF fffec100 - fffec1ff
- * Local bus MMU fffec200 - fffec2ff
- * DSP MMU fffed200 - fffed2ff
+ * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310)
+ * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310)
+ * USB W2FC fffb4000 - fffb47ff
+ * Camera Interface fffb6800 - fffb6fff
+ * USB Host fffba000 - fffba7ff
+ * FAC fffba800 - fffbafff
+ * HDQ/1-Wire fffbc000 - fffbc7ff
+ * TIPB switches fffbc800 - fffbcfff
+ * Mailbox fffcf000 - fffcf7ff
+ * Local bus IF fffec100 - fffec1ff
+ * Local bus MMU fffec200 - fffec2ff
+ * DSP MMU fffed200 - fffed2ff
*/
omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm);
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
deleted file mode 100644
index d968327..0000000
--- a/hw/arm/omap2.c
+++ /dev/null
@@ -1,2715 +0,0 @@
-/*
- * TI OMAP processors emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/error-report.h"
-#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/arm/boot.h"
-#include "hw/arm/omap.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "chardev/char-fe.h"
-#include "hw/block/flash.h"
-#include "hw/arm/soc_dma.h"
-#include "hw/sysbus.h"
-#include "hw/boards.h"
-#include "audio/audio.h"
-#include "target/arm/cpu-qom.h"
-
-/* Enhanced Audio Controller (CODEC only) */
-struct omap_eac_s {
- qemu_irq irq;
- MemoryRegion iomem;
-
- uint16_t sysconfig;
- uint8_t config[4];
- uint8_t control;
- uint8_t address;
- uint16_t data;
- uint8_t vtol;
- uint8_t vtsl;
- uint16_t mixer;
- uint16_t gain[4];
- uint8_t att;
- uint16_t max[7];
-
- struct {
- qemu_irq txdrq;
- qemu_irq rxdrq;
- uint32_t (*txrx)(void *opaque, uint32_t, int);
- void *opaque;
-
-#define EAC_BUF_LEN 1024
- uint32_t rxbuf[EAC_BUF_LEN];
- int rxoff;
- int rxlen;
- int rxavail;
- uint32_t txbuf[EAC_BUF_LEN];
- int txlen;
- int txavail;
-
- int enable;
- int rate;
-
- uint16_t config[4];
-
- /* These need to be moved to the actual codec */
- QEMUSoundCard card;
- SWVoiceIn *in_voice;
- SWVoiceOut *out_voice;
- int hw_enable;
- } codec;
-
- struct {
- uint8_t control;
- uint16_t config;
- } modem, bt;
-};
-
-static inline void omap_eac_interrupt_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */
-}
-
-static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) &&
- ((s->codec.config[1] >> 12) & 1)); /* DMAREN */
-}
-
-static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail &&
- ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */
-}
-
-static inline void omap_eac_in_refill(struct omap_eac_s *s)
-{
- int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2;
- int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2;
- int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start);
- int recv = 1;
- uint8_t *buf = (uint8_t *) s->codec.rxbuf + start;
-
- left -= leftwrap;
- start = 0;
- while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start,
- leftwrap)) > 0) { /* Be defensive */
- start += recv;
- leftwrap -= recv;
- }
- if (recv <= 0)
- s->codec.rxavail = 0;
- else
- s->codec.rxavail -= start >> 2;
- s->codec.rxlen += start >> 2;
-
- if (recv > 0 && left > 0) {
- start = 0;
- while (left && (recv = AUD_read(s->codec.in_voice,
- (uint8_t *) s->codec.rxbuf + start,
- left)) > 0) { /* Be defensive */
- start += recv;
- left -= recv;
- }
- if (recv <= 0)
- s->codec.rxavail = 0;
- else
- s->codec.rxavail -= start >> 2;
- s->codec.rxlen += start >> 2;
- }
-}
-
-static inline void omap_eac_out_empty(struct omap_eac_s *s)
-{
- int left = s->codec.txlen << 2;
- int start = 0;
- int sent = 1;
-
- while (left && (sent = AUD_write(s->codec.out_voice,
- (uint8_t *) s->codec.txbuf + start,
- left)) > 0) { /* Be defensive */
- start += sent;
- left -= sent;
- }
-
- if (!sent) {
- s->codec.txavail = 0;
- omap_eac_out_dmarequest_update(s);
- }
-
- if (start)
- s->codec.txlen = 0;
-}
-
-static void omap_eac_in_cb(void *opaque, int avail_b)
-{
- struct omap_eac_s *s = opaque;
-
- s->codec.rxavail = avail_b >> 2;
- omap_eac_in_refill(s);
- /* TODO: possibly discard current buffer if overrun */
- omap_eac_in_dmarequest_update(s);
-}
-
-static void omap_eac_out_cb(void *opaque, int free_b)
-{
- struct omap_eac_s *s = opaque;
-
- s->codec.txavail = free_b >> 2;
- if (s->codec.txlen)
- omap_eac_out_empty(s);
- else
- omap_eac_out_dmarequest_update(s);
-}
-
-static void omap_eac_enable_update(struct omap_eac_s *s)
-{
- s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */
- (s->codec.config[1] & 2) && /* AUDEN */
- s->codec.hw_enable;
-}
-
-static const int omap_eac_fsint[4] = {
- 8000,
- 11025,
- 22050,
- 44100,
-};
-
-static const int omap_eac_fsint2[8] = {
- 8000,
- 11025,
- 22050,
- 44100,
- 48000,
- 0, 0, 0,
-};
-
-static const int omap_eac_fsint3[16] = {
- 8000,
- 11025,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000,
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static void omap_eac_rate_update(struct omap_eac_s *s)
-{
- int fsint[3];
-
- fsint[2] = (s->codec.config[3] >> 9) & 0xf;
- fsint[1] = (s->codec.config[2] >> 0) & 0x7;
- fsint[0] = (s->codec.config[0] >> 6) & 0x3;
- if (fsint[2] < 0xf)
- s->codec.rate = omap_eac_fsint3[fsint[2]];
- else if (fsint[1] < 0x7)
- s->codec.rate = omap_eac_fsint2[fsint[1]];
- else
- s->codec.rate = omap_eac_fsint[fsint[0]];
-}
-
-static void omap_eac_volume_update(struct omap_eac_s *s)
-{
- /* TODO */
-}
-
-static void omap_eac_format_update(struct omap_eac_s *s)
-{
- struct audsettings fmt;
-
- /* The hardware buffers at most one sample */
- if (s->codec.rxlen)
- s->codec.rxlen = 1;
-
- if (s->codec.in_voice) {
- AUD_set_active_in(s->codec.in_voice, 0);
- AUD_close_in(&s->codec.card, s->codec.in_voice);
- s->codec.in_voice = NULL;
- }
- if (s->codec.out_voice) {
- omap_eac_out_empty(s);
- AUD_set_active_out(s->codec.out_voice, 0);
- AUD_close_out(&s->codec.card, s->codec.out_voice);
- s->codec.out_voice = NULL;
- s->codec.txavail = 0;
- }
- /* Discard what couldn't be written */
- s->codec.txlen = 0;
-
- omap_eac_enable_update(s);
- if (!s->codec.enable)
- return;
-
- omap_eac_rate_update(s);
- fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */
- fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */
- fmt.freq = s->codec.rate;
- /* TODO: signedness possibly depends on the CODEC hardware - or
- * does I2S specify it? */
- /* All register writes are 16 bits so we store 16-bit samples
- * in the buffers regardless of AGCFR[B8_16] value. */
- fmt.fmt = AUDIO_FORMAT_U16;
-
- s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice,
- "eac.codec.in", s, omap_eac_in_cb, &fmt);
- s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice,
- "eac.codec.out", s, omap_eac_out_cb, &fmt);
-
- omap_eac_volume_update(s);
-
- AUD_set_active_in(s->codec.in_voice, 1);
- AUD_set_active_out(s->codec.out_voice, 1);
-}
-
-static void omap_eac_reset(struct omap_eac_s *s)
-{
- s->sysconfig = 0;
- s->config[0] = 0x0c;
- s->config[1] = 0x09;
- s->config[2] = 0xab;
- s->config[3] = 0x03;
- s->control = 0x00;
- s->address = 0x00;
- s->data = 0x0000;
- s->vtol = 0x00;
- s->vtsl = 0x00;
- s->mixer = 0x0000;
- s->gain[0] = 0xe7e7;
- s->gain[1] = 0x6767;
- s->gain[2] = 0x6767;
- s->gain[3] = 0x6767;
- s->att = 0xce;
- s->max[0] = 0;
- s->max[1] = 0;
- s->max[2] = 0;
- s->max[3] = 0;
- s->max[4] = 0;
- s->max[5] = 0;
- s->max[6] = 0;
-
- s->modem.control = 0x00;
- s->modem.config = 0x0000;
- s->bt.control = 0x00;
- s->bt.config = 0x0000;
- s->codec.config[0] = 0x0649;
- s->codec.config[1] = 0x0000;
- s->codec.config[2] = 0x0007;
- s->codec.config[3] = 0x1ffc;
- s->codec.rxoff = 0;
- s->codec.rxlen = 0;
- s->codec.txlen = 0;
- s->codec.rxavail = 0;
- s->codec.txavail = 0;
-
- omap_eac_format_update(s);
- omap_eac_interrupt_update(s);
-}
-
-static uint64_t omap_eac_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_eac_s *s = opaque;
- uint32_t ret;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* CPCFR1 */
- return s->config[0];
- case 0x004: /* CPCFR2 */
- return s->config[1];
- case 0x008: /* CPCFR3 */
- return s->config[2];
- case 0x00c: /* CPCFR4 */
- return s->config[3];
-
- case 0x010: /* CPTCTL */
- return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) |
- ((s->codec.txlen < s->codec.txavail) << 5);
-
- case 0x014: /* CPTTADR */
- return s->address;
- case 0x018: /* CPTDATL */
- return s->data & 0xff;
- case 0x01c: /* CPTDATH */
- return s->data >> 8;
- case 0x020: /* CPTVSLL */
- return s->vtol;
- case 0x024: /* CPTVSLH */
- return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */
- case 0x040: /* MPCTR */
- return s->modem.control;
- case 0x044: /* MPMCCFR */
- return s->modem.config;
- case 0x060: /* BPCTR */
- return s->bt.control;
- case 0x064: /* BPMCCFR */
- return s->bt.config;
- case 0x080: /* AMSCFR */
- return s->mixer;
- case 0x084: /* AMVCTR */
- return s->gain[0];
- case 0x088: /* AM1VCTR */
- return s->gain[1];
- case 0x08c: /* AM2VCTR */
- return s->gain[2];
- case 0x090: /* AM3VCTR */
- return s->gain[3];
- case 0x094: /* ASTCTR */
- return s->att;
- case 0x098: /* APD1LCR */
- return s->max[0];
- case 0x09c: /* APD1RCR */
- return s->max[1];
- case 0x0a0: /* APD2LCR */
- return s->max[2];
- case 0x0a4: /* APD2RCR */
- return s->max[3];
- case 0x0a8: /* APD3LCR */
- return s->max[4];
- case 0x0ac: /* APD3RCR */
- return s->max[5];
- case 0x0b0: /* APD4R */
- return s->max[6];
- case 0x0b4: /* ADWR */
- /* This should be write-only? Docs list it as read-only. */
- return 0x0000;
- case 0x0b8: /* ADRDR */
- if (likely(s->codec.rxlen > 1)) {
- ret = s->codec.rxbuf[s->codec.rxoff ++];
- s->codec.rxlen --;
- s->codec.rxoff &= EAC_BUF_LEN - 1;
- return ret;
- } else if (s->codec.rxlen) {
- ret = s->codec.rxbuf[s->codec.rxoff ++];
- s->codec.rxlen --;
- s->codec.rxoff &= EAC_BUF_LEN - 1;
- if (s->codec.rxavail)
- omap_eac_in_refill(s);
- omap_eac_in_dmarequest_update(s);
- return ret;
- }
- return 0x0000;
- case 0x0bc: /* AGCFR */
- return s->codec.config[0];
- case 0x0c0: /* AGCTR */
- return s->codec.config[1] | ((s->codec.config[1] & 2) << 14);
- case 0x0c4: /* AGCFR2 */
- return s->codec.config[2];
- case 0x0c8: /* AGCFR3 */
- return s->codec.config[3];
- case 0x0cc: /* MBPDMACTR */
- case 0x0d0: /* MPDDMARR */
- case 0x0d8: /* MPUDMARR */
- case 0x0e4: /* BPDDMARR */
- case 0x0ec: /* BPUDMARR */
- return 0x0000;
-
- case 0x100: /* VERSION_NUMBER */
- return 0x0010;
-
- case 0x104: /* SYSCONFIG */
- return s->sysconfig;
-
- case 0x108: /* SYSSTATUS */
- return 1 | 0xe; /* RESETDONE | stuff */
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_eac_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_eac_s *s = opaque;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x098: /* APD1LCR */
- case 0x09c: /* APD1RCR */
- case 0x0a0: /* APD2LCR */
- case 0x0a4: /* APD2RCR */
- case 0x0a8: /* APD3LCR */
- case 0x0ac: /* APD3RCR */
- case 0x0b0: /* APD4R */
- case 0x0b8: /* ADRDR */
- case 0x0d0: /* MPDDMARR */
- case 0x0d8: /* MPUDMARR */
- case 0x0e4: /* BPDDMARR */
- case 0x0ec: /* BPUDMARR */
- case 0x100: /* VERSION_NUMBER */
- case 0x108: /* SYSSTATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x000: /* CPCFR1 */
- s->config[0] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x004: /* CPCFR2 */
- s->config[1] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x008: /* CPCFR3 */
- s->config[2] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x00c: /* CPCFR4 */
- s->config[3] = value & 0xff;
- omap_eac_format_update(s);
- break;
-
- case 0x010: /* CPTCTL */
- /* Assuming TXF and TXE bits are read-only... */
- s->control = value & 0x5f;
- omap_eac_interrupt_update(s);
- break;
-
- case 0x014: /* CPTTADR */
- s->address = value & 0xff;
- break;
- case 0x018: /* CPTDATL */
- s->data &= 0xff00;
- s->data |= value & 0xff;
- break;
- case 0x01c: /* CPTDATH */
- s->data &= 0x00ff;
- s->data |= value << 8;
- break;
- case 0x020: /* CPTVSLL */
- s->vtol = value & 0xf8;
- break;
- case 0x024: /* CPTVSLH */
- s->vtsl = value & 0x9f;
- break;
- case 0x040: /* MPCTR */
- s->modem.control = value & 0x8f;
- break;
- case 0x044: /* MPMCCFR */
- s->modem.config = value & 0x7fff;
- break;
- case 0x060: /* BPCTR */
- s->bt.control = value & 0x8f;
- break;
- case 0x064: /* BPMCCFR */
- s->bt.config = value & 0x7fff;
- break;
- case 0x080: /* AMSCFR */
- s->mixer = value & 0x0fff;
- break;
- case 0x084: /* AMVCTR */
- s->gain[0] = value & 0xffff;
- break;
- case 0x088: /* AM1VCTR */
- s->gain[1] = value & 0xff7f;
- break;
- case 0x08c: /* AM2VCTR */
- s->gain[2] = value & 0xff7f;
- break;
- case 0x090: /* AM3VCTR */
- s->gain[3] = value & 0xff7f;
- break;
- case 0x094: /* ASTCTR */
- s->att = value & 0xff;
- break;
-
- case 0x0b4: /* ADWR */
- s->codec.txbuf[s->codec.txlen ++] = value;
- if (unlikely(s->codec.txlen == EAC_BUF_LEN ||
- s->codec.txlen == s->codec.txavail)) {
- if (s->codec.txavail)
- omap_eac_out_empty(s);
- /* Discard what couldn't be written */
- s->codec.txlen = 0;
- }
- break;
-
- case 0x0bc: /* AGCFR */
- s->codec.config[0] = value & 0x07ff;
- omap_eac_format_update(s);
- break;
- case 0x0c0: /* AGCTR */
- s->codec.config[1] = value & 0x780f;
- omap_eac_format_update(s);
- break;
- case 0x0c4: /* AGCFR2 */
- s->codec.config[2] = value & 0x003f;
- omap_eac_format_update(s);
- break;
- case 0x0c8: /* AGCFR3 */
- s->codec.config[3] = value & 0xffff;
- omap_eac_format_update(s);
- break;
- case 0x0cc: /* MBPDMACTR */
- case 0x0d4: /* MPDDMAWR */
- case 0x0e0: /* MPUDMAWR */
- case 0x0e8: /* BPDDMAWR */
- case 0x0f0: /* BPUDMAWR */
- break;
-
- case 0x104: /* SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_eac_reset(s);
- s->sysconfig = value & 0x31d;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_eac_ops = {
- .read = omap_eac_read,
- .write = omap_eac_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
- qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_eac_s *s = g_new0(struct omap_eac_s, 1);
-
- s->irq = irq;
- s->codec.rxdrq = *drq ++;
- s->codec.txdrq = *drq;
- omap_eac_reset(s);
-
- if (current_machine->audiodev) {
- s->codec.card.name = g_strdup(current_machine->audiodev);
- s->codec.card.state = audio_state_by_name(s->codec.card.name, &error_fatal);
- }
- AUD_register_card("OMAP EAC", &s->codec.card, &error_fatal);
-
- memory_region_init_io(&s->iomem, NULL, &omap_eac_ops, s, "omap.eac",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-/* STI/XTI (emulation interface) console - reverse engineered only */
-struct omap_sti_s {
- qemu_irq irq;
- MemoryRegion iomem;
- MemoryRegion iomem_fifo;
- CharBackend chr;
-
- uint32_t sysconfig;
- uint32_t systest;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t clkcontrol;
- uint32_t serial_config;
-};
-
-#define STI_TRACE_CONSOLE_CHANNEL 239
-#define STI_TRACE_CONTROL_CHANNEL 253
-
-static inline void omap_sti_interrupt_update(struct omap_sti_s *s)
-{
- qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static void omap_sti_reset(struct omap_sti_s *s)
-{
- s->sysconfig = 0;
- s->irqst = 0;
- s->irqen = 0;
- s->clkcontrol = 0;
- s->serial_config = 0;
-
- omap_sti_interrupt_update(s);
-}
-
-static uint64_t omap_sti_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_sti_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* STI_REVISION */
- return 0x10;
-
- case 0x10: /* STI_SYSCONFIG */
- return s->sysconfig;
-
- case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
- return 0x00;
-
- case 0x18: /* STI_IRQSTATUS */
- return s->irqst;
-
- case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */
- return s->irqen;
-
- case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */
- case 0x28: /* STI_RX_DR / XTI_RXDATA */
- /* TODO */
- return 0;
-
- case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */
- return s->clkcontrol;
-
- case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */
- return s->serial_config;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sti_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sti_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* STI_REVISION */
- case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* STI_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_sti_reset(s);
- s->sysconfig = value & 0xfe;
- break;
-
- case 0x18: /* STI_IRQSTATUS */
- s->irqst &= ~value;
- omap_sti_interrupt_update(s);
- break;
-
- case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */
- s->irqen = value & 0xffff;
- omap_sti_interrupt_update(s);
- break;
-
- case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */
- s->clkcontrol = value & 0xff;
- break;
-
- case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */
- s->serial_config = value & 0xff;
- break;
-
- case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */
- case 0x28: /* STI_RX_DR / XTI_RXDATA */
- /* TODO */
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_sti_ops = {
- .read = omap_sti_read,
- .write = omap_sti_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, unsigned size)
-{
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sti_fifo_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sti_s *s = opaque;
- int ch = addr >> 6;
- uint8_t byte = value;
-
- if (size != 1) {
- omap_badwidth_write8(opaque, addr, size);
- return;
- }
-
- if (ch == STI_TRACE_CONTROL_CHANNEL) {
- /* Flush channel <i>value</i>. */
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\r", 1);
- } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
- if (value == 0xc0 || value == 0xc3) {
- /* Open channel <i>ch</i>. */
- } else if (value == 0x00) {
- qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\n", 1);
- } else {
- qemu_chr_fe_write_all(&s->chr, &byte, 1);
- }
- }
-}
-
-static const MemoryRegionOps omap_sti_fifo_ops = {
- .read = omap_sti_fifo_read,
- .write = omap_sti_fifo_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- hwaddr channel_base, qemu_irq irq, omap_clk clk,
- Chardev *chr)
-{
- struct omap_sti_s *s = g_new0(struct omap_sti_s, 1);
-
- s->irq = irq;
- omap_sti_reset(s);
-
- qemu_chr_fe_init(&s->chr, chr ?: qemu_chr_new("null", "null", NULL),
- &error_abort);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- memory_region_init_io(&s->iomem_fifo, NULL, &omap_sti_fifo_ops, s,
- "omap.sti.fifo", 0x10000);
- memory_region_add_subregion(sysmem, channel_base, &s->iomem_fifo);
-
- return s;
-}
-
-/* L4 Interconnect */
-#define L4TA(n) (n)
-#define L4TAO(n) ((n) + 39)
-
-static const struct omap_l4_region_s omap_l4_region[125] = {
- [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */
- [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */
- [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */
- [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */
- [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */
- [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */
- [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */
- [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */
- [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */
- [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */
- [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */
- [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */
- [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */
- [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */
- [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */
- [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */
- [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */
- [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */
- [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */
- [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */
- [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */
- [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */
- [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */
- [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */
- [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */
- [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */
- [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */
- [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */
- [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */
- [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */
- [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */
- [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */
- [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */
- [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */
- [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */
- [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */
- [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */
- [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */
- [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */
- [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */
- [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */
- [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */
- [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */
- [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */
- [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */
- [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */
- [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */
- [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */
- [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */
- [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */
- [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */
- [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */
- [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */
- [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */
- [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */
- [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */
- [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */
- [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */
- [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */
- [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */
- [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */
- [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */
- [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */
- [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */
- [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */
- [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */
- [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */
- [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */
- [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */
- [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */
- [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */
- [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */
- [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */
- [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */
- [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */
- [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */
- [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */
- [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */
- [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */
- [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */
- [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */
- [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */
- [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */
- [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */
- [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */
- [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */
- [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */
- [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */
- [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */
- [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */
- [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */
- [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */
- [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */
- [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */
- [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */
- [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */
- [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */
- [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */
- [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */
- [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */
- [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */
- [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */
- [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */
- [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */
- [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */
- [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */
- [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */
- [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */
- [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */
- [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */
- [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */
- [111] = { 0xa0000, 0x1000, 32 }, /* RNG */
- [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */
- [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */
- [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */
- [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */
- [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */
- [117] = { 0xa6000, 0x1000, 32 }, /* AES */
- [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */
- [119] = { 0xa8000, 0x2000, 32 }, /* PKA */
- [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */
- [121] = { 0xb0000, 0x1000, 32 }, /* MG */
- [122] = { 0xb1000, 0x1000, 32 | 16 | 8 },
- [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */
- [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */
-};
-
-static const struct omap_l4_agent_info_s omap_l4_agent_info[54] = {
- { 0, 0, 3, 2 }, /* L4IA initiatior agent */
- { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */
- { L4TAO(2), 5, 2, 1 }, /* 32K timer */
- { L4TAO(3), 7, 3, 2 }, /* PRCM */
- { L4TA(1), 10, 2, 1 }, /* BCM */
- { L4TA(2), 12, 2, 1 }, /* Test JTAG */
- { L4TA(3), 14, 6, 3 }, /* Quad GPIO */
- { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */
- { L4TA(7), 24, 2, 1 }, /* GP timer 1 */
- { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */
- { L4TA(10), 28, 5, 4 }, /* Display subsystem */
- { L4TA(11), 33, 5, 4 }, /* Camera subsystem */
- { L4TA(12), 38, 2, 1 }, /* sDMA */
- { L4TA(13), 40, 5, 4 }, /* SSI */
- { L4TAO(4), 45, 2, 1 }, /* USB */
- { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */
- { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */
- { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */
- { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */
- { L4TA(18), 55, 2, 1 }, /* XTI */
- { L4TA(19), 57, 2, 1 }, /* UART1 */
- { L4TA(20), 59, 2, 1 }, /* UART2 */
- { L4TA(21), 61, 2, 1 }, /* UART3 */
- { L4TAO(5), 63, 2, 1 }, /* I2C1 */
- { L4TAO(6), 65, 2, 1 }, /* I2C2 */
- { L4TAO(7), 67, 2, 1 }, /* McBSP1 */
- { L4TAO(8), 69, 2, 1 }, /* McBSP2 */
- { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */
- { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */
- { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */
- { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */
- { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */
- { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */
- { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */
- { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */
- { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */
- { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */
- { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */
- { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */
- { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */
- { L4TA(32), 97, 2, 1 }, /* EAC */
- { L4TA(33), 99, 2, 1 }, /* FAC */
- { L4TA(34), 101, 2, 1 }, /* IPC */
- { L4TA(35), 103, 2, 1 }, /* SPI1 */
- { L4TA(36), 105, 2, 1 }, /* SPI2 */
- { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */
- { L4TAO(10), 109, 2, 1 },
- { L4TAO(11), 111, 2, 1 }, /* RNG */
- { L4TAO(12), 113, 2, 1 }, /* DES3DES */
- { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */
- { L4TA(37), 117, 2, 1 }, /* AES */
- { L4TA(38), 119, 2, 1 }, /* PKA */
- { -1, 121, 2, 1 },
- { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */
-};
-
-#define omap_l4ta(bus, cs) \
- omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TA(cs))
-#define omap_l4tao(bus, cs) \
- omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TAO(cs))
-
-/* Power, Reset, and Clock Management */
-struct omap_prcm_s {
- qemu_irq irq[3];
- struct omap_mpu_state_s *mpu;
- MemoryRegion iomem0;
- MemoryRegion iomem1;
-
- uint32_t irqst[3];
- uint32_t irqen[3];
-
- uint32_t sysconfig;
- uint32_t voltctrl;
- uint32_t scratch[20];
-
- uint32_t clksrc[1];
- uint32_t clkout[1];
- uint32_t clkemul[1];
- uint32_t clkpol[1];
- uint32_t clksel[8];
- uint32_t clken[12];
- uint32_t clkctrl[4];
- uint32_t clkidle[7];
- uint32_t setuptime[2];
-
- uint32_t wkup[3];
- uint32_t wken[3];
- uint32_t wkst[3];
- uint32_t rst[4];
- uint32_t rstctrl[1];
- uint32_t power[4];
- uint32_t rsttime_wkup;
-
- uint32_t ev;
- uint32_t evtime[2];
-
- int dpll_lock, apll_lock[2];
-};
-
-static void omap_prcm_int_update(struct omap_prcm_s *s, int dom)
-{
- qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]);
- /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */
-}
-
-static uint64_t omap_prcm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_prcm_s *s = opaque;
- uint32_t ret;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* PRCM_REVISION */
- return 0x10;
-
- case 0x010: /* PRCM_SYSCONFIG */
- return s->sysconfig;
-
- case 0x018: /* PRCM_IRQSTATUS_MPU */
- return s->irqst[0];
-
- case 0x01c: /* PRCM_IRQENABLE_MPU */
- return s->irqen[0];
-
- case 0x050: /* PRCM_VOLTCTRL */
- return s->voltctrl;
- case 0x054: /* PRCM_VOLTST */
- return s->voltctrl & 3;
-
- case 0x060: /* PRCM_CLKSRC_CTRL */
- return s->clksrc[0];
- case 0x070: /* PRCM_CLKOUT_CTRL */
- return s->clkout[0];
- case 0x078: /* PRCM_CLKEMUL_CTRL */
- return s->clkemul[0];
- case 0x080: /* PRCM_CLKCFG_CTRL */
- case 0x084: /* PRCM_CLKCFG_STATUS */
- return 0;
-
- case 0x090: /* PRCM_VOLTSETUP */
- return s->setuptime[0];
-
- case 0x094: /* PRCM_CLKSSETUP */
- return s->setuptime[1];
-
- case 0x098: /* PRCM_POLCTRL */
- return s->clkpol[0];
-
- case 0x0b0: /* GENERAL_PURPOSE1 */
- case 0x0b4: /* GENERAL_PURPOSE2 */
- case 0x0b8: /* GENERAL_PURPOSE3 */
- case 0x0bc: /* GENERAL_PURPOSE4 */
- case 0x0c0: /* GENERAL_PURPOSE5 */
- case 0x0c4: /* GENERAL_PURPOSE6 */
- case 0x0c8: /* GENERAL_PURPOSE7 */
- case 0x0cc: /* GENERAL_PURPOSE8 */
- case 0x0d0: /* GENERAL_PURPOSE9 */
- case 0x0d4: /* GENERAL_PURPOSE10 */
- case 0x0d8: /* GENERAL_PURPOSE11 */
- case 0x0dc: /* GENERAL_PURPOSE12 */
- case 0x0e0: /* GENERAL_PURPOSE13 */
- case 0x0e4: /* GENERAL_PURPOSE14 */
- case 0x0e8: /* GENERAL_PURPOSE15 */
- case 0x0ec: /* GENERAL_PURPOSE16 */
- case 0x0f0: /* GENERAL_PURPOSE17 */
- case 0x0f4: /* GENERAL_PURPOSE18 */
- case 0x0f8: /* GENERAL_PURPOSE19 */
- case 0x0fc: /* GENERAL_PURPOSE20 */
- return s->scratch[(addr - 0xb0) >> 2];
-
- case 0x140: /* CM_CLKSEL_MPU */
- return s->clksel[0];
- case 0x148: /* CM_CLKSTCTRL_MPU */
- return s->clkctrl[0];
-
- case 0x158: /* RM_RSTST_MPU */
- return s->rst[0];
- case 0x1c8: /* PM_WKDEP_MPU */
- return s->wkup[0];
- case 0x1d4: /* PM_EVGENCTRL_MPU */
- return s->ev;
- case 0x1d8: /* PM_EVEGENONTIM_MPU */
- return s->evtime[0];
- case 0x1dc: /* PM_EVEGENOFFTIM_MPU */
- return s->evtime[1];
- case 0x1e0: /* PM_PWSTCTRL_MPU */
- return s->power[0];
- case 0x1e4: /* PM_PWSTST_MPU */
- return 0;
-
- case 0x200: /* CM_FCLKEN1_CORE */
- return s->clken[0];
- case 0x204: /* CM_FCLKEN2_CORE */
- return s->clken[1];
- case 0x210: /* CM_ICLKEN1_CORE */
- return s->clken[2];
- case 0x214: /* CM_ICLKEN2_CORE */
- return s->clken[3];
- case 0x21c: /* CM_ICLKEN4_CORE */
- return s->clken[4];
-
- case 0x220: /* CM_IDLEST1_CORE */
- /* TODO: check the actual iclk status */
- return 0x7ffffff9;
- case 0x224: /* CM_IDLEST2_CORE */
- /* TODO: check the actual iclk status */
- return 0x00000007;
- case 0x22c: /* CM_IDLEST4_CORE */
- /* TODO: check the actual iclk status */
- return 0x0000001f;
-
- case 0x230: /* CM_AUTOIDLE1_CORE */
- return s->clkidle[0];
- case 0x234: /* CM_AUTOIDLE2_CORE */
- return s->clkidle[1];
- case 0x238: /* CM_AUTOIDLE3_CORE */
- return s->clkidle[2];
- case 0x23c: /* CM_AUTOIDLE4_CORE */
- return s->clkidle[3];
-
- case 0x240: /* CM_CLKSEL1_CORE */
- return s->clksel[1];
- case 0x244: /* CM_CLKSEL2_CORE */
- return s->clksel[2];
-
- case 0x248: /* CM_CLKSTCTRL_CORE */
- return s->clkctrl[1];
-
- case 0x2a0: /* PM_WKEN1_CORE */
- return s->wken[0];
- case 0x2a4: /* PM_WKEN2_CORE */
- return s->wken[1];
-
- case 0x2b0: /* PM_WKST1_CORE */
- return s->wkst[0];
- case 0x2b4: /* PM_WKST2_CORE */
- return s->wkst[1];
- case 0x2c8: /* PM_WKDEP_CORE */
- return 0x1e;
-
- case 0x2e0: /* PM_PWSTCTRL_CORE */
- return s->power[1];
- case 0x2e4: /* PM_PWSTST_CORE */
- return 0x000030 | (s->power[1] & 0xfc00);
-
- case 0x300: /* CM_FCLKEN_GFX */
- return s->clken[5];
- case 0x310: /* CM_ICLKEN_GFX */
- return s->clken[6];
- case 0x320: /* CM_IDLEST_GFX */
- /* TODO: check the actual iclk status */
- return 0x00000001;
- case 0x340: /* CM_CLKSEL_GFX */
- return s->clksel[3];
- case 0x348: /* CM_CLKSTCTRL_GFX */
- return s->clkctrl[2];
- case 0x350: /* RM_RSTCTRL_GFX */
- return s->rstctrl[0];
- case 0x358: /* RM_RSTST_GFX */
- return s->rst[1];
- case 0x3c8: /* PM_WKDEP_GFX */
- return s->wkup[1];
-
- case 0x3e0: /* PM_PWSTCTRL_GFX */
- return s->power[2];
- case 0x3e4: /* PM_PWSTST_GFX */
- return s->power[2] & 3;
-
- case 0x400: /* CM_FCLKEN_WKUP */
- return s->clken[7];
- case 0x410: /* CM_ICLKEN_WKUP */
- return s->clken[8];
- case 0x420: /* CM_IDLEST_WKUP */
- /* TODO: check the actual iclk status */
- return 0x0000003f;
- case 0x430: /* CM_AUTOIDLE_WKUP */
- return s->clkidle[4];
- case 0x440: /* CM_CLKSEL_WKUP */
- return s->clksel[4];
- case 0x450: /* RM_RSTCTRL_WKUP */
- return 0;
- case 0x454: /* RM_RSTTIME_WKUP */
- return s->rsttime_wkup;
- case 0x458: /* RM_RSTST_WKUP */
- return s->rst[2];
- case 0x4a0: /* PM_WKEN_WKUP */
- return s->wken[2];
- case 0x4b0: /* PM_WKST_WKUP */
- return s->wkst[2];
-
- case 0x500: /* CM_CLKEN_PLL */
- return s->clken[9];
- case 0x520: /* CM_IDLEST_CKGEN */
- ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8);
- if (!(s->clksel[6] & 3))
- /* Core uses 32-kHz clock */
- ret |= 3 << 0;
- else if (!s->dpll_lock)
- /* DPLL not locked, core uses ref_clk */
- ret |= 1 << 0;
- else
- /* Core uses DPLL */
- ret |= 2 << 0;
- return ret;
- case 0x530: /* CM_AUTOIDLE_PLL */
- return s->clkidle[5];
- case 0x540: /* CM_CLKSEL1_PLL */
- return s->clksel[5];
- case 0x544: /* CM_CLKSEL2_PLL */
- return s->clksel[6];
-
- case 0x800: /* CM_FCLKEN_DSP */
- return s->clken[10];
- case 0x810: /* CM_ICLKEN_DSP */
- return s->clken[11];
- case 0x820: /* CM_IDLEST_DSP */
- /* TODO: check the actual iclk status */
- return 0x00000103;
- case 0x830: /* CM_AUTOIDLE_DSP */
- return s->clkidle[6];
- case 0x840: /* CM_CLKSEL_DSP */
- return s->clksel[7];
- case 0x848: /* CM_CLKSTCTRL_DSP */
- return s->clkctrl[3];
- case 0x850: /* RM_RSTCTRL_DSP */
- return 0;
- case 0x858: /* RM_RSTST_DSP */
- return s->rst[3];
- case 0x8c8: /* PM_WKDEP_DSP */
- return s->wkup[2];
- case 0x8e0: /* PM_PWSTCTRL_DSP */
- return s->power[3];
- case 0x8e4: /* PM_PWSTST_DSP */
- return 0x008030 | (s->power[3] & 0x3003);
-
- case 0x8f0: /* PRCM_IRQSTATUS_DSP */
- return s->irqst[1];
- case 0x8f4: /* PRCM_IRQENABLE_DSP */
- return s->irqen[1];
-
- case 0x8f8: /* PRCM_IRQSTATUS_IVA */
- return s->irqst[2];
- case 0x8fc: /* PRCM_IRQENABLE_IVA */
- return s->irqen[2];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_prcm_apll_update(struct omap_prcm_s *s)
-{
- int mode[2];
-
- mode[0] = (s->clken[9] >> 6) & 3;
- s->apll_lock[0] = (mode[0] == 3);
- mode[1] = (s->clken[9] >> 2) & 3;
- s->apll_lock[1] = (mode[1] == 3);
- /* TODO: update clocks */
-
- if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[1] == 2)
- fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n",
- __func__);
-}
-
-static void omap_prcm_dpll_update(struct omap_prcm_s *s)
-{
- omap_clk dpll = omap_findclk(s->mpu, "dpll");
- omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll");
- omap_clk core = omap_findclk(s->mpu, "core_clk");
- int mode = (s->clken[9] >> 0) & 3;
- int mult, div;
-
- mult = (s->clksel[5] >> 12) & 0x3ff;
- div = (s->clksel[5] >> 8) & 0xf;
- if (mult == 0 || mult == 1)
- mode = 1; /* Bypass */
-
- s->dpll_lock = 0;
- switch (mode) {
- case 0:
- fprintf(stderr, "%s: bad EN_DPLL\n", __func__);
- break;
- case 1: /* Low-power bypass mode (Default) */
- case 2: /* Fast-relock bypass mode */
- omap_clk_setrate(dpll, 1, 1);
- omap_clk_setrate(dpll_x2, 1, 1);
- break;
- case 3: /* Lock mode */
- s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */
-
- omap_clk_setrate(dpll, div + 1, mult);
- omap_clk_setrate(dpll_x2, div + 1, mult * 2);
- break;
- }
-
- switch ((s->clksel[6] >> 0) & 3) {
- case 0:
- omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz"));
- break;
- case 1:
- omap_clk_reparent(core, dpll);
- break;
- case 2:
- /* Default */
- omap_clk_reparent(core, dpll_x2);
- break;
- case 3:
- fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __func__);
- break;
- }
-}
-
-static void omap_prcm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_prcm_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x000: /* PRCM_REVISION */
- case 0x054: /* PRCM_VOLTST */
- case 0x084: /* PRCM_CLKCFG_STATUS */
- case 0x1e4: /* PM_PWSTST_MPU */
- case 0x220: /* CM_IDLEST1_CORE */
- case 0x224: /* CM_IDLEST2_CORE */
- case 0x22c: /* CM_IDLEST4_CORE */
- case 0x2c8: /* PM_WKDEP_CORE */
- case 0x2e4: /* PM_PWSTST_CORE */
- case 0x320: /* CM_IDLEST_GFX */
- case 0x3e4: /* PM_PWSTST_GFX */
- case 0x420: /* CM_IDLEST_WKUP */
- case 0x520: /* CM_IDLEST_CKGEN */
- case 0x820: /* CM_IDLEST_DSP */
- case 0x8e4: /* PM_PWSTST_DSP */
- OMAP_RO_REG(addr);
- return;
-
- case 0x010: /* PRCM_SYSCONFIG */
- s->sysconfig = value & 1;
- break;
-
- case 0x018: /* PRCM_IRQSTATUS_MPU */
- s->irqst[0] &= ~value;
- omap_prcm_int_update(s, 0);
- break;
- case 0x01c: /* PRCM_IRQENABLE_MPU */
- s->irqen[0] = value & 0x3f;
- omap_prcm_int_update(s, 0);
- break;
-
- case 0x050: /* PRCM_VOLTCTRL */
- s->voltctrl = value & 0xf1c3;
- break;
-
- case 0x060: /* PRCM_CLKSRC_CTRL */
- s->clksrc[0] = value & 0xdb;
- /* TODO update clocks */
- break;
-
- case 0x070: /* PRCM_CLKOUT_CTRL */
- s->clkout[0] = value & 0xbbbb;
- /* TODO update clocks */
- break;
-
- case 0x078: /* PRCM_CLKEMUL_CTRL */
- s->clkemul[0] = value & 1;
- /* TODO update clocks */
- break;
-
- case 0x080: /* PRCM_CLKCFG_CTRL */
- break;
-
- case 0x090: /* PRCM_VOLTSETUP */
- s->setuptime[0] = value & 0xffff;
- break;
- case 0x094: /* PRCM_CLKSSETUP */
- s->setuptime[1] = value & 0xffff;
- break;
-
- case 0x098: /* PRCM_POLCTRL */
- s->clkpol[0] = value & 0x701;
- break;
-
- case 0x0b0: /* GENERAL_PURPOSE1 */
- case 0x0b4: /* GENERAL_PURPOSE2 */
- case 0x0b8: /* GENERAL_PURPOSE3 */
- case 0x0bc: /* GENERAL_PURPOSE4 */
- case 0x0c0: /* GENERAL_PURPOSE5 */
- case 0x0c4: /* GENERAL_PURPOSE6 */
- case 0x0c8: /* GENERAL_PURPOSE7 */
- case 0x0cc: /* GENERAL_PURPOSE8 */
- case 0x0d0: /* GENERAL_PURPOSE9 */
- case 0x0d4: /* GENERAL_PURPOSE10 */
- case 0x0d8: /* GENERAL_PURPOSE11 */
- case 0x0dc: /* GENERAL_PURPOSE12 */
- case 0x0e0: /* GENERAL_PURPOSE13 */
- case 0x0e4: /* GENERAL_PURPOSE14 */
- case 0x0e8: /* GENERAL_PURPOSE15 */
- case 0x0ec: /* GENERAL_PURPOSE16 */
- case 0x0f0: /* GENERAL_PURPOSE17 */
- case 0x0f4: /* GENERAL_PURPOSE18 */
- case 0x0f8: /* GENERAL_PURPOSE19 */
- case 0x0fc: /* GENERAL_PURPOSE20 */
- s->scratch[(addr - 0xb0) >> 2] = value;
- break;
-
- case 0x140: /* CM_CLKSEL_MPU */
- s->clksel[0] = value & 0x1f;
- /* TODO update clocks */
- break;
- case 0x148: /* CM_CLKSTCTRL_MPU */
- s->clkctrl[0] = value & 0x1f;
- break;
-
- case 0x158: /* RM_RSTST_MPU */
- s->rst[0] &= ~value;
- break;
- case 0x1c8: /* PM_WKDEP_MPU */
- s->wkup[0] = value & 0x15;
- break;
-
- case 0x1d4: /* PM_EVGENCTRL_MPU */
- s->ev = value & 0x1f;
- break;
- case 0x1d8: /* PM_EVEGENONTIM_MPU */
- s->evtime[0] = value;
- break;
- case 0x1dc: /* PM_EVEGENOFFTIM_MPU */
- s->evtime[1] = value;
- break;
-
- case 0x1e0: /* PM_PWSTCTRL_MPU */
- s->power[0] = value & 0xc0f;
- break;
-
- case 0x200: /* CM_FCLKEN1_CORE */
- s->clken[0] = value & 0xbfffffff;
- /* TODO update clocks */
- /* The EN_EAC bit only gets/puts func_96m_clk. */
- break;
- case 0x204: /* CM_FCLKEN2_CORE */
- s->clken[1] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x210: /* CM_ICLKEN1_CORE */
- s->clken[2] = value & 0xfffffff9;
- /* TODO update clocks */
- /* The EN_EAC bit only gets/puts core_l4_iclk. */
- break;
- case 0x214: /* CM_ICLKEN2_CORE */
- s->clken[3] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x21c: /* CM_ICLKEN4_CORE */
- s->clken[4] = value & 0x0000001f;
- /* TODO update clocks */
- break;
-
- case 0x230: /* CM_AUTOIDLE1_CORE */
- s->clkidle[0] = value & 0xfffffff9;
- /* TODO update clocks */
- break;
- case 0x234: /* CM_AUTOIDLE2_CORE */
- s->clkidle[1] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x238: /* CM_AUTOIDLE3_CORE */
- s->clkidle[2] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x23c: /* CM_AUTOIDLE4_CORE */
- s->clkidle[3] = value & 0x0000001f;
- /* TODO update clocks */
- break;
-
- case 0x240: /* CM_CLKSEL1_CORE */
- s->clksel[1] = value & 0x0fffbf7f;
- /* TODO update clocks */
- break;
-
- case 0x244: /* CM_CLKSEL2_CORE */
- s->clksel[2] = value & 0x00fffffc;
- /* TODO update clocks */
- break;
-
- case 0x248: /* CM_CLKSTCTRL_CORE */
- s->clkctrl[1] = value & 0x7;
- break;
-
- case 0x2a0: /* PM_WKEN1_CORE */
- s->wken[0] = value & 0x04667ff8;
- break;
- case 0x2a4: /* PM_WKEN2_CORE */
- s->wken[1] = value & 0x00000005;
- break;
-
- case 0x2b0: /* PM_WKST1_CORE */
- s->wkst[0] &= ~value;
- break;
- case 0x2b4: /* PM_WKST2_CORE */
- s->wkst[1] &= ~value;
- break;
-
- case 0x2e0: /* PM_PWSTCTRL_CORE */
- s->power[1] = (value & 0x00fc3f) | (1 << 2);
- break;
-
- case 0x300: /* CM_FCLKEN_GFX */
- s->clken[5] = value & 6;
- /* TODO update clocks */
- break;
- case 0x310: /* CM_ICLKEN_GFX */
- s->clken[6] = value & 1;
- /* TODO update clocks */
- break;
- case 0x340: /* CM_CLKSEL_GFX */
- s->clksel[3] = value & 7;
- /* TODO update clocks */
- break;
- case 0x348: /* CM_CLKSTCTRL_GFX */
- s->clkctrl[2] = value & 1;
- break;
- case 0x350: /* RM_RSTCTRL_GFX */
- s->rstctrl[0] = value & 1;
- /* TODO: reset */
- break;
- case 0x358: /* RM_RSTST_GFX */
- s->rst[1] &= ~value;
- break;
- case 0x3c8: /* PM_WKDEP_GFX */
- s->wkup[1] = value & 0x13;
- break;
- case 0x3e0: /* PM_PWSTCTRL_GFX */
- s->power[2] = (value & 0x00c0f) | (3 << 2);
- break;
-
- case 0x400: /* CM_FCLKEN_WKUP */
- s->clken[7] = value & 0xd;
- /* TODO update clocks */
- break;
- case 0x410: /* CM_ICLKEN_WKUP */
- s->clken[8] = value & 0x3f;
- /* TODO update clocks */
- break;
- case 0x430: /* CM_AUTOIDLE_WKUP */
- s->clkidle[4] = value & 0x0000003f;
- /* TODO update clocks */
- break;
- case 0x440: /* CM_CLKSEL_WKUP */
- s->clksel[4] = value & 3;
- /* TODO update clocks */
- break;
- case 0x450: /* RM_RSTCTRL_WKUP */
- /* TODO: reset */
- if (value & 2)
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- break;
- case 0x454: /* RM_RSTTIME_WKUP */
- s->rsttime_wkup = value & 0x1fff;
- break;
- case 0x458: /* RM_RSTST_WKUP */
- s->rst[2] &= ~value;
- break;
- case 0x4a0: /* PM_WKEN_WKUP */
- s->wken[2] = value & 0x00000005;
- break;
- case 0x4b0: /* PM_WKST_WKUP */
- s->wkst[2] &= ~value;
- break;
-
- case 0x500: /* CM_CLKEN_PLL */
- if (value & 0xffffff30)
- fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for "
- "future compatibility\n", __func__);
- if ((s->clken[9] ^ value) & 0xcc) {
- s->clken[9] &= ~0xcc;
- s->clken[9] |= value & 0xcc;
- omap_prcm_apll_update(s);
- }
- if ((s->clken[9] ^ value) & 3) {
- s->clken[9] &= ~3;
- s->clken[9] |= value & 3;
- omap_prcm_dpll_update(s);
- }
- break;
- case 0x530: /* CM_AUTOIDLE_PLL */
- s->clkidle[5] = value & 0x000000cf;
- /* TODO update clocks */
- break;
- case 0x540: /* CM_CLKSEL1_PLL */
- if (value & 0xfc4000d7)
- fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for "
- "future compatibility\n", __func__);
- if ((s->clksel[5] ^ value) & 0x003fff00) {
- s->clksel[5] = value & 0x03bfff28;
- omap_prcm_dpll_update(s);
- }
- /* TODO update the other clocks */
-
- s->clksel[5] = value & 0x03bfff28;
- break;
- case 0x544: /* CM_CLKSEL2_PLL */
- if (value & ~3)
- fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for "
- "future compatibility\n", __func__);
- if (s->clksel[6] != (value & 3)) {
- s->clksel[6] = value & 3;
- omap_prcm_dpll_update(s);
- }
- break;
-
- case 0x800: /* CM_FCLKEN_DSP */
- s->clken[10] = value & 0x501;
- /* TODO update clocks */
- break;
- case 0x810: /* CM_ICLKEN_DSP */
- s->clken[11] = value & 0x2;
- /* TODO update clocks */
- break;
- case 0x830: /* CM_AUTOIDLE_DSP */
- s->clkidle[6] = value & 0x2;
- /* TODO update clocks */
- break;
- case 0x840: /* CM_CLKSEL_DSP */
- s->clksel[7] = value & 0x3fff;
- /* TODO update clocks */
- break;
- case 0x848: /* CM_CLKSTCTRL_DSP */
- s->clkctrl[3] = value & 0x101;
- break;
- case 0x850: /* RM_RSTCTRL_DSP */
- /* TODO: reset */
- break;
- case 0x858: /* RM_RSTST_DSP */
- s->rst[3] &= ~value;
- break;
- case 0x8c8: /* PM_WKDEP_DSP */
- s->wkup[2] = value & 0x13;
- break;
- case 0x8e0: /* PM_PWSTCTRL_DSP */
- s->power[3] = (value & 0x03017) | (3 << 2);
- break;
-
- case 0x8f0: /* PRCM_IRQSTATUS_DSP */
- s->irqst[1] &= ~value;
- omap_prcm_int_update(s, 1);
- break;
- case 0x8f4: /* PRCM_IRQENABLE_DSP */
- s->irqen[1] = value & 0x7;
- omap_prcm_int_update(s, 1);
- break;
-
- case 0x8f8: /* PRCM_IRQSTATUS_IVA */
- s->irqst[2] &= ~value;
- omap_prcm_int_update(s, 2);
- break;
- case 0x8fc: /* PRCM_IRQENABLE_IVA */
- s->irqen[2] = value & 0x7;
- omap_prcm_int_update(s, 2);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_prcm_ops = {
- .read = omap_prcm_read,
- .write = omap_prcm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_prcm_reset(struct omap_prcm_s *s)
-{
- s->sysconfig = 0;
- s->irqst[0] = 0;
- s->irqst[1] = 0;
- s->irqst[2] = 0;
- s->irqen[0] = 0;
- s->irqen[1] = 0;
- s->irqen[2] = 0;
- s->voltctrl = 0x1040;
- s->ev = 0x14;
- s->evtime[0] = 0;
- s->evtime[1] = 0;
- s->clkctrl[0] = 0;
- s->clkctrl[1] = 0;
- s->clkctrl[2] = 0;
- s->clkctrl[3] = 0;
- s->clken[1] = 7;
- s->clken[3] = 7;
- s->clken[4] = 0;
- s->clken[5] = 0;
- s->clken[6] = 0;
- s->clken[7] = 0xc;
- s->clken[8] = 0x3e;
- s->clken[9] = 0x0d;
- s->clken[10] = 0;
- s->clken[11] = 0;
- s->clkidle[0] = 0;
- s->clkidle[2] = 7;
- s->clkidle[3] = 0;
- s->clkidle[4] = 0;
- s->clkidle[5] = 0x0c;
- s->clkidle[6] = 0;
- s->clksel[0] = 0x01;
- s->clksel[1] = 0x02100121;
- s->clksel[2] = 0x00000000;
- s->clksel[3] = 0x01;
- s->clksel[4] = 0;
- s->clksel[7] = 0x0121;
- s->wkup[0] = 0x15;
- s->wkup[1] = 0x13;
- s->wkup[2] = 0x13;
- s->wken[0] = 0x04667ff8;
- s->wken[1] = 0x00000005;
- s->wken[2] = 5;
- s->wkst[0] = 0;
- s->wkst[1] = 0;
- s->wkst[2] = 0;
- s->power[0] = 0x00c;
- s->power[1] = 4;
- s->power[2] = 0x0000c;
- s->power[3] = 0x14;
- s->rstctrl[0] = 1;
- s->rst[3] = 1;
- omap_prcm_apll_update(s);
- omap_prcm_dpll_update(s);
-}
-
-static void omap_prcm_coldreset(struct omap_prcm_s *s)
-{
- s->setuptime[0] = 0;
- s->setuptime[1] = 0;
- memset(&s->scratch, 0, sizeof(s->scratch));
- s->rst[0] = 0x01;
- s->rst[1] = 0x00;
- s->rst[2] = 0x01;
- s->clken[0] = 0;
- s->clken[2] = 0;
- s->clkidle[1] = 0;
- s->clksel[5] = 0;
- s->clksel[6] = 2;
- s->clksrc[0] = 0x43;
- s->clkout[0] = 0x0303;
- s->clkemul[0] = 0;
- s->clkpol[0] = 0x100;
- s->rsttime_wkup = 0x1002;
-
- omap_prcm_reset(s);
-}
-
-static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
- qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
- struct omap_mpu_state_s *mpu)
-{
- struct omap_prcm_s *s = g_new0(struct omap_prcm_s, 1);
-
- s->irq[0] = mpu_int;
- s->irq[1] = dsp_int;
- s->irq[2] = iva_int;
- s->mpu = mpu;
- omap_prcm_coldreset(s);
-
- memory_region_init_io(&s->iomem0, NULL, &omap_prcm_ops, s, "omap.pcrm0",
- omap_l4_region_size(ta, 0));
- memory_region_init_io(&s->iomem1, NULL, &omap_prcm_ops, s, "omap.pcrm1",
- omap_l4_region_size(ta, 1));
- omap_l4_attach(ta, 0, &s->iomem0);
- omap_l4_attach(ta, 1, &s->iomem1);
-
- return s;
-}
-
-/* System and Pinout control */
-struct omap_sysctl_s {
- struct omap_mpu_state_s *mpu;
- MemoryRegion iomem;
-
- uint32_t sysconfig;
- uint32_t devconfig;
- uint32_t psaconfig;
- uint32_t padconf[0x45];
- uint8_t obs;
- uint32_t msuspendmux[5];
-};
-
-static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr)
-{
-
- struct omap_sysctl_s *s = opaque;
- int pad_offset, byte_offset;
- int value;
-
- switch (addr) {
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- pad_offset = (addr - 0x30) >> 2;
- byte_offset = (addr - 0x30) & (4 - 1);
-
- value = s->padconf[pad_offset];
- value = (value >> (byte_offset * 8)) & 0xff;
-
- return value;
-
- default:
- break;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_sysctl_read(void *opaque, hwaddr addr)
-{
- struct omap_sysctl_s *s = opaque;
-
- switch (addr) {
- case 0x000: /* CONTROL_REVISION */
- return 0x20;
-
- case 0x010: /* CONTROL_SYSCONFIG */
- return s->sysconfig;
-
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- return s->padconf[(addr - 0x30) >> 2];
-
- case 0x270: /* CONTROL_DEBOBS */
- return s->obs;
-
- case 0x274: /* CONTROL_DEVCONF */
- return s->devconfig;
-
- case 0x28c: /* CONTROL_EMU_SUPPORT */
- return 0;
-
- case 0x290: /* CONTROL_MSUSPENDMUX_0 */
- return s->msuspendmux[0];
- case 0x294: /* CONTROL_MSUSPENDMUX_1 */
- return s->msuspendmux[1];
- case 0x298: /* CONTROL_MSUSPENDMUX_2 */
- return s->msuspendmux[2];
- case 0x29c: /* CONTROL_MSUSPENDMUX_3 */
- return s->msuspendmux[3];
- case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */
- return s->msuspendmux[4];
- case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */
- return 0;
-
- case 0x2b8: /* CONTROL_PSA_CTRL */
- return s->psaconfig;
- case 0x2bc: /* CONTROL_PSA_CMD */
- case 0x2c0: /* CONTROL_PSA_VALUE */
- return 0;
-
- case 0x2b0: /* CONTROL_SEC_CTRL */
- return 0x800000f1;
- case 0x2d0: /* CONTROL_SEC_EMU */
- return 0x80000015;
- case 0x2d4: /* CONTROL_SEC_TAP */
- return 0x8000007f;
- case 0x2b4: /* CONTROL_SEC_TEST */
- case 0x2f0: /* CONTROL_SEC_STATUS */
- case 0x2f4: /* CONTROL_SEC_ERR_STATUS */
- /* Secure mode is not present on general-pusrpose device. Outside
- * secure mode these values cannot be read or written. */
- return 0;
-
- case 0x2d8: /* CONTROL_OCM_RAM_PERM */
- return 0xff;
- case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */
- case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */
- case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */
- /* No secure mode so no Extended Secure RAM present. */
- return 0;
-
- case 0x2f8: /* CONTROL_STATUS */
- /* Device Type => General-purpose */
- return 0x0300;
- case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */
-
- case 0x300: /* CONTROL_RPUB_KEY_H_0 */
- case 0x304: /* CONTROL_RPUB_KEY_H_1 */
- case 0x308: /* CONTROL_RPUB_KEY_H_2 */
- case 0x30c: /* CONTROL_RPUB_KEY_H_3 */
- return 0xdecafbad;
-
- case 0x310: /* CONTROL_RAND_KEY_0 */
- case 0x314: /* CONTROL_RAND_KEY_1 */
- case 0x318: /* CONTROL_RAND_KEY_2 */
- case 0x31c: /* CONTROL_RAND_KEY_3 */
- case 0x320: /* CONTROL_CUST_KEY_0 */
- case 0x324: /* CONTROL_CUST_KEY_1 */
- case 0x330: /* CONTROL_TEST_KEY_0 */
- case 0x334: /* CONTROL_TEST_KEY_1 */
- case 0x338: /* CONTROL_TEST_KEY_2 */
- case 0x33c: /* CONTROL_TEST_KEY_3 */
- case 0x340: /* CONTROL_TEST_KEY_4 */
- case 0x344: /* CONTROL_TEST_KEY_5 */
- case 0x348: /* CONTROL_TEST_KEY_6 */
- case 0x34c: /* CONTROL_TEST_KEY_7 */
- case 0x350: /* CONTROL_TEST_KEY_8 */
- case 0x354: /* CONTROL_TEST_KEY_9 */
- /* Can only be accessed in secure mode and when C_FieldAccEnable
- * bit is set in CONTROL_SEC_CTRL.
- * TODO: otherwise an interconnect access error is generated. */
- return 0;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sysctl_write8(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_sysctl_s *s = opaque;
- int pad_offset, byte_offset;
- int prev_value;
-
- switch (addr) {
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- pad_offset = (addr - 0x30) >> 2;
- byte_offset = (addr - 0x30) & (4 - 1);
-
- prev_value = s->padconf[pad_offset];
- prev_value &= ~(0xff << (byte_offset * 8));
- prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f;
- s->padconf[pad_offset] = prev_value;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- break;
- }
-}
-
-static void omap_sysctl_write(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_sysctl_s *s = opaque;
-
- switch (addr) {
- case 0x000: /* CONTROL_REVISION */
- case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */
- case 0x2c0: /* CONTROL_PSA_VALUE */
- case 0x2f8: /* CONTROL_STATUS */
- case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */
- case 0x300: /* CONTROL_RPUB_KEY_H_0 */
- case 0x304: /* CONTROL_RPUB_KEY_H_1 */
- case 0x308: /* CONTROL_RPUB_KEY_H_2 */
- case 0x30c: /* CONTROL_RPUB_KEY_H_3 */
- case 0x310: /* CONTROL_RAND_KEY_0 */
- case 0x314: /* CONTROL_RAND_KEY_1 */
- case 0x318: /* CONTROL_RAND_KEY_2 */
- case 0x31c: /* CONTROL_RAND_KEY_3 */
- case 0x320: /* CONTROL_CUST_KEY_0 */
- case 0x324: /* CONTROL_CUST_KEY_1 */
- case 0x330: /* CONTROL_TEST_KEY_0 */
- case 0x334: /* CONTROL_TEST_KEY_1 */
- case 0x338: /* CONTROL_TEST_KEY_2 */
- case 0x33c: /* CONTROL_TEST_KEY_3 */
- case 0x340: /* CONTROL_TEST_KEY_4 */
- case 0x344: /* CONTROL_TEST_KEY_5 */
- case 0x348: /* CONTROL_TEST_KEY_6 */
- case 0x34c: /* CONTROL_TEST_KEY_7 */
- case 0x350: /* CONTROL_TEST_KEY_8 */
- case 0x354: /* CONTROL_TEST_KEY_9 */
- OMAP_RO_REG(addr);
- return;
-
- case 0x010: /* CONTROL_SYSCONFIG */
- s->sysconfig = value & 0x1e;
- break;
-
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- /* XXX: should check constant bits */
- s->padconf[(addr - 0x30) >> 2] = value & 0x1f1f1f1f;
- break;
-
- case 0x270: /* CONTROL_DEBOBS */
- s->obs = value & 0xff;
- break;
-
- case 0x274: /* CONTROL_DEVCONF */
- s->devconfig = value & 0xffffc7ff;
- break;
-
- case 0x28c: /* CONTROL_EMU_SUPPORT */
- break;
-
- case 0x290: /* CONTROL_MSUSPENDMUX_0 */
- s->msuspendmux[0] = value & 0x3fffffff;
- break;
- case 0x294: /* CONTROL_MSUSPENDMUX_1 */
- s->msuspendmux[1] = value & 0x3fffffff;
- break;
- case 0x298: /* CONTROL_MSUSPENDMUX_2 */
- s->msuspendmux[2] = value & 0x3fffffff;
- break;
- case 0x29c: /* CONTROL_MSUSPENDMUX_3 */
- s->msuspendmux[3] = value & 0x3fffffff;
- break;
- case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */
- s->msuspendmux[4] = value & 0x3fffffff;
- break;
-
- case 0x2b8: /* CONTROL_PSA_CTRL */
- s->psaconfig = value & 0x1c;
- s->psaconfig |= (value & 0x20) ? 2 : 1;
- break;
- case 0x2bc: /* CONTROL_PSA_CMD */
- break;
-
- case 0x2b0: /* CONTROL_SEC_CTRL */
- case 0x2b4: /* CONTROL_SEC_TEST */
- case 0x2d0: /* CONTROL_SEC_EMU */
- case 0x2d4: /* CONTROL_SEC_TAP */
- case 0x2d8: /* CONTROL_OCM_RAM_PERM */
- case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */
- case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */
- case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */
- case 0x2f0: /* CONTROL_SEC_STATUS */
- case 0x2f4: /* CONTROL_SEC_ERR_STATUS */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static uint64_t omap_sysctl_readfn(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return omap_sysctl_read8(opaque, addr);
- case 2:
- return omap_badwidth_read32(opaque, addr); /* TODO */
- case 4:
- return omap_sysctl_read(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void omap_sysctl_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 1:
- omap_sysctl_write8(opaque, addr, value);
- break;
- case 2:
- omap_badwidth_write32(opaque, addr, value); /* TODO */
- break;
- case 4:
- omap_sysctl_write(opaque, addr, value);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static const MemoryRegionOps omap_sysctl_ops = {
- .read = omap_sysctl_readfn,
- .write = omap_sysctl_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_sysctl_reset(struct omap_sysctl_s *s)
-{
- /* (power-on reset) */
- s->sysconfig = 0;
- s->obs = 0;
- s->devconfig = 0x0c000000;
- s->msuspendmux[0] = 0x00000000;
- s->msuspendmux[1] = 0x00000000;
- s->msuspendmux[2] = 0x00000000;
- s->msuspendmux[3] = 0x00000000;
- s->msuspendmux[4] = 0x00000000;
- s->psaconfig = 1;
-
- s->padconf[0x00] = 0x000f0f0f;
- s->padconf[0x01] = 0x00000000;
- s->padconf[0x02] = 0x00000000;
- s->padconf[0x03] = 0x00000000;
- s->padconf[0x04] = 0x00000000;
- s->padconf[0x05] = 0x00000000;
- s->padconf[0x06] = 0x00000000;
- s->padconf[0x07] = 0x00000000;
- s->padconf[0x08] = 0x08080800;
- s->padconf[0x09] = 0x08080808;
- s->padconf[0x0a] = 0x08080808;
- s->padconf[0x0b] = 0x08080808;
- s->padconf[0x0c] = 0x08080808;
- s->padconf[0x0d] = 0x08080800;
- s->padconf[0x0e] = 0x08080808;
- s->padconf[0x0f] = 0x08080808;
- s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */
- s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */
- s->padconf[0x15] = 0x18181818;
- s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */
- s->padconf[0x17] = 0x1f001f00;
- s->padconf[0x18] = 0x1f1f1f1f;
- s->padconf[0x19] = 0x00000000;
- s->padconf[0x1a] = 0x1f180000;
- s->padconf[0x1b] = 0x00001f1f;
- s->padconf[0x1c] = 0x1f001f00;
- s->padconf[0x1d] = 0x00000000;
- s->padconf[0x1e] = 0x00000000;
- s->padconf[0x1f] = 0x08000000;
- s->padconf[0x20] = 0x08080808;
- s->padconf[0x21] = 0x08080808;
- s->padconf[0x22] = 0x0f080808;
- s->padconf[0x23] = 0x0f0f0f0f;
- s->padconf[0x24] = 0x000f0f0f;
- s->padconf[0x25] = 0x1f1f1f0f;
- s->padconf[0x26] = 0x080f0f1f;
- s->padconf[0x27] = 0x070f1808;
- s->padconf[0x28] = 0x0f070707;
- s->padconf[0x29] = 0x000f0f1f;
- s->padconf[0x2a] = 0x0f0f0f1f;
- s->padconf[0x2b] = 0x08000000;
- s->padconf[0x2c] = 0x0000001f;
- s->padconf[0x2d] = 0x0f0f1f00;
- s->padconf[0x2e] = 0x1f1f0f0f;
- s->padconf[0x2f] = 0x0f1f1f1f;
- s->padconf[0x30] = 0x0f0f0f0f;
- s->padconf[0x31] = 0x0f1f0f1f;
- s->padconf[0x32] = 0x0f0f0f0f;
- s->padconf[0x33] = 0x0f1f0f1f;
- s->padconf[0x34] = 0x1f1f0f0f;
- s->padconf[0x35] = 0x0f0f1f1f;
- s->padconf[0x36] = 0x0f0f1f0f;
- s->padconf[0x37] = 0x0f0f0f0f;
- s->padconf[0x38] = 0x1f18180f;
- s->padconf[0x39] = 0x1f1f1f1f;
- s->padconf[0x3a] = 0x00001f1f;
- s->padconf[0x3b] = 0x00000000;
- s->padconf[0x3c] = 0x00000000;
- s->padconf[0x3d] = 0x0f0f0f0f;
- s->padconf[0x3e] = 0x18000f0f;
- s->padconf[0x3f] = 0x00070000;
- s->padconf[0x40] = 0x00000707;
- s->padconf[0x41] = 0x0f1f0700;
- s->padconf[0x42] = 0x1f1f070f;
- s->padconf[0x43] = 0x0008081f;
- s->padconf[0x44] = 0x00000800;
-}
-
-static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
- omap_clk iclk, struct omap_mpu_state_s *mpu)
-{
- struct omap_sysctl_s *s = g_new0(struct omap_sysctl_s, 1);
-
- s->mpu = mpu;
- omap_sysctl_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sysctl_ops, s, "omap.sysctl",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-/* General chip reset */
-static void omap2_mpu_reset(void *opaque)
-{
- struct omap_mpu_state_s *mpu = opaque;
-
- omap_dma_reset(mpu->dma);
- omap_prcm_reset(mpu->prcm);
- omap_sysctl_reset(mpu->sysc);
- omap_gp_timer_reset(mpu->gptimer[0]);
- omap_gp_timer_reset(mpu->gptimer[1]);
- omap_gp_timer_reset(mpu->gptimer[2]);
- omap_gp_timer_reset(mpu->gptimer[3]);
- omap_gp_timer_reset(mpu->gptimer[4]);
- omap_gp_timer_reset(mpu->gptimer[5]);
- omap_gp_timer_reset(mpu->gptimer[6]);
- omap_gp_timer_reset(mpu->gptimer[7]);
- omap_gp_timer_reset(mpu->gptimer[8]);
- omap_gp_timer_reset(mpu->gptimer[9]);
- omap_gp_timer_reset(mpu->gptimer[10]);
- omap_gp_timer_reset(mpu->gptimer[11]);
- omap_synctimer_reset(mpu->synctimer);
- omap_sdrc_reset(mpu->sdrc);
- omap_gpmc_reset(mpu->gpmc);
- omap_dss_reset(mpu->dss);
- omap_uart_reset(mpu->uart[0]);
- omap_uart_reset(mpu->uart[1]);
- omap_uart_reset(mpu->uart[2]);
- omap_mmc_reset(mpu->mmc);
- omap_mcspi_reset(mpu->mcspi[0]);
- omap_mcspi_reset(mpu->mcspi[1]);
- cpu_reset(CPU(mpu->cpu));
-}
-
-static int omap2_validate_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return 1;
-}
-
-static const struct dma_irq_map omap2_dma_irq_map[] = {
- { 0, OMAP_INT_24XX_SDMA_IRQ0 },
- { 0, OMAP_INT_24XX_SDMA_IRQ1 },
- { 0, OMAP_INT_24XX_SDMA_IRQ2 },
- { 0, OMAP_INT_24XX_SDMA_IRQ3 },
-};
-
-struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
- const char *cpu_type)
-{
- struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
- qemu_irq dma_irqs[4];
- DriveInfo *dinfo;
- int i;
- SysBusDevice *busdev;
- struct omap_target_agent_s *ta;
- MemoryRegion *sysmem = get_system_memory();
-
- /* Core */
- s->mpu_model = omap2420;
- s->cpu = ARM_CPU(cpu_create(cpu_type));
- s->sram_size = OMAP242X_SRAM_SIZE;
-
- s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0);
-
- /* Clocks */
- omap_clk_init(s);
-
- /* Memory-mapped stuff */
- memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size,
- &error_fatal);
- memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram);
-
- s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54);
-
- /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
- s->ih[0] = qdev_new("omap2-intc");
- qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
- omap_intc_set_fclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_fclk"));
- omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_iclk"));
- busdev = SYS_BUS_DEVICE(s->ih[0]);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
- sysbus_connect_irq(busdev, 1,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
- sysbus_mmio_map(busdev, 0, 0x480fe000);
- s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_PRCM_MPU_IRQ),
- NULL, NULL, s);
-
- s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
- omap_findclk(s, "omapctrl_iclk"), s);
-
- for (i = 0; i < 4; i++) {
- dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih],
- omap2_dma_irq_map[i].intr);
- }
- s->dma = omap_dma4_init(0x48056000, dma_irqs, sysmem, s, 256, 32,
- omap_findclk(s, "sdma_iclk"),
- omap_findclk(s, "sdma_fclk"));
- s->port->addr_valid = omap2_validate_addr;
-
- /* Register SDRAM and SRAM ports for fast DMA transfers. */
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(sdram),
- OMAP2_Q2_BASE, memory_region_size(sdram));
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram),
- OMAP2_SRAM_BASE, s->sram_size);
-
- s->uart[0] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 19),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART1_IRQ),
- omap_findclk(s, "uart1_fclk"),
- omap_findclk(s, "uart1_iclk"),
- s->drq[OMAP24XX_DMA_UART1_TX],
- s->drq[OMAP24XX_DMA_UART1_RX],
- "uart1",
- serial_hd(0));
- s->uart[1] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 20),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART2_IRQ),
- omap_findclk(s, "uart2_fclk"),
- omap_findclk(s, "uart2_iclk"),
- s->drq[OMAP24XX_DMA_UART2_TX],
- s->drq[OMAP24XX_DMA_UART2_RX],
- "uart2",
- serial_hd(0) ? serial_hd(1) : NULL);
- s->uart[2] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 21),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART3_IRQ),
- omap_findclk(s, "uart3_fclk"),
- omap_findclk(s, "uart3_iclk"),
- s->drq[OMAP24XX_DMA_UART3_TX],
- s->drq[OMAP24XX_DMA_UART3_RX],
- "uart3",
- serial_hd(0) && serial_hd(1) ? serial_hd(2) : NULL);
-
- s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1),
- omap_findclk(s, "wu_gpt1_clk"),
- omap_findclk(s, "wu_l4_iclk"));
- s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2),
- omap_findclk(s, "core_gpt2_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3),
- omap_findclk(s, "core_gpt3_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4),
- omap_findclk(s, "core_gpt4_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5),
- omap_findclk(s, "core_gpt5_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6),
- omap_findclk(s, "core_gpt6_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7),
- omap_findclk(s, "core_gpt7_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8),
- omap_findclk(s, "core_gpt8_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9),
- omap_findclk(s, "core_gpt9_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10),
- omap_findclk(s, "core_gpt10_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11),
- omap_findclk(s, "core_gpt11_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12),
- omap_findclk(s, "core_gpt12_clk"),
- omap_findclk(s, "core_l4_iclk"));
-
- omap_tap_init(omap_l4ta(s->l4, 2), s);
-
- s->synctimer = omap_synctimer_init(omap_l4tao(s->l4, 2), s,
- omap_findclk(s, "clk32-kHz"),
- omap_findclk(s, "core_l4_iclk"));
-
- s->i2c[0] = qdev_new("omap_i2c");
- qdev_prop_set_uint8(s->i2c[0], "revision", 0x34);
- omap_i2c_set_iclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.iclk"));
- omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.fclk"));
- busdev = SYS_BUS_DEVICE(s->i2c[0]);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ));
- sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]);
- sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0));
-
- s->i2c[1] = qdev_new("omap_i2c");
- qdev_prop_set_uint8(s->i2c[1], "revision", 0x34);
- omap_i2c_set_iclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.iclk"));
- omap_i2c_set_fclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.fclk"));
- busdev = SYS_BUS_DEVICE(s->i2c[1]);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ));
- sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]);
- sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0));
-
- s->gpio = qdev_new("omap2-gpio");
- qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
- omap2_gpio_set_iclk(OMAP2_GPIO(s->gpio), omap_findclk(s, "gpio_iclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 0, omap_findclk(s, "gpio1_dbclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 1, omap_findclk(s, "gpio2_dbclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 2, omap_findclk(s, "gpio3_dbclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 3, omap_findclk(s, "gpio4_dbclk"));
- if (s->mpu_model == omap2430) {
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 4,
- omap_findclk(s, "gpio5_dbclk"));
- }
- busdev = SYS_BUS_DEVICE(s->gpio);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1));
- sysbus_connect_irq(busdev, 3,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2));
- sysbus_connect_irq(busdev, 6,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3));
- sysbus_connect_irq(busdev, 9,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4));
- if (s->mpu_model == omap2430) {
- sysbus_connect_irq(busdev, 12,
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_243X_GPIO_BANK5));
- }
- ta = omap_l4ta(s->l4, 3);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
- sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
- sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2));
- sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4));
- sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
-
- s->sdrc = omap_sdrc_init(sysmem, 0x68009000);
- s->gpmc = omap_gpmc_init(s, 0x6800a000,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ),
- s->drq[OMAP24XX_DMA_GPMC]);
-
- dinfo = drive_get(IF_SD, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- warn_report("missing SecureDigital device");
- }
- s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9),
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
- &s->drq[OMAP24XX_DMA_MMC1_TX],
- omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
-
- s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ),
- &s->drq[OMAP24XX_DMA_SPI1_TX0],
- omap_findclk(s, "spi1_fclk"),
- omap_findclk(s, "spi1_iclk"));
- s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ),
- &s->drq[OMAP24XX_DMA_SPI2_TX0],
- omap_findclk(s, "spi2_fclk"),
- omap_findclk(s, "spi2_iclk"));
-
- s->dss = omap_dss_init(omap_l4ta(s->l4, 10), sysmem, 0x68000800,
- /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ),
- s->drq[OMAP24XX_DMA_DSS],
- omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
- omap_findclk(s, "dss_54m_clk"),
- omap_findclk(s, "dss_l3_iclk"),
- omap_findclk(s, "dss_l4_iclk"));
-
- omap_sti_init(omap_l4ta(s->l4, 18), sysmem, 0x54000000,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI),
- omap_findclk(s, "emul_ck"),
- serial_hd(0) && serial_hd(1) && serial_hd(2) ?
- serial_hd(3) : NULL);
-
- s->eac = omap_eac_init(omap_l4ta(s->l4, 32),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ),
- /* Ten consecutive lines */
- &s->drq[OMAP24XX_DMA_EAC_AC_RD],
- omap_findclk(s, "func_96m_clk"),
- omap_findclk(s, "core_l4_iclk"));
-
- /* All register mappings (including those not currently implemented):
- * SystemControlMod 48000000 - 48000fff
- * SystemControlL4 48001000 - 48001fff
- * 32kHz Timer Mod 48004000 - 48004fff
- * 32kHz Timer L4 48005000 - 48005fff
- * PRCM ModA 48008000 - 480087ff
- * PRCM ModB 48008800 - 48008fff
- * PRCM L4 48009000 - 48009fff
- * TEST-BCM Mod 48012000 - 48012fff
- * TEST-BCM L4 48013000 - 48013fff
- * TEST-TAP Mod 48014000 - 48014fff
- * TEST-TAP L4 48015000 - 48015fff
- * GPIO1 Mod 48018000 - 48018fff
- * GPIO Top 48019000 - 48019fff
- * GPIO2 Mod 4801a000 - 4801afff
- * GPIO L4 4801b000 - 4801bfff
- * GPIO3 Mod 4801c000 - 4801cfff
- * GPIO4 Mod 4801e000 - 4801efff
- * WDTIMER1 Mod 48020000 - 48010fff
- * WDTIMER Top 48021000 - 48011fff
- * WDTIMER2 Mod 48022000 - 48012fff
- * WDTIMER L4 48023000 - 48013fff
- * WDTIMER3 Mod 48024000 - 48014fff
- * WDTIMER3 L4 48025000 - 48015fff
- * WDTIMER4 Mod 48026000 - 48016fff
- * WDTIMER4 L4 48027000 - 48017fff
- * GPTIMER1 Mod 48028000 - 48018fff
- * GPTIMER1 L4 48029000 - 48019fff
- * GPTIMER2 Mod 4802a000 - 4801afff
- * GPTIMER2 L4 4802b000 - 4801bfff
- * L4-Config AP 48040000 - 480407ff
- * L4-Config IP 48040800 - 48040fff
- * L4-Config LA 48041000 - 48041fff
- * ARM11ETB Mod 48048000 - 48049fff
- * ARM11ETB L4 4804a000 - 4804afff
- * DISPLAY Top 48050000 - 480503ff
- * DISPLAY DISPC 48050400 - 480507ff
- * DISPLAY RFBI 48050800 - 48050bff
- * DISPLAY VENC 48050c00 - 48050fff
- * DISPLAY L4 48051000 - 48051fff
- * CAMERA Top 48052000 - 480523ff
- * CAMERA core 48052400 - 480527ff
- * CAMERA DMA 48052800 - 48052bff
- * CAMERA MMU 48052c00 - 48052fff
- * CAMERA L4 48053000 - 48053fff
- * SDMA Mod 48056000 - 48056fff
- * SDMA L4 48057000 - 48057fff
- * SSI Top 48058000 - 48058fff
- * SSI GDD 48059000 - 48059fff
- * SSI Port1 4805a000 - 4805afff
- * SSI Port2 4805b000 - 4805bfff
- * SSI L4 4805c000 - 4805cfff
- * USB Mod 4805e000 - 480fefff
- * USB L4 4805f000 - 480fffff
- * WIN_TRACER1 Mod 48060000 - 48060fff
- * WIN_TRACER1 L4 48061000 - 48061fff
- * WIN_TRACER2 Mod 48062000 - 48062fff
- * WIN_TRACER2 L4 48063000 - 48063fff
- * WIN_TRACER3 Mod 48064000 - 48064fff
- * WIN_TRACER3 L4 48065000 - 48065fff
- * WIN_TRACER4 Top 48066000 - 480660ff
- * WIN_TRACER4 ETT 48066100 - 480661ff
- * WIN_TRACER4 WT 48066200 - 480662ff
- * WIN_TRACER4 L4 48067000 - 48067fff
- * XTI Mod 48068000 - 48068fff
- * XTI L4 48069000 - 48069fff
- * UART1 Mod 4806a000 - 4806afff
- * UART1 L4 4806b000 - 4806bfff
- * UART2 Mod 4806c000 - 4806cfff
- * UART2 L4 4806d000 - 4806dfff
- * UART3 Mod 4806e000 - 4806efff
- * UART3 L4 4806f000 - 4806ffff
- * I2C1 Mod 48070000 - 48070fff
- * I2C1 L4 48071000 - 48071fff
- * I2C2 Mod 48072000 - 48072fff
- * I2C2 L4 48073000 - 48073fff
- * McBSP1 Mod 48074000 - 48074fff
- * McBSP1 L4 48075000 - 48075fff
- * McBSP2 Mod 48076000 - 48076fff
- * McBSP2 L4 48077000 - 48077fff
- * GPTIMER3 Mod 48078000 - 48078fff
- * GPTIMER3 L4 48079000 - 48079fff
- * GPTIMER4 Mod 4807a000 - 4807afff
- * GPTIMER4 L4 4807b000 - 4807bfff
- * GPTIMER5 Mod 4807c000 - 4807cfff
- * GPTIMER5 L4 4807d000 - 4807dfff
- * GPTIMER6 Mod 4807e000 - 4807efff
- * GPTIMER6 L4 4807f000 - 4807ffff
- * GPTIMER7 Mod 48080000 - 48080fff
- * GPTIMER7 L4 48081000 - 48081fff
- * GPTIMER8 Mod 48082000 - 48082fff
- * GPTIMER8 L4 48083000 - 48083fff
- * GPTIMER9 Mod 48084000 - 48084fff
- * GPTIMER9 L4 48085000 - 48085fff
- * GPTIMER10 Mod 48086000 - 48086fff
- * GPTIMER10 L4 48087000 - 48087fff
- * GPTIMER11 Mod 48088000 - 48088fff
- * GPTIMER11 L4 48089000 - 48089fff
- * GPTIMER12 Mod 4808a000 - 4808afff
- * GPTIMER12 L4 4808b000 - 4808bfff
- * EAC Mod 48090000 - 48090fff
- * EAC L4 48091000 - 48091fff
- * FAC Mod 48092000 - 48092fff
- * FAC L4 48093000 - 48093fff
- * MAILBOX Mod 48094000 - 48094fff
- * MAILBOX L4 48095000 - 48095fff
- * SPI1 Mod 48098000 - 48098fff
- * SPI1 L4 48099000 - 48099fff
- * SPI2 Mod 4809a000 - 4809afff
- * SPI2 L4 4809b000 - 4809bfff
- * MMC/SDIO Mod 4809c000 - 4809cfff
- * MMC/SDIO L4 4809d000 - 4809dfff
- * MS_PRO Mod 4809e000 - 4809efff
- * MS_PRO L4 4809f000 - 4809ffff
- * RNG Mod 480a0000 - 480a0fff
- * RNG L4 480a1000 - 480a1fff
- * DES3DES Mod 480a2000 - 480a2fff
- * DES3DES L4 480a3000 - 480a3fff
- * SHA1MD5 Mod 480a4000 - 480a4fff
- * SHA1MD5 L4 480a5000 - 480a5fff
- * AES Mod 480a6000 - 480a6fff
- * AES L4 480a7000 - 480a7fff
- * PKA Mod 480a8000 - 480a9fff
- * PKA L4 480aa000 - 480aafff
- * MG Mod 480b0000 - 480b0fff
- * MG L4 480b1000 - 480b1fff
- * HDQ/1-wire Mod 480b2000 - 480b2fff
- * HDQ/1-wire L4 480b3000 - 480b3fff
- * MPU interrupt 480fe000 - 480fefff
- * STI channel base 54000000 - 5400ffff
- * IVA RAM 5c000000 - 5c01ffff
- * IVA ROM 5c020000 - 5c027fff
- * IMG_BUF_A 5c040000 - 5c040fff
- * IMG_BUF_B 5c042000 - 5c042fff
- * VLCDS 5c048000 - 5c0487ff
- * IMX_COEF 5c049000 - 5c04afff
- * IMX_CMD 5c051000 - 5c051fff
- * VLCDQ 5c053000 - 5c0533ff
- * VLCDH 5c054000 - 5c054fff
- * SEQ_CMD 5c055000 - 5c055fff
- * IMX_REG 5c056000 - 5c0560ff
- * VLCD_REG 5c056100 - 5c0561ff
- * SEQ_REG 5c056200 - 5c0562ff
- * IMG_BUF_REG 5c056300 - 5c0563ff
- * SEQIRQ_REG 5c056400 - 5c0564ff
- * OCP_REG 5c060000 - 5c060fff
- * SYSC_REG 5c070000 - 5c070fff
- * MMU_REG 5d000000 - 5d000fff
- * sDMA R 68000400 - 680005ff
- * sDMA W 68000600 - 680007ff
- * Display Control 68000800 - 680009ff
- * DSP subsystem 68000a00 - 68000bff
- * MPU subsystem 68000c00 - 68000dff
- * IVA subsystem 68001000 - 680011ff
- * USB 68001200 - 680013ff
- * Camera 68001400 - 680015ff
- * VLYNQ (firewall) 68001800 - 68001bff
- * VLYNQ 68001e00 - 68001fff
- * SSI 68002000 - 680021ff
- * L4 68002400 - 680025ff
- * DSP (firewall) 68002800 - 68002bff
- * DSP subsystem 68002e00 - 68002fff
- * IVA (firewall) 68003000 - 680033ff
- * IVA 68003600 - 680037ff
- * GFX 68003a00 - 68003bff
- * CMDWR emulation 68003c00 - 68003dff
- * SMS 68004000 - 680041ff
- * OCM 68004200 - 680043ff
- * GPMC 68004400 - 680045ff
- * RAM (firewall) 68005000 - 680053ff
- * RAM (err login) 68005400 - 680057ff
- * ROM (firewall) 68005800 - 68005bff
- * ROM (err login) 68005c00 - 68005fff
- * GPMC (firewall) 68006000 - 680063ff
- * GPMC (err login) 68006400 - 680067ff
- * SMS (err login) 68006c00 - 68006fff
- * SMS registers 68008000 - 68008fff
- * SDRC registers 68009000 - 68009fff
- * GPMC registers 6800a000 6800afff
- */
-
- qemu_register_reset(omap2_mpu_reset, s);
-
- return s;
-}
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index 62d7915..5d4a31b 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -1,7 +1,7 @@
/* omap_sx1.c Support for the Siemens SX1 smartphone emulation.
*
* Copyright (C) 2008
- * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
* Copyright (C) 2007 Vladimir Ananiev <vovan888@gmail.com>
*
* based on PalmOne's (TM) PDAs support (palm.c)
@@ -33,8 +33,8 @@
#include "hw/boards.h"
#include "hw/arm/boot.h"
#include "hw/block/flash.h"
-#include "sysemu/qtest.h"
-#include "exec/address-spaces.h"
+#include "system/qtest.h"
+#include "system/address-spaces.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
@@ -76,10 +76,6 @@ static uint64_t static_read(void *opaque, hwaddr offset,
static void static_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
-#ifdef SPY
- printf("%s: value %" PRIx64 " %u bytes written at 0x%x\n",
- __func__, value, size, (int)offset);
-#endif
}
static const MemoryRegionOps static_ops = {
@@ -206,7 +202,7 @@ static void sx1_init_v2(MachineState *machine)
sx1_init(machine, 2);
}
-static void sx1_machine_v2_class_init(ObjectClass *oc, void *data)
+static void sx1_machine_v2_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -216,6 +212,7 @@ static void sx1_machine_v2_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t");
mc->default_ram_size = SDRAM_SIZE;
mc->default_ram_id = "omap1.dram";
+ mc->auto_create_sdcard = true;
}
static const TypeInfo sx1_machine_v2_type = {
@@ -224,7 +221,7 @@ static const TypeInfo sx1_machine_v2_type = {
.class_init = sx1_machine_v2_class_init,
};
-static void sx1_machine_v1_class_init(ObjectClass *oc, void *data)
+static void sx1_machine_v1_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -234,6 +231,7 @@ static void sx1_machine_v1_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t");
mc->default_ram_size = SDRAM_SIZE;
mc->default_ram_id = "omap1.dram";
+ mc->auto_create_sdcard = true;
}
static const TypeInfo sx1_machine_v1_type = {
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index 77e3281..e095688 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -19,7 +19,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/boards.h"
@@ -121,6 +121,7 @@ static void orangepi_machine_init(MachineClass *mc)
mc->valid_cpu_types = valid_cpu_types;
mc->default_ram_size = 1 * GiB;
mc->default_ram_id = "orangepi.ram";
+ mc->auto_create_sdcard = true;
}
DEFINE_MACHINE("orangepi-pc", orangepi_machine_init)
diff --git a/hw/arm/palm.c b/hw/arm/palm.c
deleted file mode 100644
index e04ac92..0000000
--- a/hw/arm/palm.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "audio/audio.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-#include "hw/boards.h"
-#include "hw/arm/boot.h"
-#include "hw/input/tsc2xxx.h"
-#include "hw/irq.h"
-#include "hw/loader.h"
-#include "qemu/cutils.h"
-#include "qom/object.h"
-#include "qemu/error-report.h"
-
-
-static uint64_t static_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t *val = (uint32_t *)opaque;
- uint32_t sizemask = 7 >> size;
-
- return *val >> ((offset & sizemask) << 3);
-}
-
-static void static_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
-#ifdef SPY
- printf("%s: value %08lx written at " PA_FMT "\n",
- __func__, value, offset);
-#endif
-}
-
-static const MemoryRegionOps static_ops = {
- .read = static_read,
- .write = static_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Palm Tunsgten|E support */
-
-/* Shared GPIOs */
-#define PALMTE_USBDETECT_GPIO 0
-#define PALMTE_USB_OR_DC_GPIO 1
-#define PALMTE_TSC_GPIO 4
-#define PALMTE_PINTDAV_GPIO 6
-#define PALMTE_MMC_WP_GPIO 8
-#define PALMTE_MMC_POWER_GPIO 9
-#define PALMTE_HDQ_GPIO 11
-#define PALMTE_HEADPHONES_GPIO 14
-#define PALMTE_SPEAKER_GPIO 15
-/* MPU private GPIOs */
-#define PALMTE_DC_GPIO 2
-#define PALMTE_MMC_SWITCH_GPIO 4
-#define PALMTE_MMC1_GPIO 6
-#define PALMTE_MMC2_GPIO 7
-#define PALMTE_MMC3_GPIO 11
-
-static MouseTransformInfo palmte_pointercal = {
- .x = 320,
- .y = 320,
- .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
-};
-
-static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
-{
- uWireSlave *tsc;
-
- tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
-
- omap_uwire_attach(cpu->microwire, tsc, 0);
- omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
-
- tsc210x_set_transform(tsc, &palmte_pointercal);
-}
-
-static struct {
- int row;
- int column;
-} palmte_keymap[0x80] = {
- [0 ... 0x7f] = { -1, -1 },
- [0x3b] = { 0, 0 }, /* F1 -> Calendar */
- [0x3c] = { 1, 0 }, /* F2 -> Contacts */
- [0x3d] = { 2, 0 }, /* F3 -> Tasks List */
- [0x3e] = { 3, 0 }, /* F4 -> Note Pad */
- [0x01] = { 4, 0 }, /* Esc -> Power */
- [0x4b] = { 0, 1 }, /* Left */
- [0x50] = { 1, 1 }, /* Down */
- [0x48] = { 2, 1 }, /* Up */
- [0x4d] = { 3, 1 }, /* Right */
- [0x4c] = { 4, 1 }, /* Centre */
- [0x39] = { 4, 1 }, /* Spc -> Centre */
-};
-
-static void palmte_button_event(void *opaque, int keycode)
-{
- struct omap_mpu_state_s *cpu = opaque;
-
- if (palmte_keymap[keycode & 0x7f].row != -1)
- omap_mpuio_key(cpu->mpuio,
- palmte_keymap[keycode & 0x7f].row,
- palmte_keymap[keycode & 0x7f].column,
- !(keycode & 0x80));
-}
-
-/*
- * Encapsulation of some GPIO line behaviour for the Palm board
- *
- * QEMU interface:
- * + unnamed GPIO inputs 0..6: for the various miscellaneous input lines
- */
-
-#define TYPE_PALM_MISC_GPIO "palm-misc-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(PalmMiscGPIOState, PALM_MISC_GPIO)
-
-struct PalmMiscGPIOState {
- SysBusDevice parent_obj;
-};
-
-static void palmte_onoff_gpios(void *opaque, int line, int level)
-{
- switch (line) {
- case 0:
- printf("%s: current to MMC/SD card %sabled.\n",
- __func__, level ? "dis" : "en");
- break;
- case 1:
- printf("%s: internal speaker amplifier %s.\n",
- __func__, level ? "down" : "on");
- break;
-
- /* These LCD & Audio output signals have not been identified yet. */
- case 2:
- case 3:
- case 4:
- printf("%s: LCD GPIO%i %s.\n",
- __func__, line - 1, level ? "high" : "low");
- break;
- case 5:
- case 6:
- printf("%s: Audio GPIO%i %s.\n",
- __func__, line - 4, level ? "high" : "low");
- break;
- }
-}
-
-static void palm_misc_gpio_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
-
- qdev_init_gpio_in(dev, palmte_onoff_gpios, 7);
-}
-
-static const TypeInfo palm_misc_gpio_info = {
- .name = TYPE_PALM_MISC_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PalmMiscGPIOState),
- .instance_init = palm_misc_gpio_init,
- /*
- * No class init required: device has no internal state so does not
- * need to set up reset or vmstate, and has no realize method.
- */
-};
-
-static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
-{
- DeviceState *misc_gpio;
-
- misc_gpio = sysbus_create_simple(TYPE_PALM_MISC_GPIO, -1, NULL);
-
- omap_mmc_handlers(cpu->mmc,
- qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
- qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
- [PALMTE_MMC_SWITCH_GPIO]));
-
- qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO,
- qdev_get_gpio_in(misc_gpio, 0));
- qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO,
- qdev_get_gpio_in(misc_gpio, 1));
- qdev_connect_gpio_out(cpu->gpio, 11, qdev_get_gpio_in(misc_gpio, 2));
- qdev_connect_gpio_out(cpu->gpio, 12, qdev_get_gpio_in(misc_gpio, 3));
- qdev_connect_gpio_out(cpu->gpio, 13, qdev_get_gpio_in(misc_gpio, 4));
- omap_mpuio_out_set(cpu->mpuio, 1, qdev_get_gpio_in(misc_gpio, 5));
- omap_mpuio_out_set(cpu->mpuio, 3, qdev_get_gpio_in(misc_gpio, 6));
-
- /* Reset some inputs to initial state. */
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
- qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
-}
-
-static struct arm_boot_info palmte_binfo = {
- .loader_start = OMAP_EMIFF_BASE,
- .ram_size = 0x02000000,
- .board_id = 0x331,
-};
-
-static void palmte_init(MachineState *machine)
-{
- MemoryRegion *address_space_mem = get_system_memory();
- struct omap_mpu_state_s *mpu;
- int flash_size = 0x00800000;
- static uint32_t cs0val = 0xffffffff;
- static uint32_t cs1val = 0x0000e1a0;
- static uint32_t cs2val = 0x0000e1a0;
- static uint32_t cs3val = 0xe1a0e1a0;
- int rom_size, rom_loaded = 0;
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *cs = g_new(MemoryRegion, 4);
-
- if (machine->ram_size != mc->default_ram_size) {
- char *sz = size_to_str(mc->default_ram_size);
- error_report("Invalid RAM size, should be %s", sz);
- g_free(sz);
- exit(EXIT_FAILURE);
- }
-
- memory_region_add_subregion(address_space_mem, OMAP_EMIFF_BASE,
- machine->ram);
-
- mpu = omap310_mpu_init(machine->ram, machine->cpu_type);
-
- /* External Flash (EMIFS) */
- memory_region_init_rom(flash, NULL, "palmte.flash", flash_size,
- &error_fatal);
- memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
-
- memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val, "palmte-cs0",
- OMAP_CS0_SIZE - flash_size);
- memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
- &cs[0]);
- memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, "palmte-cs1",
- OMAP_CS1_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
- memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val, "palmte-cs2",
- OMAP_CS2_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
- memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val, "palmte-cs3",
- OMAP_CS3_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
-
- palmte_microwire_setup(mpu);
-
- qemu_add_kbd_event_handler(palmte_button_event, mpu);
-
- palmte_gpio_setup(mpu);
-
- /* Setup initial (reset) machine state */
- if (nb_option_roms) {
- rom_size = get_image_size(option_rom[0].name);
- if (rom_size > flash_size) {
- fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
- __func__, rom_size, flash_size);
- rom_size = 0;
- }
- if (rom_size > 0) {
- rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
- flash_size);
- rom_loaded = 1;
- }
- if (rom_size < 0) {
- fprintf(stderr, "%s: error loading '%s'\n",
- __func__, option_rom[0].name);
- }
- }
-
- if (!rom_loaded && !machine->kernel_filename && !qtest_enabled()) {
- fprintf(stderr, "Kernel or ROM image must be specified\n");
- exit(1);
- }
-
- /* Load the kernel. */
- arm_load_kernel(mpu->cpu, machine, &palmte_binfo);
-}
-
-static void palmte_machine_init(MachineClass *mc)
-{
- mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)";
- mc->init = palmte_init;
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t");
- mc->default_ram_size = 0x02000000;
- mc->default_ram_id = "omap1.dram";
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-DEFINE_MACHINE("cheetah", palmte_machine_init)
-
-static void palm_register_types(void)
-{
- type_register_static(&palm_misc_gpio_info);
-}
-
-type_init(palm_register_types)
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
deleted file mode 100644
index 6b2e544..0000000
--- a/hw/arm/pxa2xx.c
+++ /dev/null
@@ -1,2393 +0,0 @@
-/*
- * Intel XScale PXA255/270 processor support.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "sysemu/sysemu.h"
-#include "hw/char/serial.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/ssi/ssi.h"
-#include "hw/sd/sd.h"
-#include "chardev/char-fe.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/qtest.h"
-#include "sysemu/rtc.h"
-#include "qemu/cutils.h"
-#include "qemu/log.h"
-#include "qom/object.h"
-#include "target/arm/cpregs.h"
-
-static struct {
- hwaddr io_base;
- int irqn;
-} pxa255_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0x41600000, PXA25X_PIC_HWUART },
- { 0, 0 }
-}, pxa270_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0, 0 }
-};
-
-typedef struct PXASSPDef {
- hwaddr io_base;
- int irqn;
-} PXASSPDef;
-
-#if 0
-static PXASSPDef pxa250_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0, 0 }
-};
-#endif
-
-static PXASSPDef pxa255_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41400000, PXA25X_PIC_NSSP },
- { 0, 0 }
-};
-
-#if 0
-static PXASSPDef pxa26x_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41400000, PXA25X_PIC_NSSP },
- { 0x41500000, PXA26X_PIC_ASSP },
- { 0, 0 }
-};
-#endif
-
-static PXASSPDef pxa27x_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41700000, PXA27X_PIC_SSP2 },
- { 0x41900000, PXA2XX_PIC_SSP3 },
- { 0, 0 }
-};
-
-#define PMCR 0x00 /* Power Manager Control register */
-#define PSSR 0x04 /* Power Manager Sleep Status register */
-#define PSPR 0x08 /* Power Manager Scratch-Pad register */
-#define PWER 0x0c /* Power Manager Wake-Up Enable register */
-#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */
-#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */
-#define PEDR 0x18 /* Power Manager Edge-Detect Status register */
-#define PCFR 0x1c /* Power Manager General Configuration register */
-#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */
-#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */
-#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */
-#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */
-#define RCSR 0x30 /* Reset Controller Status register */
-#define PSLR 0x34 /* Power Manager Sleep Configuration register */
-#define PTSR 0x38 /* Power Manager Standby Configuration register */
-#define PVCR 0x40 /* Power Manager Voltage Change Control register */
-#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */
-#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */
-#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */
-#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */
-#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */
-
-static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case PMCR ... PCMD31:
- if (addr & 3)
- goto fail;
-
- return s->pm_regs[addr >> 2];
- default:
- fail:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_pm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case PMCR:
- /* Clear the write-one-to-clear bits... */
- s->pm_regs[addr >> 2] &= ~(value & 0x2a);
- /* ...and set the plain r/w bits */
- s->pm_regs[addr >> 2] &= ~0x15;
- s->pm_regs[addr >> 2] |= value & 0x15;
- break;
-
- case PSSR: /* Read-clean registers */
- case RCSR:
- case PKSR:
- s->pm_regs[addr >> 2] &= ~value;
- break;
-
- default: /* Read-write registers */
- if (!(addr & 3)) {
- s->pm_regs[addr >> 2] = value;
- break;
- }
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_pm_ops = {
- .read = pxa2xx_pm_read,
- .write = pxa2xx_pm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_pm = {
- .name = "pxa2xx_pm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define CCCR 0x00 /* Core Clock Configuration register */
-#define CKEN 0x04 /* Clock Enable register */
-#define OSCC 0x08 /* Oscillator Configuration register */
-#define CCSR 0x0c /* Core Clock Status register */
-
-static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- case OSCC:
- return s->cm_regs[addr >> 2];
-
- case CCSR:
- return s->cm_regs[CCCR >> 2] | (3 << 28);
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_cm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- s->cm_regs[addr >> 2] = value;
- break;
-
- case OSCC:
- s->cm_regs[addr >> 2] &= ~0x6c;
- s->cm_regs[addr >> 2] |= value & 0x6e;
- if ((value >> 1) & 1) /* OON */
- s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_cm_ops = {
- .read = pxa2xx_cm_read,
- .write = pxa2xx_cm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_cm = {
- .name = "pxa2xx_cm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
- VMSTATE_UINT32(clkcfg, PXA2xxState),
- VMSTATE_UINT32(pmnc, PXA2xxState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- return s->clkcfg;
-}
-
-static void pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- s->clkcfg = value & 0xf;
- if (value & 2) {
- printf("%s: CPU frequency change attempt\n", __func__);
- }
-}
-
-static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- static const char *pwrmode[8] = {
- "Normal", "Idle", "Deep-idle", "Standby",
- "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
- };
-
- if (value & 8) {
- printf("%s: CPU voltage change attempt\n", __func__);
- }
- switch (value & 7) {
- case 0:
- /* Do nothing */
- break;
-
- case 1:
- /* Idle */
- if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
- break;
- }
- /* Fall through. */
-
- case 2:
- /* Deep-Idle */
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
- goto message;
-
- case 3:
- s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
- s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
- s->cpu->env.cp15.sctlr_ns = 0;
- s->cpu->env.cp15.cpacr_el1 = 0;
- s->cpu->env.cp15.ttbr0_el[1] = 0;
- s->cpu->env.cp15.dacr_ns = 0;
- s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
-
- /*
- * The scratch-pad register is almost universally used
- * for storing the return address on suspend. For the
- * lack of a resuming bootloader, perform a jump
- * directly to that address.
- */
- memset(s->cpu->env.regs, 0, 4 * 15);
- s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2];
-
-#if 0
- buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
- cpu_physical_memory_write(0, &buffer, 4);
- buffer = s->pm_regs[PSPR >> 2];
- cpu_physical_memory_write(8, &buffer, 4);
-#endif
-
- /* Suspend */
- cpu_interrupt(current_cpu, CPU_INTERRUPT_HALT);
-
- goto message;
-
- default:
- message:
- printf("%s: machine entered %s mode\n", __func__,
- pwrmode[value & 7]);
- }
-}
-
-static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- return s->pmnc;
-}
-
-static void pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- s->pmnc = value;
-}
-
-static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- if (s->pmnc & 1) {
- return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- } else {
- return 0;
- }
-}
-
-static const ARMCPRegInfo pxa_cp_reginfo[] = {
- /* cp14 crm==1: perf registers */
- { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write },
- { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore },
- { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- /* cp14 crm==2: performance count registers */
- { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- /* cp14 crn==6: CLKCFG */
- { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write },
- /* cp14 crn==7: PWRMODE */
- { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
-};
-
-static void pxa2xx_setup_cp14(PXA2xxState *s)
-{
- define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s);
-}
-
-#define MDCNFG 0x00 /* SDRAM Configuration register */
-#define MDREFR 0x04 /* SDRAM Refresh Control register */
-#define MSC0 0x08 /* Static Memory Control register 0 */
-#define MSC1 0x0c /* Static Memory Control register 1 */
-#define MSC2 0x10 /* Static Memory Control register 2 */
-#define MECR 0x14 /* Expansion Memory Bus Config register */
-#define SXCNFG 0x1c /* Synchronous Static Memory Config register */
-#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */
-#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */
-#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */
-#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */
-#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */
-#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */
-#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */
-#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */
-#define ARB_CNTL 0x48 /* Arbiter Control register */
-#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */
-#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */
-#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */
-#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */
-#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */
-#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */
-#define SA1110 0x64 /* SA-1110 Memory Compatibility register */
-
-static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0)
- return s->mm_regs[addr >> 2];
- /* fall through */
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_mm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0) {
- s->mm_regs[addr >> 2] = value;
- break;
- }
- /* fallthrough */
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_mm_ops = {
- .read = pxa2xx_mm_read,
- .write = pxa2xx_mm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_mm = {
- .name = "pxa2xx_mm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define TYPE_PXA2XX_SSP "pxa2xx-ssp"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxSSPState, PXA2XX_SSP)
-
-/* Synchronous Serial Ports */
-struct PXA2xxSSPState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t enable;
- SSIBus *bus;
-
- uint32_t sscr[2];
- uint32_t sspsp;
- uint32_t ssto;
- uint32_t ssitr;
- uint32_t sssr;
- uint8_t sstsa;
- uint8_t ssrsa;
- uint8_t ssacd;
-
- uint32_t rx_fifo[16];
- uint32_t rx_level;
- uint32_t rx_start;
-};
-
-static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxSSPState *s = opaque;
-
- return s->rx_start < sizeof(s->rx_fifo);
-}
-
-static const VMStateDescription vmstate_pxa2xx_ssp = {
- .name = "pxa2xx-ssp",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(enable, PXA2xxSSPState),
- VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2),
- VMSTATE_UINT32(sspsp, PXA2xxSSPState),
- VMSTATE_UINT32(ssto, PXA2xxSSPState),
- VMSTATE_UINT32(ssitr, PXA2xxSSPState),
- VMSTATE_UINT32(sssr, PXA2xxSSPState),
- VMSTATE_UINT8(sstsa, PXA2xxSSPState),
- VMSTATE_UINT8(ssrsa, PXA2xxSSPState),
- VMSTATE_UINT8(ssacd, PXA2xxSSPState),
- VMSTATE_UINT32(rx_level, PXA2xxSSPState),
- VMSTATE_UINT32(rx_start, PXA2xxSSPState),
- VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate),
- VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define SSCR0 0x00 /* SSP Control register 0 */
-#define SSCR1 0x04 /* SSP Control register 1 */
-#define SSSR 0x08 /* SSP Status register */
-#define SSITR 0x0c /* SSP Interrupt Test register */
-#define SSDR 0x10 /* SSP Data register */
-#define SSTO 0x28 /* SSP Time-Out register */
-#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */
-#define SSTSA 0x30 /* SSP TX Time Slot Active register */
-#define SSRSA 0x34 /* SSP RX Time Slot Active register */
-#define SSTSS 0x38 /* SSP Time Slot Status register */
-#define SSACD 0x3c /* SSP Audio Clock Divider register */
-
-/* Bitfields for above registers */
-#define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
-#define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
-#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
-#define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
-#define SSCR0_SSE (1 << 7)
-#define SSCR0_RIM (1 << 22)
-#define SSCR0_TIM (1 << 23)
-#define SSCR0_MOD (1U << 31)
-#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
-#define SSCR1_RIE (1 << 0)
-#define SSCR1_TIE (1 << 1)
-#define SSCR1_LBM (1 << 2)
-#define SSCR1_MWDS (1 << 5)
-#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1)
-#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1)
-#define SSCR1_EFWR (1 << 14)
-#define SSCR1_PINTE (1 << 18)
-#define SSCR1_TINTE (1 << 19)
-#define SSCR1_RSRE (1 << 20)
-#define SSCR1_TSRE (1 << 21)
-#define SSCR1_EBCEI (1 << 29)
-#define SSITR_INT (7 << 5)
-#define SSSR_TNF (1 << 2)
-#define SSSR_RNE (1 << 3)
-#define SSSR_TFS (1 << 5)
-#define SSSR_RFS (1 << 6)
-#define SSSR_ROR (1 << 7)
-#define SSSR_PINT (1 << 18)
-#define SSSR_TINT (1 << 19)
-#define SSSR_EOC (1 << 20)
-#define SSSR_TUR (1 << 21)
-#define SSSR_BCE (1 << 23)
-#define SSSR_RW 0x00bc0080
-
-static void pxa2xx_ssp_int_update(PXA2xxSSPState *s)
-{
- int level = 0;
-
- level |= s->ssitr & SSITR_INT;
- level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI);
- level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM);
- level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT));
- level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE);
- level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE);
- level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM);
- level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
- level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
- qemu_set_irq(s->irq, !!level);
-}
-
-static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
-{
- s->sssr &= ~(0xf << 12); /* Clear RFL */
- s->sssr &= ~(0xf << 8); /* Clear TFL */
- s->sssr &= ~SSSR_TFS;
- s->sssr &= ~SSSR_TNF;
- if (s->enable) {
- s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
- if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
- s->sssr |= SSSR_RFS;
- else
- s->sssr &= ~SSSR_RFS;
- if (s->rx_level)
- s->sssr |= SSSR_RNE;
- else
- s->sssr &= ~SSSR_RNE;
- /* TX FIFO is never filled, so it is always in underrun
- condition if SSP is enabled */
- s->sssr |= SSSR_TFS;
- s->sssr |= SSSR_TNF;
- }
-
- pxa2xx_ssp_int_update(s);
-}
-
-static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
- uint32_t retval;
-
- switch (addr) {
- case SSCR0:
- return s->sscr[0];
- case SSCR1:
- return s->sscr[1];
- case SSPSP:
- return s->sspsp;
- case SSTO:
- return s->ssto;
- case SSITR:
- return s->ssitr;
- case SSSR:
- return s->sssr | s->ssitr;
- case SSDR:
- if (!s->enable)
- return 0xffffffff;
- if (s->rx_level < 1) {
- printf("%s: SSP Rx Underrun\n", __func__);
- return 0xffffffff;
- }
- s->rx_level --;
- retval = s->rx_fifo[s->rx_start ++];
- s->rx_start &= 0xf;
- pxa2xx_ssp_fifo_update(s);
- return retval;
- case SSTSA:
- return s->sstsa;
- case SSRSA:
- return s->ssrsa;
- case SSTSS:
- return 0;
- case SSACD:
- return s->ssacd;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_ssp_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
- uint32_t value = value64;
-
- switch (addr) {
- case SSCR0:
- s->sscr[0] = value & 0xc7ffffff;
- s->enable = value & SSCR0_SSE;
- if (value & SSCR0_MOD)
- printf("%s: Attempt to use network mode\n", __func__);
- if (s->enable && SSCR0_DSS(value) < 4)
- printf("%s: Wrong data size: %u bits\n", __func__,
- SSCR0_DSS(value));
- if (!(value & SSCR0_SSE)) {
- s->sssr = 0;
- s->ssitr = 0;
- s->rx_level = 0;
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSCR1:
- s->sscr[1] = value;
- if (value & (SSCR1_LBM | SSCR1_EFWR))
- printf("%s: Attempt to use SSP test mode\n", __func__);
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSPSP:
- s->sspsp = value;
- break;
-
- case SSTO:
- s->ssto = value;
- break;
-
- case SSITR:
- s->ssitr = value & SSITR_INT;
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSSR:
- s->sssr &= ~(value & SSSR_RW);
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSDR:
- if (SSCR0_UWIRE(s->sscr[0])) {
- if (s->sscr[1] & SSCR1_MWDS)
- value &= 0xffff;
- else
- value &= 0xff;
- } else
- /* Note how 32bits overflow does no harm here */
- value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
-
- /* Data goes from here to the Tx FIFO and is shifted out from
- * there directly to the slave, no need to buffer it.
- */
- if (s->enable) {
- uint32_t readval;
- readval = ssi_transfer(s->bus, value);
- if (s->rx_level < 0x10) {
- s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval;
- } else {
- s->sssr |= SSSR_ROR;
- }
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSTSA:
- s->sstsa = value;
- break;
-
- case SSRSA:
- s->ssrsa = value;
- break;
-
- case SSACD:
- s->ssacd = value;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_ssp_ops = {
- .read = pxa2xx_ssp_read,
- .write = pxa2xx_ssp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_ssp_reset(DeviceState *d)
-{
- PXA2xxSSPState *s = PXA2XX_SSP(d);
-
- s->enable = 0;
- s->sscr[0] = s->sscr[1] = 0;
- s->sspsp = 0;
- s->ssto = 0;
- s->ssitr = 0;
- s->sssr = 0;
- s->sstsa = 0;
- s->ssrsa = 0;
- s->ssacd = 0;
- s->rx_start = s->rx_level = 0;
-}
-
-static void pxa2xx_ssp_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- PXA2xxSSPState *s = PXA2XX_SSP(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_ssp_ops, s,
- "pxa2xx-ssp", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->bus = ssi_create_bus(dev, "ssi");
-}
-
-/* Real-Time Clock */
-#define RCNR 0x00 /* RTC Counter register */
-#define RTAR 0x04 /* RTC Alarm register */
-#define RTSR 0x08 /* RTC Status register */
-#define RTTR 0x0c /* RTC Timer Trim register */
-#define RDCR 0x10 /* RTC Day Counter register */
-#define RYCR 0x14 /* RTC Year Counter register */
-#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */
-#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */
-#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */
-#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */
-#define SWCR 0x28 /* RTC Stopwatch Counter register */
-#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */
-#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */
-#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */
-#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */
-
-#define TYPE_PXA2XX_RTC "pxa2xx_rtc"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxRTCState, PXA2XX_RTC)
-
-struct PXA2xxRTCState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t rttr;
- uint32_t rtsr;
- uint32_t rtar;
- uint32_t rdar1;
- uint32_t rdar2;
- uint32_t ryar1;
- uint32_t ryar2;
- uint32_t swar1;
- uint32_t swar2;
- uint32_t piar;
- uint32_t last_rcnr;
- uint32_t last_rdcr;
- uint32_t last_rycr;
- uint32_t last_swcr;
- uint32_t last_rtcpicr;
- int64_t last_hz;
- int64_t last_sw;
- int64_t last_pi;
- QEMUTimer *rtc_hz;
- QEMUTimer *rtc_rdal1;
- QEMUTimer *rtc_rdal2;
- QEMUTimer *rtc_swal1;
- QEMUTimer *rtc_swal2;
- QEMUTimer *rtc_pi;
- qemu_irq rtc_irq;
-};
-
-static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s)
-{
- qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553));
-}
-
-static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- s->last_rcnr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_rdcr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_hz = rt;
-}
-
-static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- if (s->rtsr & (1 << 12))
- s->last_swcr += (rt - s->last_sw) / 10;
- s->last_sw = rt;
-}
-
-static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- if (s->rtsr & (1 << 15))
- s->last_swcr += rt - s->last_pi;
- s->last_pi = rt;
-}
-
-static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s,
- uint32_t rtsr)
-{
- if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
- timer_mod(s->rtc_hz, s->last_hz +
- (((s->rtar - s->last_rcnr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15));
- else
- timer_del(s->rtc_hz);
-
- if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
- timer_mod(s->rtc_rdal1, s->last_hz +
- (((s->rdar1 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- timer_del(s->rtc_rdal1);
-
- if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
- timer_mod(s->rtc_rdal2, s->last_hz +
- (((s->rdar2 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- timer_del(s->rtc_rdal2);
-
- if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
- timer_mod(s->rtc_swal1, s->last_sw +
- (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
- else
- timer_del(s->rtc_swal1);
-
- if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
- timer_mod(s->rtc_swal2, s->last_sw +
- (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
- else
- timer_del(s->rtc_swal2);
-
- if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
- timer_mod(s->rtc_pi, s->last_pi +
- (s->piar & 0xffff) - s->last_rtcpicr);
- else
- timer_del(s->rtc_pi);
-}
-
-static inline void pxa2xx_rtc_hz_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 0);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 4);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 6);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal1_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 8);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal2_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 10);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_pi_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 13);
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- switch (addr) {
- case RTTR:
- return s->rttr;
- case RTSR:
- return s->rtsr;
- case RTAR:
- return s->rtar;
- case RDAR1:
- return s->rdar1;
- case RDAR2:
- return s->rdar2;
- case RYAR1:
- return s->ryar1;
- case RYAR2:
- return s->ryar2;
- case SWAR1:
- return s->swar1;
- case SWAR2:
- return s->swar2;
- case PIAR:
- return s->piar;
- case RCNR:
- return s->last_rcnr +
- ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RDCR:
- return s->last_rdcr +
- ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RYCR:
- return s->last_rycr;
- case SWCR:
- if (s->rtsr & (1 << 12))
- return s->last_swcr +
- (qemu_clock_get_ms(rtc_clock) - s->last_sw) / 10;
- else
- return s->last_swcr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_rtc_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- uint32_t value = value64;
-
- switch (addr) {
- case RTTR:
- if (!(s->rttr & (1U << 31))) {
- pxa2xx_rtc_hzupdate(s);
- s->rttr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- }
- break;
-
- case RTSR:
- if ((s->rtsr ^ value) & (1 << 15))
- pxa2xx_rtc_piupdate(s);
-
- if ((s->rtsr ^ value) & (1 << 12))
- pxa2xx_rtc_swupdate(s);
-
- if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
- pxa2xx_rtc_alarm_update(s, value);
-
- s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
- pxa2xx_rtc_int_update(s);
- break;
-
- case RTAR:
- s->rtar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR1:
- s->rdar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR2:
- s->rdar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR1:
- s->ryar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR2:
- s->ryar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR1:
- pxa2xx_rtc_swupdate(s);
- s->swar1 = value;
- s->last_swcr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR2:
- s->swar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case PIAR:
- s->piar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RCNR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rcnr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDCR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rdcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYCR:
- s->last_rycr = value;
- break;
-
- case SWCR:
- pxa2xx_rtc_swupdate(s);
- s->last_swcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RTCPICR:
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = value & 0xffff;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_rtc_ops = {
- .read = pxa2xx_rtc_read,
- .write = pxa2xx_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_rtc_init(Object *obj)
-{
- PXA2xxRTCState *s = PXA2XX_RTC(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- struct tm tm;
- int wom;
-
- s->rttr = 0x7fff;
- s->rtsr = 0;
-
- qemu_get_timedate(&tm, 0);
- wom = ((tm.tm_mday - 1) / 7) + 1;
-
- s->last_rcnr = (uint32_t) mktimegm(&tm);
- s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) |
- (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec;
- s->last_rycr = ((tm.tm_year + 1900) << 9) |
- ((tm.tm_mon + 1) << 5) | tm.tm_mday;
- s->last_swcr = (tm.tm_hour << 19) |
- (tm.tm_min << 13) | (tm.tm_sec << 7);
- s->last_rtcpicr = 0;
- s->last_hz = s->last_sw = s->last_pi = qemu_clock_get_ms(rtc_clock);
-
- sysbus_init_irq(dev, &s->rtc_irq);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_rtc_ops, s,
- "pxa2xx-rtc", 0x10000);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void pxa2xx_rtc_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxRTCState *s = PXA2XX_RTC(dev);
- s->rtc_hz = timer_new_ms(rtc_clock, pxa2xx_rtc_hz_tick, s);
- s->rtc_rdal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s);
- s->rtc_rdal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s);
- s->rtc_swal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s);
- s->rtc_swal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s);
- s->rtc_pi = timer_new_ms(rtc_clock, pxa2xx_rtc_pi_tick, s);
-}
-
-static int pxa2xx_rtc_pre_save(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- pxa2xx_rtc_hzupdate(s);
- pxa2xx_rtc_piupdate(s);
- pxa2xx_rtc_swupdate(s);
-
- return 0;
-}
-
-static int pxa2xx_rtc_post_load(void *opaque, int version_id)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- pxa2xx_rtc_alarm_update(s, s->rtsr);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
- .name = "pxa2xx_rtc",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = pxa2xx_rtc_pre_save,
- .post_load = pxa2xx_rtc_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(rttr, PXA2xxRTCState),
- VMSTATE_UINT32(rtsr, PXA2xxRTCState),
- VMSTATE_UINT32(rtar, PXA2xxRTCState),
- VMSTATE_UINT32(rdar1, PXA2xxRTCState),
- VMSTATE_UINT32(rdar2, PXA2xxRTCState),
- VMSTATE_UINT32(ryar1, PXA2xxRTCState),
- VMSTATE_UINT32(ryar2, PXA2xxRTCState),
- VMSTATE_UINT32(swar1, PXA2xxRTCState),
- VMSTATE_UINT32(swar2, PXA2xxRTCState),
- VMSTATE_UINT32(piar, PXA2xxRTCState),
- VMSTATE_UINT32(last_rcnr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rdcr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rycr, PXA2xxRTCState),
- VMSTATE_UINT32(last_swcr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState),
- VMSTATE_INT64(last_hz, PXA2xxRTCState),
- VMSTATE_INT64(last_sw, PXA2xxRTCState),
- VMSTATE_INT64(last_pi, PXA2xxRTCState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx RTC Controller";
- dc->vmsd = &vmstate_pxa2xx_rtc_regs;
- dc->realize = pxa2xx_rtc_realize;
-}
-
-static const TypeInfo pxa2xx_rtc_sysbus_info = {
- .name = TYPE_PXA2XX_RTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxRTCState),
- .instance_init = pxa2xx_rtc_init,
- .class_init = pxa2xx_rtc_sysbus_class_init,
-};
-
-/* I2C Interface */
-
-#define TYPE_PXA2XX_I2C_SLAVE "pxa2xx-i2c-slave"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxI2CSlaveState, PXA2XX_I2C_SLAVE)
-
-struct PXA2xxI2CSlaveState {
- I2CSlave parent_obj;
-
- PXA2xxI2CState *host;
-};
-
-struct PXA2xxI2CState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- PXA2xxI2CSlaveState *slave;
- I2CBus *bus;
- qemu_irq irq;
- uint32_t offset;
- uint32_t region_size;
-
- uint16_t control;
- uint16_t status;
- uint8_t ibmr;
- uint8_t data;
-};
-
-#define IBMR 0x80 /* I2C Bus Monitor register */
-#define IDBR 0x88 /* I2C Data Buffer register */
-#define ICR 0x90 /* I2C Control register */
-#define ISR 0x98 /* I2C Status register */
-#define ISAR 0xa0 /* I2C Slave Address register */
-
-static void pxa2xx_i2c_update(PXA2xxI2CState *s)
-{
- uint16_t level = 0;
- level |= s->status & s->control & (1 << 10); /* BED */
- level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */
- level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */
- level |= s->status & (1 << 9); /* SAD */
- qemu_set_irq(s->irq, !!level);
-}
-
-/* These are only stubs now. */
-static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- switch (event) {
- case I2C_START_SEND:
- s->status |= (1 << 9); /* set SAD */
- s->status &= ~(1 << 0); /* clear RWM */
- break;
- case I2C_START_RECV:
- s->status |= (1 << 9); /* set SAD */
- s->status |= 1 << 0; /* set RWM */
- break;
- case I2C_FINISH:
- s->status |= (1 << 4); /* set SSD */
- break;
- case I2C_NACK:
- s->status |= 1 << 1; /* set ACKNAK */
- break;
- default:
- return -1;
- }
- pxa2xx_i2c_update(s);
-
- return 0;
-}
-
-static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
- return 0;
- }
-
- if (s->status & (1 << 0)) { /* RWM */
- s->status |= 1 << 6; /* set ITE */
- }
- pxa2xx_i2c_update(s);
-
- return s->data;
-}
-
-static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
- return 1;
- }
-
- if (!(s->status & (1 << 0))) { /* RWM */
- s->status |= 1 << 7; /* set IRF */
- s->data = data;
- }
- pxa2xx_i2c_update(s);
-
- return 1;
-}
-
-static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
- I2CSlave *slave;
-
- addr -= s->offset;
- switch (addr) {
- case ICR:
- return s->control;
- case ISR:
- return s->status | (i2c_bus_busy(s->bus) << 2);
- case ISAR:
- slave = I2C_SLAVE(s->slave);
- return slave->address;
- case IDBR:
- return s->data;
- case IBMR:
- if (s->status & (1 << 2))
- s->ibmr ^= 3; /* Fake SCL and SDA pin changes */
- else
- s->ibmr = 0;
- return s->ibmr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2c_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
- uint32_t value = value64;
- int ack;
-
- addr -= s->offset;
- switch (addr) {
- case ICR:
- s->control = value & 0xfff7;
- if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */
- /* TODO: slave mode */
- if (value & (1 << 0)) { /* START condition */
- if (s->data & 1)
- s->status |= 1 << 0; /* set RWM */
- else
- s->status &= ~(1 << 0); /* clear RWM */
- ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
- } else {
- if (s->status & (1 << 0)) { /* RWM */
- s->data = i2c_recv(s->bus);
- if (value & (1 << 2)) /* ACKNAK */
- i2c_nack(s->bus);
- ack = 1;
- } else
- ack = !i2c_send(s->bus, s->data);
- }
-
- if (value & (1 << 1)) /* STOP condition */
- i2c_end_transfer(s->bus);
-
- if (ack) {
- if (value & (1 << 0)) /* START condition */
- s->status |= 1 << 6; /* set ITE */
- else
- if (s->status & (1 << 0)) /* RWM */
- s->status |= 1 << 7; /* set IRF */
- else
- s->status |= 1 << 6; /* set ITE */
- s->status &= ~(1 << 1); /* clear ACKNAK */
- } else {
- s->status |= 1 << 6; /* set ITE */
- s->status |= 1 << 10; /* set BED */
- s->status |= 1 << 1; /* set ACKNAK */
- }
- }
- if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */
- if (value & (1 << 4)) /* MA */
- i2c_end_transfer(s->bus);
- pxa2xx_i2c_update(s);
- break;
-
- case ISR:
- s->status &= ~(value & 0x07f0);
- pxa2xx_i2c_update(s);
- break;
-
- case ISAR:
- i2c_slave_set_address(I2C_SLAVE(s->slave), value & 0x7f);
- break;
-
- case IDBR:
- s->data = value & 0xff;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_i2c_ops = {
- .read = pxa2xx_i2c_read,
- .write = pxa2xx_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
- .name = "pxa2xx_i2c_slave",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2c = {
- .name = "pxa2xx_i2c",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT16(control, PXA2xxI2CState),
- VMSTATE_UINT16(status, PXA2xxI2CState),
- VMSTATE_UINT8(ibmr, PXA2xxI2CState),
- VMSTATE_UINT8(data, PXA2xxI2CState),
- VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
- vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
-{
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->event = pxa2xx_i2c_event;
- k->recv = pxa2xx_i2c_rx;
- k->send = pxa2xx_i2c_tx;
-}
-
-static const TypeInfo pxa2xx_i2c_slave_info = {
- .name = TYPE_PXA2XX_I2C_SLAVE,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(PXA2xxI2CSlaveState),
- .class_init = pxa2xx_i2c_slave_class_init,
-};
-
-PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
- qemu_irq irq, uint32_t region_size)
-{
- DeviceState *dev;
- SysBusDevice *i2c_dev;
- PXA2xxI2CState *s;
- I2CBus *i2cbus;
-
- dev = qdev_new(TYPE_PXA2XX_I2C);
- qdev_prop_set_uint32(dev, "size", region_size + 1);
- qdev_prop_set_uint32(dev, "offset", base & region_size);
-
- /* FIXME: Should the slave device really be on a separate bus? */
- i2cbus = i2c_init_bus(dev, "dummy");
-
- i2c_dev = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(i2c_dev, &error_fatal);
- sysbus_mmio_map(i2c_dev, 0, base & ~region_size);
- sysbus_connect_irq(i2c_dev, 0, irq);
-
- s = PXA2XX_I2C(i2c_dev);
- s->slave = PXA2XX_I2C_SLAVE(i2c_slave_create_simple(i2cbus,
- TYPE_PXA2XX_I2C_SLAVE,
- 0));
- s->slave->host = s;
-
- return s;
-}
-
-static void pxa2xx_i2c_initfn(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- PXA2xxI2CState *s = PXA2XX_I2C(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- s->bus = i2c_init_bus(dev, NULL);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_i2c_ops, s,
- "pxa2xx-i2c", s->region_size);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
-{
- return s->bus;
-}
-
-static Property pxa2xx_i2c_properties[] = {
- DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
- DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx I2C Bus Controller";
- dc->vmsd = &vmstate_pxa2xx_i2c;
- device_class_set_props(dc, pxa2xx_i2c_properties);
-}
-
-static const TypeInfo pxa2xx_i2c_info = {
- .name = TYPE_PXA2XX_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxI2CState),
- .instance_init = pxa2xx_i2c_initfn,
- .class_init = pxa2xx_i2c_class_init,
-};
-
-/* PXA Inter-IC Sound Controller */
-static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s)
-{
- i2s->rx_len = 0;
- i2s->tx_len = 0;
- i2s->fifo_len = 0;
- i2s->clk = 0x1a;
- i2s->control[0] = 0x00;
- i2s->control[1] = 0x00;
- i2s->status = 0x00;
- i2s->mask = 0x00;
-}
-
-#define SACR_TFTH(val) ((val >> 8) & 0xf)
-#define SACR_RFTH(val) ((val >> 12) & 0xf)
-#define SACR_DREC(val) (val & (1 << 3))
-#define SACR_DPRL(val) (val & (1 << 4))
-
-static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
-{
- int rfs, tfs;
- rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
- !SACR_DREC(i2s->control[1]);
- tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
- i2s->enable && !SACR_DPRL(i2s->control[1]);
-
- qemu_set_irq(i2s->rx_dma, rfs);
- qemu_set_irq(i2s->tx_dma, tfs);
-
- i2s->status &= 0xe0;
- if (i2s->fifo_len < 16 || !i2s->enable)
- i2s->status |= 1 << 0; /* TNF */
- if (i2s->rx_len)
- i2s->status |= 1 << 1; /* RNE */
- if (i2s->enable)
- i2s->status |= 1 << 2; /* BSY */
- if (tfs)
- i2s->status |= 1 << 3; /* TFS */
- if (rfs)
- i2s->status |= 1 << 4; /* RFS */
- if (!(i2s->tx_len && i2s->enable))
- i2s->status |= i2s->fifo_len << 8; /* TFL */
- i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */
-
- qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
-}
-
-#define SACR0 0x00 /* Serial Audio Global Control register */
-#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */
-#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */
-#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */
-#define SAICR 0x18 /* Serial Audio Interrupt Clear register */
-#define SADIV 0x60 /* Serial Audio Clock Divider register */
-#define SADR 0x80 /* Serial Audio Data register */
-
-static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
-
- switch (addr) {
- case SACR0:
- return s->control[0];
- case SACR1:
- return s->control[1];
- case SASR0:
- return s->status;
- case SAIMR:
- return s->mask;
- case SAICR:
- return 0;
- case SADIV:
- return s->clk;
- case SADR:
- if (s->rx_len > 0) {
- s->rx_len --;
- pxa2xx_i2s_update(s);
- return s->codec_in(s->opaque);
- }
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2s_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
- uint32_t *sample;
-
- switch (addr) {
- case SACR0:
- if (value & (1 << 3)) /* RST */
- pxa2xx_i2s_reset(s);
- s->control[0] = value & 0xff3d;
- if (!s->enable && (value & 1) && s->tx_len) { /* ENB */
- for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- s->status &= ~(1 << 7); /* I2SOFF */
- }
- if (value & (1 << 4)) /* EFWR */
- printf("%s: Attempt to use special function\n", __func__);
- s->enable = (value & 9) == 1; /* ENB && !RST*/
- pxa2xx_i2s_update(s);
- break;
- case SACR1:
- s->control[1] = value & 0x0039;
- if (value & (1 << 5)) /* ENLBF */
- printf("%s: Attempt to use loopback function\n", __func__);
- if (value & (1 << 4)) /* DPRL */
- s->fifo_len = 0;
- pxa2xx_i2s_update(s);
- break;
- case SAIMR:
- s->mask = value & 0x0078;
- pxa2xx_i2s_update(s);
- break;
- case SAICR:
- s->status &= ~(value & (3 << 5));
- pxa2xx_i2s_update(s);
- break;
- case SADIV:
- s->clk = value & 0x007f;
- break;
- case SADR:
- if (s->tx_len && s->enable) {
- s->tx_len --;
- pxa2xx_i2s_update(s);
- s->codec_out(s->opaque, value);
- } else if (s->fifo_len < 16) {
- s->fifo[s->fifo_len ++] = value;
- pxa2xx_i2s_update(s);
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_i2s_ops = {
- .read = pxa2xx_i2s_read,
- .write = pxa2xx_i2s_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2s = {
- .name = "pxa2xx_i2s",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
- VMSTATE_UINT32(status, PXA2xxI2SState),
- VMSTATE_UINT32(mask, PXA2xxI2SState),
- VMSTATE_UINT32(clk, PXA2xxI2SState),
- VMSTATE_INT32(enable, PXA2xxI2SState),
- VMSTATE_INT32(rx_len, PXA2xxI2SState),
- VMSTATE_INT32(tx_len, PXA2xxI2SState),
- VMSTATE_INT32(fifo_len, PXA2xxI2SState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
- uint32_t *sample;
-
- /* Signal FIFO errors */
- if (s->enable && s->tx_len)
- s->status |= 1 << 5; /* TUR */
- if (s->enable && s->rx_len)
- s->status |= 1 << 6; /* ROR */
-
- /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
- * handle the cases where it makes a difference. */
- s->tx_len = tx - s->fifo_len;
- s->rx_len = rx;
- /* Note that is s->codec_out wasn't set, we wouldn't get called. */
- if (s->enable)
- for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- pxa2xx_i2s_update(s);
-}
-
-static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
-{
- PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1);
-
- s->irq = irq;
- s->rx_dma = rx_dma;
- s->tx_dma = tx_dma;
- s->data_req = pxa2xx_i2s_data_req;
-
- pxa2xx_i2s_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_i2s_ops, s,
- "pxa2xx-i2s", 0x100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
-
- return s;
-}
-
-/* PXA Fast Infra-red Communications Port */
-struct PXA2xxFIrState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq rx_dma;
- qemu_irq tx_dma;
- uint32_t enable;
- CharBackend chr;
-
- uint8_t control[3];
- uint8_t status[2];
-
- uint32_t rx_len;
- uint32_t rx_start;
- uint8_t rx_fifo[64];
-};
-
-static void pxa2xx_fir_reset(DeviceState *d)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(d);
-
- s->control[0] = 0x00;
- s->control[1] = 0x00;
- s->control[2] = 0x00;
- s->status[0] = 0x00;
- s->status[1] = 0x00;
- s->enable = 0;
-}
-
-static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
-{
- static const int tresh[4] = { 8, 16, 32, 0 };
- int intr = 0;
- if ((s->control[0] & (1 << 4)) && /* RXE */
- s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */
- s->status[0] |= 1 << 4; /* RFS */
- else
- s->status[0] &= ~(1 << 4); /* RFS */
- if (s->control[0] & (1 << 3)) /* TXE */
- s->status[0] |= 1 << 3; /* TFS */
- else
- s->status[0] &= ~(1 << 3); /* TFS */
- if (s->rx_len)
- s->status[1] |= 1 << 2; /* RNE */
- else
- s->status[1] &= ~(1 << 2); /* RNE */
- if (s->control[0] & (1 << 4)) /* RXE */
- s->status[1] |= 1 << 0; /* RSY */
- else
- s->status[1] &= ~(1 << 0); /* RSY */
-
- intr |= (s->control[0] & (1 << 5)) && /* RIE */
- (s->status[0] & (1 << 4)); /* RFS */
- intr |= (s->control[0] & (1 << 6)) && /* TIE */
- (s->status[0] & (1 << 3)); /* TFS */
- intr |= (s->control[2] & (1 << 4)) && /* TRAIL */
- (s->status[0] & (1 << 6)); /* EOC */
- intr |= (s->control[0] & (1 << 2)) && /* TUS */
- (s->status[0] & (1 << 1)); /* TUR */
- intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */
-
- qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1);
- qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1);
-
- qemu_set_irq(s->irq, intr && s->enable);
-}
-
-#define ICCR0 0x00 /* FICP Control register 0 */
-#define ICCR1 0x04 /* FICP Control register 1 */
-#define ICCR2 0x08 /* FICP Control register 2 */
-#define ICDR 0x0c /* FICP Data register */
-#define ICSR0 0x14 /* FICP Status register 0 */
-#define ICSR1 0x18 /* FICP Status register 1 */
-#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */
-
-static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- uint8_t ret;
-
- switch (addr) {
- case ICCR0:
- return s->control[0];
- case ICCR1:
- return s->control[1];
- case ICCR2:
- return s->control[2];
- case ICDR:
- s->status[0] &= ~0x01;
- s->status[1] &= ~0x72;
- if (s->rx_len) {
- s->rx_len --;
- ret = s->rx_fifo[s->rx_start ++];
- s->rx_start &= 63;
- pxa2xx_fir_update(s);
- return ret;
- }
- printf("%s: Rx FIFO underrun.\n", __func__);
- break;
- case ICSR0:
- return s->status[0];
- case ICSR1:
- return s->status[1] | (1 << 3); /* TNF */
- case ICFOR:
- return s->rx_len;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_fir_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- uint32_t value = value64;
- uint8_t ch;
-
- switch (addr) {
- case ICCR0:
- s->control[0] = value;
- if (!(value & (1 << 4))) /* RXE */
- s->rx_len = s->rx_start = 0;
- if (!(value & (1 << 3))) { /* TXE */
- /* Nop */
- }
- s->enable = value & 1; /* ITR */
- if (!s->enable)
- s->status[0] = 0;
- pxa2xx_fir_update(s);
- break;
- case ICCR1:
- s->control[1] = value;
- break;
- case ICCR2:
- s->control[2] = value & 0x3f;
- pxa2xx_fir_update(s);
- break;
- case ICDR:
- if (s->control[2] & (1 << 2)) { /* TXP */
- ch = value;
- } else {
- ch = ~value;
- }
- if (s->enable && (s->control[0] & (1 << 3))) { /* TXE */
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, &ch, 1);
- }
- break;
- case ICSR0:
- s->status[0] &= ~(value & 0x66);
- pxa2xx_fir_update(s);
- break;
- case ICFOR:
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_fir_ops = {
- .read = pxa2xx_fir_read,
- .write = pxa2xx_fir_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pxa2xx_fir_is_empty(void *opaque)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- return (s->rx_len < 64);
-}
-
-static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- if (!(s->control[0] & (1 << 4))) /* RXE */
- return;
-
- while (size --) {
- s->status[1] |= 1 << 4; /* EOF */
- if (s->rx_len >= 64) {
- s->status[1] |= 1 << 6; /* ROR */
- break;
- }
-
- if (s->control[2] & (1 << 3)) /* RXP */
- s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
- else
- s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
- }
-
- pxa2xx_fir_update(s);
-}
-
-static void pxa2xx_fir_event(void *opaque, QEMUChrEvent event)
-{
-}
-
-static void pxa2xx_fir_instance_init(Object *obj)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s,
- "pxa2xx-fir", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->rx_dma);
- sysbus_init_irq(sbd, &s->tx_dma);
-}
-
-static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(dev);
-
- qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
- pxa2xx_fir_rx, pxa2xx_fir_event, NULL, s, NULL,
- true);
-}
-
-static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxFIrState *s = opaque;
-
- return s->rx_start < ARRAY_SIZE(s->rx_fifo);
-}
-
-static const VMStateDescription pxa2xx_fir_vmsd = {
- .name = "pxa2xx-fir",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(enable, PXA2xxFIrState),
- VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3),
- VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2),
- VMSTATE_UINT32(rx_len, PXA2xxFIrState),
- VMSTATE_UINT32(rx_start, PXA2xxFIrState),
- VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate),
- VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property pxa2xx_fir_properties[] = {
- DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_fir_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pxa2xx_fir_realize;
- dc->vmsd = &pxa2xx_fir_vmsd;
- device_class_set_props(dc, pxa2xx_fir_properties);
- dc->reset = pxa2xx_fir_reset;
-}
-
-static const TypeInfo pxa2xx_fir_info = {
- .name = TYPE_PXA2XX_FIR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxFIrState),
- .class_init = pxa2xx_fir_class_init,
- .instance_init = pxa2xx_fir_instance_init,
-};
-
-static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma,
- qemu_irq tx_dma,
- Chardev *chr)
-{
- DeviceState *dev;
- SysBusDevice *sbd;
-
- dev = qdev_new(TYPE_PXA2XX_FIR);
- qdev_prop_set_chr(dev, "chardev", chr);
- sbd = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(sbd, &error_fatal);
- sysbus_mmio_map(sbd, 0, base);
- sysbus_connect_irq(sbd, 0, irq);
- sysbus_connect_irq(sbd, 1, rx_dma);
- sysbus_connect_irq(sbd, 2, tx_dma);
- return PXA2XX_FIR(dev);
-}
-
-static void pxa2xx_reset(void *opaque, int line, int level)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */
- cpu_reset(CPU(s->cpu));
- /* TODO: reset peripherals */
- }
-}
-
-/* Initialise a PXA270 integrated chip (ARM based core). */
-PXA2xxState *pxa270_init(unsigned int sdram_size, const char *cpu_type)
-{
- MemoryRegion *address_space = get_system_memory();
- PXA2xxState *s;
- int i;
- DriveInfo *dinfo;
- s = g_new0(PXA2xxState, 1);
-
- if (strncmp(cpu_type, "pxa27", 5)) {
- error_report("Machine requires a PXA27x processor");
- exit(1);
- }
-
- s->cpu = ARM_CPU(cpu_create(cpu_type));
- s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
-
- /* SDRAM & Internal Memory Storage */
- memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size,
- &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
- memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000,
- &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
- &s->internal);
-
- s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
-
- s->dma = pxa27x_dma_init(0x40000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
-
- sysbus_create_varargs("pxa27x-timer", 0x40a00000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
- qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11),
- NULL);
-
- s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121);
-
- s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
- dinfo = drive_get(IF_SD, 0, 0);
- if (dinfo) {
- DeviceState *carddev;
-
- /* Create and plug in the sd card */
- carddev = qdev_new(TYPE_SD_CARD);
- qdev_prop_set_drive_err(carddev, "drive",
- blk_by_legacy_dinfo(dinfo), &error_fatal);
- qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
- "sd-bus"),
- &error_fatal);
- } else if (!qtest_enabled()) {
- warn_report("missing SecureDigital device");
- }
-
- for (i = 0; pxa270_serial[i].io_base; i++) {
- if (serial_hd(i)) {
- serial_mm_init(address_space, pxa270_serial[i].io_base, 2,
- qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
- 14857000 / 16, serial_hd(i),
- DEVICE_NATIVE_ENDIAN);
- } else {
- break;
- }
- }
- if (serial_hd(i))
- s->fir = pxa2xx_fir_init(address_space, 0x40800000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
- serial_hd(i));
-
- s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
-
- s->cm_base = 0x41300000;
- s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */
- s->clkcfg = 0x00000009; /* Turbo mode active */
- memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
- memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
-
- pxa2xx_setup_cp14(s);
-
- s->mm_base = 0x48000000;
- s->mm_regs[MDMRS >> 2] = 0x00020002;
- s->mm_regs[MDREFR >> 2] = 0x03ca4000;
- s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
- memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
- memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
-
- s->pm_base = 0x40f00000;
- memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
- memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
-
- for (i = 0; pxa27x_ssp[i].io_base; i ++);
- s->ssp = g_new0(SSIBus *, i);
- for (i = 0; pxa27x_ssp[i].io_base; i ++) {
- DeviceState *dev;
- dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base,
- qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn));
- s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
- }
-
- sysbus_create_simple("sysbus-ohci", 0x4c000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
-
- s->pcmcia[0] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x20000000, NULL));
- s->pcmcia[1] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x30000000, NULL));
-
- sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
-
- s->i2c[0] = pxa2xx_i2c_init(0x40301600,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
- s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
-
- s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
-
- s->kp = pxa27x_keypad_init(address_space, 0x41500000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD));
-
- /* GPIO1 resets the processor */
- /* The handler can be overridden by board-specific code */
- qdev_connect_gpio_out(s->gpio, 1, s->reset);
- return s;
-}
-
-/* Initialise a PXA255 integrated chip (ARM based core). */
-PXA2xxState *pxa255_init(unsigned int sdram_size)
-{
- MemoryRegion *address_space = get_system_memory();
- PXA2xxState *s;
- int i;
- DriveInfo *dinfo;
-
- s = g_new0(PXA2xxState, 1);
-
- s->cpu = ARM_CPU(cpu_create(ARM_CPU_TYPE_NAME("pxa255")));
- s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
-
- /* SDRAM & Internal Memory Storage */
- memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size,
- &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
- memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
- PXA2XX_INTERNAL_SIZE, &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
- &s->internal);
-
- s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
-
- s->dma = pxa255_dma_init(0x40000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
-
- sysbus_create_varargs("pxa25x-timer", 0x40a00000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
- NULL);
-
- s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85);
-
- s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
- dinfo = drive_get(IF_SD, 0, 0);
- if (dinfo) {
- DeviceState *carddev;
-
- /* Create and plug in the sd card */
- carddev = qdev_new(TYPE_SD_CARD);
- qdev_prop_set_drive_err(carddev, "drive",
- blk_by_legacy_dinfo(dinfo), &error_fatal);
- qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
- "sd-bus"),
- &error_fatal);
- } else if (!qtest_enabled()) {
- warn_report("missing SecureDigital device");
- }
-
- for (i = 0; pxa255_serial[i].io_base; i++) {
- if (serial_hd(i)) {
- serial_mm_init(address_space, pxa255_serial[i].io_base, 2,
- qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
- 14745600 / 16, serial_hd(i),
- DEVICE_NATIVE_ENDIAN);
- } else {
- break;
- }
- }
- if (serial_hd(i))
- s->fir = pxa2xx_fir_init(address_space, 0x40800000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
- serial_hd(i));
-
- s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
-
- s->cm_base = 0x41300000;
- s->cm_regs[CCCR >> 2] = 0x00000121; /* from datasheet */
- s->cm_regs[CKEN >> 2] = 0x00017def; /* from datasheet */
-
- s->clkcfg = 0x00000009; /* Turbo mode active */
- memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
- memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
-
- pxa2xx_setup_cp14(s);
-
- s->mm_base = 0x48000000;
- s->mm_regs[MDMRS >> 2] = 0x00020002;
- s->mm_regs[MDREFR >> 2] = 0x03ca4000;
- s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
- memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
- memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
-
- s->pm_base = 0x40f00000;
- memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
- memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
-
- for (i = 0; pxa255_ssp[i].io_base; i ++);
- s->ssp = g_new0(SSIBus *, i);
- for (i = 0; pxa255_ssp[i].io_base; i ++) {
- DeviceState *dev;
- dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base,
- qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn));
- s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
- }
-
- s->pcmcia[0] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x20000000, NULL));
- s->pcmcia[1] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x30000000, NULL));
-
- sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
-
- s->i2c[0] = pxa2xx_i2c_init(0x40301600,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
- s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
-
- s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
-
- /* GPIO1 resets the processor */
- /* The handler can be overridden by board-specific code */
- qdev_connect_gpio_out(s->gpio, 1, s->reset);
- return s;
-}
-
-static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = pxa2xx_ssp_reset;
- dc->vmsd = &vmstate_pxa2xx_ssp;
-}
-
-static const TypeInfo pxa2xx_ssp_info = {
- .name = TYPE_PXA2XX_SSP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxSSPState),
- .instance_init = pxa2xx_ssp_init,
- .class_init = pxa2xx_ssp_class_init,
-};
-
-static void pxa2xx_register_types(void)
-{
- type_register_static(&pxa2xx_i2c_slave_info);
- type_register_static(&pxa2xx_ssp_info);
- type_register_static(&pxa2xx_i2c_info);
- type_register_static(&pxa2xx_rtc_sysbus_info);
- type_register_static(&pxa2xx_fir_info);
-}
-
-type_init(pxa2xx_register_types)
diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c
deleted file mode 100644
index 41dca03..0000000
--- a/hw/arm/pxa2xx_gpio.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Intel XScale PXA255/270 GPIO controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define PXA2XX_GPIO_BANKS 4
-
-#define TYPE_PXA2XX_GPIO "pxa2xx-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxGPIOInfo, PXA2XX_GPIO)
-
-struct PXA2xxGPIOInfo {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq0, irq1, irqX;
- int lines;
- ARMCPU *cpu;
-
- /* XXX: GNU C vectors are more suitable */
- uint32_t ilevel[PXA2XX_GPIO_BANKS];
- uint32_t olevel[PXA2XX_GPIO_BANKS];
- uint32_t dir[PXA2XX_GPIO_BANKS];
- uint32_t rising[PXA2XX_GPIO_BANKS];
- uint32_t falling[PXA2XX_GPIO_BANKS];
- uint32_t status[PXA2XX_GPIO_BANKS];
- uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
-
- uint32_t prev_level[PXA2XX_GPIO_BANKS];
- qemu_irq handler[PXA2XX_GPIO_BANKS * 32];
- qemu_irq read_notify;
-};
-
-static struct {
- enum {
- GPIO_NONE,
- GPLR,
- GPSR,
- GPCR,
- GPDR,
- GRER,
- GFER,
- GEDR,
- GAFR_L,
- GAFR_U,
- } reg;
- int bank;
-} pxa2xx_gpio_regs[0x200] = {
- [0 ... 0x1ff] = { GPIO_NONE, 0 },
-#define PXA2XX_REG(reg, a0, a1, a2, a3) \
- [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
-
- PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
- PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
- PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
- PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
- PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
- PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
- PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
- PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
- PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
-};
-
-static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s)
-{
- if (s->status[0] & (1 << 0))
- qemu_irq_raise(s->irq0);
- else
- qemu_irq_lower(s->irq0);
-
- if (s->status[0] & (1 << 1))
- qemu_irq_raise(s->irq1);
- else
- qemu_irq_lower(s->irq1);
-
- if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
- qemu_irq_raise(s->irqX);
- else
- qemu_irq_lower(s->irqX);
-}
-
-/* Bitmap of pins used as standby and sleep wake-up sources. */
-static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
- 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
-};
-
-static void pxa2xx_gpio_set(void *opaque, int line, int level)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- CPUState *cpu = CPU(s->cpu);
- int bank;
- uint32_t mask;
-
- if (line >= s->lines) {
- printf("%s: No GPIO pin %i\n", __func__, line);
- return;
- }
-
- bank = line >> 5;
- mask = 1U << (line & 31);
-
- if (level) {
- s->status[bank] |= s->rising[bank] & mask &
- ~s->ilevel[bank] & ~s->dir[bank];
- s->ilevel[bank] |= mask;
- } else {
- s->status[bank] |= s->falling[bank] & mask &
- s->ilevel[bank] & ~s->dir[bank];
- s->ilevel[bank] &= ~mask;
- }
-
- if (s->status[bank] & mask)
- pxa2xx_gpio_irq_update(s);
-
- /* Wake-up GPIOs */
- if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
- }
-}
-
-static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) {
- uint32_t level, diff;
- int i, bit, line;
- for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
- level = s->olevel[i] & s->dir[i];
-
- for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- line = bit + 32 * i;
- qemu_set_irq(s->handler[line], (level >> bit) & 1);
- }
-
- s->prev_level[i] = level;
- }
-}
-
-static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- uint32_t ret;
- int bank;
- if (offset >= 0x200)
- return 0;
-
- bank = pxa2xx_gpio_regs[offset].bank;
- switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction registers */
- return s->dir[bank];
-
- case GPSR: /* GPIO Pin-Output Set registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx GPIO: read from write only register GPSR\n");
- return 0;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx GPIO: read from write only register GPCR\n");
- return 0;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- return s->rising[bank];
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- return s->falling[bank];
-
- case GAFR_L: /* GPIO Alternate Function registers */
- return s->gafr[bank * 2];
-
- case GAFR_U: /* GPIO Alternate Function registers */
- return s->gafr[bank * 2 + 1];
-
- case GPLR: /* GPIO Pin-Level registers */
- ret = (s->olevel[bank] & s->dir[bank]) |
- (s->ilevel[bank] & ~s->dir[bank]);
- qemu_irq_raise(s->read_notify);
- return ret;
-
- case GEDR: /* GPIO Edge Detect Status registers */
- return s->status[bank];
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- int bank;
- if (offset >= 0x200)
- return;
-
- bank = pxa2xx_gpio_regs[offset].bank;
- switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction registers */
- s->dir[bank] = value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GPSR: /* GPIO Pin-Output Set registers */
- s->olevel[bank] |= value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- s->olevel[bank] &= ~value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- s->rising[bank] = value;
- break;
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- s->falling[bank] = value;
- break;
-
- case GAFR_L: /* GPIO Alternate Function registers */
- s->gafr[bank * 2] = value;
- break;
-
- case GAFR_U: /* GPIO Alternate Function registers */
- s->gafr[bank * 2 + 1] = value;
- break;
-
- case GEDR: /* GPIO Edge Detect Status registers */
- s->status[bank] &= ~value;
- pxa2xx_gpio_irq_update(s);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa_gpio_ops = {
- .read = pxa2xx_gpio_read,
- .write = pxa2xx_gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-DeviceState *pxa2xx_gpio_init(hwaddr base,
- ARMCPU *cpu, DeviceState *pic, int lines)
-{
- DeviceState *dev;
-
- dev = qdev_new(TYPE_PXA2XX_GPIO);
- qdev_prop_set_int32(dev, "lines", lines);
- object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0));
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1));
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X));
-
- return dev;
-}
-
-static void pxa2xx_gpio_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- DeviceState *dev = DEVICE(sbd);
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- memory_region_init_io(&s->iomem, obj, &pxa_gpio_ops,
- s, "pxa2xx-gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq0);
- sysbus_init_irq(sbd, &s->irq1);
- sysbus_init_irq(sbd, &s->irqX);
-}
-
-static void pxa2xx_gpio_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines);
- qdev_init_gpio_out(dev, s->handler, s->lines);
-}
-
-/*
- * Registers a callback to notify on GPLR reads. This normally
- * shouldn't be needed but it is used for the hack on Spitz machines.
- */
-void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler)
-{
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- s->read_notify = handler;
-}
-
-static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
- .name = "pxa2xx-gpio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2),
- VMSTATE_UINT32_ARRAY(prev_level, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_gpio_properties[] = {
- DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
- DEFINE_PROP_LINK("cpu", PXA2xxGPIOInfo, cpu, TYPE_ARM_CPU, ARMCPU *),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx GPIO controller";
- device_class_set_props(dc, pxa2xx_gpio_properties);
- dc->vmsd = &vmstate_pxa2xx_gpio_regs;
- dc->realize = pxa2xx_gpio_realize;
-}
-
-static const TypeInfo pxa2xx_gpio_info = {
- .name = TYPE_PXA2XX_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxGPIOInfo),
- .instance_init = pxa2xx_gpio_initfn,
- .class_init = pxa2xx_gpio_class_init,
-};
-
-static void pxa2xx_gpio_register_types(void)
-{
- type_register_static(&pxa2xx_gpio_info);
-}
-
-type_init(pxa2xx_gpio_register_types)
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
deleted file mode 100644
index 34c5555..0000000
--- a/hw/arm/pxa2xx_pic.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Intel XScale PXA Programmable Interrupt Controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "qemu/log.h"
-#include "cpu.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
-#include "qom/object.h"
-#include "target/arm/cpregs.h"
-
-#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */
-#define ICMR 0x04 /* Interrupt Controller Mask register */
-#define ICLR 0x08 /* Interrupt Controller Level register */
-#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */
-#define ICPR 0x10 /* Interrupt Controller Pending register */
-#define ICCR 0x14 /* Interrupt Controller Control register */
-#define ICHP 0x18 /* Interrupt Controller Highest Priority register */
-#define IPR0 0x1c /* Interrupt Controller Priority register 0 */
-#define IPR31 0x98 /* Interrupt Controller Priority register 31 */
-#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */
-#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */
-#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */
-#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */
-#define ICPR2 0xac /* Interrupt Controller Pending register 2 */
-#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */
-#define IPR39 0xcc /* Interrupt Controller Priority register 39 */
-
-#define PXA2XX_PIC_SRCS 40
-
-#define TYPE_PXA2XX_PIC "pxa2xx_pic"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxPICState, PXA2XX_PIC)
-
-struct PXA2xxPICState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- ARMCPU *cpu;
- uint32_t int_enabled[2];
- uint32_t int_pending[2];
- uint32_t is_fiq[2];
- uint32_t int_idle;
- uint32_t priority[PXA2XX_PIC_SRCS];
-};
-
-static void pxa2xx_pic_update(void *opaque)
-{
- uint32_t mask[2];
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
- CPUState *cpu = CPU(s->cpu);
-
- if (cpu->halted) {
- mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
- mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
- if (mask[0] || mask[1]) {
- cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
- }
- }
-
- mask[0] = s->int_pending[0] & s->int_enabled[0];
- mask[1] = s->int_pending[1] & s->int_enabled[1];
-
- if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_FIQ);
- } else {
- cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ);
- }
-
- if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
- }
-}
-
-/* Note: Here level means state of the signal on a pin, not
- * IRQ/FIQ distinction as in PXA Developer Manual. */
-static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
- int int_set = (irq >= 32);
- irq &= 31;
-
- if (level)
- s->int_pending[int_set] |= 1 << irq;
- else
- s->int_pending[int_set] &= ~(1 << irq);
-
- pxa2xx_pic_update(opaque);
-}
-
-static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
- int i, int_set, irq;
- uint32_t bit, mask[2];
- uint32_t ichp = 0x003f003f; /* Both IDs invalid */
-
- mask[0] = s->int_pending[0] & s->int_enabled[0];
- mask[1] = s->int_pending[1] & s->int_enabled[1];
-
- for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
- irq = s->priority[i] & 0x3f;
- if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) {
- /* Source peripheral ID is valid. */
- bit = 1 << (irq & 31);
- int_set = (irq >= 32);
-
- if (mask[int_set] & bit & s->is_fiq[int_set]) {
- /* FIQ asserted */
- ichp &= 0xffff0000;
- ichp |= (1 << 15) | irq;
- }
-
- if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
- /* IRQ asserted */
- ichp &= 0x0000ffff;
- ichp |= (1U << 31) | (irq << 16);
- }
- }
- }
-
- return ichp;
-}
-
-static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-
- switch (offset) {
- case ICIP: /* IRQ Pending register */
- return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
- case ICIP2: /* IRQ Pending register 2 */
- return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
- case ICMR: /* Mask register */
- return s->int_enabled[0];
- case ICMR2: /* Mask register 2 */
- return s->int_enabled[1];
- case ICLR: /* Level register */
- return s->is_fiq[0];
- case ICLR2: /* Level register 2 */
- return s->is_fiq[1];
- case ICCR: /* Idle mask */
- return (s->int_idle == 0);
- case ICFP: /* FIQ Pending register */
- return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
- case ICFP2: /* FIQ Pending register 2 */
- return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
- case ICPR: /* Pending register */
- return s->int_pending[0];
- case ICPR2: /* Pending register 2 */
- return s->int_pending[1];
- case IPR0 ... IPR31:
- return s->priority[0 + ((offset - IPR0 ) >> 2)];
- case IPR32 ... IPR39:
- return s->priority[32 + ((offset - IPR32) >> 2)];
- case ICHP: /* Highest Priority register */
- return pxa2xx_pic_highest(s);
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx_pic_mem_read: bad register offset 0x%" HWADDR_PRIx
- "\n", offset);
- return 0;
- }
-}
-
-static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-
- switch (offset) {
- case ICMR: /* Mask register */
- s->int_enabled[0] = value;
- break;
- case ICMR2: /* Mask register 2 */
- s->int_enabled[1] = value;
- break;
- case ICLR: /* Level register */
- s->is_fiq[0] = value;
- break;
- case ICLR2: /* Level register 2 */
- s->is_fiq[1] = value;
- break;
- case ICCR: /* Idle mask */
- s->int_idle = (value & 1) ? 0 : ~0;
- break;
- case IPR0 ... IPR31:
- s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
- break;
- case IPR32 ... IPR39:
- s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx_pic_mem_write: bad register offset 0x%"
- HWADDR_PRIx "\n", offset);
- return;
- }
- pxa2xx_pic_update(opaque);
-}
-
-/* Interrupt Controller Coprocessor Space Register Mapping */
-static const int pxa2xx_cp_reg_map[0x10] = {
- [0x0 ... 0xf] = -1,
- [0x0] = ICIP,
- [0x1] = ICMR,
- [0x2] = ICLR,
- [0x3] = ICFP,
- [0x4] = ICPR,
- [0x5] = ICHP,
- [0x6] = ICIP2,
- [0x7] = ICMR2,
- [0x8] = ICLR2,
- [0x9] = ICFP2,
- [0xa] = ICPR2,
-};
-
-static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- int offset = pxa2xx_cp_reg_map[ri->crn];
- return pxa2xx_pic_mem_read(ri->opaque, offset, 4);
-}
-
-static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- int offset = pxa2xx_cp_reg_map[ri->crn];
- pxa2xx_pic_mem_write(ri->opaque, offset, value, 4);
-}
-
-#define REGINFO_FOR_PIC_CP(NAME, CRN) \
- { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \
- .access = PL1_RW, .type = ARM_CP_IO, \
- .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write }
-
-static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {
- REGINFO_FOR_PIC_CP("ICIP", 0),
- REGINFO_FOR_PIC_CP("ICMR", 1),
- REGINFO_FOR_PIC_CP("ICLR", 2),
- REGINFO_FOR_PIC_CP("ICFP", 3),
- REGINFO_FOR_PIC_CP("ICPR", 4),
- REGINFO_FOR_PIC_CP("ICHP", 5),
- REGINFO_FOR_PIC_CP("ICIP2", 6),
- REGINFO_FOR_PIC_CP("ICMR2", 7),
- REGINFO_FOR_PIC_CP("ICLR2", 8),
- REGINFO_FOR_PIC_CP("ICFP2", 9),
- REGINFO_FOR_PIC_CP("ICPR2", 0xa),
-};
-
-static const MemoryRegionOps pxa2xx_pic_ops = {
- .read = pxa2xx_pic_mem_read,
- .write = pxa2xx_pic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pxa2xx_pic_post_load(void *opaque, int version_id)
-{
- pxa2xx_pic_update(opaque);
- return 0;
-}
-
-static void pxa2xx_pic_reset_hold(Object *obj, ResetType type)
-{
- PXA2xxPICState *s = PXA2XX_PIC(obj);
-
- s->int_pending[0] = 0;
- s->int_pending[1] = 0;
- s->int_enabled[0] = 0;
- s->int_enabled[1] = 0;
- s->is_fiq[0] = 0;
- s->is_fiq[1] = 0;
-}
-
-DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu)
-{
- DeviceState *dev = qdev_new(TYPE_PXA2XX_PIC);
-
- object_property_set_link(OBJECT(dev), "arm-cpu",
- OBJECT(cpu), &error_abort);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static void pxa2xx_pic_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxPICState *s = PXA2XX_PIC(dev);
-
- qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS);
-
- /* Enable IC memory-mapped registers access. */
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_pic_ops, s,
- "pxa2xx-pic", 0x00100000);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
-
- /* Enable IC coprocessor access. */
- define_arm_cp_regs_with_opaque(s->cpu, pxa_pic_cp_reginfo, s);
-}
-
-static const VMStateDescription vmstate_pxa2xx_pic_regs = {
- .name = "pxa2xx_pic",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = pxa2xx_pic_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
- VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2),
- VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2),
- VMSTATE_UINT32(int_idle, PXA2xxPICState),
- VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_pic_properties[] = {
- DEFINE_PROP_LINK("arm-cpu", PXA2xxPICState, cpu,
- TYPE_ARM_CPU, ARMCPU *),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ResettableClass *rc = RESETTABLE_CLASS(klass);
-
- device_class_set_props(dc, pxa2xx_pic_properties);
- dc->realize = pxa2xx_pic_realize;
- dc->desc = "PXA2xx PIC";
- dc->vmsd = &vmstate_pxa2xx_pic_regs;
- rc->phases.hold = pxa2xx_pic_reset_hold;
-}
-
-static const TypeInfo pxa2xx_pic_info = {
- .name = TYPE_PXA2XX_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxPICState),
- .class_init = pxa2xx_pic_class_init,
-};
-
-static void pxa2xx_pic_register_types(void)
-{
- type_register_static(&pxa2xx_pic_info);
-}
-
-type_init(pxa2xx_pic_register_types)
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index a7a662f..9d9af63 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -337,48 +337,53 @@ static void raspi_machine_class_init(MachineClass *mc,
mc->init = raspi_machine_init;
};
-static void raspi0_machine_class_init(ObjectClass *oc, void *data)
+static void raspi0_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
+ mc->auto_create_sdcard = true;
rmc->board_rev = 0x920092; /* Revision 1.2 */
raspi_machine_class_init(mc, rmc->board_rev);
};
-static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
+static void raspi1ap_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
+ mc->auto_create_sdcard = true;
rmc->board_rev = 0x900021; /* Revision 1.1 */
raspi_machine_class_init(mc, rmc->board_rev);
};
-static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
+static void raspi2b_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
+ mc->auto_create_sdcard = true;
rmc->board_rev = 0xa21041;
raspi_machine_class_init(mc, rmc->board_rev);
};
#ifdef TARGET_AARCH64
-static void raspi3ap_machine_class_init(ObjectClass *oc, void *data)
+static void raspi3ap_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
+ mc->auto_create_sdcard = true;
rmc->board_rev = 0x9020e0; /* Revision 1.0 */
raspi_machine_class_init(mc, rmc->board_rev);
};
-static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
+static void raspi3b_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
+ mc->auto_create_sdcard = true;
rmc->board_rev = 0xa02082;
raspi_machine_class_init(mc, rmc->board_rev);
};
diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c
index 8587788..20082d5 100644
--- a/hw/arm/raspi4b.c
+++ b/hw/arm/raspi4b.c
@@ -15,7 +15,7 @@
#include "hw/display/bcm2835_fb.h"
#include "hw/registerfields.h"
#include "qemu/error-report.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/arm/boot.h"
@@ -107,7 +107,7 @@ static void raspi4b_machine_init(MachineState *machine)
raspi_base_machine_init(machine, &soc->parent_obj);
}
-static void raspi4b_machine_class_init(ObjectClass *oc, void *data)
+static void raspi4b_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
@@ -118,6 +118,7 @@ static void raspi4b_machine_class_init(ObjectClass *oc, void *data)
rmc->board_rev = 0xb03115; /* Revision 1.5, 2 Gb RAM */
#endif
raspi_machine_class_common_init(mc, rmc->board_rev);
+ mc->auto_create_sdcard = true;
mc->init = raspi4b_machine_init;
}
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index b186f96..5c90504 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -19,7 +19,7 @@
#include "hw/pci/pci.h"
#include "hw/qdev-core.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/i2c/i2c.h"
#include "qemu/error-report.h"
@@ -35,6 +35,8 @@
#define SMP_BOOT_ADDR 0xe0000000
#define SMP_BOOTREG_ADDR 0x10000030
+#define GIC_EXT_IRQS 64 /* Realview PBX-A9 development board */
+
/* Board init. */
static struct arm_boot_info realview_binfo = {
@@ -185,7 +187,12 @@ static void realview_init(MachineState *machine,
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
if (is_mpcore) {
- dev = qdev_new(is_pb ? TYPE_A9MPCORE_PRIV : "realview_mpcore");
+ if (is_pb) {
+ dev = qdev_new(TYPE_A9MPCORE_PRIV);
+ qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
+ } else {
+ dev = qdev_new("realview_mpcore");
+ }
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
@@ -201,7 +208,7 @@ static void realview_init(MachineState *machine,
/* For now just create the nIRQ GIC, and ignore the others. */
dev = sysbus_create_simple(TYPE_REALVIEW_GIC, gic_addr, cpu_irq[0]);
}
- for (n = 0; n < 64; n++) {
+ for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
@@ -406,7 +413,7 @@ static void realview_pbx_a9_init(MachineState *machine)
realview_init(machine, BOARD_PBX_A9);
}
-static void realview_eb_class_init(ObjectClass *oc, void *data)
+static void realview_eb_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -415,6 +422,7 @@ static void realview_eb_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_SCSI;
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
}
@@ -425,7 +433,7 @@ static const TypeInfo realview_eb_type = {
.class_init = realview_eb_class_init,
};
-static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data)
+static void realview_eb_mpcore_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -435,6 +443,7 @@ static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data)
mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm11mpcore");
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
}
@@ -445,7 +454,7 @@ static const TypeInfo realview_eb_mpcore_type = {
.class_init = realview_eb_mpcore_class_init,
};
-static void realview_pb_a8_class_init(ObjectClass *oc, void *data)
+static void realview_pb_a8_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -453,6 +462,7 @@ static void realview_pb_a8_class_init(ObjectClass *oc, void *data)
mc->init = realview_pb_a8_init;
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a8");
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
}
@@ -463,7 +473,7 @@ static const TypeInfo realview_pb_a8_type = {
.class_init = realview_pb_a8_class_init,
};
-static void realview_pbx_a9_class_init(ObjectClass *oc, void *data)
+static void realview_pbx_a9_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -472,6 +482,7 @@ static void realview_pbx_a9_class_init(ObjectClass *oc, void *data)
mc->max_cpus = 4;
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
}
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
index 56f184b..df60d47 100644
--- a/hw/arm/sabrelite.c
+++ b/hw/arm/sabrelite.c
@@ -17,7 +17,7 @@
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
static struct arm_boot_info sabrelite_binfo = {
/* DDR memory start */
@@ -110,6 +110,7 @@ static void sabrelite_machine_init(MachineClass *mc)
mc->max_cpus = FSL_IMX6_NUM_CPUS;
mc->ignore_memory_transaction_failures = true;
mc->default_ram_id = "sabrelite.ram";
+ mc->auto_create_sdcard = true;
}
DEFINE_MACHINE("sabrelite", sabrelite_machine_init)
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index ae37a92..deae5cf 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -23,11 +23,11 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/units.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/kvm.h"
-#include "sysemu/numa.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/device_tree.h"
+#include "system/kvm.h"
+#include "system/numa.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "exec/hwaddr.h"
#include "kvm_arm.h"
#include "hw/arm/boot.h"
@@ -48,7 +48,7 @@
#include "hw/char/pl011.h"
#include "hw/watchdog/sbsa_gwdt.h"
#include "net/net.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qom/object.h"
#include "target/arm/cpu-qom.h"
#include "target/arm/gtimer.h"
@@ -164,23 +164,20 @@ static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
static void sbsa_fdt_add_gic_node(SBSAMachineState *sms)
{
- char *nodename;
+ const char *intc_nodename = "/intc";
+ const char *its_nodename = "/intc/its";
- nodename = g_strdup_printf("/intc");
- qemu_fdt_add_subnode(sms->fdt, nodename);
- qemu_fdt_setprop_sized_cells(sms->fdt, nodename, "reg",
+ qemu_fdt_add_subnode(sms->fdt, intc_nodename);
+ qemu_fdt_setprop_sized_cells(sms->fdt, intc_nodename, "reg",
2, sbsa_ref_memmap[SBSA_GIC_DIST].base,
2, sbsa_ref_memmap[SBSA_GIC_DIST].size,
2, sbsa_ref_memmap[SBSA_GIC_REDIST].base,
2, sbsa_ref_memmap[SBSA_GIC_REDIST].size);
- nodename = g_strdup_printf("/intc/its");
- qemu_fdt_add_subnode(sms->fdt, nodename);
- qemu_fdt_setprop_sized_cells(sms->fdt, nodename, "reg",
+ qemu_fdt_add_subnode(sms->fdt, its_nodename);
+ qemu_fdt_setprop_sized_cells(sms->fdt, its_nodename, "reg",
2, sbsa_ref_memmap[SBSA_GIC_ITS].base,
2, sbsa_ref_memmap[SBSA_GIC_ITS].size);
-
- g_free(nodename);
}
/*
@@ -487,6 +484,8 @@ static void create_gic(SBSAMachineState *sms, MemoryRegion *mem)
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
[GTIMER_HYPVIRT] = ARCH_TIMER_NS_EL2_VIRT_IRQ,
+ [GTIMER_S_EL2_PHYS] = ARCH_TIMER_S_EL2_IRQ,
+ [GTIMER_S_EL2_VIRT] = ARCH_TIMER_S_EL2_VIRT_IRQ,
};
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
@@ -621,6 +620,7 @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus)
dev = qdev_new(TYPE_ARM_SMMUV3);
+ object_property_set_str(OBJECT(dev), "stage", "nested", &error_abort);
object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
&error_abort);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -675,7 +675,7 @@ static void create_pcie(SBSAMachineState *sms)
/* Map IO port space */
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(sms->gic, irq + i));
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
@@ -880,7 +880,7 @@ static void sbsa_ref_instance_init(Object *obj)
sbsa_flash_create(sms);
}
-static void sbsa_ref_class_init(ObjectClass *oc, void *data)
+static void sbsa_ref_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static const char * const valid_cpu_types[] = {
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 3f82728..f39b99e 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -225,6 +225,27 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova);
}
+static gboolean
+smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
+{
+ SMMUDevice *sdev = (SMMUDevice *)key;
+ uint32_t sid = smmu_get_sid(sdev);
+ SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
+
+ if (sid < sid_range->start || sid > sid_range->end) {
+ return false;
+ }
+ trace_smmu_config_cache_inv(sid);
+ return true;
+}
+
+void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range)
+{
+ trace_smmu_configs_inv_sid_range(sid_range.start, sid_range.end);
+ g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range,
+ &sid_range);
+}
+
void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
uint8_t tg, uint64_t num_pages, uint8_t ttl)
{
@@ -691,7 +712,6 @@ static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
/* parent_perm has s2 perm while perm keeps s1 perm. */
tlbe->parent_perm = tlbe_s2->entry.perm;
- return;
}
/**
@@ -924,7 +944,12 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
}
}
-static void smmu_base_reset_hold(Object *obj, ResetType type)
+/*
+ * Make sure the IOMMU is reset in 'exit' phase after
+ * all outstanding DMA requests have been quiesced during
+ * the 'enter' or 'hold' reset phases
+ */
+static void smmu_base_reset_exit(Object *obj, ResetType type)
{
SMMUState *s = ARM_SMMU(obj);
@@ -934,14 +959,13 @@ static void smmu_base_reset_hold(Object *obj, ResetType type)
g_hash_table_remove_all(s->iotlb);
}
-static Property smmu_dev_properties[] = {
+static const Property smmu_dev_properties[] = {
DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0),
DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus,
TYPE_PCI_BUS, PCIBus *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void smmu_base_class_init(ObjectClass *klass, void *data)
+static void smmu_base_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -950,7 +974,7 @@ static void smmu_base_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, smmu_dev_properties);
device_class_set_parent_realize(dc, smmu_base_realize,
&sbc->parent_realize);
- rc->phases.hold = smmu_base_reset_hold;
+ rc->phases.exit = smmu_base_reset_exit;
}
static const TypeInfo smmu_base_info = {
diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
index 843bebb..d143d29 100644
--- a/hw/arm/smmu-internal.h
+++ b/hw/arm/smmu-internal.h
@@ -141,9 +141,4 @@ typedef struct SMMUIOTLBPageInvInfo {
uint64_t mask;
} SMMUIOTLBPageInvInfo;
-typedef struct SMMUSIDRange {
- uint32_t start;
- uint32_t end;
-} SMMUSIDRange;
-
#endif
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 3971976..ab67972 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -25,6 +25,7 @@
#include "hw/qdev-core.h"
#include "hw/pci/pci.h"
#include "cpu.h"
+#include "exec/target_page.h"
#include "trace.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
@@ -377,7 +378,7 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
qemu_log_mask(LOG_GUEST_ERROR,
"Cannot fetch pte at address=0x%"PRIx64"\n", addr);
event->type = SMMU_EVT_F_CD_FETCH;
- event->u.f_ste_fetch.addr = addr;
+ event->u.f_cd_fetch.addr = addr;
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(buf->word); i++) {
@@ -903,7 +904,7 @@ static void smmuv3_flush_config(SMMUDevice *sdev)
SMMUv3State *s = sdev->smmu;
SMMUState *bc = &s->smmu_state;
- trace_smmuv3_config_cache_inv(smmu_get_sid(sdev));
+ trace_smmu_config_cache_inv(smmu_get_sid(sdev));
g_hash_table_remove(bc->configs, sdev);
}
@@ -1277,20 +1278,6 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
}
}
-static gboolean
-smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data)
-{
- SMMUDevice *sdev = (SMMUDevice *)key;
- uint32_t sid = smmu_get_sid(sdev);
- SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
-
- if (sid < sid_range->start || sid > sid_range->end) {
- return false;
- }
- trace_smmuv3_config_cache_inv(sid);
- return true;
-}
-
static int smmuv3_cmdq_consume(SMMUv3State *s)
{
SMMUState *bs = ARM_SMMU(s);
@@ -1373,8 +1360,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
sid_range.end = sid_range.start + mask;
trace_smmuv3_cmdq_cfgi_ste_range(sid_range.start, sid_range.end);
- g_hash_table_foreach_remove(bs->configs, smmuv3_invalidate_ste,
- &sid_range);
+ smmu_configs_inv_sid_range(bs, sid_range);
break;
}
case SMMU_CMD_CFGI_CD:
@@ -1870,13 +1856,19 @@ static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev)
}
}
-static void smmu_reset_hold(Object *obj, ResetType type)
+/*
+ * Make sure the IOMMU is reset in 'exit' phase after
+ * all outstanding DMA requests have been quiesced during
+ * the 'enter' or 'hold' reset phases
+ */
+static void smmu_reset_exit(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, type);
+ trace_smmu_reset_exit();
+ if (c->parent_phases.exit) {
+ c->parent_phases.exit(obj, type);
}
smmuv3_init_regs(s);
@@ -1976,15 +1968,15 @@ static const VMStateDescription vmstate_smmuv3 = {
}
};
-static Property smmuv3_properties[] = {
+static const Property smmuv3_properties[] = {
/*
* Stages of translation advertised.
* "1": Stage 1
* "2": Stage 2
+ * "nested": Both stage 1 and stage 2
* Defaults to stage 1
*/
DEFINE_PROP_STRING("stage", SMMUv3State, stage),
- DEFINE_PROP_END_OF_LIST()
};
static void smmuv3_instance_init(Object *obj)
@@ -1992,14 +1984,14 @@ static void smmuv3_instance_init(Object *obj)
/* Nothing much to do here as of now */
}
-static void smmuv3_class_init(ObjectClass *klass, void *data)
+static void smmuv3_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
SMMUv3Class *c = ARM_SMMUV3_CLASS(klass);
dc->vmsd = &vmstate_smmuv3;
- resettable_class_set_parent_phases(rc, NULL, smmu_reset_hold, NULL,
+ resettable_class_set_parent_phases(rc, NULL, NULL, smmu_reset_exit,
&c->parent_phases);
device_class_set_parent_realize(dc, smmu_realize,
&c->parent_realize);
@@ -2039,7 +2031,7 @@ static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
}
static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
@@ -2064,8 +2056,8 @@ static const TypeInfo smmuv3_iommu_memory_region_info = {
static void smmuv3_register_types(void)
{
- type_register(&smmuv3_type_info);
- type_register(&smmuv3_iommu_memory_region_info);
+ type_register_static(&smmuv3_type_info);
+ type_register_static(&smmuv3_iommu_memory_region_info);
}
type_init(smmuv3_register_types)
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
deleted file mode 100644
index 62cd55b..0000000
--- a/hw/arm/spitz.c
+++ /dev/null
@@ -1,1284 +0,0 @@
-/*
- * PXA270-based Clamshell PDA platforms.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
-#include "hw/pcmcia.h"
-#include "hw/qdev-properties.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "hw/block/flash.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-#include "hw/arm/sharpsl.h"
-#include "ui/console.h"
-#include "hw/audio/wm8750.h"
-#include "audio/audio.h"
-#include "hw/boards.h"
-#include "hw/sysbus.h"
-#include "hw/adc/max111x.h"
-#include "migration/vmstate.h"
-#include "exec/address-spaces.h"
-#include "qom/object.h"
-#include "audio/audio.h"
-
-enum spitz_model_e { spitz, akita, borzoi, terrier };
-
-struct SpitzMachineClass {
- MachineClass parent;
- enum spitz_model_e model;
- int arm_id;
-};
-
-struct SpitzMachineState {
- MachineState parent;
- PXA2xxState *mpu;
- DeviceState *mux;
- DeviceState *lcdtg;
- DeviceState *ads7846;
- DeviceState *max1111;
- DeviceState *scp0;
- DeviceState *scp1;
- DeviceState *misc_gpio;
-};
-
-#define TYPE_SPITZ_MACHINE "spitz-common"
-OBJECT_DECLARE_TYPE(SpitzMachineState, SpitzMachineClass, SPITZ_MACHINE)
-
-#define zaurus_printf(format, ...) \
- fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__)
-
-/* Spitz Flash */
-#define FLASH_BASE 0x0c000000
-#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */
-#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */
-#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */
-#define FLASH_ECCCNTR 0x0c /* ECC byte counter */
-#define FLASH_ECCCLRR 0x10 /* Clear ECC */
-#define FLASH_FLASHIO 0x14 /* Flash I/O */
-#define FLASH_FLASHCTL 0x18 /* Flash Control */
-
-#define FLASHCTL_CE0 (1 << 0)
-#define FLASHCTL_CLE (1 << 1)
-#define FLASHCTL_ALE (1 << 2)
-#define FLASHCTL_WP (1 << 3)
-#define FLASHCTL_CE1 (1 << 4)
-#define FLASHCTL_RYBY (1 << 5)
-#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
-
-#define TYPE_SL_NAND "sl-nand"
-OBJECT_DECLARE_SIMPLE_TYPE(SLNANDState, SL_NAND)
-
-struct SLNANDState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- DeviceState *nand;
- uint8_t ctl;
- uint8_t manf_id;
- uint8_t chip_id;
- ECCState ecc;
-};
-
-static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size)
-{
- SLNANDState *s = (SLNANDState *) opaque;
- int ryby;
-
- switch (addr) {
-#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to))
- case FLASH_ECCLPLB:
- return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
- BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
-
-#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to))
- case FLASH_ECCLPUB:
- return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
- BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
-
- case FLASH_ECCCP:
- return s->ecc.cp;
-
- case FLASH_ECCCNTR:
- return s->ecc.count & 0xff;
-
- case FLASH_FLASHCTL:
- nand_getpins(s->nand, &ryby);
- if (ryby)
- return s->ctl | FLASHCTL_RYBY;
- else
- return s->ctl;
-
- case FLASH_FLASHIO:
- if (size == 4) {
- return ecc_digest(&s->ecc, nand_getio(s->nand)) |
- (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
- }
- return ecc_digest(&s->ecc, nand_getio(s->nand));
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "sl_read: bad register offset 0x%02" HWADDR_PRIx "\n",
- addr);
- }
- return 0;
-}
-
-static void sl_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SLNANDState *s = (SLNANDState *) opaque;
-
- switch (addr) {
- case FLASH_ECCCLRR:
- /* Value is ignored. */
- ecc_reset(&s->ecc);
- break;
-
- case FLASH_FLASHCTL:
- s->ctl = value & 0xff & ~FLASHCTL_RYBY;
- nand_setpins(s->nand,
- s->ctl & FLASHCTL_CLE,
- s->ctl & FLASHCTL_ALE,
- s->ctl & FLASHCTL_NCE,
- s->ctl & FLASHCTL_WP,
- 0);
- break;
-
- case FLASH_FLASHIO:
- nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff));
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "sl_write: bad register offset 0x%02" HWADDR_PRIx "\n",
- addr);
- }
-}
-
-enum {
- FLASH_128M,
- FLASH_1024M,
-};
-
-static const MemoryRegionOps sl_ops = {
- .read = sl_read,
- .write = sl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void sl_flash_register(PXA2xxState *cpu, int size)
-{
- DeviceState *dev;
-
- dev = qdev_new(TYPE_SL_NAND);
-
- qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
- if (size == FLASH_128M)
- qdev_prop_set_uint8(dev, "chip_id", 0x73);
- else if (size == FLASH_1024M)
- qdev_prop_set_uint8(dev, "chip_id", 0xf1);
-
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE);
-}
-
-static void sl_nand_init(Object *obj)
-{
- SLNANDState *s = SL_NAND(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- s->ctl = 0;
-
- memory_region_init_io(&s->iomem, obj, &sl_ops, s, "sl", 0x40);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void sl_nand_realize(DeviceState *dev, Error **errp)
-{
- SLNANDState *s = SL_NAND(dev);
- DriveInfo *nand;
-
- /* FIXME use a qdev drive property instead of drive_get() */
- nand = drive_get(IF_MTD, 0, 0);
- s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- s->manf_id, s->chip_id);
-}
-
-/* Spitz Keyboard */
-
-#define SPITZ_KEY_STROBE_NUM 11
-#define SPITZ_KEY_SENSE_NUM 7
-
-static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
- 12, 17, 91, 34, 36, 38, 39
-};
-
-static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = {
- 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114
-};
-
-/* Eighth additional row maps the special keys */
-static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
- { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 },
- { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 },
- { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 },
- { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 },
- { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 },
- { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 },
- { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 },
- { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 },
-};
-
-#define SPITZ_GPIO_AK_INT 13 /* Remote control */
-#define SPITZ_GPIO_SYNC 16 /* Sync button */
-#define SPITZ_GPIO_ON_KEY 95 /* Power button */
-#define SPITZ_GPIO_SWA 97 /* Lid */
-#define SPITZ_GPIO_SWB 96 /* Tablet mode */
-
-/* The special buttons are mapped to unused keys */
-static const int spitz_gpiomap[5] = {
- SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
- SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
-};
-
-#define TYPE_SPITZ_KEYBOARD "spitz-keyboard"
-OBJECT_DECLARE_SIMPLE_TYPE(SpitzKeyboardState, SPITZ_KEYBOARD)
-
-struct SpitzKeyboardState {
- SysBusDevice parent_obj;
-
- qemu_irq sense[SPITZ_KEY_SENSE_NUM];
- qemu_irq gpiomap[5];
- int keymap[0x80];
- uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
- uint16_t strobe_state;
- uint16_t sense_state;
-
- uint16_t pre_map[0x100];
- uint16_t modifiers;
- uint16_t imodifiers;
- uint8_t fifo[16];
- int fifopos, fifolen;
- QEMUTimer *kbdtimer;
-};
-
-static void spitz_keyboard_sense_update(SpitzKeyboardState *s)
-{
- int i;
- uint16_t strobe, sense = 0;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) {
- strobe = s->keyrow[i] & s->strobe_state;
- if (strobe) {
- sense |= 1 << i;
- if (!(s->sense_state & (1 << i)))
- qemu_irq_raise(s->sense[i]);
- } else if (s->sense_state & (1 << i))
- qemu_irq_lower(s->sense[i]);
- }
-
- s->sense_state = sense;
-}
-
-static void spitz_keyboard_strobe(void *opaque, int line, int level)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- if (level)
- s->strobe_state |= 1 << line;
- else
- s->strobe_state &= ~(1 << line);
- spitz_keyboard_sense_update(s);
-}
-
-static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
-{
- int spitz_keycode = s->keymap[keycode & 0x7f];
- if (spitz_keycode == -1)
- return;
-
- /* Handle the additional keys */
- if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
- qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
- return;
- }
-
- if (keycode & 0x80)
- s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf));
- else
- s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf);
-
- spitz_keyboard_sense_update(s);
-}
-
-#define SPITZ_MOD_SHIFT (1 << 7)
-#define SPITZ_MOD_CTRL (1 << 8)
-#define SPITZ_MOD_FN (1 << 9)
-
-#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
-
-static void spitz_keyboard_handler(void *opaque, int keycode)
-{
- SpitzKeyboardState *s = opaque;
- uint16_t code;
- int mapcode;
- switch (keycode) {
- case 0x2a: /* Left Shift */
- s->modifiers |= 1;
- break;
- case 0xaa:
- s->modifiers &= ~1;
- break;
- case 0x36: /* Right Shift */
- s->modifiers |= 2;
- break;
- case 0xb6:
- s->modifiers &= ~2;
- break;
- case 0x1d: /* Control */
- s->modifiers |= 4;
- break;
- case 0x9d:
- s->modifiers &= ~4;
- break;
- case 0x38: /* Alt */
- s->modifiers |= 8;
- break;
- case 0xb8:
- s->modifiers &= ~8;
- break;
- }
-
- code = s->pre_map[mapcode = ((s->modifiers & 3) ?
- (keycode | SPITZ_MOD_SHIFT) :
- (keycode & ~SPITZ_MOD_SHIFT))];
-
- if (code != mapcode) {
-#if 0
- if ((code & SPITZ_MOD_SHIFT) && !(s->modifiers & 1)) {
- QUEUE_KEY(0x2a | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_CTRL) && !(s->modifiers & 4)) {
- QUEUE_KEY(0x1d | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && !(s->modifiers & 8)) {
- QUEUE_KEY(0x38 | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 1)) {
- QUEUE_KEY(0x2a | (~keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 2)) {
- QUEUE_KEY(0x36 | (~keycode & 0x80));
- }
-#else
- if (keycode & 0x80) {
- if ((s->imodifiers & 1 ) && !(s->modifiers & 1))
- QUEUE_KEY(0x2a | 0x80);
- if ((s->imodifiers & 4 ) && !(s->modifiers & 4))
- QUEUE_KEY(0x1d | 0x80);
- if ((s->imodifiers & 8 ) && !(s->modifiers & 8))
- QUEUE_KEY(0x38 | 0x80);
- if ((s->imodifiers & 0x10) && (s->modifiers & 1))
- QUEUE_KEY(0x2a);
- if ((s->imodifiers & 0x20) && (s->modifiers & 2))
- QUEUE_KEY(0x36);
- s->imodifiers = 0;
- } else {
- if ((code & SPITZ_MOD_SHIFT) &&
- !((s->modifiers | s->imodifiers) & 1)) {
- QUEUE_KEY(0x2a);
- s->imodifiers |= 1;
- }
- if ((code & SPITZ_MOD_CTRL) &&
- !((s->modifiers | s->imodifiers) & 4)) {
- QUEUE_KEY(0x1d);
- s->imodifiers |= 4;
- }
- if ((code & SPITZ_MOD_FN) &&
- !((s->modifiers | s->imodifiers) & 8)) {
- QUEUE_KEY(0x38);
- s->imodifiers |= 8;
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 1) &&
- !(s->imodifiers & 0x10)) {
- QUEUE_KEY(0x2a | 0x80);
- s->imodifiers |= 0x10;
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 2) &&
- !(s->imodifiers & 0x20)) {
- QUEUE_KEY(0x36 | 0x80);
- s->imodifiers |= 0x20;
- }
- }
-#endif
- }
-
- QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
-}
-
-static void spitz_keyboard_tick(void *opaque)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- if (s->fifolen) {
- spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]);
- s->fifolen --;
- if (s->fifopos >= 16)
- s->fifopos = 0;
- }
-
- timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 32);
-}
-
-static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
-{
- int i;
- for (i = 0; i < 0x100; i ++)
- s->pre_map[i] = i;
- s->pre_map[0x02 | SPITZ_MOD_SHIFT] = 0x02 | SPITZ_MOD_SHIFT; /* exclam */
- s->pre_map[0x28 | SPITZ_MOD_SHIFT] = 0x03 | SPITZ_MOD_SHIFT; /* quotedbl */
- s->pre_map[0x04 | SPITZ_MOD_SHIFT] = 0x04 | SPITZ_MOD_SHIFT; /* # */
- s->pre_map[0x05 | SPITZ_MOD_SHIFT] = 0x05 | SPITZ_MOD_SHIFT; /* dollar */
- s->pre_map[0x06 | SPITZ_MOD_SHIFT] = 0x06 | SPITZ_MOD_SHIFT; /* percent */
- s->pre_map[0x08 | SPITZ_MOD_SHIFT] = 0x07 | SPITZ_MOD_SHIFT; /* ampersand */
- s->pre_map[0x28] = 0x08 | SPITZ_MOD_SHIFT; /* ' */
- s->pre_map[0x0a | SPITZ_MOD_SHIFT] = 0x09 | SPITZ_MOD_SHIFT; /* ( */
- s->pre_map[0x0b | SPITZ_MOD_SHIFT] = 0x0a | SPITZ_MOD_SHIFT; /* ) */
- s->pre_map[0x29 | SPITZ_MOD_SHIFT] = 0x0b | SPITZ_MOD_SHIFT; /* tilde */
- s->pre_map[0x03 | SPITZ_MOD_SHIFT] = 0x0c | SPITZ_MOD_SHIFT; /* at */
- s->pre_map[0xd3] = 0x0e | SPITZ_MOD_FN; /* Delete */
- s->pre_map[0x3a] = 0x0f | SPITZ_MOD_FN; /* Caps_Lock */
- s->pre_map[0x07 | SPITZ_MOD_SHIFT] = 0x11 | SPITZ_MOD_FN; /* ^ */
- s->pre_map[0x0d] = 0x12 | SPITZ_MOD_FN; /* equal */
- s->pre_map[0x0d | SPITZ_MOD_SHIFT] = 0x13 | SPITZ_MOD_FN; /* plus */
- s->pre_map[0x1a] = 0x14 | SPITZ_MOD_FN; /* [ */
- s->pre_map[0x1b] = 0x15 | SPITZ_MOD_FN; /* ] */
- s->pre_map[0x1a | SPITZ_MOD_SHIFT] = 0x16 | SPITZ_MOD_FN; /* { */
- s->pre_map[0x1b | SPITZ_MOD_SHIFT] = 0x17 | SPITZ_MOD_FN; /* } */
- s->pre_map[0x27] = 0x22 | SPITZ_MOD_FN; /* semicolon */
- s->pre_map[0x27 | SPITZ_MOD_SHIFT] = 0x23 | SPITZ_MOD_FN; /* colon */
- s->pre_map[0x09 | SPITZ_MOD_SHIFT] = 0x24 | SPITZ_MOD_FN; /* asterisk */
- s->pre_map[0x2b] = 0x25 | SPITZ_MOD_FN; /* backslash */
- s->pre_map[0x2b | SPITZ_MOD_SHIFT] = 0x26 | SPITZ_MOD_FN; /* bar */
- s->pre_map[0x0c | SPITZ_MOD_SHIFT] = 0x30 | SPITZ_MOD_FN; /* _ */
- s->pre_map[0x33 | SPITZ_MOD_SHIFT] = 0x33 | SPITZ_MOD_FN; /* less */
- s->pre_map[0x35] = 0x33 | SPITZ_MOD_SHIFT; /* slash */
- s->pre_map[0x34 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_FN; /* greater */
- s->pre_map[0x35 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_SHIFT; /* question */
- s->pre_map[0x49] = 0x48 | SPITZ_MOD_FN; /* Page_Up */
- s->pre_map[0x51] = 0x50 | SPITZ_MOD_FN; /* Page_Down */
-
- s->modifiers = 0;
- s->imodifiers = 0;
- s->fifopos = 0;
- s->fifolen = 0;
-}
-
-#undef SPITZ_MOD_SHIFT
-#undef SPITZ_MOD_CTRL
-#undef SPITZ_MOD_FN
-
-static int spitz_keyboard_post_load(void *opaque, int version_id)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- /* Release all pressed keys */
- memset(s->keyrow, 0, sizeof(s->keyrow));
- spitz_keyboard_sense_update(s);
- s->modifiers = 0;
- s->imodifiers = 0;
- s->fifopos = 0;
- s->fifolen = 0;
-
- return 0;
-}
-
-static void spitz_keyboard_register(PXA2xxState *cpu)
-{
- int i;
- DeviceState *dev;
- SpitzKeyboardState *s;
-
- dev = sysbus_create_simple(TYPE_SPITZ_KEYBOARD, -1, NULL);
- s = SPITZ_KEYBOARD(dev);
-
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
- qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
-
- for (i = 0; i < 5; i ++)
- s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
-
- if (!graphic_rotate)
- s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
-
- for (i = 0; i < 5; i++)
- qemu_set_irq(s->gpiomap[i], 0);
-
- for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
- qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
- qdev_get_gpio_in(dev, i));
-
- timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
-
- qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
-}
-
-static void spitz_keyboard_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SpitzKeyboardState *s = SPITZ_KEYBOARD(obj);
- int i, j;
-
- for (i = 0; i < 0x80; i ++)
- s->keymap[i] = -1;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++)
- for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++)
- if (spitz_keymap[i][j] != -1)
- s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
-
- spitz_keyboard_pre_map(s);
-
- qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
- qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM);
-}
-
-static void spitz_keyboard_realize(DeviceState *dev, Error **errp)
-{
- SpitzKeyboardState *s = SPITZ_KEYBOARD(dev);
- s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s);
-}
-
-/* LCD backlight controller */
-
-#define LCDTG_RESCTL 0x00
-#define LCDTG_PHACTRL 0x01
-#define LCDTG_DUTYCTRL 0x02
-#define LCDTG_POWERREG0 0x03
-#define LCDTG_POWERREG1 0x04
-#define LCDTG_GPOR3 0x05
-#define LCDTG_PICTRL 0x06
-#define LCDTG_POLCTRL 0x07
-
-#define TYPE_SPITZ_LCDTG "spitz-lcdtg"
-OBJECT_DECLARE_SIMPLE_TYPE(SpitzLCDTG, SPITZ_LCDTG)
-
-struct SpitzLCDTG {
- SSIPeripheral ssidev;
- uint32_t bl_intensity;
- uint32_t bl_power;
-};
-
-static void spitz_bl_update(SpitzLCDTG *s)
-{
- if (s->bl_power && s->bl_intensity)
- zaurus_printf("LCD Backlight now at %u/63\n", s->bl_intensity);
- else
- zaurus_printf("LCD Backlight now off\n");
-}
-
-static inline void spitz_bl_bit5(void *opaque, int line, int level)
-{
- SpitzLCDTG *s = opaque;
- int prev = s->bl_intensity;
-
- if (level)
- s->bl_intensity &= ~0x20;
- else
- s->bl_intensity |= 0x20;
-
- if (s->bl_power && prev != s->bl_intensity)
- spitz_bl_update(s);
-}
-
-static inline void spitz_bl_power(void *opaque, int line, int level)
-{
- SpitzLCDTG *s = opaque;
- s->bl_power = !!level;
- spitz_bl_update(s);
-}
-
-static uint32_t spitz_lcdtg_transfer(SSIPeripheral *dev, uint32_t value)
-{
- SpitzLCDTG *s = SPITZ_LCDTG(dev);
- int addr;
- addr = value >> 5;
- value &= 0x1f;
-
- switch (addr) {
- case LCDTG_RESCTL:
- if (value)
- zaurus_printf("LCD in QVGA mode\n");
- else
- zaurus_printf("LCD in VGA mode\n");
- break;
-
- case LCDTG_DUTYCTRL:
- s->bl_intensity &= ~0x1f;
- s->bl_intensity |= value;
- if (s->bl_power)
- spitz_bl_update(s);
- break;
-
- case LCDTG_POWERREG0:
- /* Set common voltage to M62332FP */
- break;
- }
- return 0;
-}
-
-static void spitz_lcdtg_realize(SSIPeripheral *ssi, Error **errp)
-{
- SpitzLCDTG *s = SPITZ_LCDTG(ssi);
- DeviceState *dev = DEVICE(s);
-
- s->bl_power = 0;
- s->bl_intensity = 0x20;
-
- qdev_init_gpio_in_named(dev, spitz_bl_bit5, "bl_bit5", 1);
- qdev_init_gpio_in_named(dev, spitz_bl_power, "bl_power", 1);
-}
-
-/* SSP devices */
-
-#define CORGI_SSP_PORT 2
-
-#define SPITZ_GPIO_LCDCON_CS 53
-#define SPITZ_GPIO_ADS7846_CS 14
-#define SPITZ_GPIO_MAX1111_CS 20
-#define SPITZ_GPIO_TP_INT 11
-
-#define TYPE_CORGI_SSP "corgi-ssp"
-OBJECT_DECLARE_SIMPLE_TYPE(CorgiSSPState, CORGI_SSP)
-
-/* "Demux" the signal based on current chipselect */
-struct CorgiSSPState {
- SSIPeripheral ssidev;
- SSIBus *bus[3];
- uint32_t enable[3];
-};
-
-static uint32_t corgi_ssp_transfer(SSIPeripheral *dev, uint32_t value)
-{
- CorgiSSPState *s = CORGI_SSP(dev);
- int i;
-
- for (i = 0; i < 3; i++) {
- if (s->enable[i]) {
- return ssi_transfer(s->bus[i], value);
- }
- }
- return 0;
-}
-
-static void corgi_ssp_gpio_cs(void *opaque, int line, int level)
-{
- CorgiSSPState *s = (CorgiSSPState *)opaque;
- assert(line >= 0 && line < 3);
- s->enable[line] = !level;
-}
-
-#define MAX1111_BATT_VOLT 1
-#define MAX1111_BATT_TEMP 2
-#define MAX1111_ACIN_VOLT 3
-
-#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */
-#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */
-#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */
-
-static void corgi_ssp_realize(SSIPeripheral *d, Error **errp)
-{
- DeviceState *dev = DEVICE(d);
- CorgiSSPState *s = CORGI_SSP(d);
-
- qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3);
- s->bus[0] = ssi_create_bus(dev, "ssi0");
- s->bus[1] = ssi_create_bus(dev, "ssi1");
- s->bus[2] = ssi_create_bus(dev, "ssi2");
-}
-
-static void spitz_ssp_attach(SpitzMachineState *sms)
-{
- void *bus;
-
- sms->mux = ssi_create_peripheral(sms->mpu->ssp[CORGI_SSP_PORT - 1],
- TYPE_CORGI_SSP);
-
- bus = qdev_get_child_bus(sms->mux, "ssi0");
- sms->lcdtg = ssi_create_peripheral(bus, TYPE_SPITZ_LCDTG);
-
- bus = qdev_get_child_bus(sms->mux, "ssi1");
- sms->ads7846 = ssi_create_peripheral(bus, "ads7846");
- qdev_connect_gpio_out(sms->ads7846, 0,
- qdev_get_gpio_in(sms->mpu->gpio, SPITZ_GPIO_TP_INT));
-
- bus = qdev_get_child_bus(sms->mux, "ssi2");
- sms->max1111 = qdev_new(TYPE_MAX_1111);
- qdev_prop_set_uint8(sms->max1111, "input1" /* BATT_VOLT */,
- SPITZ_BATTERY_VOLT);
- qdev_prop_set_uint8(sms->max1111, "input2" /* BATT_TEMP */, 0);
- qdev_prop_set_uint8(sms->max1111, "input3" /* ACIN_VOLT */,
- SPITZ_CHARGEON_ACIN);
- ssi_realize_and_unref(sms->max1111, bus, &error_fatal);
-
- qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_LCDCON_CS,
- qdev_get_gpio_in(sms->mux, 0));
- qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_ADS7846_CS,
- qdev_get_gpio_in(sms->mux, 1));
- qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_MAX1111_CS,
- qdev_get_gpio_in(sms->mux, 2));
-}
-
-/* CF Microdrive */
-
-static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
-{
- PCMCIACardState *md;
- DriveInfo *dinfo;
-
- dinfo = drive_get(IF_IDE, 0, 0);
- if (!dinfo || dinfo->media_cd)
- return;
- md = dscm1xxxx_init(dinfo);
- pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
-}
-
-/* Wm8750 and Max7310 on I2C */
-
-#define AKITA_MAX_ADDR 0x18
-#define SPITZ_WM_ADDRL 0x1b
-#define SPITZ_WM_ADDRH 0x1a
-
-#define SPITZ_GPIO_WM 5
-
-static void spitz_wm8750_addr(void *opaque, int line, int level)
-{
- I2CSlave *wm = (I2CSlave *) opaque;
- if (level)
- i2c_slave_set_address(wm, SPITZ_WM_ADDRH);
- else
- i2c_slave_set_address(wm, SPITZ_WM_ADDRL);
-}
-
-static void spitz_i2c_setup(MachineState *machine, PXA2xxState *cpu)
-{
- /* Attach the CPU on one end of our I2C bus. */
- I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
-
- /* Attach a WM8750 to the bus */
- I2CSlave *i2c_dev = i2c_slave_new(TYPE_WM8750, 0);
- DeviceState *wm = DEVICE(i2c_dev);
-
- if (machine->audiodev) {
- qdev_prop_set_string(wm, "audiodev", machine->audiodev);
- }
- i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort);
-
- spitz_wm8750_addr(wm, 0, 0);
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
- qemu_allocate_irq(spitz_wm8750_addr, wm, 0));
- /* .. and to the sound interface. */
- cpu->i2s->opaque = wm;
- cpu->i2s->codec_out = wm8750_dac_dat;
- cpu->i2s->codec_in = wm8750_adc_dat;
- wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
-}
-
-static void spitz_akita_i2c_setup(PXA2xxState *cpu)
-{
- /* Attach a Max7310 to Akita I2C bus. */
- i2c_slave_create_simple(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310",
- AKITA_MAX_ADDR);
-}
-
-/* Other peripherals */
-
-/*
- * Encapsulation of some miscellaneous GPIO line behaviour for the Spitz boards.
- *
- * QEMU interface:
- * + named GPIO inputs "green-led", "orange-led", "charging", "discharging":
- * these currently just print messages that the line has been signalled
- * + named GPIO input "adc-temp-on": set to cause the battery-temperature
- * value to be passed to the max111x ADC
- * + named GPIO output "adc-temp": the ADC value, to be wired up to the max111x
- */
-#define TYPE_SPITZ_MISC_GPIO "spitz-misc-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(SpitzMiscGPIOState, SPITZ_MISC_GPIO)
-
-struct SpitzMiscGPIOState {
- SysBusDevice parent_obj;
-
- qemu_irq adc_value;
-};
-
-static void spitz_misc_charging(void *opaque, int n, int level)
-{
- zaurus_printf("Charging %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_discharging(void *opaque, int n, int level)
-{
- zaurus_printf("Discharging %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_green_led(void *opaque, int n, int level)
-{
- zaurus_printf("Green LED %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_orange_led(void *opaque, int n, int level)
-{
- zaurus_printf("Orange LED %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_adc_temp(void *opaque, int n, int level)
-{
- SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(opaque);
- int batt_temp = level ? SPITZ_BATTERY_TEMP : 0;
-
- qemu_set_irq(s->adc_value, batt_temp);
-}
-
-static void spitz_misc_gpio_init(Object *obj)
-{
- SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(obj);
- DeviceState *dev = DEVICE(obj);
-
- qdev_init_gpio_in_named(dev, spitz_misc_charging, "charging", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_discharging, "discharging", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_green_led, "green-led", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_orange_led, "orange-led", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_adc_temp, "adc-temp-on", 1);
-
- qdev_init_gpio_out_named(dev, &s->adc_value, "adc-temp", 1);
-}
-
-#define SPITZ_SCP_LED_GREEN 1
-#define SPITZ_SCP_JK_B 2
-#define SPITZ_SCP_CHRG_ON 3
-#define SPITZ_SCP_MUTE_L 4
-#define SPITZ_SCP_MUTE_R 5
-#define SPITZ_SCP_CF_POWER 6
-#define SPITZ_SCP_LED_ORANGE 7
-#define SPITZ_SCP_JK_A 8
-#define SPITZ_SCP_ADC_TEMP_ON 9
-#define SPITZ_SCP2_IR_ON 1
-#define SPITZ_SCP2_AKIN_PULLUP 2
-#define SPITZ_SCP2_BACKLIGHT_CONT 7
-#define SPITZ_SCP2_BACKLIGHT_ON 8
-#define SPITZ_SCP2_MIC_BIAS 9
-
-static void spitz_scoop_gpio_setup(SpitzMachineState *sms)
-{
- DeviceState *miscdev = sysbus_create_simple(TYPE_SPITZ_MISC_GPIO, -1, NULL);
-
- sms->misc_gpio = miscdev;
-
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_CHRG_ON,
- qdev_get_gpio_in_named(miscdev, "charging", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_JK_B,
- qdev_get_gpio_in_named(miscdev, "discharging", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_GREEN,
- qdev_get_gpio_in_named(miscdev, "green-led", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_ORANGE,
- qdev_get_gpio_in_named(miscdev, "orange-led", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_ADC_TEMP_ON,
- qdev_get_gpio_in_named(miscdev, "adc-temp-on", 0));
- qdev_connect_gpio_out_named(miscdev, "adc-temp", 0,
- qdev_get_gpio_in(sms->max1111, MAX1111_BATT_TEMP));
-
- if (sms->scp1) {
- qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_CONT,
- qdev_get_gpio_in_named(sms->lcdtg, "bl_bit5", 0));
- qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_ON,
- qdev_get_gpio_in_named(sms->lcdtg, "bl_power", 0));
- }
-}
-
-#define SPITZ_GPIO_HSYNC 22
-#define SPITZ_GPIO_SD_DETECT 9
-#define SPITZ_GPIO_SD_WP 81
-#define SPITZ_GPIO_ON_RESET 89
-#define SPITZ_GPIO_BAT_COVER 90
-#define SPITZ_GPIO_CF1_IRQ 105
-#define SPITZ_GPIO_CF1_CD 94
-#define SPITZ_GPIO_CF2_IRQ 106
-#define SPITZ_GPIO_CF2_CD 93
-
-static int spitz_hsync;
-
-static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
-{
- PXA2xxState *cpu = (PXA2xxState *) opaque;
- qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
- spitz_hsync ^= 1;
-}
-
-static void spitz_reset(void *opaque, int line, int level)
-{
- if (level) {
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- }
-}
-
-static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
-{
- qemu_irq lcd_hsync;
- qemu_irq reset;
-
- /*
- * Bad hack: We toggle the LCD hsync GPIO on every GPIO status
- * read to satisfy broken guests that poll-wait for hsync.
- * Simulating a real hsync event would be less practical and
- * wouldn't guarantee that a guest ever exits the loop.
- */
- spitz_hsync = 0;
- lcd_hsync = qemu_allocate_irq(spitz_lcd_hsync_handler, cpu, 0);
- pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync);
- pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(cpu->mmc,
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
-
- /* Battery lock always closed */
- qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
-
- /* Handle reset */
- reset = qemu_allocate_irq(spitz_reset, cpu, 0);
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, reset);
-
- /* PCMCIA signals: card's IRQ and Card-Detect */
- if (slots >= 1)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
- if (slots >= 2)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
-}
-
-/* Board init. */
-#define SPITZ_RAM 0x04000000
-#define SPITZ_ROM 0x00800000
-
-static struct arm_boot_info spitz_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = 0x04000000,
-};
-
-static void spitz_common_init(MachineState *machine)
-{
- SpitzMachineClass *smc = SPITZ_MACHINE_GET_CLASS(machine);
- SpitzMachineState *sms = SPITZ_MACHINE(machine);
- enum spitz_model_e model = smc->model;
- PXA2xxState *mpu;
- MemoryRegion *rom = g_new(MemoryRegion, 1);
-
- /* Setup CPU & memory */
- mpu = pxa270_init(spitz_binfo.ram_size, machine->cpu_type);
- sms->mpu = mpu;
-
- sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
-
- memory_region_init_rom(rom, NULL, "spitz.rom", SPITZ_ROM, &error_fatal);
- memory_region_add_subregion(get_system_memory(), 0, rom);
-
- /* Setup peripherals */
- spitz_keyboard_register(mpu);
-
- spitz_ssp_attach(sms);
-
- sms->scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
- if (model != akita) {
- sms->scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
- } else {
- sms->scp1 = NULL;
- }
-
- spitz_scoop_gpio_setup(sms);
-
- spitz_gpio_setup(mpu, (model == akita) ? 1 : 2);
-
- spitz_i2c_setup(machine, mpu);
-
- if (model == akita)
- spitz_akita_i2c_setup(mpu);
-
- if (model == terrier)
- /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */
- spitz_microdrive_attach(mpu, 1);
- else if (model != akita)
- /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
- spitz_microdrive_attach(mpu, 0);
-
- spitz_binfo.board_id = smc->arm_id;
- arm_load_kernel(mpu->cpu, machine, &spitz_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static void spitz_common_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->block_default_type = IF_IDE;
- mc->ignore_memory_transaction_failures = true;
- mc->init = spitz_common_init;
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-static const TypeInfo spitz_common_info = {
- .name = TYPE_SPITZ_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(SpitzMachineState),
- .class_size = sizeof(SpitzMachineClass),
- .class_init = spitz_common_class_init,
-};
-
-static void akitapda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
- smc->model = akita;
- smc->arm_id = 0x2e8;
-}
-
-static const TypeInfo akitapda_type = {
- .name = MACHINE_TYPE_NAME("akita"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = akitapda_class_init,
-};
-
-static void spitzpda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
- smc->model = spitz;
- smc->arm_id = 0x2c9;
-}
-
-static const TypeInfo spitzpda_type = {
- .name = MACHINE_TYPE_NAME("spitz"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = spitzpda_class_init,
-};
-
-static void borzoipda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
- smc->model = borzoi;
- smc->arm_id = 0x33f;
-}
-
-static const TypeInfo borzoipda_type = {
- .name = MACHINE_TYPE_NAME("borzoi"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = borzoipda_class_init,
-};
-
-static void terrierpda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
- smc->model = terrier;
- smc->arm_id = 0x33f;
-}
-
-static const TypeInfo terrierpda_type = {
- .name = MACHINE_TYPE_NAME("terrier"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = terrierpda_class_init,
-};
-
-static void spitz_machine_init(void)
-{
- type_register_static(&spitz_common_info);
- type_register_static(&akitapda_type);
- type_register_static(&spitzpda_type);
- type_register_static(&borzoipda_type);
- type_register_static(&terrierpda_type);
-}
-
-type_init(spitz_machine_init)
-
-static bool is_version_0(void *opaque, int version_id)
-{
- return version_id == 0;
-}
-
-static const VMStateDescription vmstate_sl_nand_info = {
- .name = "sl-nand",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(ctl, SLNANDState),
- VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property sl_nand_properties[] = {
- DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
- DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sl_nand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_sl_nand_info;
- device_class_set_props(dc, sl_nand_properties);
- dc->realize = sl_nand_realize;
- /* Reason: init() method uses drive_get() */
- dc->user_creatable = false;
-}
-
-static const TypeInfo sl_nand_info = {
- .name = TYPE_SL_NAND,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SLNANDState),
- .instance_init = sl_nand_init,
- .class_init = sl_nand_class_init,
-};
-
-static const VMStateDescription vmstate_spitz_kbd = {
- .name = "spitz-keyboard",
- .version_id = 1,
- .minimum_version_id = 0,
- .post_load = spitz_keyboard_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT16(sense_state, SpitzKeyboardState),
- VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
- VMSTATE_UNUSED_TEST(is_version_0, 5),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_spitz_kbd;
- dc->realize = spitz_keyboard_realize;
-}
-
-static const TypeInfo spitz_keyboard_info = {
- .name = TYPE_SPITZ_KEYBOARD,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SpitzKeyboardState),
- .instance_init = spitz_keyboard_init,
- .class_init = spitz_keyboard_class_init,
-};
-
-static const VMStateDescription vmstate_corgi_ssp_regs = {
- .name = "corgi-ssp",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, CorgiSSPState),
- VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void corgi_ssp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = corgi_ssp_realize;
- k->transfer = corgi_ssp_transfer;
- dc->vmsd = &vmstate_corgi_ssp_regs;
-}
-
-static const TypeInfo corgi_ssp_info = {
- .name = TYPE_CORGI_SSP,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(CorgiSSPState),
- .class_init = corgi_ssp_class_init,
-};
-
-static const VMStateDescription vmstate_spitz_lcdtg_regs = {
- .name = "spitz-lcdtg",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, SpitzLCDTG),
- VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
- VMSTATE_UINT32(bl_power, SpitzLCDTG),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = spitz_lcdtg_realize;
- k->transfer = spitz_lcdtg_transfer;
- dc->vmsd = &vmstate_spitz_lcdtg_regs;
-}
-
-static const TypeInfo spitz_lcdtg_info = {
- .name = TYPE_SPITZ_LCDTG,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(SpitzLCDTG),
- .class_init = spitz_lcdtg_class_init,
-};
-
-static const TypeInfo spitz_misc_gpio_info = {
- .name = TYPE_SPITZ_MISC_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SpitzMiscGPIOState),
- .instance_init = spitz_misc_gpio_init,
- /*
- * No class_init required: device has no internal state so does not
- * need to set up reset or vmstate, and does not have a realize method.
- */
-};
-
-static void spitz_register_types(void)
-{
- type_register_static(&corgi_ssp_info);
- type_register_static(&spitz_lcdtg_info);
- type_register_static(&spitz_keyboard_info);
- type_register_static(&sl_nand_info);
- type_register_static(&spitz_misc_gpio_info);
-}
-
-type_init(spitz_register_types)
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 3767462..031ea3a 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -8,6 +8,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/bitops.h"
#include "qapi/error.h"
#include "hw/core/split-irq.h"
#include "hw/sysbus.h"
@@ -19,8 +20,8 @@
#include "net/net.h"
#include "hw/boards.h"
#include "qemu/log.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
#include "hw/arm/armv7m.h"
#include "hw/char/pl011.h"
#include "hw/input/stellaris_gamepad.h"
@@ -31,7 +32,7 @@
#include "hw/timer/stellaris-gptm.h"
#include "hw/qdev-clock.h"
#include "qom/object.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "ui/input.h"
#define GPIO_A 0
@@ -49,6 +50,31 @@
#define NUM_IRQ_LINES 64
#define NUM_PRIO_BITS 3
+#define NUM_GPIO 7
+#define NUM_UART 4
+#define NUM_GPTM 4
+#define NUM_I2C 2
+
+/*
+ * See Stellaris Data Sheet chapter 5.2.5 "System Control",
+ * Register 13 .. 17: Device Capabilities 0 .. 4 (DC0 .. DC4).
+ */
+#define DC1_WDT 3
+#define DC1_HIB 6
+#define DC1_MPU 7
+#define DC1_ADC 16
+#define DC1_PWM 20
+#define DC2_UART(n) (n)
+#define DC2_SSI 4
+#define DC2_QEI(n) (8 + n)
+#define DC2_I2C(n) (12 + 2 * n)
+#define DC2_GPTM(n) (16 + n)
+#define DC2_COMP(n) (24 + n)
+#define DC4_GPIO(n) (n)
+#define DC4_EMAC 28
+
+#define DEV_CAP(_dc, _cap) extract32(board->dc##_dc, DC##_dc##_##_cap, 1)
+
typedef const struct {
const char *name;
uint32_t did0;
@@ -101,7 +127,7 @@ static void ssys_update(ssys_state *s)
qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
}
-static uint32_t pllcfg_sandstorm[16] = {
+static const uint32_t pllcfg_sandstorm[16] = {
0x31c0, /* 1 Mhz */
0x1ae0, /* 1.8432 Mhz */
0x18c0, /* 2 Mhz */
@@ -120,7 +146,7 @@ static uint32_t pllcfg_sandstorm[16] = {
0x585b /* 8.192 Mhz */
};
-static uint32_t pllcfg_fury[16] = {
+static const uint32_t pllcfg_fury[16] = {
0x3200, /* 1 Mhz */
0x1b20, /* 1.8432 Mhz */
0x1900, /* 2 Mhz */
@@ -438,7 +464,7 @@ static const VMStateDescription vmstate_stellaris_sys = {
}
};
-static Property stellaris_sys_properties[] = {
+static const Property stellaris_sys_properties[] = {
DEFINE_PROP_UINT32("user0", ssys_state, user0, 0),
DEFINE_PROP_UINT32("user1", ssys_state, user1, 0),
DEFINE_PROP_UINT32("did0", ssys_state, did0, 0),
@@ -448,7 +474,6 @@ static Property stellaris_sys_properties[] = {
DEFINE_PROP_UINT32("dc2", ssys_state, dc2, 0),
DEFINE_PROP_UINT32("dc3", ssys_state, dc3, 0),
DEFINE_PROP_UINT32("dc4", ssys_state, dc4, 0),
- DEFINE_PROP_END_OF_LIST()
};
static void stellaris_sys_instance_init(Object *obj)
@@ -965,7 +990,7 @@ static void stellaris_adc_init(Object *obj)
}
/* Board init. */
-static stellaris_board_info stellaris_boards[] = {
+static const stellaris_board_info stellaris_boards[] = {
{ "LM3S811EVB",
0,
0x0032000e,
@@ -990,19 +1015,20 @@ static stellaris_board_info stellaris_boards[] = {
static void stellaris_init(MachineState *ms, stellaris_board_info *board)
{
- static const int uart_irq[] = {5, 6, 33, 34};
- static const int timer_irq[] = {19, 21, 23, 35};
- static const uint32_t gpio_addr[7] =
+ static const int uart_irq[NUM_UART] = {5, 6, 33, 34};
+ static const int timer_irq[NUM_GPTM] = {19, 21, 23, 35};
+ static const uint32_t gpio_addr[NUM_GPIO] =
{ 0x40004000, 0x40005000, 0x40006000, 0x40007000,
0x40024000, 0x40025000, 0x40026000};
- static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
+ static const int gpio_irq[NUM_GPIO] = {0, 1, 2, 3, 4, 30, 31};
+ static const uint32_t i2c_addr[NUM_I2C] = {0x40020000, 0x40021000};
+ static const int i2c_irq[NUM_I2C] = {8, 37};
/* Memory map of SoC devices, from
* Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
* http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
*
* 40000000 wdtimer
- * 40002000 i2c (unimplemented)
* 40004000 GPIO
* 40005000 GPIO
* 40006000 GPIO
@@ -1032,13 +1058,13 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
*/
Object *soc_container;
- DeviceState *gpio_dev[7], *nvic;
- qemu_irq gpio_in[7][8];
- qemu_irq gpio_out[7][8];
+ DeviceState *gpio_dev[NUM_GPIO], *armv7m, *nvic;
+ qemu_irq gpio_in[NUM_GPIO][8];
+ qemu_irq gpio_out[NUM_GPIO][8];
qemu_irq adc;
int sram_size;
int flash_size;
- I2CBus *i2c;
+ DeviceState *i2c_dev[NUM_I2C] = { };
DeviceState *dev;
DeviceState *ssys_dev;
int i;
@@ -1053,7 +1079,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
flash_size = (((board->dc0 & 0xffff) + 1) << 1) * 1024;
sram_size = ((board->dc0 >> 18) + 1) * 1024;
- soc_container = object_new("container");
+ soc_container = object_new(TYPE_CONTAINER);
object_property_add_child(OBJECT(ms), "soc", soc_container);
/* Flash programming is done via the SCU, so pretend it is ROM. */
@@ -1096,25 +1122,26 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
qdev_prop_set_uint32(ssys_dev, "dc4", board->dc4);
sysbus_realize_and_unref(SYS_BUS_DEVICE(ssys_dev), &error_fatal);
- nvic = qdev_new(TYPE_ARMV7M);
- object_property_add_child(soc_container, "v7m", OBJECT(nvic));
- qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES);
- qdev_prop_set_uint8(nvic, "num-prio-bits", NUM_PRIO_BITS);
- qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type);
- qdev_prop_set_bit(nvic, "enable-bitband", true);
- qdev_connect_clock_in(nvic, "cpuclk",
+ armv7m = qdev_new(TYPE_ARMV7M);
+ object_property_add_child(soc_container, "v7m", OBJECT(armv7m));
+ qdev_prop_set_uint32(armv7m, "num-irq", NUM_IRQ_LINES);
+ qdev_prop_set_uint8(armv7m, "num-prio-bits", NUM_PRIO_BITS);
+ qdev_prop_set_string(armv7m, "cpu-type", ms->cpu_type);
+ qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ qdev_connect_clock_in(armv7m, "cpuclk",
qdev_get_clock_out(ssys_dev, "SYSCLK"));
/* This SoC does not connect the systick reference clock */
- object_property_set_link(OBJECT(nvic), "memory",
+ object_property_set_link(OBJECT(armv7m), "memory",
OBJECT(get_system_memory()), &error_abort);
/* This will exit with an error if the user passed us a bad cpu_type */
- sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(armv7m), &error_fatal);
+ nvic = armv7m;
/* Now we can wire up the IRQ and MMIO of the system registers */
sysbus_mmio_map(SYS_BUS_DEVICE(ssys_dev), 0, 0x400fe000);
sysbus_connect_irq(SYS_BUS_DEVICE(ssys_dev), 0, qdev_get_gpio_in(nvic, 28));
- if (board->dc1 & (1 << 16)) {
+ if (DEV_CAP(1, ADC)) {
dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
qdev_get_gpio_in(nvic, 14),
qdev_get_gpio_in(nvic, 15),
@@ -1125,8 +1152,8 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
} else {
adc = NULL;
}
- for (i = 0; i < 4; i++) {
- if (board->dc2 & (0x10000 << i)) {
+ for (i = 0; i < NUM_GPTM; i++) {
+ if (DEV_CAP(2, GPTM(i))) {
SysBusDevice *sbd;
dev = qdev_new(TYPE_STELLARIS_GPTM);
@@ -1143,7 +1170,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
}
}
- if (board->dc1 & (1 << 3)) { /* watchdog present */
+ if (DEV_CAP(1, WDT)) {
dev = qdev_new(TYPE_LUMINARY_WATCHDOG);
object_property_add_child(soc_container, "wdg", OBJECT(dev));
qdev_connect_clock_in(dev, "WDOGCLK",
@@ -1159,8 +1186,8 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
}
- for (i = 0; i < 7; i++) {
- if (board->dc4 & (1 << i)) {
+ for (i = 0; i < NUM_GPIO; i++) {
+ if (DEV_CAP(4, GPIO(i))) {
gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
qdev_get_gpio_in(nvic,
gpio_irq[i]));
@@ -1171,17 +1198,21 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
}
}
- if (board->dc2 & (1 << 12)) {
- dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000,
- qdev_get_gpio_in(nvic, 8));
- i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
- if (board->peripherals & BP_OLED_I2C) {
- i2c_slave_create_simple(i2c, "ssd0303", 0x3d);
+ for (i = 0; i < NUM_I2C; i++) {
+ if (DEV_CAP(2, I2C(i))) {
+ i2c_dev[i] = sysbus_create_simple(TYPE_STELLARIS_I2C, i2c_addr[i],
+ qdev_get_gpio_in(nvic,
+ i2c_irq[i]));
}
}
+ if (board->peripherals & BP_OLED_I2C) {
+ I2CBus *bus = (I2CBus *)qdev_get_child_bus(i2c_dev[0], "i2c");
- for (i = 0; i < 4; i++) {
- if (board->dc2 & (1 << i)) {
+ i2c_slave_create_simple(bus, "ssd0303", 0x3d);
+ }
+
+ for (i = 0; i < NUM_UART; i++) {
+ if (DEV_CAP(2, UART(i))) {
SysBusDevice *sbd;
dev = qdev_new("pl011_luminary");
@@ -1193,7 +1224,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(nvic, uart_irq[i]));
}
}
- if (board->dc2 & (1 << 4)) {
+ if (DEV_CAP(2, SSI)) {
dev = sysbus_create_simple("pl022", 0x40008000,
qdev_get_gpio_in(nvic, 7));
if (board->peripherals & BP_OLED_SSI) {
@@ -1302,7 +1333,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
qemu_irq_raise(gpio_out[GPIO_D][0]);
}
}
- if (board->dc4 & (1 << 28)) {
+ if (DEV_CAP(4, EMAC)) {
DeviceState *enet;
enet = qdev_new("stellaris_enet");
@@ -1357,8 +1388,6 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
/* Add dummy regions for the devices we don't implement yet,
* so guest accesses don't cause unlogged crashes.
*/
- create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
- create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
create_unimplemented_device("PWM", 0x40028000, 0x1000);
create_unimplemented_device("QEI-0", 0x4002c000, 0x1000);
create_unimplemented_device("QEI-1", 0x4002d000, 0x1000);
@@ -1366,7 +1395,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
- armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, 0, flash_size);
+ armv7m_load_kernel(ARMV7M(armv7m)->cpu, ms->kernel_filename, 0, flash_size);
}
/* FIXME: Figure out how to generate these from stellaris_boards. */
@@ -1380,7 +1409,11 @@ static void lm3s6965evb_init(MachineState *machine)
stellaris_init(machine, &stellaris_boards[1]);
}
-static void lm3s811evb_class_init(ObjectClass *oc, void *data)
+/*
+ * Stellaris LM3S811 Evaluation Board Schematics:
+ * https://www.ti.com/lit/ug/symlink/spmu030.pdf
+ */
+static void lm3s811evb_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1396,7 +1429,11 @@ static const TypeInfo lm3s811evb_type = {
.class_init = lm3s811evb_class_init,
};
-static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
+/*
+ * Stellaris: LM3S6965 Evaluation Board Schematics:
+ * https://www.ti.com/lit/ug/symlink/spmu029.pdf
+ */
+static void lm3s6965evb_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1404,6 +1441,7 @@ static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
mc->init = lm3s6965evb_init;
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
+ mc->auto_create_sdcard = true;
}
static const TypeInfo lm3s6965evb_type = {
@@ -1420,7 +1458,7 @@ static void stellaris_machine_init(void)
type_init(stellaris_machine_init)
-static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
+static void stellaris_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -1439,7 +1477,7 @@ static const TypeInfo stellaris_i2c_info = {
.class_init = stellaris_i2c_class_init,
};
-static void stellaris_adc_class_init(ObjectClass *klass, void *data)
+static void stellaris_adc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -1456,7 +1494,7 @@ static const TypeInfo stellaris_adc_info = {
.class_init = stellaris_adc_class_init,
};
-static void stellaris_sys_class_init(ObjectClass *klass, void *data)
+static void stellaris_sys_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c
index 808b783..0702d51 100644
--- a/hw/arm/stm32f100_soc.c
+++ b/hw/arm/stm32f100_soc.c
@@ -27,12 +27,12 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "hw/arm/boot.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/arm/stm32f100_soc.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
/* stm32f100_soc implementation is derived from stm32f205_soc */
@@ -181,7 +181,7 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("CRC", 0x40023000, 0x400);
}
-static void stm32f100_soc_class_init(ObjectClass *klass, void *data)
+static void stm32f100_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index a451e21..229af7f 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -26,11 +26,11 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "hw/arm/boot.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/arm/stm32f205_soc.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-clock.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
/* At the moment only Timer 2 to 5 are modelled */
static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
@@ -202,7 +202,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
}
}
-static void stm32f205_soc_class_init(ObjectClass *klass, void *data)
+static void stm32f205_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c
index 2ad5b79..c8684e2 100644
--- a/hw/arm/stm32f405_soc.c
+++ b/hw/arm/stm32f405_soc.c
@@ -24,12 +24,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
#include "hw/arm/stm32f405_soc.h"
#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
+#define RCC_ADDR 0x40023800
#define SYSCFG_ADD 0x40013800
static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800,
0x40004C00, 0x40005000, 0x40011400,
@@ -59,6 +60,8 @@ static void stm32f405_soc_initfn(Object *obj)
object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
+ object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32_RCC);
+
object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32F4XX_SYSCFG);
for (i = 0; i < STM_NUM_USARTS; i++) {
@@ -160,6 +163,14 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
+ /* Reset and clock controller */
+ dev = DEVICE(&s->rcc);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rcc), errp)) {
+ return;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, RCC_ADDR);
+
/* System configuration controller */
dev = DEVICE(&s->syscfg);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), errp)) {
@@ -276,7 +287,6 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("GPIOH", 0x40021C00, 0x400);
create_unimplemented_device("GPIOI", 0x40022000, 0x400);
create_unimplemented_device("CRC", 0x40023000, 0x400);
- create_unimplemented_device("RCC", 0x40023800, 0x400);
create_unimplemented_device("Flash Int", 0x40023C00, 0x400);
create_unimplemented_device("BKPSRAM", 0x40024000, 0x400);
create_unimplemented_device("DMA1", 0x40026000, 0x400);
@@ -288,7 +298,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("RNG", 0x50060800, 0x400);
}
-static void stm32f405_soc_class_init(ObjectClass *klass, void *data)
+static void stm32f405_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
index fac83d3..64da555 100644
--- a/hw/arm/stm32l4x5_soc.c
+++ b/hw/arm/stm32l4x5_soc.c
@@ -24,8 +24,8 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
#include "hw/or-irq.h"
#include "hw/arm/stm32l4x5_soc.h"
#include "hw/char/stm32l4x5_usart.h"
@@ -236,6 +236,8 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
/* System configuration controller */
busdev = SYS_BUS_DEVICE(&s->syscfg);
+ qdev_connect_clock_in(DEVICE(&s->syscfg), "clk",
+ qdev_get_clock_out(DEVICE(&(s->rcc)), "syscfg-out"));
if (!sysbus_realize(busdev, errp)) {
return;
}
@@ -433,7 +435,7 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("QUADSPI", 0xA0001000, 0x400);
}
-static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data)
+static void stm32l4x5_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -444,21 +446,21 @@ static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data)
/* No vmstate or reset required: device has no internal state */
}
-static void stm32l4x5xc_soc_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5xc_soc_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc);
ssc->flash_size = 256 * KiB;
}
-static void stm32l4x5xe_soc_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5xe_soc_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc);
ssc->flash_size = 512 * KiB;
}
-static void stm32l4x5xg_soc_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5xg_soc_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc);
diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c
index cc41935..e6c1f5b 100644
--- a/hw/arm/stm32vldiscovery.c
+++ b/hw/arm/stm32vldiscovery.c
@@ -51,7 +51,7 @@ static void stm32vldiscovery_init(MachineState *machine)
qdev_connect_clock_in(dev, "sysclk", sysclk);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- armv7m_load_kernel(ARM_CPU(first_cpu),
+ armv7m_load_kernel(STM32F100_SOC(dev)->armv7m.cpu,
machine->kernel_filename,
0, FLASH_SIZE);
}
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 823b493..229c98d 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -38,8 +38,8 @@
#include "hw/arm/boot.h"
#include "chardev/char-fe.h"
#include "chardev/char-serial.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
+#include "system/system.h"
+#include "system/rtc.h"
#include "hw/ssi/ssi.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
@@ -215,7 +215,7 @@ static const VMStateDescription vmstate_strongarm_pic_regs = {
},
};
-static void strongarm_pic_class_init(ObjectClass *klass, void *data)
+static void strongarm_pic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -448,7 +448,8 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = {
},
};
-static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data)
+static void strongarm_rtc_sysbus_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -693,7 +694,7 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = {
},
};
-static void strongarm_gpio_class_init(ObjectClass *klass, void *data)
+static void strongarm_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -865,7 +866,7 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = {
},
};
-static void strongarm_ppc_class_init(ObjectClass *klass, void *data)
+static void strongarm_ppc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1332,17 +1333,16 @@ static const VMStateDescription vmstate_strongarm_uart_regs = {
},
};
-static Property strongarm_uart_properties[] = {
+static const Property strongarm_uart_properties[] = {
DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void strongarm_uart_class_init(ObjectClass *klass, void *data)
+static void strongarm_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "StrongARM UART controller";
- dc->reset = strongarm_uart_reset;
+ device_class_set_legacy_reset(dc, strongarm_uart_reset);
dc->vmsd = &vmstate_strongarm_uart_regs;
device_class_set_props(dc, strongarm_uart_properties);
dc->realize = strongarm_uart_realize;
@@ -1590,12 +1590,12 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = {
},
};
-static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
+static void strongarm_ssp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "StrongARM SSP controller";
- dc->reset = strongarm_ssp_reset;
+ device_class_set_legacy_reset(dc, strongarm_ssp_reset);
dc->vmsd = &vmstate_strongarm_ssp_regs;
}
diff --git a/hw/arm/strongarm.h b/hw/arm/strongarm.h
index 192821f..b11b3a3 100644
--- a/hw/arm/strongarm.h
+++ b/hw/arm/strongarm.h
@@ -1,7 +1,7 @@
#ifndef STRONGARM_H
#define STRONGARM_H
-#include "exec/memory.h"
+#include "system/memory.h"
#include "target/arm/cpu-qom.h"
#define SA_CS0 0x00000000
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
deleted file mode 100644
index 5891f60..0000000
--- a/hw/arm/tosa.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* vim:set shiftwidth=4 ts=4 et: */
-/*
- * PXA255 Sharp Zaurus SL-6000 PDA platform
- *
- * Copyright (c) 2008 Dmitry Baryshkov
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "sysemu/runstate.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "hw/arm/sharpsl.h"
-#include "hw/pcmcia.h"
-#include "hw/boards.h"
-#include "hw/display/tc6393xb.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "hw/sysbus.h"
-#include "hw/misc/led.h"
-#include "exec/address-spaces.h"
-#include "qom/object.h"
-
-#define TOSA_RAM 0x04000000
-#define TOSA_ROM 0x00800000
-
-#define TOSA_GPIO_USB_IN (5)
-#define TOSA_GPIO_nSD_DETECT (9)
-#define TOSA_GPIO_ON_RESET (19)
-#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */
-#define TOSA_GPIO_CF_CD (13)
-#define TOSA_GPIO_TC6393XB_INT (15)
-#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */
-
-#define TOSA_SCOOP_GPIO_BASE 1
-#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2)
-#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3)
-#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4)
-
-#define TOSA_SCOOP_JC_GPIO_BASE 1
-#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0)
-#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1)
-#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2)
-#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5)
-#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7)
-
-#define DAC_BASE 0x4e
-#define DAC_CH1 0
-#define DAC_CH2 1
-
-static void tosa_microdrive_attach(PXA2xxState *cpu)
-{
- PCMCIACardState *md;
- DriveInfo *dinfo;
-
- dinfo = drive_get(IF_IDE, 0, 0);
- if (!dinfo || dinfo->media_cd)
- return;
- md = dscm1xxxx_init(dinfo);
- pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
-}
-
-/*
- * Encapsulation of some GPIO line behaviour for the Tosa board
- *
- * QEMU interface:
- * + named GPIO inputs "leds[0..3]": assert to light LEDs
- * + named GPIO input "reset": when asserted, resets the system
- */
-
-#define TYPE_TOSA_MISC_GPIO "tosa-misc-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(TosaMiscGPIOState, TOSA_MISC_GPIO)
-
-struct TosaMiscGPIOState {
- SysBusDevice parent_obj;
-};
-
-static void tosa_reset(void *opaque, int line, int level)
-{
- if (level) {
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- }
-}
-
-static void tosa_misc_gpio_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
-
- qdev_init_gpio_in_named(dev, tosa_reset, "reset", 1);
-}
-
-static void tosa_gpio_setup(PXA2xxState *cpu,
- DeviceState *scp0,
- DeviceState *scp1,
- TC6393xbState *tmio)
-{
- DeviceState *misc_gpio;
- LEDState *led[4];
-
- misc_gpio = sysbus_create_simple(TYPE_TOSA_MISC_GPIO, -1, NULL);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(cpu->mmc,
- qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
- qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
-
- /* Handle reset */
- qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET,
- qdev_get_gpio_in_named(misc_gpio, "reset", 0));
-
- /* PCMCIA signals: card's IRQ and Card-Detect */
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
-
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
- NULL);
-
- led[0] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_BLUE, "bluetooth");
- led[1] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "note");
- led[2] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_AMBER, "charger-error");
- led[3] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "wlan");
-
- qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED,
- qdev_get_gpio_in(DEVICE(led[0]), 0));
- qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED,
- qdev_get_gpio_in(DEVICE(led[1]), 0));
- qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED,
- qdev_get_gpio_in(DEVICE(led[2]), 0));
- qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED,
- qdev_get_gpio_in(DEVICE(led[3]), 0));
-
- qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
-
- /* UDC Vbus */
- qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
-}
-
-static uint32_t tosa_ssp_tansfer(SSIPeripheral *dev, uint32_t value)
-{
- fprintf(stderr, "TG: %u %02x\n", value >> 5, value & 0x1f);
- return 0;
-}
-
-static void tosa_ssp_realize(SSIPeripheral *dev, Error **errp)
-{
- /* Nothing to do. */
-}
-
-#define TYPE_TOSA_DAC "tosa_dac"
-OBJECT_DECLARE_SIMPLE_TYPE(TosaDACState, TOSA_DAC)
-
-struct TosaDACState {
- I2CSlave parent_obj;
-
- int len;
- char buf[3];
-};
-
-static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
-{
- TosaDACState *s = TOSA_DAC(i2c);
-
- s->buf[s->len] = data;
- if (s->len ++ > 2) {
-#ifdef VERBOSE
- fprintf(stderr, "%s: message too long (%i bytes)\n", __func__, s->len);
-#endif
- return 1;
- }
-
- if (s->len == 2) {
- fprintf(stderr, "dac: channel %d value 0x%02x\n",
- s->buf[0], s->buf[1]);
- }
-
- return 0;
-}
-
-static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
-{
- TosaDACState *s = TOSA_DAC(i2c);
-
- s->len = 0;
- switch (event) {
- case I2C_START_SEND:
- break;
- case I2C_START_RECV:
- printf("%s: recv not supported!!!\n", __func__);
- break;
- case I2C_FINISH:
-#ifdef VERBOSE
- if (s->len < 2)
- printf("%s: message too short (%i bytes)\n", __func__, s->len);
- if (s->len > 2)
- printf("%s: message too long\n", __func__);
-#endif
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static uint8_t tosa_dac_recv(I2CSlave *s)
-{
- printf("%s: recv not supported!!!\n", __func__);
- return 0xff;
-}
-
-static void tosa_tg_init(PXA2xxState *cpu)
-{
- I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
- i2c_slave_create_simple(bus, TYPE_TOSA_DAC, DAC_BASE);
- ssi_create_peripheral(cpu->ssp[1], "tosa-ssp");
-}
-
-
-static struct arm_boot_info tosa_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = 0x04000000,
-};
-
-static void tosa_init(MachineState *machine)
-{
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- PXA2xxState *mpu;
- TC6393xbState *tmio;
- DeviceState *scp0, *scp1;
-
- mpu = pxa255_init(tosa_binfo.ram_size);
-
- memory_region_init_rom(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal);
- memory_region_add_subregion(address_space_mem, 0, rom);
-
- tmio = tc6393xb_init(address_space_mem, 0x10000000,
- qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT));
-
- scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
- scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
-
- tosa_gpio_setup(mpu, scp0, scp1, tmio);
-
- tosa_microdrive_attach(mpu);
-
- tosa_tg_init(mpu);
-
- tosa_binfo.board_id = 0x208;
- arm_load_kernel(mpu->cpu, machine, &tosa_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static void tosapda_machine_init(MachineClass *mc)
-{
- mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)";
- mc->init = tosa_init;
- mc->block_default_type = IF_IDE;
- mc->ignore_memory_transaction_failures = true;
- mc->deprecation_reason = "machine is old and unmaintained";
-}
-
-DEFINE_MACHINE("tosa", tosapda_machine_init)
-
-static void tosa_dac_class_init(ObjectClass *klass, void *data)
-{
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->event = tosa_dac_event;
- k->recv = tosa_dac_recv;
- k->send = tosa_dac_send;
-}
-
-static const TypeInfo tosa_dac_info = {
- .name = TYPE_TOSA_DAC,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(TosaDACState),
- .class_init = tosa_dac_class_init,
-};
-
-static void tosa_ssp_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = tosa_ssp_realize;
- k->transfer = tosa_ssp_tansfer;
-}
-
-static const TypeInfo tosa_ssp_info = {
- .name = "tosa-ssp",
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(SSIPeripheral),
- .class_init = tosa_ssp_class_init,
-};
-
-static const TypeInfo tosa_misc_gpio_info = {
- .name = TYPE_TOSA_MISC_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TosaMiscGPIOState),
- .instance_init = tosa_misc_gpio_init,
- /*
- * No class init required: device has no internal state so does not
- * need to set up reset or vmstate, and has no realize method.
- */
-};
-
-static void tosa_register_types(void)
-{
- type_register_static(&tosa_dac_info);
- type_register_static(&tosa_ssp_info);
- type_register_static(&tosa_misc_gpio_info);
-}
-
-type_init(tosa_register_types)
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index be6c8f7..f3386bd 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -1,5 +1,12 @@
# See docs/devel/tracing.rst for syntax documentation.
+# omap1.c
+omap1_pwl_clocking_scheme(const char *scheme) "omap1 CLKM: clocking scheme set to %s"
+omap1_pwl_backlight(int output) "omap1 PWL: backlight now at %d/256"
+omap1_pwt_buzz(int freq) "omap1 PWT: %dHz buzz on"
+omap1_pwt_silence(void) "omap1 PWT: buzzer silenced"
+omap1_lpg_led(const char *onoff) "omap1 LPG: LED is %s"
+
# virt-acpi-build.c
virt_acpi_setup(void) "No fw cfg or ACPI disabled. Bailing out."
@@ -15,6 +22,8 @@ smmu_iotlb_inv_asid_vmid(int asid, int vmid) "IOTLB invalidate asid=%d vmid=%d"
smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
smmu_iotlb_inv_vmid_s1(int vmid) "IOTLB invalidate vmid=%d"
smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
+smmu_configs_inv_sid_range(uint32_t start, uint32_t end) "Config cache INV SID range from 0x%x to 0x%x"
+smmu_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
smmu_iotlb_lookup_miss(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
@@ -52,10 +61,10 @@ smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
smmuv3_cmdq_tlbi_nsnh(void) ""
smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
-smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages, int stage) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" stage=%d"
+smmu_reset_exit(void) ""
# strongarm.c
strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
@@ -68,10 +77,5 @@ z2_aer915_send_too_long(int8_t msg) "message too long (%i bytes)"
z2_aer915_send(uint8_t reg, uint8_t value) "reg %d value 0x%02x"
z2_aer915_event(int8_t event, int8_t len) "i2c event =0x%x len=%d bytes"
-# xen_arm.c
-xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64
-xen_init_ram(uint64_t machine_ram_size) "Initialized xen ram with size 0x%"PRIx64
-xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64
-
# bcm2838.c
bcm2838_gic_set_irq(int irq, int level) "gic irq:%d lvl:%d"
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index d482354..5cf1a70 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -14,7 +14,7 @@
#include "hw/arm/boot.h"
#include "hw/net/smc91c111.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/pci/pci.h"
#include "hw/i2c/i2c.h"
#include "hw/i2c/arm_sbcon_i2c.h"
@@ -27,6 +27,7 @@
#include "qom/object.h"
#include "audio/audio.h"
#include "target/arm/cpu-qom.h"
+#include "qemu/log.h"
#define VERSATILE_FLASH_ADDR 0x34000000
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
@@ -110,7 +111,8 @@ static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
case 8: /* PICENABLE */
return s->pic_enable;
default:
- printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
return 0;
}
}
@@ -144,7 +146,8 @@ static void vpb_sic_write(void *opaque, hwaddr offset,
vpb_sic_update_pic(s);
break;
default:
- printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
return;
}
vpb_sic_update(s);
@@ -409,7 +412,7 @@ static void vab_init(MachineState *machine)
versatile_init(machine, 0x25e);
}
-static void versatilepb_class_init(ObjectClass *oc, void *data)
+static void versatilepb_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -419,6 +422,7 @@ static void versatilepb_class_init(ObjectClass *oc, void *data)
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
mc->default_ram_id = "versatile.ram";
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
}
@@ -429,7 +433,7 @@ static const TypeInfo versatilepb_type = {
.class_init = versatilepb_class_init,
};
-static void versatileab_class_init(ObjectClass *oc, void *data)
+static void versatileab_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -439,6 +443,7 @@ static void versatileab_class_init(ObjectClass *oc, void *data)
mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
mc->default_ram_id = "versatile.ram";
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
}
@@ -457,7 +462,7 @@ static void versatile_machine_init(void)
type_init(versatile_machine_init)
-static void vpb_sic_class_init(ObjectClass *klass, void *data)
+static void vpb_sic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index de815d8..35f8d05 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -30,11 +30,11 @@
#include "hw/net/lan9118.h"
#include "hw/i2c/i2c.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/block/flash.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "qemu/error-report.h"
#include <libfdt.h>
#include "hw/char/pl011.h"
@@ -42,7 +42,7 @@
#include "hw/cpu/a15mpcore.h"
#include "hw/i2c/arm_sbcon_i2c.h"
#include "hw/sd/sd.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qom/object.h"
#include "audio/audio.h"
#include "target/arm/cpu-qom.h"
@@ -51,6 +51,8 @@
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)
+#define GIC_EXT_IRQS 64 /* Versatile Express A9 development board */
+
/* Number of virtio transports to create (0..8; limited by
* number of available IRQ lines).
*/
@@ -241,6 +243,7 @@ static void init_cpus(MachineState *ms, const char *cpu_type,
*/
dev = qdev_new(privdev);
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+ qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, periphbase);
@@ -251,7 +254,7 @@ static void init_cpus(MachineState *ms, const char *cpu_type,
* external interrupts starting from 32 (because there
* are internal interrupts 0..31).
*/
- for (n = 0; n < 64; n++) {
+ for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
@@ -543,7 +546,7 @@ static void vexpress_common_init(MachineState *machine)
VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
VEDBoardInfo *daughterboard = vmc->daughterboard;
DeviceState *dev, *sysctl, *pl041;
- qemu_irq pic[64];
+ qemu_irq pic[GIC_EXT_IRQS];
uint32_t sys_id;
DriveInfo *dinfo;
PFlashCFI01 *pflash0;
@@ -774,7 +777,7 @@ static void vexpress_a9_instance_init(Object *obj)
vms->virt = false;
}
-static void vexpress_class_init(ObjectClass *oc, void *data)
+static void vexpress_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -792,7 +795,7 @@ static void vexpress_class_init(ObjectClass *oc, void *data)
"Security Extensions (TrustZone)");
}
-static void vexpress_a9_class_init(ObjectClass *oc, void *data)
+static void vexpress_a9_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
@@ -803,11 +806,12 @@ static void vexpress_a9_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM Versatile Express for Cortex-A9";
mc->valid_cpu_types = valid_cpu_types;
+ mc->auto_create_sdcard = true;
vmc->daughterboard = &a9_daughterboard;
}
-static void vexpress_a15_class_init(ObjectClass *oc, void *data)
+static void vexpress_a15_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a15"),
@@ -818,6 +822,7 @@ static void vexpress_a15_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM Versatile Express for Cortex-A15";
mc->valid_cpu_types = valid_cpu_types;
+ mc->auto_create_sdcard = true;
vmc->daughterboard = &a15_daughterboard;
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f76fb11..7e8e0f0 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -51,13 +51,12 @@
#include "hw/intc/arm_gicv3_its_common.h"
#include "hw/mem/nvdimm.h"
#include "hw/platform-bus.h"
-#include "sysemu/numa.h"
-#include "sysemu/reset.h"
-#include "sysemu/tpm.h"
+#include "system/numa.h"
+#include "system/reset.h"
+#include "system/tpm.h"
#include "migration/vmstate.h"
#include "hw/acpi/ghes.h"
#include "hw/acpi/viot.h"
-#include "hw/acpi/acpi_generic_initiator.h"
#include "hw/virtio/virtio-acpi.h"
#include "target/arm/multiprocessing.h"
@@ -464,8 +463,12 @@ spcr_setup(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
.pci_flags = 0,
.pci_segment = 0,
};
-
- build_spcr(table_data, linker, &serial, 2, vms->oem_id, vms->oem_table_id);
+ /*
+ * Passing NULL as the SPCR Table for Revision 2 doesn't support
+ * NameSpaceString.
+ */
+ build_spcr(table_data, linker, &serial, 2, vms->oem_id, vms->oem_table_id,
+ NULL);
}
/*
@@ -511,7 +514,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
- build_srat_generic_pci_initiator(table_data);
+ build_srat_generic_affinity_structures(table_data);
if (ms->nvdimms_state->is_enabled) {
nvdimm_build_srat(table_data);
@@ -534,15 +537,12 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
static void
build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
- VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
/*
* Table 5-117 Flag Definitions
* set only "Timer interrupt Mode" and assume "Timer Interrupt
* polarity" bit as '0: Interrupt is Active high'
*/
- uint32_t irqflags = vmc->claim_edge_triggered_timers ?
- 1 : /* Interrupt is Edge triggered */
- 0; /* Interrupt is Level triggered */
+ const uint32_t irqflags = 0; /* Interrupt is Level triggered */
AcpiTable table = { .sig = "GTDT", .rev = 3, .oem_id = vms->oem_id,
.oem_table_id = vms->oem_table_id };
@@ -667,7 +667,6 @@ static void
build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
int i;
- VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
const MemMapEntry *memmap = vms->memmap;
AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id,
.oem_table_id = vms->oem_table_id };
@@ -738,7 +737,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
memmap[VIRT_HIGH_GIC_REDIST2].size);
}
- if (its_class_name() && !vmc->no_its) {
+ if (its_class_name()) {
/*
* ACPI spec, Revision 6.0 Errata A
* (original 6.0 definition has invalid Length)
@@ -943,10 +942,9 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
build_dbg2(tables_blob, tables->linker, vms);
if (vms->ras) {
- build_ghes_error_table(tables->hardware_errors, tables->linker);
acpi_add_table(table_offsets, tables_blob);
- acpi_build_hest(tables_blob, tables->linker, vms->oem_id,
- vms->oem_table_id);
+ acpi_build_hest(tables_blob, tables->hardware_errors, tables->linker,
+ vms->oem_id, vms->oem_table_id);
}
if (ms->numa_state->num_nodes > 0) {
@@ -971,7 +969,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
vms->oem_table_id);
}
- if (its_class_name() && !vmc->no_its) {
+ if (its_class_name()) {
acpi_add_table(table_offsets, tables_blob);
build_iort(tables_blob, tables->linker, vms);
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 687fe0b..99fde58 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -42,17 +42,18 @@
#include "hw/vfio/vfio-amd-xgbe.h"
#include "hw/display/ramfb.h"
#include "net/net.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/numa.h"
-#include "sysemu/runstate.h"
-#include "sysemu/tpm.h"
-#include "sysemu/tcg.h"
-#include "sysemu/kvm.h"
-#include "sysemu/hvf.h"
-#include "sysemu/qtest.h"
+#include "system/device_tree.h"
+#include "system/numa.h"
+#include "system/runstate.h"
+#include "system/tpm.h"
+#include "system/tcg.h"
+#include "system/kvm.h"
+#include "system/hvf.h"
+#include "system/qtest.h"
#include "hw/loader.h"
#include "qapi/error.h"
#include "qemu/bitops.h"
+#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "hw/pci-host/gpex.h"
@@ -66,10 +67,11 @@
#include "hw/intc/arm_gicv3_its_common.h"
#include "hw/irq.h"
#include "kvm_arm.h"
+#include "hvf_arm.h"
#include "hw/firmware/smbios.h"
#include "qapi/visitor.h"
#include "qapi/qapi-visit-common.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h"
#include "hw/acpi/acpi.h"
@@ -80,6 +82,7 @@
#include "hw/mem/pc-dimm.h"
#include "hw/mem/nvdimm.h"
#include "hw/acpi/generic_event_device.h"
+#include "hw/uefi/var-service-api.h"
#include "hw/virtio/virtio-md-pci.h"
#include "hw/virtio/virtio-iommu.h"
#include "hw/char/pl011.h"
@@ -104,7 +107,7 @@ static void arm_virt_compat_set(MachineClass *mc)
#define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \
static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \
ObjectClass *oc, \
- void *data) \
+ const void *data) \
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
arm_virt_compat_set(mc); \
@@ -191,6 +194,10 @@ static const MemMapEntry base_memmap[] = {
[VIRT_MEM] = { GiB, LEGACY_RAMLIMIT_BYTES },
};
+/* Update the docs for highmem-mmio-size when changing this default */
+#define DEFAULT_HIGH_PCIE_MMIO_SIZE_GB 512
+#define DEFAULT_HIGH_PCIE_MMIO_SIZE (DEFAULT_HIGH_PCIE_MMIO_SIZE_GB * GiB)
+
/*
* Highmem IO Regions: This memory map is floating, located after the RAM.
* Each MemMapEntry base (GPA) will be dynamically computed, depending on the
@@ -206,13 +213,16 @@ static const MemMapEntry base_memmap[] = {
* PA space for one specific region is always reserved, even if the region
* has been disabled or doesn't fit into the PA space. However, the PA space
* for the region won't be reserved in these circumstances with compact layout.
+ *
+ * Note that the highmem-mmio-size property will update the high PCIE MMIO size
+ * field in this array.
*/
static MemMapEntry extended_memmap[] = {
/* Additional 64 MB redist region (can contain up to 512 redistributors) */
[VIRT_HIGH_GIC_REDIST2] = { 0x0, 64 * MiB },
[VIRT_HIGH_PCIE_ECAM] = { 0x0, 256 * MiB },
/* Second PCIe window */
- [VIRT_HIGH_PCIE_MMIO] = { 0x0, 512 * GiB },
+ [VIRT_HIGH_PCIE_MMIO] = { 0x0, DEFAULT_HIGH_PCIE_MMIO_SIZE },
};
static const int a15irqmap[] = {
@@ -360,14 +370,9 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
* the correct information.
*/
ARMCPU *armcpu;
- VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI;
MachineState *ms = MACHINE(vms);
- if (vmc->claim_edge_triggered_timers) {
- irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
- }
-
if (vms->gic_version == VIRT_GIC_VERSION_2) {
irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
GIC_FDT_IRQ_PPI_CPU_WIDTH,
@@ -872,6 +877,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
[GTIMER_HYPVIRT] = ARCH_TIMER_NS_EL2_VIRT_IRQ,
+ [GTIMER_S_EL2_PHYS] = ARCH_TIMER_S_EL2_IRQ,
+ [GTIMER_S_EL2_VIRT] = ARCH_TIMER_S_EL2_VIRT_IRQ,
};
for (unsigned irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
@@ -1408,6 +1415,7 @@ static void create_pcie_irq_map(const MachineState *ms,
static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
char *node;
const char compat[] = "arm,smmu-v3";
int irq = vms->irqmap[VIRT_SMMU];
@@ -1424,6 +1432,9 @@ static void create_smmu(const VirtMachineState *vms,
dev = qdev_new(TYPE_ARM_SMMUV3);
+ if (!vmc->no_nested_smmu) {
+ object_property_set_str(OBJECT(dev), "stage", "nested", &error_fatal);
+ }
object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
&error_abort);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -1476,9 +1487,12 @@ static void create_virtio_iommu_dt_bindings(VirtMachineState *vms)
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
g_free(node);
- qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
- 0x0, vms->iommu_phandle, 0x0, bdf,
- bdf + 1, vms->iommu_phandle, bdf + 1, 0xffff - bdf);
+ if (!vms->default_bus_bypass_iommu) {
+ qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
+ 0x0, vms->iommu_phandle, 0x0, bdf,
+ bdf + 1, vms->iommu_phandle, bdf + 1,
+ 0xffff - bdf);
+ }
}
static void create_pcie(VirtMachineState *vms)
@@ -1542,7 +1556,7 @@ static void create_pcie(VirtMachineState *vms)
/* Map IO port space */
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(vms->gic, irq + i));
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
@@ -1601,8 +1615,10 @@ static void create_pcie(VirtMachineState *vms)
switch (vms->iommu) {
case VIRT_IOMMU_SMMUV3:
create_smmu(vms, vms->bus);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
- 0x0, vms->iommu_phandle, 0x0, 0x10000);
+ if (!vms->default_bus_bypass_iommu) {
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
+ 0x0, vms->iommu_phandle, 0x0, 0x10000);
+ }
break;
default:
g_assert_not_reached();
@@ -1688,7 +1704,6 @@ static void virt_build_smbios(VirtMachineState *vms)
{
MachineClass *mc = MACHINE_GET_CLASS(vms);
MachineState *ms = MACHINE(vms);
- VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
uint8_t *smbios_tables, *smbios_anchor;
size_t smbios_tables_len, smbios_anchor_len;
struct smbios_phys_mem_area mem_array;
@@ -1698,8 +1713,7 @@ static void virt_build_smbios(VirtMachineState *vms)
product = "KVM Virtual Machine";
}
- smbios_set_defaults("QEMU", product,
- vmc->smbios_old_sys_ver ? "1.0" : mc->name);
+ smbios_set_defaults("QEMU", product, mc->name);
/* build the array of physical mem area from base_memmap */
mem_array.address = vms->memmap[VIRT_MEM].base;
@@ -1741,11 +1755,12 @@ void virt_machine_done(Notifier *notifier, void *data)
vms->memmap[VIRT_PLATFORM_BUS].size,
vms->irqmap[VIRT_PLATFORM_BUS]);
}
- if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) {
+ if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms, cpu) < 0) {
exit(1);
}
- fw_cfg_add_extra_pci_roots(vms->bus, vms->fw_cfg);
+ pci_bus_add_fw_cfg_extra_pci_roots(vms->fw_cfg, vms->bus,
+ &error_abort);
virt_acpi_setup(vms);
virt_build_smbios(vms);
@@ -1753,24 +1768,18 @@ void virt_machine_done(Notifier *notifier, void *data)
static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx)
{
- uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER;
- VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
+ uint8_t clustersz;
- if (!vmc->disallow_affinity_adjustment) {
- /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the
- * GIC's target-list limitations. 32-bit KVM hosts currently
- * always create clusters of 4 CPUs, but that is expected to
- * change when they gain support for gicv3. When KVM is enabled
- * it will override the changes we make here, therefore our
- * purposes are to make TCG consistent (with 64-bit KVM hosts)
- * and to improve SGI efficiency.
- */
- if (vms->gic_version == VIRT_GIC_VERSION_2) {
- clustersz = GIC_TARGETLIST_BITS;
- } else {
- clustersz = GICV3_TARGETLIST_BITS;
- }
+ /*
+ * Adjust MPIDR to make TCG consistent (with 64-bit KVM hosts)
+ * and to improve SGI efficiency.
+ */
+ if (vms->gic_version == VIRT_GIC_VERSION_2) {
+ clustersz = GIC_TARGETLIST_BITS;
+ } else {
+ clustersz = GICV3_TARGETLIST_BITS;
}
+
return arm_build_mp_affinity(idx, clustersz);
}
@@ -2107,7 +2116,8 @@ static void machvirt_init(MachineState *machine)
/*
* In accelerated mode, the memory map is computed earlier in kvm_type()
- * to create a VM with the right number of IPA bits.
+ * for Linux, or hvf_get_physical_address_range() for macOS to create a
+ * VM with the right number of IPA bits.
*/
if (!vms->memmap) {
Object *cpuobj;
@@ -2207,7 +2217,7 @@ static void machvirt_init(MachineState *machine)
exit(1);
}
- if (vms->mte && (kvm_enabled() || hvf_enabled())) {
+ if (vms->mte && hvf_enabled()) {
error_report("mach-virt: %s does not support providing "
"MTE to the guest CPU",
current_accel_name());
@@ -2255,10 +2265,6 @@ static void machvirt_init(MachineState *machine)
object_property_set_bool(cpuobj, "kvm-steal-time", false, NULL);
}
- if (vmc->no_pmu && object_property_find(cpuobj, "pmu")) {
- object_property_set_bool(cpuobj, "pmu", false, NULL);
- }
-
if (vmc->no_tcg_lpa2 && object_property_find(cpuobj, "lpa2")) {
object_property_set_bool(cpuobj, "lpa2", false, NULL);
}
@@ -2277,39 +2283,51 @@ static void machvirt_init(MachineState *machine)
}
if (vms->mte) {
- /* Create the memory region only once, but link to all cpus. */
- if (!tag_sysmem) {
- /*
- * The property exists only if MemTag is supported.
- * If it is, we must allocate the ram to back that up.
- */
- if (!object_property_find(cpuobj, "tag-memory")) {
- error_report("MTE requested, but not supported "
- "by the guest CPU");
- exit(1);
+ if (tcg_enabled()) {
+ /* Create the memory region only once, but link to all cpus. */
+ if (!tag_sysmem) {
+ /*
+ * The property exists only if MemTag is supported.
+ * If it is, we must allocate the ram to back that up.
+ */
+ if (!object_property_find(cpuobj, "tag-memory")) {
+ error_report("MTE requested, but not supported "
+ "by the guest CPU");
+ exit(1);
+ }
+
+ tag_sysmem = g_new(MemoryRegion, 1);
+ memory_region_init(tag_sysmem, OBJECT(machine),
+ "tag-memory", UINT64_MAX / 32);
+
+ if (vms->secure) {
+ secure_tag_sysmem = g_new(MemoryRegion, 1);
+ memory_region_init(secure_tag_sysmem, OBJECT(machine),
+ "secure-tag-memory",
+ UINT64_MAX / 32);
+
+ /* As with ram, secure-tag takes precedence over tag. */
+ memory_region_add_subregion_overlap(secure_tag_sysmem,
+ 0, tag_sysmem, -1);
+ }
}
- tag_sysmem = g_new(MemoryRegion, 1);
- memory_region_init(tag_sysmem, OBJECT(machine),
- "tag-memory", UINT64_MAX / 32);
-
+ object_property_set_link(cpuobj, "tag-memory",
+ OBJECT(tag_sysmem), &error_abort);
if (vms->secure) {
- secure_tag_sysmem = g_new(MemoryRegion, 1);
- memory_region_init(secure_tag_sysmem, OBJECT(machine),
- "secure-tag-memory", UINT64_MAX / 32);
-
- /* As with ram, secure-tag takes precedence over tag. */
- memory_region_add_subregion_overlap(secure_tag_sysmem, 0,
- tag_sysmem, -1);
+ object_property_set_link(cpuobj, "secure-tag-memory",
+ OBJECT(secure_tag_sysmem),
+ &error_abort);
}
- }
-
- object_property_set_link(cpuobj, "tag-memory", OBJECT(tag_sysmem),
- &error_abort);
- if (vms->secure) {
- object_property_set_link(cpuobj, "secure-tag-memory",
- OBJECT(secure_tag_sysmem),
- &error_abort);
+ } else if (kvm_enabled()) {
+ if (!kvm_arm_mte_supported()) {
+ error_report("MTE requested, but not supported by KVM");
+ exit(1);
+ }
+ kvm_arm_enable_mte(cpuobj, &error_abort);
+ } else {
+ error_report("MTE requested, but not supported ");
+ exit(1);
}
}
@@ -2531,6 +2549,40 @@ static void virt_set_highmem_mmio(Object *obj, bool value, Error **errp)
vms->highmem_mmio = value;
}
+static void virt_get_highmem_mmio_size(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ uint64_t size = extended_memmap[VIRT_HIGH_PCIE_MMIO].size;
+
+ visit_type_size(v, name, &size, errp);
+}
+
+static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ uint64_t size;
+
+ if (!visit_type_size(v, name, &size, errp)) {
+ return;
+ }
+
+ if (!is_power_of_2(size)) {
+ error_setg(errp, "highmem-mmio-size is not a power of 2");
+ return;
+ }
+
+ if (size < DEFAULT_HIGH_PCIE_MMIO_SIZE) {
+ char *sz = size_to_str(DEFAULT_HIGH_PCIE_MMIO_SIZE);
+ error_setg(errp, "highmem-mmio-size cannot be set to a lower value "
+ "than the default (%s)", sz);
+ g_free(sz);
+ return;
+ }
+
+ extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
+}
static bool virt_get_its(Object *obj, Error **errp)
{
@@ -3027,7 +3079,40 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
return fixed_ipa ? 0 : requested_pa_size;
}
-static void virt_machine_class_init(ObjectClass *oc, void *data)
+static int virt_hvf_get_physical_address_range(MachineState *ms)
+{
+ VirtMachineState *vms = VIRT_MACHINE(ms);
+
+ int default_ipa_size = hvf_arm_get_default_ipa_bit_size();
+ int max_ipa_size = hvf_arm_get_max_ipa_bit_size();
+
+ /* We freeze the memory map to compute the highest gpa */
+ virt_set_memmap(vms, max_ipa_size);
+
+ int requested_ipa_size = 64 - clz64(vms->highest_gpa);
+
+ /*
+ * If we're <= the default IPA size just use the default.
+ * If we're above the default but below the maximum, round up to
+ * the maximum. hvf_arm_get_max_ipa_bit_size() conveniently only
+ * returns values that are valid ARM PARange values.
+ */
+ if (requested_ipa_size <= default_ipa_size) {
+ requested_ipa_size = default_ipa_size;
+ } else if (requested_ipa_size <= max_ipa_size) {
+ requested_ipa_size = max_ipa_size;
+ } else {
+ error_report("-m and ,maxmem option values "
+ "require an IPA range (%d bits) larger than "
+ "the one supported by the host (%d bits)",
+ requested_ipa_size, max_ipa_size);
+ return -1;
+ }
+
+ return requested_ipa_size;
+}
+
+static void virt_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -3068,6 +3153,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
@@ -3086,6 +3172,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->valid_cpu_types = valid_cpu_types;
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
+ mc->hvf_get_physical_address_range = virt_hvf_get_physical_address_range;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
hc->pre_plug = virt_machine_device_pre_plug_cb;
@@ -3154,6 +3241,14 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
"Set on/off to enable/disable high "
"memory region for PCI MMIO");
+ object_class_property_add(oc, "highmem-mmio-size", "size",
+ virt_get_highmem_mmio_size,
+ virt_set_highmem_mmio_size,
+ NULL, NULL);
+ object_class_property_set_description(oc, "highmem-mmio-size",
+ "Set the high memory region size "
+ "for PCI MMIO");
+
object_class_property_add_str(oc, "gic-version", virt_get_gic_version,
virt_set_gic_version);
object_class_property_set_description(oc, "gic-version",
@@ -3241,21 +3336,17 @@ static void virt_instance_init(Object *obj)
vms->highmem_compact = !vmc->no_highmem_compact;
vms->gic_version = VIRT_GIC_VERSION_NOSEL;
- vms->highmem_ecam = !vmc->no_highmem_ecam;
+ vms->highmem_ecam = true;
vms->highmem_mmio = true;
vms->highmem_redists = true;
- if (vmc->no_its) {
- vms->its = false;
- } else {
- /* Default allows ITS instantiation */
- vms->its = true;
+ /* Default allows ITS instantiation */
+ vms->its = true;
- if (vmc->no_tcg_its) {
- vms->tcg_its = false;
- } else {
- vms->tcg_its = true;
- }
+ if (vmc->no_tcg_its) {
+ vms->tcg_its = false;
+ } else {
+ vms->tcg_its = true;
}
/* Default disallows iommu instantiation */
@@ -3289,7 +3380,7 @@ static const TypeInfo virt_machine_info = {
.class_size = sizeof(VirtMachineClass),
.class_init = virt_machine_class_init,
.instance_init = virt_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
},
@@ -3301,10 +3392,35 @@ static void machvirt_machine_init(void)
}
type_init(machvirt_machine_init);
+static void virt_machine_10_1_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(10, 1)
+
+static void virt_machine_10_0_options(MachineClass *mc)
+{
+ virt_machine_10_1_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len);
+}
+DEFINE_VIRT_MACHINE(10, 0)
+
+static void virt_machine_9_2_options(MachineClass *mc)
+{
+ virt_machine_10_0_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_2, hw_compat_9_2_len);
+}
+DEFINE_VIRT_MACHINE(9, 2)
+
static void virt_machine_9_1_options(MachineClass *mc)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
+ virt_machine_9_2_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
+ /* 9.1 and earlier have only a stage-1 SMMU, not a nested s1+2 one */
+ vmc->no_nested_smmu = true;
}
-DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
+DEFINE_VIRT_MACHINE(9, 1)
static void virt_machine_9_0_options(MachineClass *mc)
{
@@ -3451,99 +3567,3 @@ static void virt_machine_4_1_options(MachineClass *mc)
mc->auto_enable_numa_with_memhp = false;
}
DEFINE_VIRT_MACHINE(4, 1)
-
-static void virt_machine_4_0_options(MachineClass *mc)
-{
- virt_machine_4_1_options(mc);
- compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
-}
-DEFINE_VIRT_MACHINE(4, 0)
-
-static void virt_machine_3_1_options(MachineClass *mc)
-{
- virt_machine_4_0_options(mc);
- compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
-}
-DEFINE_VIRT_MACHINE(3, 1)
-
-static void virt_machine_3_0_options(MachineClass *mc)
-{
- virt_machine_3_1_options(mc);
- compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
-}
-DEFINE_VIRT_MACHINE(3, 0)
-
-static void virt_machine_2_12_options(MachineClass *mc)
-{
- VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
-
- virt_machine_3_0_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
- vmc->no_highmem_ecam = true;
- mc->max_cpus = 255;
-}
-DEFINE_VIRT_MACHINE(2, 12)
-
-static void virt_machine_2_11_options(MachineClass *mc)
-{
- VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
-
- virt_machine_2_12_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
- vmc->smbios_old_sys_ver = true;
-}
-DEFINE_VIRT_MACHINE(2, 11)
-
-static void virt_machine_2_10_options(MachineClass *mc)
-{
- virt_machine_2_11_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
- /* before 2.11 we never faulted accesses to bad addresses */
- mc->ignore_memory_transaction_failures = true;
-}
-DEFINE_VIRT_MACHINE(2, 10)
-
-static void virt_machine_2_9_options(MachineClass *mc)
-{
- virt_machine_2_10_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
-}
-DEFINE_VIRT_MACHINE(2, 9)
-
-static void virt_machine_2_8_options(MachineClass *mc)
-{
- VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
-
- virt_machine_2_9_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
- /* For 2.8 and earlier we falsely claimed in the DT that
- * our timers were edge-triggered, not level-triggered.
- */
- vmc->claim_edge_triggered_timers = true;
-}
-DEFINE_VIRT_MACHINE(2, 8)
-
-static void virt_machine_2_7_options(MachineClass *mc)
-{
- VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
-
- virt_machine_2_8_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
- /* ITS was introduced with 2.8 */
- vmc->no_its = true;
- /* Stick with 1K pages for migration compatibility */
- mc->minimum_page_bits = 0;
-}
-DEFINE_VIRT_MACHINE(2, 7)
-
-static void virt_machine_2_6_options(MachineClass *mc)
-{
- VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
-
- virt_machine_2_7_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
- vmc->disallow_affinity_adjustment = true;
- /* Disable PMU for 2.6 as PMU support was first introduced in 2.7 */
- vmc->no_pmu = true;
-}
-DEFINE_VIRT_MACHINE(2, 6)
diff --git a/hw/arm/xen-pvh.c b/hw/arm/xen-pvh.c
new file mode 100644
index 0000000..4b26bcf
--- /dev/null
+++ b/hw/arm/xen-pvh.c
@@ -0,0 +1,106 @@
+/*
+ * QEMU ARM Xen PVH Machine
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/qapi-commands-migration.h"
+#include "hw/boards.h"
+#include "system/system.h"
+#include "hw/xen/xen-pvh-common.h"
+#include "hw/xen/arch_hvm.h"
+
+#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
+
+/*
+ * VIRTIO_MMIO_DEV_SIZE is imported from tools/libs/light/libxl_arm.c under Xen
+ * repository.
+ *
+ * Origin: git://xenbits.xen.org/xen.git 2128143c114c
+ */
+#define VIRTIO_MMIO_DEV_SIZE 0x200
+
+#define NR_VIRTIO_MMIO_DEVICES \
+ (GUEST_VIRTIO_MMIO_SPI_LAST - GUEST_VIRTIO_MMIO_SPI_FIRST)
+
+static void xen_arm_instance_init(Object *obj)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(obj);
+
+ /* Default values. */
+ s->cfg.ram_low = (MemMapEntry) { GUEST_RAM0_BASE, GUEST_RAM0_SIZE };
+ s->cfg.ram_high = (MemMapEntry) { GUEST_RAM1_BASE, GUEST_RAM1_SIZE };
+
+ s->cfg.virtio_mmio_num = NR_VIRTIO_MMIO_DEVICES;
+ s->cfg.virtio_mmio_irq_base = GUEST_VIRTIO_MMIO_SPI_FIRST;
+ s->cfg.virtio_mmio = (MemMapEntry) { GUEST_VIRTIO_MMIO_BASE,
+ VIRTIO_MMIO_DEV_SIZE };
+}
+
+static void xen_pvh_set_pci_intx_irq(void *opaque, int intx_irq, int level)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(opaque);
+ int irq = s->cfg.pci_intx_irq_base + intx_irq;
+
+ if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
+ error_report("xendevicemodel_set_pci_intx_level failed");
+ }
+}
+
+static void xen_arm_machine_class_init(ObjectClass *oc, const void *data)
+{
+ XenPVHMachineClass *xpc = XEN_PVH_MACHINE_CLASS(oc);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Xen PVH ARM machine";
+
+ /*
+ * mc->max_cpus holds the MAX value allowed in the -smp command-line opts.
+ *
+ * 1. If users don't pass any -smp option:
+ * ms->smp.cpus will default to 1.
+ * ms->smp.max_cpus will default to 1.
+ *
+ * 2. If users pass -smp X:
+ * ms->smp.cpus will be set to X.
+ * ms->smp.max_cpus will also be set to X.
+ *
+ * 3. If users pass -smp X,maxcpus=Y:
+ * ms->smp.cpus will be set to X.
+ * ms->smp.max_cpus will be set to Y.
+ *
+ * In scenarios 2 and 3, if X or Y are set to something larger than
+ * mc->max_cpus, QEMU will bail out with an error message.
+ */
+ mc->max_cpus = GUEST_MAX_VCPUS;
+
+ /* Xen/ARM does not use buffered IOREQs. */
+ xpc->handle_bufioreq = HVM_IOREQSRV_BUFIOREQ_OFF;
+
+ /* PCI INTX delivery. */
+ xpc->set_pci_intx_irq = xen_pvh_set_pci_intx_irq;
+
+ /* List of supported features known to work on PVH ARM. */
+ xpc->has_pci = true;
+ xpc->has_tpm = true;
+ xpc->has_virtio_mmio = true;
+
+ xen_pvh_class_setup_common_props(xpc);
+}
+
+static const TypeInfo xen_arm_machine_type = {
+ .name = TYPE_XEN_ARM,
+ .parent = TYPE_XEN_PVH_MACHINE,
+ .class_init = xen_arm_machine_class_init,
+ .instance_size = sizeof(XenPVHMachineState),
+ .instance_init = xen_arm_instance_init,
+};
+
+static void xen_arm_machine_register_types(void)
+{
+ type_register_static(&xen_arm_machine_type);
+}
+
+type_init(xen_arm_machine_register_types)
diff --git a/hw/arm/xen-stubs.c b/hw/arm/xen-stubs.c
new file mode 100644
index 0000000..6a83043
--- /dev/null
+++ b/hw/arm/xen-stubs.c
@@ -0,0 +1,30 @@
+/*
+ * Stubs for unimplemented Xen functions for ARM.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-commands-migration.h"
+#include "system/xen.h"
+#include "hw/hw.h"
+#include "hw/xen/xen-hvm-common.h"
+#include "hw/xen/arch_hvm.h"
+
+void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
+{
+ hw_error("Invalid ioreq type 0x%x\n", req->type);
+}
+
+void arch_xen_set_memory(XenIOState *state, MemoryRegionSection *section,
+ bool add)
+{
+}
+
+void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
+{
+}
+
+void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
+{
+}
diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c
deleted file mode 100644
index 6fad829e..0000000
--- a/hw/arm/xen_arm.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * QEMU ARM Xen PVH Machine
- *
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/error-report.h"
-#include "qapi/qapi-commands-migration.h"
-#include "qapi/visitor.h"
-#include "hw/boards.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/sysemu.h"
-#include "hw/xen/xen-hvm-common.h"
-#include "sysemu/tpm.h"
-#include "hw/xen/arch_hvm.h"
-#include "trace.h"
-
-#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
-OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM)
-
-static const MemoryListener xen_memory_listener = {
- .region_add = xen_region_add,
- .region_del = xen_region_del,
- .log_start = NULL,
- .log_stop = NULL,
- .log_sync = NULL,
- .log_global_start = NULL,
- .log_global_stop = NULL,
- .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
-};
-
-struct XenArmState {
- /*< private >*/
- MachineState parent;
-
- XenIOState *state;
-
- struct {
- uint64_t tpm_base_addr;
- } cfg;
-};
-
-static MemoryRegion ram_lo, ram_hi;
-
-/*
- * VIRTIO_MMIO_DEV_SIZE is imported from tools/libs/light/libxl_arm.c under Xen
- * repository.
- *
- * Origin: git://xenbits.xen.org/xen.git 2128143c114c
- */
-#define VIRTIO_MMIO_DEV_SIZE 0x200
-
-#define NR_VIRTIO_MMIO_DEVICES \
- (GUEST_VIRTIO_MMIO_SPI_LAST - GUEST_VIRTIO_MMIO_SPI_FIRST)
-
-static void xen_set_irq(void *opaque, int irq, int level)
-{
- if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
- error_report("xendevicemodel_set_irq_level failed");
- }
-}
-
-static void xen_create_virtio_mmio_devices(XenArmState *xam)
-{
- int i;
-
- for (i = 0; i < NR_VIRTIO_MMIO_DEVICES; i++) {
- hwaddr base = GUEST_VIRTIO_MMIO_BASE + i * VIRTIO_MMIO_DEV_SIZE;
- qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL,
- GUEST_VIRTIO_MMIO_SPI_FIRST + i);
-
- sysbus_create_simple("virtio-mmio", base, irq);
-
- trace_xen_create_virtio_mmio_devices(i,
- GUEST_VIRTIO_MMIO_SPI_FIRST + i,
- base);
- }
-}
-
-static void xen_init_ram(MachineState *machine)
-{
- MemoryRegion *sysmem = get_system_memory();
- ram_addr_t block_len, ram_size[GUEST_RAM_BANKS];
-
- trace_xen_init_ram(machine->ram_size);
- if (machine->ram_size <= GUEST_RAM0_SIZE) {
- ram_size[0] = machine->ram_size;
- ram_size[1] = 0;
- block_len = GUEST_RAM0_BASE + ram_size[0];
- } else {
- ram_size[0] = GUEST_RAM0_SIZE;
- ram_size[1] = machine->ram_size - GUEST_RAM0_SIZE;
- block_len = GUEST_RAM1_BASE + ram_size[1];
- }
-
- memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len,
- &error_fatal);
-
- memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &xen_memory,
- GUEST_RAM0_BASE, ram_size[0]);
- memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo);
- if (ram_size[1] > 0) {
- memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &xen_memory,
- GUEST_RAM1_BASE, ram_size[1]);
- memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi);
- }
-
- /* Setup support for grants. */
- memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
- &error_fatal);
- memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
-}
-
-void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
-{
- hw_error("Invalid ioreq type 0x%x\n", req->type);
-
- return;
-}
-
-void arch_xen_set_memory(XenIOState *state, MemoryRegionSection *section,
- bool add)
-{
-}
-
-void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
-{
-}
-
-void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
-{
-}
-
-#ifdef CONFIG_TPM
-static void xen_enable_tpm(XenArmState *xam)
-{
- Error *errp = NULL;
- DeviceState *dev;
- SysBusDevice *busdev;
-
- TPMBackend *be = qemu_find_tpm_be("tpm0");
- if (be == NULL) {
- error_report("Couldn't find tmp0 backend");
- return;
- }
- dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
- object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp);
- object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr);
-
- trace_xen_enable_tpm(xam->cfg.tpm_base_addr);
-}
-#endif
-
-static void xen_arm_init(MachineState *machine)
-{
- XenArmState *xam = XEN_ARM(machine);
-
- xam->state = g_new0(XenIOState, 1);
-
- if (machine->ram_size == 0) {
- warn_report("%s non-zero ram size not specified. QEMU machine started"
- " without IOREQ (no emulated devices including virtio)",
- MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc);
- return;
- }
-
- xen_init_ram(machine);
-
- xen_register_ioreq(xam->state, machine->smp.cpus, &xen_memory_listener);
-
- xen_create_virtio_mmio_devices(xam);
-
-#ifdef CONFIG_TPM
- if (xam->cfg.tpm_base_addr) {
- xen_enable_tpm(xam);
- } else {
- warn_report("tpm-base-addr is not provided. TPM will not be enabled");
- }
-#endif
-}
-
-#ifdef CONFIG_TPM
-static void xen_arm_get_tpm_base_addr(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- XenArmState *xam = XEN_ARM(obj);
- uint64_t value = xam->cfg.tpm_base_addr;
-
- visit_type_uint64(v, name, &value, errp);
-}
-
-static void xen_arm_set_tpm_base_addr(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- XenArmState *xam = XEN_ARM(obj);
- uint64_t value;
-
- if (!visit_type_uint64(v, name, &value, errp)) {
- return;
- }
-
- xam->cfg.tpm_base_addr = value;
-}
-#endif
-
-static void xen_arm_machine_class_init(ObjectClass *oc, void *data)
-{
-
- MachineClass *mc = MACHINE_CLASS(oc);
- mc->desc = "Xen Para-virtualized PC";
- mc->init = xen_arm_init;
- mc->max_cpus = 1;
- mc->default_machine_opts = "accel=xen";
- /* Set explicitly here to make sure that real ram_size is passed */
- mc->default_ram_size = 0;
-
-#ifdef CONFIG_TPM
- object_class_property_add(oc, "tpm-base-addr", "uint64_t",
- xen_arm_get_tpm_base_addr,
- xen_arm_set_tpm_base_addr,
- NULL, NULL);
- object_class_property_set_description(oc, "tpm-base-addr",
- "Set Base address for TPM device.");
-
- machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
-#endif
-}
-
-static const TypeInfo xen_arm_machine_type = {
- .name = TYPE_XEN_ARM,
- .parent = TYPE_MACHINE,
- .class_init = xen_arm_machine_class_init,
- .instance_size = sizeof(XenArmState),
-};
-
-static void xen_arm_machine_register_types(void)
-{
- type_register_static(&xen_arm_machine_type);
-}
-
-type_init(xen_arm_machine_register_types)
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 3c56b9a..0372cd0 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -21,7 +21,7 @@
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/block/flash.h"
#include "hw/loader.h"
@@ -34,7 +34,8 @@
#include "hw/net/cadence_gem.h"
#include "hw/cpu/a9mpcore.h"
#include "hw/qdev-clock.h"
-#include "sysemu/reset.h"
+#include "hw/misc/unimp.h"
+#include "system/reset.h"
#include "qom/object.h"
#include "exec/tswap.h"
#include "target/arm/cpu-qom.h"
@@ -53,11 +54,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE)
#define FLASH_SIZE (64 * 1024 * 1024)
#define FLASH_SECTOR_SIZE (128 * 1024)
-#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
-
#define MPCORE_PERIPHBASE 0xF8F00000
#define ZYNQ_BOARD_MIDR 0x413FC090
+#define GIC_EXT_IRQS 64 /* Zynq 7000 SoC */
+
static const int dma_irqs[8] = {
46, 47, 48, 49, 72, 73, 74, 75
};
@@ -206,7 +207,7 @@ static void zynq_init(MachineState *machine)
MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
DeviceState *dev, *slcr;
SysBusDevice *busdev;
- qemu_irq pic[64];
+ qemu_irq pic[GIC_EXT_IRQS];
int n;
unsigned int smp_cpus = machine->smp.cpus;
@@ -219,14 +220,6 @@ static void zynq_init(MachineState *machine)
for (n = 0; n < smp_cpus; n++) {
Object *cpuobj = object_new(machine->cpu_type);
- /*
- * By default A9 CPUs have EL3 enabled. This board does not currently
- * support EL3 so the CPU EL3 property is disabled before realization.
- */
- if (object_property_find(cpuobj, "has_el3")) {
- object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
- }
-
object_property_set_int(cpuobj, "midr", ZYNQ_BOARD_MIDR,
&error_fatal);
object_property_set_int(cpuobj, "reset-cbar", MPCORE_PERIPHBASE,
@@ -270,6 +263,7 @@ static void zynq_init(MachineState *machine)
dev = qdev_new(TYPE_A9MPCORE_PRIV);
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+ qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
@@ -284,16 +278,16 @@ static void zynq_init(MachineState *machine)
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
}
- for (n = 0; n < 64; n++) {
+ for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
- n = zynq_init_spi_flashes(0xE0006000, pic[58 - IRQ_OFFSET], false, 0);
- n = zynq_init_spi_flashes(0xE0007000, pic[81 - IRQ_OFFSET], false, n);
- n = zynq_init_spi_flashes(0xE000D000, pic[51 - IRQ_OFFSET], true, n);
+ n = zynq_init_spi_flashes(0xE0006000, pic[58 - GIC_INTERNAL], false, 0);
+ n = zynq_init_spi_flashes(0xE0007000, pic[81 - GIC_INTERNAL], false, n);
+ n = zynq_init_spi_flashes(0xE000D000, pic[51 - GIC_INTERNAL], true, n);
- sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]);
- sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]);
+ sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - GIC_INTERNAL]);
+ sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - GIC_INTERNAL]);
dev = qdev_new(TYPE_CADENCE_UART);
busdev = SYS_BUS_DEVICE(dev);
@@ -302,7 +296,7 @@ static void zynq_init(MachineState *machine)
qdev_get_clock_out(slcr, "uart0_ref_clk"));
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, 0xE0000000);
- sysbus_connect_irq(busdev, 0, pic[59 - IRQ_OFFSET]);
+ sysbus_connect_irq(busdev, 0, pic[59 - GIC_INTERNAL]);
dev = qdev_new(TYPE_CADENCE_UART);
busdev = SYS_BUS_DEVICE(dev);
qdev_prop_set_chr(dev, "chardev", serial_hd(1));
@@ -310,15 +304,15 @@ static void zynq_init(MachineState *machine)
qdev_get_clock_out(slcr, "uart1_ref_clk"));
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, 0xE0001000);
- sysbus_connect_irq(busdev, 0, pic[82 - IRQ_OFFSET]);
+ sysbus_connect_irq(busdev, 0, pic[82 - GIC_INTERNAL]);
sysbus_create_varargs("cadence_ttc", 0xF8001000,
- pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL);
+ pic[42-GIC_INTERNAL], pic[43-GIC_INTERNAL], pic[44-GIC_INTERNAL], NULL);
sysbus_create_varargs("cadence_ttc", 0xF8002000,
- pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL);
+ pic[69-GIC_INTERNAL], pic[70-GIC_INTERNAL], pic[71-GIC_INTERNAL], NULL);
- gem_init(0xE000B000, pic[54 - IRQ_OFFSET]);
- gem_init(0xE000C000, pic[77 - IRQ_OFFSET]);
+ gem_init(0xE000B000, pic[54 - GIC_INTERNAL]);
+ gem_init(0xE000C000, pic[77 - GIC_INTERNAL]);
for (n = 0; n < 2; n++) {
int hci_irq = n ? 79 : 56;
@@ -337,7 +331,7 @@ static void zynq_init(MachineState *machine)
qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - IRQ_OFFSET]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - GIC_INTERNAL]);
di = drive_get(IF_SD, 0, n);
blk = di ? blk_by_legacy_dinfo(di) : NULL;
@@ -350,7 +344,7 @@ static void zynq_init(MachineState *machine)
dev = qdev_new(TYPE_ZYNQ_XADC);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-GIC_INTERNAL]);
dev = qdev_new("pl330");
object_property_set_link(OBJECT(dev), "memory",
@@ -370,17 +364,86 @@ static void zynq_init(MachineState *machine)
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, 0xF8003000);
- sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */
+ sysbus_connect_irq(busdev, 0, pic[45-GIC_INTERNAL]); /* abort irq line */
for (n = 0; n < ARRAY_SIZE(dma_irqs); ++n) { /* event irqs */
- sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
+ sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - GIC_INTERNAL]);
}
dev = qdev_new("xlnx.ps7-dev-cfg");
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]);
+ sysbus_connect_irq(busdev, 0, pic[40 - GIC_INTERNAL]);
sysbus_mmio_map(busdev, 0, 0xF8007000);
+ /*
+ * Refer to the ug585-Zynq-7000-TRM manual B.3 (Module Summary) and
+ * the zynq-7000.dtsi. Add placeholders for unimplemented devices.
+ */
+ create_unimplemented_device("zynq.i2c0", 0xE0004000, 4 * KiB);
+ create_unimplemented_device("zynq.i2c1", 0xE0005000, 4 * KiB);
+ create_unimplemented_device("zynq.can0", 0xE0008000, 4 * KiB);
+ create_unimplemented_device("zynq.can1", 0xE0009000, 4 * KiB);
+ create_unimplemented_device("zynq.gpio", 0xE000A000, 4 * KiB);
+ create_unimplemented_device("zynq.smcc", 0xE000E000, 4 * KiB);
+
+ /* Direct Memory Access Controller, PL330, Non-Secure Mode */
+ create_unimplemented_device("zynq.dma_ns", 0xF8004000, 4 * KiB);
+
+ /* System Watchdog Timer Registers */
+ create_unimplemented_device("zynq.swdt", 0xF8005000, 4 * KiB);
+
+ /* DDR memory controller */
+ create_unimplemented_device("zynq.ddrc", 0xF8006000, 4 * KiB);
+
+ /* AXI_HP Interface (AFI) */
+ create_unimplemented_device("zynq.axi_hp0", 0xF8008000, 0x28);
+ create_unimplemented_device("zynq.axi_hp1", 0xF8009000, 0x28);
+ create_unimplemented_device("zynq.axi_hp2", 0xF800A000, 0x28);
+ create_unimplemented_device("zynq.axi_hp3", 0xF800B000, 0x28);
+
+ create_unimplemented_device("zynq.efuse", 0xF800d000, 0x20);
+
+ /* Embedded Trace Buffer */
+ create_unimplemented_device("zynq.etb", 0xF8801000, 4 * KiB);
+
+ /* Cross Trigger Interface, ETB and TPIU */
+ create_unimplemented_device("zynq.cti_etb_tpiu", 0xF8802000, 4 * KiB);
+
+ /* Trace Port Interface Unit */
+ create_unimplemented_device("zynq.tpiu", 0xF8803000, 4 * KiB);
+
+ /* CoreSight Trace Funnel */
+ create_unimplemented_device("zynq.funnel", 0xF8804000, 4 * KiB);
+
+ /* Instrumentation Trace Macrocell */
+ create_unimplemented_device("zynq.itm", 0xF8805000, 4 * KiB);
+
+ /* Cross Trigger Interface, FTM */
+ create_unimplemented_device("zynq.cti_ftm", 0xF8809000, 4 * KiB);
+
+ /* Fabric Trace Macrocell */
+ create_unimplemented_device("zynq.ftm", 0xF880B000, 4 * KiB);
+
+ /* Cortex A9 Performance Monitoring Unit, CPU */
+ create_unimplemented_device("cortex-a9.pmu0", 0xF8891000, 4 * KiB);
+ create_unimplemented_device("cortex-a9.pmu1", 0xF8893000, 4 * KiB);
+
+ /* Cross Trigger Interface, CPU */
+ create_unimplemented_device("zynq.cpu_cti0", 0xF8898000, 4 * KiB);
+ create_unimplemented_device("zynq.cpu_cti1", 0xF8899000, 4 * KiB);
+
+ /* CoreSight PTM-A9, CPU */
+ create_unimplemented_device("cortex-a9.ptm0", 0xF889c000, 4 * KiB);
+ create_unimplemented_device("cortex-a9.ptm1", 0xF889d000, 4 * KiB);
+
+ /* AMBA NIC301 TrustZone */
+ create_unimplemented_device("zynq.trustZone", 0xF8900000, 0x20);
+
+ /* AMBA Network Interconnect Advanced Quality of Service (QoS-301) */
+ create_unimplemented_device("zynq.qos301_cpu", 0xF8946000, 0x130);
+ create_unimplemented_device("zynq.qos301_dmac", 0xF8947000, 0x130);
+ create_unimplemented_device("zynq.qos301_iou", 0xF8948000, 0x130);
+
zynq_binfo.ram_size = machine->ram_size;
zynq_binfo.board_id = 0xd32;
zynq_binfo.loader_start = 0;
@@ -390,7 +453,7 @@ static void zynq_init(MachineState *machine)
arm_load_kernel(zynq_machine->cpu[0], machine, &zynq_binfo);
}
-static void zynq_machine_class_init(ObjectClass *oc, void *data)
+static void zynq_machine_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
@@ -398,10 +461,9 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data)
};
MachineClass *mc = MACHINE_CLASS(oc);
ObjectProperty *prop;
- mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
+ mc->desc = "Xilinx Zynq 7000 Platform Baseboard for Cortex-A9";
mc->init = zynq_init;
mc->max_cpus = ZYNQ_MAX_CPUS;
- mc->no_sdcard = 1;
mc->ignore_memory_transaction_failures = true;
mc->valid_cpu_types = valid_cpu_types;
mc->default_ram_id = "zynq.ext_ram";
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 962f98f..adadbb7 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/block/flash.h"
#include "hw/boards.h"
#include "hw/sysbus.h"
@@ -761,9 +761,9 @@ static void versal_virt_init(MachineState *machine)
if (!flash_klass ||
object_class_is_abstract(flash_klass) ||
!object_class_dynamic_cast(flash_klass, TYPE_M25P80)) {
- error_setg(&error_fatal, "'%s' is either abstract or"
+ error_report("'%s' is either abstract or"
" not a subtype of m25p80", s->ospi_model);
- return;
+ exit(1);
}
}
@@ -808,7 +808,7 @@ static void versal_virt_machine_finalize(Object *obj)
g_free(s->ospi_model);
}
-static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
+static void versal_virt_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -818,6 +818,7 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
mc->max_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS;
mc->default_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS;
mc->no_cdrom = true;
+ mc->auto_create_sdcard = true;
mc->default_ram_id = "ddr";
object_class_property_add_str(oc, "ospi-flash", versal_get_ospi_model,
versal_set_ospi_model);
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index 50cb060..a42b9e7 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -12,14 +12,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
+#include "system/system.h"
#include "hw/arm/boot.h"
-#include "kvm_arm.h"
#include "hw/misc/unimp.h"
#include "hw/arm/xlnx-versal.h"
#include "qemu/log.h"
@@ -258,14 +256,23 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
char *name = g_strdup_printf("gem%d", i);
DeviceState *dev;
MemoryRegion *mr;
+ OrIRQState *or_irq;
object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i],
TYPE_CADENCE_GEM);
+ or_irq = &s->lpd.iou.gem_irq_orgate[i];
+ object_initialize_child(OBJECT(s), "gem-irq-orgate[*]",
+ or_irq, TYPE_OR_IRQ);
dev = DEVICE(&s->lpd.iou.gem[i]);
qemu_configure_nic_device(dev, true, NULL);
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
object_property_set_int(OBJECT(dev), "num-priority-queues", 2,
&error_abort);
+ object_property_set_int(OBJECT(or_irq),
+ "num-lines", 2, &error_fatal);
+ qdev_realize(DEVICE(or_irq), NULL, &error_fatal);
+ qdev_connect_gpio_out(DEVICE(or_irq), 0, pic[irqs[i]]);
+
object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
&error_abort);
sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -273,7 +280,8 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(or_irq), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, qdev_get_gpio_in(DEVICE(or_irq), 1));
g_free(name);
}
}
@@ -958,17 +966,16 @@ static void versal_init(Object *obj)
"mr-rpu-ps-alias", &s->mr_ps, 0, UINT64_MAX);
}
-static Property versal_properties[] = {
+static const Property versal_properties[] = {
DEFINE_PROP_LINK("ddr", Versal, cfg.mr_ddr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_LINK("canbus0", Versal, lpd.iou.canbus[0],
TYPE_CAN_BUS, CanBusState *),
DEFINE_PROP_LINK("canbus1", Versal, lpd.iou.canbus[1],
TYPE_CAN_BUS, CanBusState *),
- DEFINE_PROP_END_OF_LIST()
};
-static void versal_class_init(ObjectClass *klass, void *data)
+static void versal_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
index 4667cb3..14b6641 100644
--- a/hw/arm/xlnx-zcu102.c
+++ b/hw/arm/xlnx-zcu102.c
@@ -22,7 +22,7 @@
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "qom/object.h"
#include "net/can_emu.h"
#include "audio/audio.h"
@@ -267,7 +267,7 @@ static void xlnx_zcu102_machine_instance_init(Object *obj)
0);
}
-static void xlnx_zcu102_machine_class_init(ObjectClass *oc, void *data)
+static void xlnx_zcu102_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -280,6 +280,7 @@ static void xlnx_zcu102_machine_class_init(ObjectClass *oc, void *data)
mc->max_cpus = XLNX_ZYNQMP_NUM_APU_CPUS + XLNX_ZYNQMP_NUM_RPU_CPUS;
mc->default_cpus = XLNX_ZYNQMP_NUM_APU_CPUS;
mc->default_ram_id = "ddr-ram";
+ mc->auto_create_sdcard = true;
machine_add_audiodev_property(mc);
object_class_property_add_bool(oc, "secure", zcu102_get_secure,
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index afeb3f8..ec96a46 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -22,9 +22,7 @@
#include "hw/intc/arm_gic_common.h"
#include "hw/misc/unimp.h"
#include "hw/boards.h"
-#include "sysemu/kvm.h"
-#include "sysemu/sysemu.h"
-#include "kvm_arm.h"
+#include "system/system.h"
#include "target/arm/cpu-qom.h"
#include "target/arm/gtimer.h"
@@ -394,6 +392,8 @@ static void xlnx_zynqmp_init(Object *obj)
for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
object_initialize_child(obj, "gem[*]", &s->gem[i], TYPE_CADENCE_GEM);
+ object_initialize_child(obj, "gem-irq-orgate[*]",
+ &s->gem_irq_orgate[i], TYPE_OR_IRQ);
}
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
@@ -625,12 +625,19 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
&error_abort);
object_property_set_int(OBJECT(&s->gem[i]), "num-priority-queues", 2,
&error_abort);
+ object_property_set_int(OBJECT(&s->gem_irq_orgate[i]),
+ "num-lines", 2, &error_fatal);
+ qdev_realize(DEVICE(&s->gem_irq_orgate[i]), NULL, &error_fatal);
+ qdev_connect_gpio_out(DEVICE(&s->gem_irq_orgate[i]), 0, gic_spi[gem_intr[i]]);
+
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0,
- gic_spi[gem_intr[i]]);
+ qdev_get_gpio_in(DEVICE(&s->gem_irq_orgate[i]), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 1,
+ qdev_get_gpio_in(DEVICE(&s->gem_irq_orgate[i]), 1));
}
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
@@ -680,16 +687,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
* - SDIO Specification Version 3.0
* - eMMC Specification Version 4.51
*/
- if (!object_property_set_uint(sdhci, "sd-spec-version", 3, errp)) {
- return;
- }
- if (!object_property_set_uint(sdhci, "capareg", SDHCI_CAPABILITIES,
- errp)) {
- return;
- }
- if (!object_property_set_uint(sdhci, "uhs", UHS_I, errp)) {
- return;
- }
+ object_property_set_uint(sdhci, "sd-spec-version", 3, &error_abort);
+ object_property_set_uint(sdhci, "capareg", SDHCI_CAPABILITIES,
+ &error_abort);
+ object_property_set_uint(sdhci, "uhs", UHS_I, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(sdhci), errp)) {
return;
}
@@ -754,14 +755,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
xlnx_zynqmp_create_unimp_mmio(s);
for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) {
- if (!object_property_set_uint(OBJECT(&s->gdma[i]), "bus-width", 128,
- errp)) {
- return;
- }
- if (!object_property_set_link(OBJECT(&s->gdma[i]), "dma",
- OBJECT(system_memory), errp)) {
- return;
- }
+ object_property_set_uint(OBJECT(&s->gdma[i]), "bus-width", 128,
+ &error_abort);
+ object_property_set_link(OBJECT(&s->gdma[i]), "dma",
+ OBJECT(system_memory), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gdma[i]), errp)) {
return;
}
@@ -802,10 +799,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi_dma), 0,
qdev_get_gpio_in(DEVICE(&s->qspi_irq_orgate), 0));
- if (!object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
- OBJECT(&s->qspi_dma), errp)) {
- return;
- }
+ object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
+ OBJECT(&s->qspi_dma), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi), errp)) {
return;
}
@@ -824,10 +819,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
}
for (i = 0; i < XLNX_ZYNQMP_NUM_USB; i++) {
- if (!object_property_set_link(OBJECT(&s->usb[i].sysbus_xhci), "dma",
- OBJECT(system_memory), errp)) {
- return;
- }
+ object_property_set_link(OBJECT(&s->usb[i].sysbus_xhci), "dma",
+ OBJECT(system_memory), &error_abort);
qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "intrs", 4);
qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2);
@@ -848,7 +841,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
}
}
-static Property xlnx_zynqmp_props[] = {
+static const Property xlnx_zynqmp_props[] = {
DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false),
DEFINE_PROP_BOOL("virtualization", XlnxZynqMPState, virt, false),
@@ -858,10 +851,9 @@ static Property xlnx_zynqmp_props[] = {
CanBusState *),
DEFINE_PROP_LINK("canbus1", XlnxZynqMPState, canbus[1], TYPE_CAN_BUS,
CanBusState *),
- DEFINE_PROP_END_OF_LIST()
};
-static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
+static void xlnx_zynqmp_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
deleted file mode 100644
index fc5672e..0000000
--- a/hw/arm/z2.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * PXA270-based Zipit Z2 device
- *
- * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Code is based on mainstone platform.
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "migration/vmstate.h"
-#include "hw/boards.h"
-#include "hw/block/flash.h"
-#include "ui/console.h"
-#include "hw/audio/wm8750.h"
-#include "audio/audio.h"
-#include "exec/address-spaces.h"
-#include "qom/object.h"
-#include "qapi/error.h"
-#include "trace.h"
-
-static const struct keymap map[0x100] = {
- [0 ... 0xff] = { -1, -1 },
- [0x3b] = {0, 0}, /* Option = F1 */
- [0xc8] = {0, 1}, /* Up */
- [0xd0] = {0, 2}, /* Down */
- [0xcb] = {0, 3}, /* Left */
- [0xcd] = {0, 4}, /* Right */
- [0xcf] = {0, 5}, /* End */
- [0x0d] = {0, 6}, /* KPPLUS */
- [0xc7] = {1, 0}, /* Home */
- [0x10] = {1, 1}, /* Q */
- [0x17] = {1, 2}, /* I */
- [0x22] = {1, 3}, /* G */
- [0x2d] = {1, 4}, /* X */
- [0x1c] = {1, 5}, /* Enter */
- [0x0c] = {1, 6}, /* KPMINUS */
- [0xc9] = {2, 0}, /* PageUp */
- [0x11] = {2, 1}, /* W */
- [0x18] = {2, 2}, /* O */
- [0x23] = {2, 3}, /* H */
- [0x2e] = {2, 4}, /* C */
- [0x38] = {2, 5}, /* LeftAlt */
- [0xd1] = {3, 0}, /* PageDown */
- [0x12] = {3, 1}, /* E */
- [0x19] = {3, 2}, /* P */
- [0x24] = {3, 3}, /* J */
- [0x2f] = {3, 4}, /* V */
- [0x2a] = {3, 5}, /* LeftShift */
- [0x01] = {4, 0}, /* Esc */
- [0x13] = {4, 1}, /* R */
- [0x1e] = {4, 2}, /* A */
- [0x25] = {4, 3}, /* K */
- [0x30] = {4, 4}, /* B */
- [0x1d] = {4, 5}, /* LeftCtrl */
- [0x0f] = {5, 0}, /* Tab */
- [0x14] = {5, 1}, /* T */
- [0x1f] = {5, 2}, /* S */
- [0x26] = {5, 3}, /* L */
- [0x31] = {5, 4}, /* N */
- [0x39] = {5, 5}, /* Space */
- [0x3c] = {6, 0}, /* Stop = F2 */
- [0x15] = {6, 1}, /* Y */
- [0x20] = {6, 2}, /* D */
- [0x0e] = {6, 3}, /* Backspace */
- [0x32] = {6, 4}, /* M */
- [0x33] = {6, 5}, /* Comma */
- [0x3d] = {7, 0}, /* Play = F3 */
- [0x16] = {7, 1}, /* U */
- [0x21] = {7, 2}, /* F */
- [0x2c] = {7, 3}, /* Z */
- [0x27] = {7, 4}, /* Semicolon */
- [0x34] = {7, 5}, /* Dot */
-};
-
-#define Z2_RAM_SIZE 0x02000000
-#define Z2_FLASH_BASE 0x00000000
-#define Z2_FLASH_SIZE 0x00800000
-
-static struct arm_boot_info z2_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = Z2_RAM_SIZE,
-};
-
-#define Z2_GPIO_SD_DETECT 96
-#define Z2_GPIO_AC_IN 0
-#define Z2_GPIO_KEY_ON 1
-#define Z2_GPIO_LCD_CS 88
-
-struct ZipitLCD {
- SSIPeripheral ssidev;
- int32_t selected;
- int32_t enabled;
- uint8_t buf[3];
- uint32_t cur_reg;
- int pos;
-};
-
-#define TYPE_ZIPIT_LCD "zipit-lcd"
-OBJECT_DECLARE_SIMPLE_TYPE(ZipitLCD, ZIPIT_LCD)
-
-static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
-{
- ZipitLCD *z = ZIPIT_LCD(dev);
- uint16_t val;
-
- trace_z2_lcd_reg_update(z->cur_reg, z->buf[0], z->buf[1], z->buf[2], value);
- if (z->selected) {
- z->buf[z->pos] = value & 0xff;
- z->pos++;
- }
- if (z->pos == 3) {
- switch (z->buf[0]) {
- case 0x74:
- z->cur_reg = z->buf[2];
- break;
- case 0x76:
- val = z->buf[1] << 8 | z->buf[2];
- if (z->cur_reg == 0x22 && val == 0x0000) {
- z->enabled = 1;
- trace_z2_lcd_enable_disable_result("enabled");
- } else if (z->cur_reg == 0x10 && val == 0x0000) {
- z->enabled = 0;
- trace_z2_lcd_enable_disable_result("disabled");
- }
- break;
- default:
- break;
- }
- z->pos = 0;
- }
- return 0;
-}
-
-static void z2_lcd_cs(void *opaque, int line, int level)
-{
- ZipitLCD *z2_lcd = opaque;
- z2_lcd->selected = !level;
-}
-
-static void zipit_lcd_realize(SSIPeripheral *dev, Error **errp)
-{
- ZipitLCD *z = ZIPIT_LCD(dev);
- z->selected = 0;
- z->enabled = 0;
- z->pos = 0;
-}
-
-static const VMStateDescription vmstate_zipit_lcd_state = {
- .name = "zipit-lcd",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, ZipitLCD),
- VMSTATE_INT32(selected, ZipitLCD),
- VMSTATE_INT32(enabled, ZipitLCD),
- VMSTATE_BUFFER(buf, ZipitLCD),
- VMSTATE_UINT32(cur_reg, ZipitLCD),
- VMSTATE_INT32(pos, ZipitLCD),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void zipit_lcd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = zipit_lcd_realize;
- k->transfer = zipit_lcd_transfer;
- dc->vmsd = &vmstate_zipit_lcd_state;
-}
-
-static const TypeInfo zipit_lcd_info = {
- .name = TYPE_ZIPIT_LCD,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(ZipitLCD),
- .class_init = zipit_lcd_class_init,
-};
-
-#define TYPE_AER915 "aer915"
-OBJECT_DECLARE_SIMPLE_TYPE(AER915State, AER915)
-
-struct AER915State {
- I2CSlave parent_obj;
-
- int len;
- uint8_t buf[3];
-};
-
-static int aer915_send(I2CSlave *i2c, uint8_t data)
-{
- AER915State *s = AER915(i2c);
-
- s->buf[s->len] = data;
- if (s->len++ > 2) {
- trace_z2_aer915_send_too_long(s->len);
- return 1;
- }
-
- if (s->len == 2) {
- trace_z2_aer915_send(s->buf[0], s->buf[1]);
- }
-
- return 0;
-}
-
-static int aer915_event(I2CSlave *i2c, enum i2c_event event)
-{
- AER915State *s = AER915(i2c);
-
- trace_z2_aer915_event(s->len, event);
- switch (event) {
- case I2C_START_SEND:
- s->len = 0;
- break;
- case I2C_START_RECV:
- break;
- case I2C_FINISH:
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static uint8_t aer915_recv(I2CSlave *slave)
-{
- AER915State *s = AER915(slave);
- int retval = 0x00;
-
- switch (s->buf[0]) {
- /* Return hardcoded battery voltage,
- * 0xf0 means ~4.1V
- */
- case 0x02:
- retval = 0xf0;
- break;
- /* Return 0x00 for other regs,
- * we don't know what they are for,
- * anyway they return 0x00 on real hardware.
- */
- default:
- break;
- }
-
- return retval;
-}
-
-static const VMStateDescription vmstate_aer915_state = {
- .name = "aer915",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(len, AER915State),
- VMSTATE_BUFFER(buf, AER915State),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void aer915_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->event = aer915_event;
- k->recv = aer915_recv;
- k->send = aer915_send;
- dc->vmsd = &vmstate_aer915_state;
-}
-
-static const TypeInfo aer915_info = {
- .name = TYPE_AER915,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(AER915State),
- .class_init = aer915_class_init,
-};
-
-#define FLASH_SECTOR_SIZE (64 * KiB)
-
-static void z2_init(MachineState *machine)
-{
- PXA2xxState *mpu;
- DriveInfo *dinfo;
- void *z2_lcd;
- I2CBus *bus;
- DeviceState *wm;
- I2CSlave *i2c_dev;
-
- /* Setup CPU & memory */
- mpu = pxa270_init(z2_binfo.ram_size, machine->cpu_type);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0);
-
- /* setup keypad */
- pxa27x_register_keypad(mpu->kp, map, 0x100);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(mpu->mmc,
- NULL,
- qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT));
-
- type_register_static(&zipit_lcd_info);
- type_register_static(&aer915_info);
- z2_lcd = ssi_create_peripheral(mpu->ssp[1], TYPE_ZIPIT_LCD);
- bus = pxa2xx_i2c_bus(mpu->i2c[0]);
-
- i2c_slave_create_simple(bus, TYPE_AER915, 0x55);
-
- i2c_dev = i2c_slave_new(TYPE_WM8750, 0x1b);
- wm = DEVICE(i2c_dev);
-
- if (machine->audiodev) {
- qdev_prop_set_string(wm, "audiodev", machine->audiodev);
- }
- i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort);
-
- mpu->i2s->opaque = wm;
- mpu->i2s->codec_out = wm8750_dac_dat;
- mpu->i2s->codec_in = wm8750_adc_dat;
- wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s);
-
- qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS,
- qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0));
-
- z2_binfo.board_id = 0x6dd;
- arm_load_kernel(mpu->cpu, machine, &z2_binfo);
-}
-
-static void z2_machine_init(MachineClass *mc)
-{
- mc->desc = "Zipit Z2 (PXA27x)";
- mc->init = z2_init;
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-DEFINE_MACHINE("z2", z2_machine_init)
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index 3f0053f..eb7a847 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -24,7 +24,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qom/object.h"
#include "ac97.h"
@@ -886,7 +886,7 @@ static void nabm_writel(void *opaque, uint32_t addr, uint32_t val)
static int write_audio(AC97LinkState *s, AC97BusMasterRegs *r,
int max, int *stop)
{
- uint8_t tmpbuf[4096];
+ QEMU_UNINITIALIZED uint8_t tmpbuf[4096];
uint32_t addr = r->bd.addr;
uint32_t temp = r->picb << 1;
uint32_t written = 0;
@@ -959,7 +959,7 @@ static void write_bup(AC97LinkState *s, int elapsed)
static int read_audio(AC97LinkState *s, AC97BusMasterRegs *r,
int max, int *stop)
{
- uint8_t tmpbuf[4096];
+ QEMU_UNINITIALIZED uint8_t tmpbuf[4096];
uint32_t addr = r->bd.addr;
uint32_t temp = r->picb << 1;
uint32_t nread = 0;
@@ -1324,12 +1324,11 @@ static void ac97_exit(PCIDevice *dev)
AUD_remove_card(&s->card);
}
-static Property ac97_properties[] = {
+static const Property ac97_properties[] = {
DEFINE_AUDIO_PROPERTIES(AC97LinkState, card),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ac97_class_init(ObjectClass *klass, void *data)
+static void ac97_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1344,7 +1343,7 @@ static void ac97_class_init(ObjectClass *klass, void *data)
dc->desc = "Intel 82801AA AC97 Audio";
dc->vmsd = &vmstate_ac97;
device_class_set_props(dc, ac97_properties);
- dc->reset = ac97_on_reset;
+ device_class_set_legacy_reset(dc, ac97_on_reset);
}
static const TypeInfo ac97_info = {
@@ -1352,7 +1351,7 @@ static const TypeInfo ac97_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(AC97LinkState),
.class_init = ac97_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index bd73806..1f29a7e 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -297,14 +297,13 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0);
}
-static Property adlib_properties[] = {
+static const Property adlib_properties[] = {
DEFINE_AUDIO_PROPERTIES(AdlibState, card),
DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220),
DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100),
- DEFINE_PROP_END_OF_LIST (),
};
-static void adlib_class_initfn (ObjectClass *klass, void *data)
+static void adlib_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
diff --git a/hw/audio/asc.c b/hw/audio/asc.c
index 8054163..edd42d6 100644
--- a/hw/audio/asc.c
+++ b/hw/audio/asc.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/timer.h"
+#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "audio/audio.h"
@@ -406,7 +407,6 @@ static void asc_fifo_write(void *opaque, hwaddr addr, uint64_t value,
} else {
fs->fifo[addr] = value;
}
- return;
}
static const MemoryRegionOps asc_fifo_ops = {
@@ -654,11 +654,17 @@ static void asc_realize(DeviceState *dev, Error **errp)
s->voice = AUD_open_out(&s->card, s->voice, "asc.out", s, asc_out_cb,
&as);
+ if (!s->voice) {
+ AUD_remove_card(&s->card);
+ error_setg(errp, "Initializing audio stream failed");
+ return;
+ }
+
s->shift = 1;
s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift;
s->mixbuf = g_malloc0(s->samples << s->shift);
- s->silentbuf = g_malloc0(s->samples << s->shift);
+ s->silentbuf = g_malloc(s->samples << s->shift);
memset(s->silentbuf, 0x80, s->samples << s->shift);
/* Add easc registers if required */
@@ -695,13 +701,12 @@ static void asc_init(Object *obj)
sysbus_init_mmio(sbd, &s->asc);
}
-static Property asc_properties[] = {
+static const Property asc_properties[] = {
DEFINE_AUDIO_PROPERTIES(ASCState, card),
DEFINE_PROP_UINT8("asctype", ASCState, type, ASC_TYPE_ASC),
- DEFINE_PROP_END_OF_LIST(),
};
-static void asc_class_init(ObjectClass *oc, void *data)
+static void asc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
diff --git a/hw/audio/cs4231.c b/hw/audio/cs4231.c
index 967caa7..97cceb4 100644
--- a/hw/audio/cs4231.c
+++ b/hw/audio/cs4231.c
@@ -160,11 +160,11 @@ static void cs4231_init(Object *obj)
sysbus_init_irq(dev, &s->irq);
}
-static void cs4231_class_init(ObjectClass *klass, void *data)
+static void cs4231_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = cs_reset;
+ device_class_set_legacy_reset(dc, cs_reset);
dc->vmsd = &vmstate_cs4231;
}
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index 9ef57f0..6dfff20 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -528,7 +528,7 @@ static int cs_write_audio (CSState *s, int nchan, int dma_pos,
int dma_len, int len)
{
int temp, net;
- uint8_t tmpbuf[4096];
+ QEMU_UNINITIALIZED uint8_t tmpbuf[4096];
IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
temp = len;
@@ -547,7 +547,7 @@ static int cs_write_audio (CSState *s, int nchan, int dma_pos,
copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy);
if (s->tab) {
int i;
- int16_t linbuf[4096];
+ QEMU_UNINITIALIZED int16_t linbuf[4096];
for (i = 0; i < copied; ++i)
linbuf[i] = s->tab[tmpbuf[i]];
@@ -682,6 +682,10 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp)
return;
}
+ if (s->irq >= ISA_NUM_IRQS) {
+ error_setg(errp, "Invalid IRQ %d (max %d)", s->irq, ISA_NUM_IRQS - 1);
+ return;
+ }
s->pic = isa_bus_get_irq(bus, s->irq);
k = ISADMA_GET_CLASS(s->isa_dma);
k->register_channel(s->isa_dma, s->dma, cs_dma_read, s);
@@ -689,20 +693,19 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp)
isa_register_ioport (d, &s->ioports, s->port);
}
-static Property cs4231a_properties[] = {
+static const Property cs4231a_properties[] = {
DEFINE_AUDIO_PROPERTIES(CSState, card),
DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
- DEFINE_PROP_END_OF_LIST (),
};
-static void cs4231a_class_initfn (ObjectClass *klass, void *data)
+static void cs4231a_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
dc->realize = cs4231a_realizefn;
- dc->reset = cs4231a_reset;
+ device_class_set_legacy_reset(dc, cs4231a_reset);
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "Crystal Semiconductor CS4231A";
dc->vmsd = &vmstate_cs4231a;
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 4ab61d3..a6a32a6 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -32,7 +32,7 @@
#include "migration/vmstate.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qom/object.h"
#include "trace.h"
@@ -604,7 +604,7 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size)
static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
int max, bool *irq)
{
- uint8_t tmpbuf[4096];
+ QEMU_UNINITIALIZED uint8_t tmpbuf[4096];
size_t to_transfer;
uint32_t addr = d->frame_addr;
int sc = d->scount & 0xffff;
@@ -868,12 +868,11 @@ static void es1370_exit(PCIDevice *dev)
AUD_remove_card(&s->card);
}
-static Property es1370_properties[] = {
+static const Property es1370_properties[] = {
DEFINE_AUDIO_PROPERTIES(ES1370State, card),
- DEFINE_PROP_END_OF_LIST(),
};
-static void es1370_class_init (ObjectClass *klass, void *data)
+static void es1370_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
@@ -888,7 +887,7 @@ static void es1370_class_init (ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "ENSONIQ AudioPCI ES1370";
dc->vmsd = &vmstate_es1370;
- dc->reset = es1370_on_reset;
+ device_class_set_legacy_reset(dc, es1370_on_reset);
device_class_set_props(dc, es1370_properties);
}
@@ -897,7 +896,7 @@ static const TypeInfo es1370_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof (ES1370State),
.class_init = es1370_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index 4beb3fd..c36df02 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -183,7 +183,7 @@ static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
{
GUSState *s = opaque;
IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
- char tmpbuf[4096];
+ QEMU_UNINITIALIZED char tmpbuf[4096];
int pos = dma_pos, mode, left = dma_len - dma_pos;
ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
@@ -290,16 +290,15 @@ static void gus_realizefn (DeviceState *dev, Error **errp)
AUD_set_active_out (s->voice, 1);
}
-static Property gus_properties[] = {
+static const Property gus_properties[] = {
DEFINE_AUDIO_PROPERTIES(GUSState, card),
DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
DEFINE_PROP_UINT32 ("iobase", GUSState, port, 0x240),
DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3),
- DEFINE_PROP_END_OF_LIST (),
};
-static void gus_class_initfn (ObjectClass *klass, void *data)
+static void gus_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index b22e486..66edad2 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -487,8 +487,7 @@ static void hda_audio_setup(HDAAudioStream *st)
if (st->output) {
if (use_timer) {
cb = hda_audio_output_cb;
- st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- hda_audio_output_timer, st);
+ timer_del(st->buft);
} else {
cb = hda_audio_compat_output_cb;
}
@@ -497,8 +496,7 @@ static void hda_audio_setup(HDAAudioStream *st)
} else {
if (use_timer) {
cb = hda_audio_input_cb;
- st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- hda_audio_input_timer, st);
+ timer_del(st->buft);
} else {
cb = hda_audio_compat_input_cb;
}
@@ -726,8 +724,12 @@ static void hda_audio_init(HDACodecDevice *hda,
st->gain_right = QEMU_HDA_AMP_STEPS;
st->compat_bpos = sizeof(st->compat_buf);
st->output = true;
+ st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ hda_audio_output_timer, st);
} else {
st->output = false;
+ st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ hda_audio_input_timer, st);
}
st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
(1 << AC_FMT_CHAN_SHIFT);
@@ -750,9 +752,7 @@ static void hda_audio_exit(HDACodecDevice *hda)
if (st->node == NULL) {
continue;
}
- if (a->use_timer) {
- timer_del(st->buft);
- }
+ timer_free(st->buft);
if (st->output) {
AUD_close_out(&a->card, st->voice.out);
} else {
@@ -857,12 +857,11 @@ static const VMStateDescription vmstate_hda_audio = {
}
};
-static Property hda_audio_properties[] = {
+static const Property hda_audio_properties[] = {
DEFINE_AUDIO_PROPERTIES(HDAAudioState, card),
DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
DEFINE_PROP_BOOL("use-timer", HDAAudioState, use_timer, true),
- DEFINE_PROP_END_OF_LIST(),
};
static void hda_audio_init_output(HDACodecDevice *hda, Error **errp)
@@ -901,7 +900,7 @@ static void hda_audio_init_micro(HDACodecDevice *hda, Error **errp)
hda_audio_init(hda, desc, errp);
}
-static void hda_audio_base_class_init(ObjectClass *klass, void *data)
+static void hda_audio_base_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
@@ -910,7 +909,7 @@ static void hda_audio_base_class_init(ObjectClass *klass, void *data)
k->command = hda_audio_command;
k->stream = hda_audio_stream;
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->reset = hda_audio_reset;
+ device_class_set_legacy_reset(dc, hda_audio_reset);
dc->vmsd = &vmstate_hda_audio;
device_class_set_props(dc, hda_audio_properties);
}
@@ -923,7 +922,7 @@ static const TypeInfo hda_audio_info = {
.abstract = true,
};
-static void hda_audio_output_class_init(ObjectClass *klass, void *data)
+static void hda_audio_output_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
@@ -938,7 +937,7 @@ static const TypeInfo hda_audio_output_info = {
.class_init = hda_audio_output_class_init,
};
-static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
+static void hda_audio_duplex_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
@@ -953,7 +952,7 @@ static const TypeInfo hda_audio_duplex_info = {
.class_init = hda_audio_duplex_class_init,
};
-static void hda_audio_micro_class_init(ObjectClass *klass, void *data)
+static void hda_audio_micro_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 9c54e60..b256c8c 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -30,16 +30,15 @@
#include "intel-hda.h"
#include "migration/vmstate.h"
#include "intel-hda-defs.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qapi/error.h"
#include "qom/object.h"
/* --------------------------------------------------------------------- */
/* hda bus */
-static Property hda_props[] = {
+static const Property hda_props[] = {
DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
- DEFINE_PROP_END_OF_LIST()
};
static const TypeInfo hda_codec_bus_info = {
@@ -1215,14 +1214,13 @@ static const VMStateDescription vmstate_intel_hda = {
}
};
-static Property intel_hda_properties[] = {
+static const Property intel_hda_properties[] = {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
DEFINE_PROP_ON_OFF_AUTO("msi", IntelHDAState, msi, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void intel_hda_class_init(ObjectClass *klass, void *data)
+static void intel_hda_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1231,12 +1229,12 @@ static void intel_hda_class_init(ObjectClass *klass, void *data)
k->exit = intel_hda_exit;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
- dc->reset = intel_hda_reset;
+ device_class_set_legacy_reset(dc, intel_hda_reset);
dc->vmsd = &vmstate_intel_hda;
device_class_set_props(dc, intel_hda_properties);
}
-static void intel_hda_class_init_ich6(ObjectClass *klass, void *data)
+static void intel_hda_class_init_ich6(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1247,7 +1245,7 @@ static void intel_hda_class_init_ich6(ObjectClass *klass, void *data)
dc->desc = "Intel HD Audio Controller (ich6)";
}
-static void intel_hda_class_init_ich9(ObjectClass *klass, void *data)
+static void intel_hda_class_init_ich9(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1264,7 +1262,7 @@ static const TypeInfo intel_hda_info = {
.instance_size = sizeof(IntelHDAState),
.class_init = intel_hda_class_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -1282,7 +1280,7 @@ static const TypeInfo intel_hda_info_ich9 = {
.class_init = intel_hda_class_init_ich9,
};
-static void hda_codec_device_class_init(ObjectClass *klass, void *data)
+static void hda_codec_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = hda_codec_dev_realize;
diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c
index cc28544..c5c79d0 100644
--- a/hw/audio/marvell_88w8618.c
+++ b/hw/audio/marvell_88w8618.c
@@ -66,7 +66,7 @@ static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
{
mv88w8618_audio_state *s = opaque;
int16_t *codec_buffer;
- int8_t buf[4096];
+ QEMU_UNINITIALIZED int8_t buf[4096];
int8_t *mem_buffer;
int pos, block_size;
@@ -287,12 +287,12 @@ static const VMStateDescription mv88w8618_audio_vmsd = {
}
};
-static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
+static void mv88w8618_audio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mv88w8618_audio_realize;
- dc->reset = mv88w8618_audio_reset;
+ device_class_set_legacy_reset(dc, mv88w8618_audio_reset);
dc->vmsd = &mv88w8618_audio_vmsd;
dc->user_creatable = false;
}
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
index a4b89f1..a419161 100644
--- a/hw/audio/pcspk.c
+++ b/hw/audio/pcspk.c
@@ -215,14 +215,13 @@ static const VMStateDescription vmstate_spk = {
}
};
-static Property pcspk_properties[] = {
+static const Property pcspk_properties[] = {
DEFINE_AUDIO_PROPERTIES(PCSpkState, card),
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, 0x61),
DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pcspk_class_initfn(ObjectClass *klass, void *data)
+static void pcspk_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c
index b435208..5d9d6c1 100644
--- a/hw/audio/pl041.c
+++ b/hw/audio/pl041.c
@@ -625,21 +625,20 @@ static const VMStateDescription vmstate_pl041 = {
}
};
-static Property pl041_device_properties[] = {
+static const Property pl041_device_properties[] = {
DEFINE_AUDIO_PROPERTIES(PL041State, codec.card),
/* Non-compact FIFO depth property */
DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth,
DEFAULT_FIFO_DEPTH),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pl041_device_class_init(ObjectClass *klass, void *data)
+static void pl041_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pl041_realize;
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->reset = pl041_device_reset;
+ device_class_set_legacy_reset(dc, pl041_device_reset);
dc->vmsd = &vmstate_pl041;
device_class_set_props(dc, pl041_device_properties);
}
diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c
index fd76e78..bac6411 100644
--- a/hw/audio/sb16.c
+++ b/hw/audio/sb16.c
@@ -1181,7 +1181,7 @@ static int write_audio (SB16State *s, int nchan, int dma_pos,
IsaDma *isa_dma = nchan == s->dma ? s->isa_dma : s->isa_hdma;
IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma);
int temp, net;
- uint8_t tmpbuf[4096];
+ QEMU_UNINITIALIZED uint8_t tmpbuf[4096];
temp = len;
net = 0;
@@ -1440,17 +1440,16 @@ static void sb16_realizefn (DeviceState *dev, Error **errp)
s->can_write = 1;
}
-static Property sb16_properties[] = {
+static const Property sb16_properties[] = {
DEFINE_AUDIO_PROPERTIES(SB16State, card),
DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
- DEFINE_PROP_END_OF_LIST (),
};
-static void sb16_class_initfn (ObjectClass *klass, void *data)
+static void sb16_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c
index b387b0e..d18fd9f 100644
--- a/hw/audio/soundhw.c
+++ b/hw/audio/soundhw.c
@@ -88,7 +88,8 @@ void select_soundhw(const char *name, const char *audiodev)
struct soundhw *c;
if (selected) {
- error_setg(&error_fatal, "only one -soundhw option is allowed");
+ error_report("only one -soundhw option is allowed");
+ exit(1);
}
for (c = soundhw; c->name; ++c) {
diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index b1870ff..b8ef572 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -41,7 +41,6 @@ asc_update_irq(int irq, int a, int b) "set IRQ to %d (A: 0x%x B: 0x%x)"
#virtio-snd.c
virtio_snd_get_config(void *vdev, uint32_t jacks, uint32_t streams, uint32_t chmaps) "snd %p: get_config jacks=%"PRIu32" streams=%"PRIu32" chmaps=%"PRIu32""
-virtio_snd_set_config(void *vdev, uint32_t jacks, uint32_t new_jacks, uint32_t streams, uint32_t new_streams, uint32_t chmaps, uint32_t new_chmaps) "snd %p: set_config jacks from %"PRIu32"->%"PRIu32", streams from %"PRIu32"->%"PRIu32", chmaps from %"PRIu32"->%"PRIu32
virtio_snd_get_features(void *vdev, uint64_t features) "snd %p: get_features 0x%"PRIx64
virtio_snd_vm_state_running(void) "vm state running"
virtio_snd_vm_state_stopped(void) "vm state stopped"
diff --git a/hw/audio/via-ac97.c b/hw/audio/via-ac97.c
index 4c127a1..d5231e1 100644
--- a/hw/audio/via-ac97.c
+++ b/hw/audio/via-ac97.c
@@ -175,7 +175,7 @@ static void out_cb(void *opaque, int avail)
ViaAC97SGDChannel *c = &s->aur;
int temp, to_copy, copied;
bool stop = false;
- uint8_t tmpbuf[4096];
+ QEMU_UNINITIALIZED uint8_t tmpbuf[4096];
if (c->stat & STAT_PAUSED) {
return;
@@ -459,12 +459,11 @@ static void via_ac97_exit(PCIDevice *dev)
AUD_remove_card(&s->card);
}
-static Property via_ac97_properties[] = {
+static const Property via_ac97_properties[] = {
DEFINE_AUDIO_PROPERTIES(ViaAC97State, card),
- DEFINE_PROP_END_OF_LIST(),
};
-static void via_ac97_class_init(ObjectClass *klass, void *data)
+static void via_ac97_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -478,7 +477,7 @@ static void via_ac97_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, via_ac97_properties);
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "VIA AC97";
- dc->reset = via_ac97_reset;
+ device_class_set_legacy_reset(dc, via_ac97_reset);
/* Reason: Part of a south bridge chip */
dc->user_creatable = false;
}
@@ -488,7 +487,7 @@ static const TypeInfo via_ac97_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(ViaAC97State),
.class_init = via_ac97_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -502,7 +501,7 @@ static void via_mc97_realize(PCIDevice *pci_dev, Error **errp)
pci_set_long(pci_dev->config + PCI_INTERRUPT_PIN, 0x03);
}
-static void via_mc97_class_init(ObjectClass *klass, void *data)
+static void via_mc97_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -523,7 +522,7 @@ static const TypeInfo via_mc97_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = via_mc97_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/audio/virtio-snd-pci.c b/hw/audio/virtio-snd-pci.c
index ab58c64..9eb0007 100644
--- a/hw/audio/virtio-snd-pci.c
+++ b/hw/audio/virtio-snd-pci.c
@@ -27,11 +27,10 @@ struct VirtIOSoundPCI {
VirtIOSound vdev;
};
-static Property virtio_snd_pci_properties[] = {
+static const Property virtio_snd_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -43,7 +42,7 @@ static void virtio_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void virtio_snd_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_snd_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index d1cf5eb..eca3319 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -20,8 +20,7 @@
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qemu/lockable.h"
-#include "exec/tswap.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "trace.h"
#include "qapi/error.h"
#include "hw/audio/virtio-snd.h"
@@ -78,7 +77,7 @@ static const VMStateDescription vmstate_virtio_snd = {
},
};
-static Property virtio_snd_properties[] = {
+static const Property virtio_snd_properties[] = {
DEFINE_AUDIO_PROPERTIES(VirtIOSound, card),
DEFINE_PROP_UINT32("jacks", VirtIOSound, snd_conf.jacks,
VIRTIO_SOUND_JACK_DEFAULT),
@@ -86,7 +85,6 @@ static Property virtio_snd_properties[] = {
VIRTIO_SOUND_STREAM_DEFAULT),
DEFINE_PROP_UINT32("chmaps", VirtIOSound, snd_conf.chmaps,
VIRTIO_SOUND_CHMAP_DEFAULT),
- DEFINE_PROP_END_OF_LIST(),
};
static void
@@ -108,29 +106,6 @@ virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
}
static void
-virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
-{
- VirtIOSound *s = VIRTIO_SND(vdev);
- const virtio_snd_config *sndconfig =
- (const virtio_snd_config *)config;
-
-
- trace_virtio_snd_set_config(vdev,
- s->snd_conf.jacks,
- sndconfig->jacks,
- s->snd_conf.streams,
- sndconfig->streams,
- s->snd_conf.chmaps,
- sndconfig->chmaps);
-
- memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config));
- le32_to_cpus(&s->snd_conf.jacks);
- le32_to_cpus(&s->snd_conf.streams);
- le32_to_cpus(&s->snd_conf.chmaps);
-
-}
-
-static void
virtio_snd_pcm_buffer_free(VirtIOSoundPCMBuffer *buffer)
{
g_free(buffer->elem);
@@ -1386,7 +1361,7 @@ static void virtio_snd_reset(VirtIODevice *vdev)
}
}
-static void virtio_snd_class_init(ObjectClass *klass, void *data)
+static void virtio_snd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -1400,7 +1375,6 @@ static void virtio_snd_class_init(ObjectClass *klass, void *data)
vdc->realize = virtio_snd_realize;
vdc->unrealize = virtio_snd_unrealize;
vdc->get_config = virtio_snd_get_config;
- vdc->set_config = virtio_snd_set_config;
vdc->get_features = get_features;
vdc->reset = virtio_snd_reset;
vdc->legacy_features = 0;
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
index ec2c4e1..2846b55 100644
--- a/hw/audio/wm8750.c
+++ b/hw/audio/wm8750.c
@@ -706,12 +706,11 @@ void wm8750_set_bclk_in(void *opaque, int new_hz)
wm8750_clk_update(s, 1);
}
-static Property wm8750_properties[] = {
+static const Property wm8750_properties[] = {
DEFINE_AUDIO_PROPERTIES(WM8750State, card),
- DEFINE_PROP_END_OF_LIST(),
};
-static void wm8750_class_init(ObjectClass *klass, void *data)
+static void wm8750_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
diff --git a/hw/avr/arduino.c b/hw/avr/arduino.c
index 48ef478..e166ca1 100644
--- a/hw/avr/arduino.c
+++ b/hw/avr/arduino.c
@@ -56,7 +56,7 @@ static void arduino_machine_init(MachineState *machine)
}
}
-static void arduino_machine_class_init(ObjectClass *oc, void *data)
+static void arduino_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -69,7 +69,7 @@ static void arduino_machine_class_init(ObjectClass *oc, void *data)
mc->no_parallel = 1;
}
-static void arduino_duemilanove_class_init(ObjectClass *oc, void *data)
+static void arduino_duemilanove_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
@@ -84,7 +84,7 @@ static void arduino_duemilanove_class_init(ObjectClass *oc, void *data)
amc->xtal_hz = 16 * 1000 * 1000;
};
-static void arduino_uno_class_init(ObjectClass *oc, void *data)
+static void arduino_uno_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
@@ -99,7 +99,7 @@ static void arduino_uno_class_init(ObjectClass *oc, void *data)
amc->xtal_hz = 16 * 1000 * 1000;
};
-static void arduino_mega_class_init(ObjectClass *oc, void *data)
+static void arduino_mega_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
@@ -114,7 +114,7 @@ static void arduino_mega_class_init(ObjectClass *oc, void *data)
amc->xtal_hz = 16 * 1000 * 1000;
};
-static void arduino_mega2560_class_init(ObjectClass *oc, void *data)
+static void arduino_mega2560_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
index 31c8992..95b6da5 100644
--- a/hw/avr/atmega.c
+++ b/hw/avr/atmega.c
@@ -12,13 +12,15 @@
#include "qemu/module.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
+#include "exec/target_page.h"
+#include "system/memory.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "qom/object.h"
#include "hw/misc/unimp.h"
+#include "migration/vmstate.h"
#include "atmega.h"
enum AtmegaPeripheral {
@@ -224,8 +226,6 @@ static void atmega_realize(DeviceState *dev, Error **errp)
char *devname;
size_t i;
- assert(mc->io_size <= 0x200);
-
if (!s->xtal_freq_hz) {
error_setg(errp, "\"xtal-frequency-hz\" property must be provided.");
return;
@@ -240,11 +240,37 @@ static void atmega_realize(DeviceState *dev, Error **errp)
qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
cpudev = DEVICE(&s->cpu);
- /* SRAM */
- memory_region_init_ram(&s->sram, OBJECT(dev), "sram", mc->sram_size,
- &error_abort);
- memory_region_add_subregion(get_system_memory(),
- OFFSET_DATA + mc->io_size, &s->sram);
+ /*
+ * SRAM
+ *
+ * Softmmu is not able mix i/o and ram on the same page.
+ * Therefore in all cases, the first page exclusively contains i/o.
+ *
+ * If the MCU's i/o region matches the page size, then we can simply
+ * allocate all ram starting at the second page. Otherwise, we must
+ * allocate some ram as i/o to complete the first page.
+ */
+ assert(mc->io_size == 0x100 || mc->io_size == 0x200);
+ if (mc->io_size >= TARGET_PAGE_SIZE) {
+ memory_region_init_ram(&s->sram, OBJECT(dev), "sram", mc->sram_size,
+ &error_abort);
+ memory_region_add_subregion(get_system_memory(),
+ OFFSET_DATA + mc->io_size, &s->sram);
+ } else {
+ int sram_io_size = TARGET_PAGE_SIZE - mc->io_size;
+ void *sram_io_mem = g_malloc0(sram_io_size);
+
+ memory_region_init_ram_device_ptr(&s->sram_io, OBJECT(dev), "sram-as-io",
+ sram_io_size, sram_io_mem);
+ memory_region_add_subregion(get_system_memory(),
+ OFFSET_DATA + mc->io_size, &s->sram_io);
+ vmstate_register_ram(&s->sram_io, dev);
+
+ memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
+ mc->sram_size - sram_io_size, &error_abort);
+ memory_region_add_subregion(get_system_memory(),
+ OFFSET_DATA + TARGET_PAGE_SIZE, &s->sram);
+ }
/* Flash */
memory_region_init_rom(&s->flash, OBJECT(dev),
@@ -355,13 +381,12 @@ static void atmega_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("avr-eeprom", OFFSET_DATA + 0x03f, 3);
}
-static Property atmega_props[] = {
+static const Property atmega_props[] = {
DEFINE_PROP_UINT64("xtal-frequency-hz", AtmegaMcuState,
xtal_freq_hz, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void atmega_class_init(ObjectClass *oc, void *data)
+static void atmega_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -371,7 +396,7 @@ static void atmega_class_init(ObjectClass *oc, void *data)
dc->user_creatable = false;
}
-static void atmega168_class_init(ObjectClass *oc, void *data)
+static void atmega168_class_init(ObjectClass *oc, const void *data)
{
AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc);
@@ -386,7 +411,7 @@ static void atmega168_class_init(ObjectClass *oc, void *data)
amc->dev = dev168_328;
};
-static void atmega328_class_init(ObjectClass *oc, void *data)
+static void atmega328_class_init(ObjectClass *oc, const void *data)
{
AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc);
@@ -401,7 +426,7 @@ static void atmega328_class_init(ObjectClass *oc, void *data)
amc->dev = dev168_328;
};
-static void atmega1280_class_init(ObjectClass *oc, void *data)
+static void atmega1280_class_init(ObjectClass *oc, const void *data)
{
AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc);
@@ -416,7 +441,7 @@ static void atmega1280_class_init(ObjectClass *oc, void *data)
amc->dev = dev1280_2560;
};
-static void atmega2560_class_init(ObjectClass *oc, void *data)
+static void atmega2560_class_init(ObjectClass *oc, const void *data)
{
AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc);
diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h
index a99ee15..9ac4678 100644
--- a/hw/avr/atmega.h
+++ b/hw/avr/atmega.h
@@ -41,6 +41,7 @@ struct AtmegaMcuState {
MemoryRegion flash;
MemoryRegion eeprom;
MemoryRegion sram;
+ MemoryRegion sram_io;
DeviceState *io;
AVRMaskState pwr[POWER_MAX];
AVRUsartState usart[USART_MAX];
diff --git a/hw/avr/boot.c b/hw/avr/boot.c
index 617f3a1..e5a29c7 100644
--- a/hw/avr/boot.c
+++ b/hw/avr/boot.c
@@ -71,11 +71,9 @@ bool avr_load_firmware(AVRCPU *cpu, MachineState *ms,
return false;
}
- bytes_loaded = load_elf_ram_sym(filename,
- NULL, NULL, NULL,
- &entry, NULL, NULL,
- &e_flags, 0, EM_AVR, 0, 0,
- NULL, true, NULL);
+ bytes_loaded = load_elf_as(filename, NULL, NULL, NULL,
+ &entry, NULL, NULL,
+ &e_flags, ELFDATA2LSB, EM_AVR, 0, 0, NULL);
if (bytes_loaded >= 0) {
/* If ELF file is provided, determine CPU type reading ELF e_flags. */
const char *elf_cpu = avr_elf_e_flags_to_cpu_type(e_flags);
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 9e8f28f..737dbcd 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -13,24 +13,12 @@ config FDC_SYSBUS
config SSI_M25P80
bool
-config NAND
- bool
-
config PFLASH_CFI01
bool
config PFLASH_CFI02
bool
-config ECC
- bool
-
-config ONENAND
- bool
-
-config TC58128
- bool
-
config VIRTIO_BLK
bool
default y
diff --git a/hw/block/block.c b/hw/block/block.c
index 3ceca7d..2e10611 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -9,9 +9,10 @@
#include "qemu/osdep.h"
#include "block/block_int-common.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/block-backend.h"
+#include "system/blockdev.h"
+#include "system/block-backend.h"
#include "hw/block/block.h"
+#include "migration/cpr.h"
#include "qapi/error.h"
#include "qapi/qapi-types-block.h"
@@ -66,6 +67,10 @@ bool blk_check_size_and_read_all(BlockBackend *blk, DeviceState *dev,
int ret;
g_autofree char *dev_id = NULL;
+ if (cpr_is_incoming()) {
+ return true;
+ }
+
blk_len = blk_getlength(blk);
if (blk_len < 0) {
error_setg_errno(errp, -blk_len,
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
index 98501e6..48c2e31 100644
--- a/hw/block/dataplane/xen-block.c
+++ b/hw/block/dataplane/xen-block.c
@@ -27,8 +27,8 @@
#include "hw/xen/xen.h"
#include "hw/block/xen_blkif.h"
#include "hw/xen/interface/io/ring.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/iothread.h"
+#include "system/block-backend.h"
+#include "system/iothread.h"
#include "xen-block.h"
typedef struct XenBlockRequest {
diff --git a/hw/block/dataplane/xen-block.h b/hw/block/dataplane/xen-block.h
index 7b8e9df..eb70327 100644
--- a/hw/block/dataplane/xen-block.h
+++ b/hw/block/dataplane/xen-block.h
@@ -10,7 +10,7 @@
#include "hw/block/block.h"
#include "hw/xen/xen-bus.h"
-#include "sysemu/iothread.h"
+#include "system/iothread.h"
typedef struct XenBlockDataPlane XenBlockDataPlane;
diff --git a/hw/block/ecc.c b/hw/block/ecc.c
deleted file mode 100644
index ed889a4..0000000
--- a/hw/block/ecc.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Calculate Error-correcting Codes. Used by NAND Flash controllers
- * (not by NAND chips).
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "migration/vmstate.h"
-#include "hw/block/flash.h"
-
-/*
- * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux.
- */
-static const uint8_t nand_ecc_precalc_table[] = {
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
-};
-
-/* Update ECC parity count. */
-uint8_t ecc_digest(ECCState *s, uint8_t sample)
-{
- uint8_t idx = nand_ecc_precalc_table[sample];
-
- s->cp ^= idx & 0x3f;
- if (idx & 0x40) {
- s->lp[0] ^= ~s->count;
- s->lp[1] ^= s->count;
- }
- s->count ++;
-
- return sample;
-}
-
-/* Reinitialise the counters. */
-void ecc_reset(ECCState *s)
-{
- s->lp[0] = 0x0000;
- s->lp[1] = 0x0000;
- s->cp = 0x00;
- s->count = 0;
-}
-
-/* Save/restore */
-const VMStateDescription vmstate_ecc_state = {
- .name = "ecc-state",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(cp, ECCState),
- VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
- VMSTATE_UINT16(count, ECCState),
- VMSTATE_END_OF_LIST(),
- },
-};
diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c
index 796835f..6d1790e 100644
--- a/hw/block/fdc-isa.c
+++ b/hw/block/fdc-isa.c
@@ -39,10 +39,10 @@
#include "hw/qdev-properties-system.h"
#include "migration/vmstate.h"
#include "hw/block/block.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "exec/ioport.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
+#include "system/system.h"
+#include "system/ioport.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
@@ -283,7 +283,7 @@ static const VMStateDescription vmstate_isa_fdc = {
}
};
-static Property isa_fdc_properties[] = {
+static const Property isa_fdc_properties[] = {
DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
@@ -296,10 +296,9 @@ static Property isa_fdc_properties[] = {
DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
FloppyDriveType),
- DEFINE_PROP_END_OF_LIST(),
};
-static void isabus_fdc_class_init(ObjectClass *klass, void *data)
+static void isabus_fdc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
@@ -307,7 +306,7 @@ static void isabus_fdc_class_init(ObjectClass *klass, void *data)
dc->desc = "virtual floppy controller";
dc->realize = isabus_fdc_realize;
dc->fw_name = "fdc";
- dc->reset = fdctrl_external_reset_isa;
+ device_class_set_legacy_reset(dc, fdctrl_external_reset_isa);
dc->vmsd = &vmstate_isa_fdc;
adevc->build_dev_aml = build_fdc_aml;
device_class_set_props(dc, isa_fdc_properties);
@@ -332,7 +331,7 @@ static const TypeInfo isa_fdc_info = {
.instance_size = sizeof(FDCtrlISABus),
.class_init = isabus_fdc_class_init,
.instance_init = isabus_fdc_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/block/fdc-sysbus.c b/hw/block/fdc-sysbus.c
index 035bc08..956860a 100644
--- a/hw/block/fdc-sysbus.c
+++ b/hw/block/fdc-sysbus.c
@@ -26,7 +26,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qom/object.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/sysbus.h"
#include "hw/block/fdc.h"
#include "migration/vmstate.h"
@@ -176,12 +176,12 @@ static const VMStateDescription vmstate_sysbus_fdc = {
}
};
-static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data)
+static void sysbus_fdc_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sysbus_fdc_realize;
- dc->reset = fdctrl_external_reset_sysbus;
+ device_class_set_legacy_reset(dc, fdctrl_external_reset_sysbus);
dc->vmsd = &vmstate_sysbus_fdc;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
@@ -196,7 +196,7 @@ static const TypeInfo sysbus_fdc_common_typeinfo = {
.class_size = sizeof(FDCtrlSysBusClass),
};
-static Property sysbus_fdc_properties[] = {
+static const Property sysbus_fdc_properties[] = {
DEFINE_PROP_SIGNED("fdtypeA", FDCtrlSysBus, state.qdev_for_drives[0].type,
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
FloppyDriveType),
@@ -206,10 +206,9 @@ static Property sysbus_fdc_properties[] = {
DEFINE_PROP_SIGNED("fallback", FDCtrlSysBus, state.fallback,
FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
FloppyDriveType),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
+static void sysbus_fdc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -223,17 +222,16 @@ static const TypeInfo sysbus_fdc_typeinfo = {
.class_init = sysbus_fdc_class_init,
};
-static Property sun4m_fdc_properties[] = {
+static const Property sun4m_fdc_properties[] = {
DEFINE_PROP_SIGNED("fdtype", FDCtrlSysBus, state.qdev_for_drives[0].type,
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
FloppyDriveType),
DEFINE_PROP_SIGNED("fallback", FDCtrlSysBus, state.fallback,
FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
FloppyDriveType),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
+static void sun4m_fdc_class_init(ObjectClass *klass, const void *data)
{
FDCtrlSysBusClass *sbdc = SYSBUS_FDC_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 6dd94e9..d0f08c7 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -39,9 +39,9 @@
#include "hw/qdev-properties-system.h"
#include "migration/vmstate.h"
#include "hw/block/block.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
+#include "system/system.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
@@ -454,13 +454,12 @@ struct FloppyDrive {
FloppyDriveType type;
};
-static Property floppy_drive_properties[] = {
+static const Property floppy_drive_properties[] = {
DEFINE_PROP_UINT32("unit", FloppyDrive, unit, -1),
DEFINE_BLOCK_PROPERTIES(FloppyDrive, conf),
DEFINE_PROP_SIGNED("drive-type", FloppyDrive, type,
FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
FloppyDriveType),
- DEFINE_PROP_END_OF_LIST(),
};
static void floppy_drive_realize(DeviceState *qdev, Error **errp)
@@ -554,7 +553,7 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
fd_revalidate(drive);
}
-static void floppy_drive_class_init(ObjectClass *klass, void *data)
+static void floppy_drive_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = floppy_drive_realize;
diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c
index 2b0af44..f3939e7 100644
--- a/hw/block/hd-geometry.c
+++ b/hw/block/hd-geometry.c
@@ -31,7 +31,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qapi/qapi-types-block.h"
#include "qemu/bswap.h"
#include "hw/block/block.h"
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 0b94af3..a5336d9 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -23,7 +23,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "hw/block/block.h"
#include "hw/block/flash.h"
#include "hw/qdev-properties.h"
@@ -61,7 +61,8 @@ typedef struct FlashPartInfo {
*/
uint8_t id[SPI_NOR_MAX_ID_LEN];
uint8_t id_len;
- /* there is confusion between manufacturers as to what a sector is. In this
+ /*
+ * there is confusion between manufacturers as to what a sector is. In this
* device model, a "sector" is the size that is erased by the ERASE_SECTOR
* command (opcode 0xd8).
*/
@@ -168,7 +169,7 @@ typedef struct FlashPartInfo {
/*
* Spansion read mode command length in bytes,
* the mode is currently not supported.
-*/
+ */
#define SPANSION_CONTINUOUS_READ_MODE_CMD_LEN 1
#define WINBOND_CONTINUOUS_READ_MODE_CMD_LEN 1
@@ -189,7 +190,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("at45db081d", 0x1f2500, 0, 64 << 10, 16, ER_4K) },
- /* Atmel EEPROMS - it is assumed, that don't care bit in command
+ /*
+ * Atmel EEPROMS - it is assumed, that don't care bit in command
* is set to 0. Block protection is not supported.
*/
{ INFO("at25128a-nonjedec", 0x0, 0, 1, 131072, EEPROM) },
@@ -266,7 +268,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
{ INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024,
- ER_4K | ER_32K, 2) },
+ ER_4K | ER_32K, 2),
+ .sfdp_read = m25p80_sfdp_mt35xu01g },
{ INFO_STACKED("mt35xu02gbba", 0x2c5b1c, 0x104100, 128 << 10, 2048,
ER_4K | ER_32K, 4),
.sfdp_read = m25p80_sfdp_mt35xu02g },
@@ -274,10 +277,13 @@ static const FlashPartInfo known_devices[] = {
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
{ INFO_STACKED("mt25qu01g", 0x20bb21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
- { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
- { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
- /* Spansion -- single (large) sector size only, at least
+ /*
+ * Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
{ INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) },
@@ -350,7 +356,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
- { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
+ { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K),
+ .sfdp_read = m25p80_sfdp_w25q80bl },
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K),
.sfdp_read = m25p80_sfdp_w25q256 },
{ INFO("w25q512jv", 0xef4020, 0, 64 << 10, 1024, ER_4K),
@@ -424,6 +431,11 @@ typedef enum {
RDCR_EQIO = 0x35,
RSTQIO = 0xf5,
+ /*
+ * Winbond: 0x31 - write status register 2
+ */
+ WRSR2 = 0x31,
+
RNVCR = 0xB5,
WNVCR = 0xB1,
@@ -516,7 +528,7 @@ struct Flash {
struct M25P80Class {
SSIPeripheralClass parent_class;
- FlashPartInfo *pi;
+ const FlashPartInfo *pi;
};
OBJECT_DECLARE_TYPE(Flash, M25P80Class, M25P80)
@@ -548,7 +560,8 @@ static void blk_sync_complete(void *opaque, int ret)
qemu_iovec_destroy(iov);
g_free(iov);
- /* do nothing. Masters do not directly interact with the backing store,
+ /*
+ * do nothing. Masters do not directly interact with the backing store,
* only the working copy so no mutexing required.
*/
}
@@ -814,6 +827,15 @@ static void complete_collecting_data(Flash *s)
s->write_enable = false;
}
break;
+ case WRSR2:
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->quad_enable = !!(s->data[0] & 0x02);
+ break;
+ default:
+ break;
+ }
+ break;
case BRWR:
case EXTEND_ADDR_WRITE:
s->ear = s->data[0];
@@ -1273,7 +1295,31 @@ static void decode_new_cmd(Flash *s, uint32_t value)
}
s->pos = 0;
break;
+ case WRSR2:
+ /*
+ * If WP# is low and status_register_write_disabled is high,
+ * status register writes are disabled.
+ * This is also called "hardware protected mode" (HPM). All other
+ * combinations of the two states are called "software protected mode"
+ * (SPM), and status register writes are permitted.
+ */
+ if ((s->wp_level == 0 && s->status_register_write_disabled)
+ || !s->write_enable) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: Status register 2 write is disabled!\n");
+ break;
+ }
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->needed_bytes = 1;
+ s->state = STATE_COLLECTING_DATA;
+ s->pos = 0;
+ break;
+ default:
+ break;
+ }
+ break;
case WRDI:
s->write_enable = false;
if (get_man(s) == MAN_SST) {
@@ -1674,7 +1720,7 @@ static int m25p80_pre_save(void *opaque)
return 0;
}
-static Property m25p80_properties[] = {
+static const Property m25p80_properties[] = {
/* This is default value for Micron flash */
DEFINE_PROP_BOOL("write-enable", Flash, write_enable, false),
DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF),
@@ -1683,7 +1729,6 @@ static Property m25p80_properties[] = {
DEFINE_PROP_UINT8("spansion-cr3nv", Flash, spansion_cr3nv, 0x2),
DEFINE_PROP_UINT8("spansion-cr4nv", Flash, spansion_cr4nv, 0x10),
DEFINE_PROP_DRIVE("drive", Flash, blk),
- DEFINE_PROP_END_OF_LIST(),
};
static int m25p80_pre_load(void *opaque)
@@ -1812,7 +1857,7 @@ static const VMStateDescription vmstate_m25p80 = {
}
};
-static void m25p80_class_init(ObjectClass *klass, void *data)
+static void m25p80_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
@@ -1824,8 +1869,10 @@ static void m25p80_class_init(ObjectClass *klass, void *data)
k->cs_polarity = SSI_CS_LOW;
dc->vmsd = &vmstate_m25p80;
device_class_set_props(dc, m25p80_properties);
- dc->reset = m25p80_reset;
+ device_class_set_legacy_reset(dc, m25p80_reset);
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
mc->pi = data;
+ dc->desc = "Serial Flash";
}
static const TypeInfo m25p80_info = {
@@ -1842,13 +1889,13 @@ static void m25p80_register_types(void)
type_register_static(&m25p80_info);
for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
- TypeInfo ti = {
+ const TypeInfo ti = {
.name = known_devices[i].part_name,
.parent = TYPE_M25P80,
.class_init = m25p80_class_init,
- .class_data = (void *)&known_devices[i],
+ .class_data = &known_devices[i],
};
- type_register(&ti);
+ type_register_static(&ti);
}
}
diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c
index 6ee2cfa..a03a291 100644
--- a/hw/block/m25p80_sfdp.c
+++ b/hw/block/m25p80_sfdp.c
@@ -57,6 +57,43 @@ static const uint8_t sfdp_n25q256a[] = {
};
define_sfdp_read(n25q256a);
+static const uint8_t sfdp_mt35xu01g[] = {
+ 0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff,
+ 0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff,
+ 0x84, 0x00, 0x01, 0x02, 0x80, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xe5, 0x20, 0x8a, 0xff, 0xff, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x11, 0xd8,
+ 0x0f, 0x52, 0x00, 0x00, 0x24, 0x5a, 0x99, 0x00,
+ 0x8b, 0x8e, 0x03, 0xe1, 0xac, 0x01, 0x27, 0x38,
+ 0x7a, 0x75, 0x7a, 0x75, 0xfb, 0xbd, 0xd5, 0x5c,
+ 0x00, 0x00, 0x70, 0xff, 0x81, 0xb0, 0x38, 0x36,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x43, 0x0e, 0xff, 0xff, 0x21, 0xdc, 0x5c, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+define_sfdp_read(mt35xu01g);
+
static const uint8_t sfdp_mt35xu02g[] = {
0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff,
0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff,
@@ -367,6 +404,42 @@ static const uint8_t sfdp_w25q01jvq[] = {
};
define_sfdp_read(w25q01jvq);
+static const uint8_t sfdp_w25q80bl[] = {
+ 0x53, 0x46, 0x44, 0x50, 0x05, 0x01, 0x00, 0xff,
+ 0x00, 0x05, 0x01, 0x10, 0x80, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xe5, 0x20, 0xf1, 0xff, 0xff, 0xff, 0x7f, 0x00,
+ 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x42, 0xbb,
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x0f, 0x52,
+ 0x10, 0xd8, 0x00, 0x00, 0x23, 0x02, 0xa6, 0x00,
+ 0x81, 0x6c, 0x14, 0xa7, 0xed, 0x61, 0x76, 0x33,
+ 0x7a, 0x75, 0x7a, 0x75, 0xf7, 0xa2, 0xd5, 0x5c,
+ 0x00, 0xf7, 0x1d, 0xff, 0xe9, 0x30, 0xc0, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+define_sfdp_read(w25q80bl);
+
/*
* Integrated Silicon Solution (ISSI)
*/
diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h
index 1733b56..3578568 100644
--- a/hw/block/m25p80_sfdp.h
+++ b/hw/block/m25p80_sfdp.h
@@ -16,6 +16,7 @@
#define M25P80_SFDP_MAX_SIZE (1 << 24)
uint8_t m25p80_sfdp_n25q256a(uint32_t addr);
+uint8_t m25p80_sfdp_mt35xu01g(uint32_t addr);
uint8_t m25p80_sfdp_mt35xu02g(uint32_t addr);
uint8_t m25p80_sfdp_mx25l25635e(uint32_t addr);
@@ -24,7 +25,7 @@ uint8_t m25p80_sfdp_mx66l1g45g(uint32_t addr);
uint8_t m25p80_sfdp_w25q256(uint32_t addr);
uint8_t m25p80_sfdp_w25q512jv(uint32_t addr);
-
+uint8_t m25p80_sfdp_w25q80bl(uint32_t addr);
uint8_t m25p80_sfdp_w25q01jvq(uint32_t addr);
uint8_t m25p80_sfdp_is25wp256(uint32_t addr);
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 8aa4dc3..6557044 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -3,19 +3,15 @@ system_ss.add(files(
'cdrom.c',
'hd-geometry.c'
))
-system_ss.add(when: 'CONFIG_ECC', if_true: files('ecc.c'))
system_ss.add(when: 'CONFIG_FDC', if_true: files('fdc.c'))
system_ss.add(when: 'CONFIG_FDC_ISA', if_true: files('fdc-isa.c'))
system_ss.add(when: 'CONFIG_FDC_SYSBUS', if_true: files('fdc-sysbus.c'))
-system_ss.add(when: 'CONFIG_NAND', if_true: files('nand.c'))
-system_ss.add(when: 'CONFIG_ONENAND', if_true: files('onenand.c'))
system_ss.add(when: 'CONFIG_PFLASH_CFI01', if_true: files('pflash_cfi01.c'))
system_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c'))
system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c'))
system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80_sfdp.c'))
system_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-block.c'))
-system_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c'))
diff --git a/hw/block/nand.c b/hw/block/nand.c
deleted file mode 100644
index e2433c2..0000000
--- a/hw/block/nand.c
+++ /dev/null
@@ -1,836 +0,0 @@
-/*
- * Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash
- * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
- * Samsung Electronic.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
- * datasheet from Micron Technology and "NAND02G-B2C" datasheet
- * from ST Microelectronics.
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#ifndef NAND_IO
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-# define NAND_CMD_READ0 0x00
-# define NAND_CMD_READ1 0x01
-# define NAND_CMD_READ2 0x50
-# define NAND_CMD_LPREAD2 0x30
-# define NAND_CMD_NOSERIALREAD2 0x35
-# define NAND_CMD_RANDOMREAD1 0x05
-# define NAND_CMD_RANDOMREAD2 0xe0
-# define NAND_CMD_READID 0x90
-# define NAND_CMD_RESET 0xff
-# define NAND_CMD_PAGEPROGRAM1 0x80
-# define NAND_CMD_PAGEPROGRAM2 0x10
-# define NAND_CMD_CACHEPROGRAM2 0x15
-# define NAND_CMD_BLOCKERASE1 0x60
-# define NAND_CMD_BLOCKERASE2 0xd0
-# define NAND_CMD_READSTATUS 0x70
-# define NAND_CMD_COPYBACKPRG1 0x85
-
-# define NAND_IOSTATUS_ERROR (1 << 0)
-# define NAND_IOSTATUS_PLANE0 (1 << 1)
-# define NAND_IOSTATUS_PLANE1 (1 << 2)
-# define NAND_IOSTATUS_PLANE2 (1 << 3)
-# define NAND_IOSTATUS_PLANE3 (1 << 4)
-# define NAND_IOSTATUS_READY (1 << 6)
-# define NAND_IOSTATUS_UNPROTCT (1 << 7)
-
-# define MAX_PAGE 0x800
-# define MAX_OOB 0x40
-
-typedef struct NANDFlashState NANDFlashState;
-struct NANDFlashState {
- DeviceState parent_obj;
-
- uint8_t manf_id, chip_id;
- uint8_t buswidth; /* in BYTES */
- int size, pages;
- int page_shift, oob_shift, erase_shift, addr_shift;
- uint8_t *storage;
- BlockBackend *blk;
- int mem_oob;
-
- uint8_t cle, ale, ce, wp, gnd;
-
- uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
- uint8_t *ioaddr;
- int iolen;
-
- uint32_t cmd;
- uint64_t addr;
- int addrlen;
- int status;
- int offset;
-
- void (*blk_write)(NANDFlashState *s);
- void (*blk_erase)(NANDFlashState *s);
- /*
- * Returns %true when block containing (@addr + @offset) is
- * successfully loaded, otherwise %false.
- */
- bool (*blk_load)(NANDFlashState *s, uint64_t addr, unsigned offset);
-
- uint32_t ioaddr_vmstate;
-};
-
-#define TYPE_NAND "nand"
-
-OBJECT_DECLARE_SIMPLE_TYPE(NANDFlashState, NAND)
-
-static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
-{
- /* Like memcpy() but we logical-AND the data into the destination */
- int i;
- for (i = 0; i < n; i++) {
- dest[i] &= src[i];
- }
-}
-
-# define NAND_NO_AUTOINCR 0x00000001
-# define NAND_BUSWIDTH_16 0x00000002
-# define NAND_NO_PADDING 0x00000004
-# define NAND_CACHEPRG 0x00000008
-# define NAND_COPYBACK 0x00000010
-# define NAND_IS_AND 0x00000020
-# define NAND_4PAGE_ARRAY 0x00000040
-# define NAND_NO_READRDY 0x00000100
-# define NAND_SAMSUNG_LP (NAND_NO_PADDING | NAND_COPYBACK)
-
-# define NAND_IO
-
-# define PAGE(addr) ((addr) >> ADDR_SHIFT)
-# define PAGE_START(page) (PAGE(page) * (NAND_PAGE_SIZE + OOB_SIZE))
-# define PAGE_MASK ((1 << ADDR_SHIFT) - 1)
-# define OOB_SHIFT (PAGE_SHIFT - 5)
-# define OOB_SIZE (1 << OOB_SHIFT)
-# define SECTOR(addr) ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
-# define SECTOR_OFFSET(addr) ((addr) & ((511 >> PAGE_SHIFT) << 8))
-
-# define NAND_PAGE_SIZE 256
-# define PAGE_SHIFT 8
-# define PAGE_SECTORS 1
-# define ADDR_SHIFT 8
-# include "nand.c"
-# define NAND_PAGE_SIZE 512
-# define PAGE_SHIFT 9
-# define PAGE_SECTORS 1
-# define ADDR_SHIFT 8
-# include "nand.c"
-# define NAND_PAGE_SIZE 2048
-# define PAGE_SHIFT 11
-# define PAGE_SECTORS 4
-# define ADDR_SHIFT 16
-# include "nand.c"
-
-/* Information based on Linux drivers/mtd/nand/raw/nand_ids.c */
-static const struct {
- int size;
- int width;
- int page_shift;
- int erase_shift;
- uint32_t options;
-} nand_flash_ids[0x100] = {
- [0 ... 0xff] = { 0 },
-
- [0x6b] = { 4, 8, 9, 4, 0 },
- [0xe3] = { 4, 8, 9, 4, 0 },
- [0xe5] = { 4, 8, 9, 4, 0 },
- [0xd6] = { 8, 8, 9, 4, 0 },
- [0xe6] = { 8, 8, 9, 4, 0 },
-
- [0x33] = { 16, 8, 9, 5, 0 },
- [0x73] = { 16, 8, 9, 5, 0 },
- [0x43] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x53] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x35] = { 32, 8, 9, 5, 0 },
- [0x75] = { 32, 8, 9, 5, 0 },
- [0x45] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x55] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x36] = { 64, 8, 9, 5, 0 },
- [0x76] = { 64, 8, 9, 5, 0 },
- [0x46] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x56] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x78] = { 128, 8, 9, 5, 0 },
- [0x39] = { 128, 8, 9, 5, 0 },
- [0x79] = { 128, 8, 9, 5, 0 },
- [0x72] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x49] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x74] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
- [0x59] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
-
- [0x71] = { 256, 8, 9, 5, 0 },
-
- /*
- * These are the new chips with large page size. The pagesize and the
- * erasesize is determined from the extended id bytes
- */
-# define LP_OPTIONS (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
-# define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
-
- /* 512 Megabit */
- [0xa2] = { 64, 8, 0, 0, LP_OPTIONS },
- [0xf2] = { 64, 8, 0, 0, LP_OPTIONS },
- [0xb2] = { 64, 16, 0, 0, LP_OPTIONS16 },
- [0xc2] = { 64, 16, 0, 0, LP_OPTIONS16 },
-
- /* 1 Gigabit */
- [0xa1] = { 128, 8, 0, 0, LP_OPTIONS },
- [0xf1] = { 128, 8, 0, 0, LP_OPTIONS },
- [0xb1] = { 128, 16, 0, 0, LP_OPTIONS16 },
- [0xc1] = { 128, 16, 0, 0, LP_OPTIONS16 },
-
- /* 2 Gigabit */
- [0xaa] = { 256, 8, 0, 0, LP_OPTIONS },
- [0xda] = { 256, 8, 0, 0, LP_OPTIONS },
- [0xba] = { 256, 16, 0, 0, LP_OPTIONS16 },
- [0xca] = { 256, 16, 0, 0, LP_OPTIONS16 },
-
- /* 4 Gigabit */
- [0xac] = { 512, 8, 0, 0, LP_OPTIONS },
- [0xdc] = { 512, 8, 0, 0, LP_OPTIONS },
- [0xbc] = { 512, 16, 0, 0, LP_OPTIONS16 },
- [0xcc] = { 512, 16, 0, 0, LP_OPTIONS16 },
-
- /* 8 Gigabit */
- [0xa3] = { 1024, 8, 0, 0, LP_OPTIONS },
- [0xd3] = { 1024, 8, 0, 0, LP_OPTIONS },
- [0xb3] = { 1024, 16, 0, 0, LP_OPTIONS16 },
- [0xc3] = { 1024, 16, 0, 0, LP_OPTIONS16 },
-
- /* 16 Gigabit */
- [0xa5] = { 2048, 8, 0, 0, LP_OPTIONS },
- [0xd5] = { 2048, 8, 0, 0, LP_OPTIONS },
- [0xb5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
- [0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
-};
-
-static void nand_reset(DeviceState *dev)
-{
- NANDFlashState *s = NAND(dev);
- s->cmd = NAND_CMD_READ0;
- s->addr = 0;
- s->addrlen = 0;
- s->iolen = 0;
- s->offset = 0;
- s->status &= NAND_IOSTATUS_UNPROTCT;
- s->status |= NAND_IOSTATUS_READY;
-}
-
-static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
-{
- s->ioaddr[s->iolen++] = value;
- for (value = s->buswidth; --value;) {
- s->ioaddr[s->iolen++] = 0;
- }
-}
-
-/*
- * nand_load_block: Load block containing (s->addr + @offset).
- * Returns length of data available at @offset in this block.
- */
-static unsigned nand_load_block(NANDFlashState *s, unsigned offset)
-{
- unsigned iolen;
-
- if (!s->blk_load(s, s->addr, offset)) {
- return 0;
- }
-
- iolen = (1 << s->page_shift);
- if (s->gnd) {
- iolen += 1 << s->oob_shift;
- }
- assert(offset <= iolen);
- iolen -= offset;
-
- return iolen;
-}
-
-static void nand_command(NANDFlashState *s)
-{
- switch (s->cmd) {
- case NAND_CMD_READ0:
- s->iolen = 0;
- break;
-
- case NAND_CMD_READID:
- s->ioaddr = s->io;
- s->iolen = 0;
- nand_pushio_byte(s, s->manf_id);
- nand_pushio_byte(s, s->chip_id);
- nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- /* Page Size, Block Size, Spare Size; bit 6 indicates
- * 8 vs 16 bit width NAND.
- */
- nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
- } else {
- nand_pushio_byte(s, 0xc0); /* Multi-plane */
- }
- break;
-
- case NAND_CMD_RANDOMREAD2:
- case NAND_CMD_NOSERIALREAD2:
- if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
- break;
- s->iolen = nand_load_block(s, s->addr & ((1 << s->addr_shift) - 1));
- break;
-
- case NAND_CMD_RESET:
- nand_reset(DEVICE(s));
- break;
-
- case NAND_CMD_PAGEPROGRAM1:
- s->ioaddr = s->io;
- s->iolen = 0;
- break;
-
- case NAND_CMD_PAGEPROGRAM2:
- if (s->wp) {
- s->blk_write(s);
- }
- break;
-
- case NAND_CMD_BLOCKERASE1:
- break;
-
- case NAND_CMD_BLOCKERASE2:
- s->addr &= (1ull << s->addrlen * 8) - 1;
- s->addr <<= nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP ?
- 16 : 8;
-
- if (s->wp) {
- s->blk_erase(s);
- }
- break;
-
- case NAND_CMD_READSTATUS:
- s->ioaddr = s->io;
- s->iolen = 0;
- nand_pushio_byte(s, s->status);
- break;
-
- default:
- printf("%s: Unknown NAND command 0x%02x\n", __func__, s->cmd);
- }
-}
-
-static int nand_pre_save(void *opaque)
-{
- NANDFlashState *s = NAND(opaque);
-
- s->ioaddr_vmstate = s->ioaddr - s->io;
-
- return 0;
-}
-
-static int nand_post_load(void *opaque, int version_id)
-{
- NANDFlashState *s = NAND(opaque);
-
- if (s->ioaddr_vmstate > sizeof(s->io)) {
- return -EINVAL;
- }
- s->ioaddr = s->io + s->ioaddr_vmstate;
-
- return 0;
-}
-
-static const VMStateDescription vmstate_nand = {
- .name = "nand",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = nand_pre_save,
- .post_load = nand_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(cle, NANDFlashState),
- VMSTATE_UINT8(ale, NANDFlashState),
- VMSTATE_UINT8(ce, NANDFlashState),
- VMSTATE_UINT8(wp, NANDFlashState),
- VMSTATE_UINT8(gnd, NANDFlashState),
- VMSTATE_BUFFER(io, NANDFlashState),
- VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
- VMSTATE_INT32(iolen, NANDFlashState),
- VMSTATE_UINT32(cmd, NANDFlashState),
- VMSTATE_UINT64(addr, NANDFlashState),
- VMSTATE_INT32(addrlen, NANDFlashState),
- VMSTATE_INT32(status, NANDFlashState),
- VMSTATE_INT32(offset, NANDFlashState),
- /* XXX: do we want to save s->storage too? */
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void nand_realize(DeviceState *dev, Error **errp)
-{
- int pagesize;
- NANDFlashState *s = NAND(dev);
- int ret;
-
-
- s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
- s->size = nand_flash_ids[s->chip_id].size << 20;
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- s->page_shift = 11;
- s->erase_shift = 6;
- } else {
- s->page_shift = nand_flash_ids[s->chip_id].page_shift;
- s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
- }
-
- switch (1 << s->page_shift) {
- case 256:
- nand_init_256(s);
- break;
- case 512:
- nand_init_512(s);
- break;
- case 2048:
- nand_init_2048(s);
- break;
- default:
- error_setg(errp, "Unsupported NAND block size %#x",
- 1 << s->page_shift);
- return;
- }
-
- pagesize = 1 << s->oob_shift;
- s->mem_oob = 1;
- if (s->blk) {
- if (!blk_supports_write_perm(s->blk)) {
- error_setg(errp, "Can't use a read-only drive");
- return;
- }
- ret = blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
- BLK_PERM_ALL, errp);
- if (ret < 0) {
- return;
- }
- if (blk_getlength(s->blk) >=
- (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
- pagesize = 0;
- s->mem_oob = 0;
- }
- } else {
- pagesize += 1 << s->page_shift;
- }
- if (pagesize) {
- s->storage = (uint8_t *) memset(g_malloc(s->pages * pagesize),
- 0xff, s->pages * pagesize);
- }
- /* Give s->ioaddr a sane value in case we save state before it is used. */
- s->ioaddr = s->io;
-}
-
-static Property nand_properties[] = {
- DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
- DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
- DEFINE_PROP_DRIVE("drive", NANDFlashState, blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void nand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = nand_realize;
- dc->reset = nand_reset;
- dc->vmsd = &vmstate_nand;
- device_class_set_props(dc, nand_properties);
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo nand_info = {
- .name = TYPE_NAND,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(NANDFlashState),
- .class_init = nand_class_init,
-};
-
-static void nand_register_types(void)
-{
- type_register_static(&nand_info);
-}
-
-/*
- * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip
- * outputs are R/B and eight I/O pins.
- *
- * CE, WP and R/B are active low.
- */
-void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
- uint8_t ce, uint8_t wp, uint8_t gnd)
-{
- NANDFlashState *s = NAND(dev);
-
- s->cle = cle;
- s->ale = ale;
- s->ce = ce;
- s->wp = wp;
- s->gnd = gnd;
- if (wp) {
- s->status |= NAND_IOSTATUS_UNPROTCT;
- } else {
- s->status &= ~NAND_IOSTATUS_UNPROTCT;
- }
-}
-
-void nand_getpins(DeviceState *dev, int *rb)
-{
- *rb = 1;
-}
-
-void nand_setio(DeviceState *dev, uint32_t value)
-{
- int i;
- NANDFlashState *s = NAND(dev);
-
- if (!s->ce && s->cle) {
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
- return;
- if (value == NAND_CMD_RANDOMREAD1) {
- s->addr &= ~((1 << s->addr_shift) - 1);
- s->addrlen = 0;
- return;
- }
- }
- if (value == NAND_CMD_READ0) {
- s->offset = 0;
- } else if (value == NAND_CMD_READ1) {
- s->offset = 0x100;
- value = NAND_CMD_READ0;
- } else if (value == NAND_CMD_READ2) {
- s->offset = 1 << s->page_shift;
- value = NAND_CMD_READ0;
- }
-
- s->cmd = value;
-
- if (s->cmd == NAND_CMD_READSTATUS ||
- s->cmd == NAND_CMD_PAGEPROGRAM2 ||
- s->cmd == NAND_CMD_BLOCKERASE1 ||
- s->cmd == NAND_CMD_BLOCKERASE2 ||
- s->cmd == NAND_CMD_NOSERIALREAD2 ||
- s->cmd == NAND_CMD_RANDOMREAD2 ||
- s->cmd == NAND_CMD_RESET) {
- nand_command(s);
- }
-
- if (s->cmd != NAND_CMD_RANDOMREAD2) {
- s->addrlen = 0;
- }
- }
-
- if (s->ale) {
- unsigned int shift = s->addrlen * 8;
- uint64_t mask = ~(0xffull << shift);
- uint64_t v = (uint64_t)value << shift;
-
- s->addr = (s->addr & mask) | v;
- s->addrlen ++;
-
- switch (s->addrlen) {
- case 1:
- if (s->cmd == NAND_CMD_READID) {
- nand_command(s);
- }
- break;
- case 2: /* fix cache address as a byte address */
- s->addr <<= (s->buswidth - 1);
- break;
- case 3:
- if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- (s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1)) {
- nand_command(s);
- }
- break;
- case 4:
- if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */
- (s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1)) {
- nand_command(s);
- }
- break;
- case 5:
- if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */
- (s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1)) {
- nand_command(s);
- }
- break;
- default:
- break;
- }
- }
-
- if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
- if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
- for (i = s->buswidth; i--; value >>= 8) {
- s->io[s->iolen ++] = (uint8_t) (value & 0xff);
- }
- }
- } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
- if ((s->addr & ((1 << s->addr_shift) - 1)) <
- (1 << s->page_shift) + (1 << s->oob_shift)) {
- for (i = s->buswidth; i--; s->addr++, value >>= 8) {
- s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
- (uint8_t) (value & 0xff);
- }
- }
- }
-}
-
-uint32_t nand_getio(DeviceState *dev)
-{
- int offset;
- uint32_t x = 0;
- NANDFlashState *s = NAND(dev);
-
- /* Allow sequential reading */
- if (!s->iolen && s->cmd == NAND_CMD_READ0) {
- offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
- s->offset = 0;
- s->iolen = nand_load_block(s, offset);
- }
-
- if (s->ce || s->iolen <= 0) {
- return 0;
- }
-
- for (offset = s->buswidth; offset--;) {
- x |= s->ioaddr[offset] << (offset << 3);
- }
- /* after receiving READ STATUS command all subsequent reads will
- * return the status register value until another command is issued
- */
- if (s->cmd != NAND_CMD_READSTATUS) {
- s->addr += s->buswidth;
- s->ioaddr += s->buswidth;
- s->iolen -= s->buswidth;
- }
- return x;
-}
-
-uint32_t nand_getbuswidth(DeviceState *dev)
-{
- NANDFlashState *s = (NANDFlashState *) dev;
- return s->buswidth << 3;
-}
-
-DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id)
-{
- DeviceState *dev;
-
- if (nand_flash_ids[chip_id].size == 0) {
- hw_error("%s: Unsupported NAND chip ID.\n", __func__);
- }
- dev = qdev_new(TYPE_NAND);
- qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
- qdev_prop_set_uint8(dev, "chip_id", chip_id);
- if (blk) {
- qdev_prop_set_drive_err(dev, "drive", blk, &error_fatal);
- }
-
- qdev_realize(dev, NULL, &error_fatal);
- return dev;
-}
-
-type_init(nand_register_types)
-
-#else
-
-/* Program a single page */
-static void glue(nand_blk_write_, NAND_PAGE_SIZE)(NANDFlashState *s)
-{
- uint64_t off, page, sector, soff;
- uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
- if (PAGE(s->addr) >= s->pages)
- return;
-
- if (!s->blk) {
- mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
- s->offset, s->io, s->iolen);
- } else if (s->mem_oob) {
- sector = SECTOR(s->addr);
- off = (s->addr & PAGE_MASK) + s->offset;
- soff = SECTOR_OFFSET(s->addr);
- if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
- PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
- return;
- }
-
- mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, NAND_PAGE_SIZE - off));
- if (off + s->iolen > NAND_PAGE_SIZE) {
- page = PAGE(s->addr);
- mem_and(s->storage + (page << OOB_SHIFT), s->io + NAND_PAGE_SIZE - off,
- MIN(OOB_SIZE, off + s->iolen - NAND_PAGE_SIZE));
- }
-
- if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
- PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
- }
- } else {
- off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
- sector = off >> 9;
- soff = off & 0x1ff;
- if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
- (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
- return;
- }
-
- mem_and(iobuf + soff, s->io, s->iolen);
-
- if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
- (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
- }
- }
- s->offset = 0;
-}
-
-/* Erase a single block */
-static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)
-{
- uint64_t i, page, addr;
- uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
- addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
-
- if (PAGE(addr) >= s->pages) {
- return;
- }
-
- if (!s->blk) {
- memset(s->storage + PAGE_START(addr),
- 0xff, (NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift);
- } else if (s->mem_oob) {
- memset(s->storage + (PAGE(addr) << OOB_SHIFT),
- 0xff, OOB_SIZE << s->erase_shift);
- i = SECTOR(addr);
- page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
- for (; i < page; i ++)
- if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
- }
- } else {
- addr = PAGE_START(addr);
- page = addr >> 9;
- if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
- }
- memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
- if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
- }
-
- memset(iobuf, 0xff, 0x200);
- i = (addr & ~0x1ff) + 0x200;
- for (addr += ((NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
- i < addr; i += 0x200) {
- if (blk_pwrite(s->blk, i, BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n",
- __func__, i >> 9);
- }
- }
-
- page = i >> 9;
- if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
- }
- memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
- if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
- printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
- }
- }
-}
-
-static bool glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
- uint64_t addr, unsigned offset)
-{
- if (PAGE(addr) >= s->pages) {
- return false;
- }
-
- if (offset > NAND_PAGE_SIZE + OOB_SIZE) {
- return false;
- }
-
- if (s->blk) {
- if (s->mem_oob) {
- if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS,
- PAGE_SECTORS << BDRV_SECTOR_BITS, s->io, 0) < 0) {
- printf("%s: read error in sector %" PRIu64 "\n",
- __func__, SECTOR(addr));
- }
- memcpy(s->io + SECTOR_OFFSET(s->addr) + NAND_PAGE_SIZE,
- s->storage + (PAGE(s->addr) << OOB_SHIFT),
- OOB_SIZE);
- s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
- } else {
- if (blk_pread(s->blk, PAGE_START(addr),
- (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, s->io, 0)
- < 0) {
- printf("%s: read error in sector %" PRIu64 "\n",
- __func__, PAGE_START(addr) >> 9);
- }
- s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
- }
- } else {
- memcpy(s->io, s->storage + PAGE_START(s->addr) +
- offset, NAND_PAGE_SIZE + OOB_SIZE - offset);
- s->ioaddr = s->io;
- }
-
- return true;
-}
-
-static void glue(nand_init_, NAND_PAGE_SIZE)(NANDFlashState *s)
-{
- s->oob_shift = PAGE_SHIFT - 5;
- s->pages = s->size >> PAGE_SHIFT;
- s->addr_shift = ADDR_SHIFT;
-
- s->blk_erase = glue(nand_blk_erase_, NAND_PAGE_SIZE);
- s->blk_write = glue(nand_blk_write_, NAND_PAGE_SIZE);
- s->blk_load = glue(nand_blk_load_, NAND_PAGE_SIZE);
-}
-
-# undef NAND_PAGE_SIZE
-# undef PAGE_SHIFT
-# undef PAGE_SECTORS
-# undef ADDR_SHIFT
-#endif /* NAND_IO */
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
deleted file mode 100644
index d8a6944..0000000
--- a/hw/block/onenand.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * OneNAND flash memories emulation.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "sysemu/block-backend.h"
-#include "exec/memory.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "qemu/error-report.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
-#define PAGE_SHIFT 11
-
-/* Fixed */
-#define BLOCK_SHIFT (PAGE_SHIFT + 6)
-
-#define TYPE_ONE_NAND "onenand"
-OBJECT_DECLARE_SIMPLE_TYPE(OneNANDState, ONE_NAND)
-
-struct OneNANDState {
- SysBusDevice parent_obj;
-
- struct {
- uint16_t man;
- uint16_t dev;
- uint16_t ver;
- } id;
- int shift;
- hwaddr base;
- qemu_irq intr;
- qemu_irq rdy;
- BlockBackend *blk;
- BlockBackend *blk_cur;
- uint8_t *image;
- uint8_t *otp;
- uint8_t *current;
- MemoryRegion ram;
- MemoryRegion mapped_ram;
- uint8_t current_direction;
- uint8_t *boot[2];
- uint8_t *data[2][2];
- MemoryRegion iomem;
- MemoryRegion container;
- int cycle;
- int otpmode;
-
- uint16_t addr[8];
- uint16_t unladdr[8];
- int bufaddr;
- int count;
- uint16_t command;
- uint16_t config[2];
- uint16_t status;
- uint16_t intstatus;
- uint16_t wpstatus;
-
- ECCState ecc;
-
- int density_mask;
- int secs;
- int secs_cur;
- int blocks;
- uint8_t *blockwp;
-};
-
-enum {
- ONEN_BUF_BLOCK = 0,
- ONEN_BUF_BLOCK2 = 1,
- ONEN_BUF_DEST_BLOCK = 2,
- ONEN_BUF_DEST_PAGE = 3,
- ONEN_BUF_PAGE = 7,
-};
-
-enum {
- ONEN_ERR_CMD = 1 << 10,
- ONEN_ERR_ERASE = 1 << 11,
- ONEN_ERR_PROG = 1 << 12,
- ONEN_ERR_LOAD = 1 << 13,
-};
-
-enum {
- ONEN_INT_RESET = 1 << 4,
- ONEN_INT_ERASE = 1 << 5,
- ONEN_INT_PROG = 1 << 6,
- ONEN_INT_LOAD = 1 << 7,
- ONEN_INT = 1 << 15,
-};
-
-enum {
- ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
- ONEN_LOCK_LOCKED = 1 << 1,
- ONEN_LOCK_UNLOCKED = 1 << 2,
-};
-
-static void onenand_mem_setup(OneNANDState *s)
-{
- /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
- * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
- * write boot commands. Also take note of the BWPS bit. */
- memory_region_init(&s->container, OBJECT(s), "onenand",
- 0x10000 << s->shift);
- memory_region_add_subregion(&s->container, 0, &s->iomem);
- memory_region_init_alias(&s->mapped_ram, OBJECT(s), "onenand-mapped-ram",
- &s->ram, 0x0200 << s->shift,
- 0xbe00 << s->shift);
- memory_region_add_subregion_overlap(&s->container,
- 0x0200 << s->shift,
- &s->mapped_ram,
- 1);
-}
-
-static void onenand_intr_update(OneNANDState *s)
-{
- qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
-}
-
-static int onenand_pre_save(void *opaque)
-{
- OneNANDState *s = opaque;
- if (s->current == s->otp) {
- s->current_direction = 1;
- } else if (s->current == s->image) {
- s->current_direction = 2;
- } else {
- s->current_direction = 0;
- }
-
- return 0;
-}
-
-static int onenand_post_load(void *opaque, int version_id)
-{
- OneNANDState *s = opaque;
- switch (s->current_direction) {
- case 0:
- break;
- case 1:
- s->current = s->otp;
- break;
- case 2:
- s->current = s->image;
- break;
- default:
- return -1;
- }
- onenand_intr_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_onenand = {
- .name = "onenand",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = onenand_pre_save,
- .post_load = onenand_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(current_direction, OneNANDState),
- VMSTATE_INT32(cycle, OneNANDState),
- VMSTATE_INT32(otpmode, OneNANDState),
- VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
- VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
- VMSTATE_INT32(bufaddr, OneNANDState),
- VMSTATE_INT32(count, OneNANDState),
- VMSTATE_UINT16(command, OneNANDState),
- VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
- VMSTATE_UINT16(status, OneNANDState),
- VMSTATE_UINT16(intstatus, OneNANDState),
- VMSTATE_UINT16(wpstatus, OneNANDState),
- VMSTATE_INT32(secs_cur, OneNANDState),
- VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
- VMSTATE_UINT8(ecc.cp, OneNANDState),
- VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
- VMSTATE_UINT16(ecc.count, OneNANDState),
- VMSTATE_BUFFER_POINTER_UNSAFE(otp, OneNANDState, 0,
- ((64 + 2) << PAGE_SHIFT)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
-static void onenand_reset(OneNANDState *s, int cold)
-{
- memset(&s->addr, 0, sizeof(s->addr));
- s->command = 0;
- s->count = 1;
- s->bufaddr = 0;
- s->config[0] = 0x40c0;
- s->config[1] = 0x0000;
- onenand_intr_update(s);
- qemu_irq_raise(s->rdy);
- s->status = 0x0000;
- s->intstatus = cold ? 0x8080 : 0x8010;
- s->unladdr[0] = 0;
- s->unladdr[1] = 0;
- s->wpstatus = 0x0002;
- s->cycle = 0;
- s->otpmode = 0;
- s->blk_cur = s->blk;
- s->current = s->image;
- s->secs_cur = s->secs;
-
- if (cold) {
- /* Lock the whole flash */
- memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
-
- if (s->blk_cur && blk_pread(s->blk_cur, 0, 8 << BDRV_SECTOR_BITS,
- s->boot[0], 0) < 0) {
- hw_error("%s: Loading the BootRAM failed.\n", __func__);
- }
- }
-}
-
-static void onenand_system_reset(DeviceState *dev)
-{
- OneNANDState *s = ONE_NAND(dev);
-
- onenand_reset(s, 1);
-}
-
-static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
- void *dest)
-{
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
- if (s->blk_cur) {
- return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS,
- secn << BDRV_SECTOR_BITS, dest, 0) < 0;
- } else if (sec + secn > s->secs_cur) {
- return 1;
- }
-
- memcpy(dest, s->current + (sec << 9), secn << 9);
-
- return 0;
-}
-
-static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
- void *src)
-{
- int result = 0;
-
- if (secn > 0) {
- uint32_t size = secn << BDRV_SECTOR_BITS;
- uint32_t offset = sec << BDRV_SECTOR_BITS;
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
- const uint8_t *sp = (const uint8_t *)src;
- uint8_t *dp = 0;
- if (s->blk_cur) {
- dp = g_malloc(size);
- if (!dp || blk_pread(s->blk_cur, offset, size, dp, 0) < 0) {
- result = 1;
- }
- } else {
- if (sec + secn > s->secs_cur) {
- result = 1;
- } else {
- dp = (uint8_t *)s->current + offset;
- }
- }
- if (!result) {
- uint32_t i;
- for (i = 0; i < size; i++) {
- dp[i] &= sp[i];
- }
- if (s->blk_cur) {
- result = blk_pwrite(s->blk_cur, offset, size, dp, 0) < 0;
- }
- }
- if (dp && s->blk_cur) {
- g_free(dp);
- }
- }
-
- return result;
-}
-
-static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
- void *dest)
-{
- uint8_t buf[512];
-
- if (s->blk_cur) {
- uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
- if (blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, buf, 0) < 0) {
- return 1;
- }
- memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
- } else if (sec + secn > s->secs_cur) {
- return 1;
- } else {
- memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
- }
-
- return 0;
-}
-
-static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
- void *src)
-{
- int result = 0;
- if (secn > 0) {
- const uint8_t *sp = (const uint8_t *)src;
- uint8_t *dp = 0, *dpp = 0;
- uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > s->secs_cur + (sec >> 5));
- if (s->blk_cur) {
- dp = g_malloc(512);
- if (!dp
- || blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp, 0) < 0) {
- result = 1;
- } else {
- dpp = dp + ((sec & 31) << 4);
- }
- } else {
- if (sec + secn > s->secs_cur) {
- result = 1;
- } else {
- dpp = s->current + (s->secs_cur << 9) + (sec << 4);
- }
- }
- if (!result) {
- uint32_t i;
- for (i = 0; i < (secn << 4); i++) {
- dpp[i] &= sp[i];
- }
- if (s->blk_cur) {
- result = blk_pwrite(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp,
- 0) < 0;
- }
- }
- g_free(dp);
- }
- return result;
-}
-
-static inline int onenand_erase(OneNANDState *s, int sec, int num)
-{
- uint8_t *blankbuf, *tmpbuf;
-
- blankbuf = g_malloc(512);
- tmpbuf = g_malloc(512);
- memset(blankbuf, 0xff, 512);
- for (; num > 0; num--, sec++) {
- if (s->blk_cur) {
- int erasesec = s->secs_cur + (sec >> 5);
- if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, blankbuf, 0) < 0) {
- goto fail;
- }
- if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) {
- goto fail;
- }
- memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
- if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) {
- goto fail;
- }
- } else {
- if (sec + 1 > s->secs_cur) {
- goto fail;
- }
- memcpy(s->current + (sec << 9), blankbuf, 512);
- memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
- blankbuf, 1 << 4);
- }
- }
-
- g_free(tmpbuf);
- g_free(blankbuf);
- return 0;
-
-fail:
- g_free(tmpbuf);
- g_free(blankbuf);
- return 1;
-}
-
-static void onenand_command(OneNANDState *s)
-{
- int b;
- int sec;
- void *buf;
-#define SETADDR(block, page) \
- sec = (s->addr[page] & 3) + \
- ((((s->addr[page] >> 2) & 0x3f) + \
- (((s->addr[block] & 0xfff) | \
- (s->addr[block] >> 15 ? s->density_mask : 0)) \
- << 6)) \
- << (PAGE_SHIFT - 9));
-#define SETBUF_M() \
- buf = (s->bufaddr & 8) ? s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0]; \
- buf += (s->bufaddr & 3) << 9;
-#define SETBUF_S() \
- buf = (s->bufaddr & 8) ? \
- s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1]; \
- buf += (s->bufaddr & 3) << 4;
-
- switch (s->command) {
- case 0x00: /* Load single/multiple sector data unit into buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_M()
- if (onenand_load_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
-#if 0
- SETBUF_S()
- if (onenand_load_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-#endif
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
- break;
- case 0x13: /* Load single/multiple spare sector into buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_S()
- if (onenand_load_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
- break;
- case 0x80: /* Program single/multiple sector data unit from buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_M()
- if (onenand_prog_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
-#if 0
- SETBUF_S()
- if (onenand_prog_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-#endif
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
- case 0x1a: /* Program single/multiple spare area sector from buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_S()
- if (onenand_prog_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
- case 0x1b: /* Copy-back program */
- SETBUF_S()
-
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
- if (onenand_load_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
- if (onenand_prog_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- /* TODO: spare areas */
-
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
-
- case 0x23: /* Unlock NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- /* XXX the previous (?) area should be locked automatically */
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
- }
- break;
- case 0x27: /* Unlock All NAND array blocks */
- s->intstatus |= ONEN_INT;
-
- for (b = 0; b < s->blocks; b ++) {
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
- }
- break;
-
- case 0x2a: /* Lock NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
- }
- break;
- case 0x2c: /* Lock-tight NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
- continue;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
- }
- break;
-
- case 0x71: /* Erase-Verify-Read */
- s->intstatus |= ONEN_INT;
- break;
- case 0x95: /* Multi-block erase */
- qemu_irq_pulse(s->intr);
- /* Fall through. */
- case 0x94: /* Block erase */
- sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
- (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
- << (BLOCK_SHIFT - 9);
- if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
-
- s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
- break;
- case 0xb0: /* Erase suspend */
- break;
- case 0x30: /* Erase resume */
- s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
- break;
-
- case 0xf0: /* Reset NAND Flash core */
- onenand_reset(s, 0);
- break;
- case 0xf3: /* Reset OneNAND */
- onenand_reset(s, 0);
- break;
-
- case 0x65: /* OTP Access */
- s->intstatus |= ONEN_INT;
- s->blk_cur = NULL;
- s->current = s->otp;
- s->secs_cur = 1 << (BLOCK_SHIFT - 9);
- s->addr[ONEN_BUF_BLOCK] = 0;
- s->otpmode = 1;
- break;
-
- default:
- s->status |= ONEN_ERR_CMD;
- s->intstatus |= ONEN_INT;
- qemu_log_mask(LOG_GUEST_ERROR, "unknown OneNAND command %x\n",
- s->command);
- }
-
- onenand_intr_update(s);
-}
-
-static uint64_t onenand_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- OneNANDState *s = (OneNANDState *) opaque;
- int offset = addr >> s->shift;
-
- switch (offset) {
- case 0x0000 ... 0xbffe:
- return lduw_le_p(s->boot[0] + addr);
-
- case 0xf000: /* Manufacturer ID */
- return s->id.man;
- case 0xf001: /* Device ID */
- return s->id.dev;
- case 0xf002: /* Version ID */
- return s->id.ver;
- /* TODO: get the following values from a real chip! */
- case 0xf003: /* Data Buffer size */
- return 1 << PAGE_SHIFT;
- case 0xf004: /* Boot Buffer size */
- return 0x200;
- case 0xf005: /* Amount of buffers */
- return 1 | (2 << 8);
- case 0xf006: /* Technology */
- return 0;
-
- case 0xf100 ... 0xf107: /* Start addresses */
- return s->addr[offset - 0xf100];
-
- case 0xf200: /* Start buffer */
- return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
-
- case 0xf220: /* Command */
- return s->command;
- case 0xf221: /* System Configuration 1 */
- return s->config[0] & 0xffe0;
- case 0xf222: /* System Configuration 2 */
- return s->config[1];
-
- case 0xf240: /* Controller Status */
- return s->status;
- case 0xf241: /* Interrupt */
- return s->intstatus;
- case 0xf24c: /* Unlock Start Block Address */
- return s->unladdr[0];
- case 0xf24d: /* Unlock End Block Address */
- return s->unladdr[1];
- case 0xf24e: /* Write Protection Status */
- return s->wpstatus;
-
- case 0xff00: /* ECC Status */
- return 0x00;
- case 0xff01: /* ECC Result of main area data */
- case 0xff02: /* ECC Result of spare area data */
- case 0xff03: /* ECC Result of main area data */
- case 0xff04: /* ECC Result of spare area data */
- qemu_log_mask(LOG_UNIMP,
- "onenand: ECC result registers unimplemented\n");
- return 0x0000;
- }
-
- qemu_log_mask(LOG_GUEST_ERROR, "read of unknown OneNAND register 0x%x\n",
- offset);
- return 0;
-}
-
-static void onenand_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- OneNANDState *s = (OneNANDState *) opaque;
- int offset = addr >> s->shift;
- int sec;
-
- switch (offset) {
- case 0x0000 ... 0x01ff:
- case 0x8000 ... 0x800f:
- if (s->cycle) {
- s->cycle = 0;
-
- if (value == 0x0000) {
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
- onenand_load_main(s, sec,
- 1 << (PAGE_SHIFT - 9), s->data[0][0]);
- s->addr[ONEN_BUF_PAGE] += 4;
- s->addr[ONEN_BUF_PAGE] &= 0xff;
- }
- break;
- }
-
- switch (value) {
- case 0x00f0: /* Reset OneNAND */
- onenand_reset(s, 0);
- break;
-
- case 0x00e0: /* Load Data into Buffer */
- s->cycle = 1;
- break;
-
- case 0x0090: /* Read Identification Data */
- memset(s->boot[0], 0, 3 << s->shift);
- s->boot[0][0 << s->shift] = s->id.man & 0xff;
- s->boot[0][1 << s->shift] = s->id.dev & 0xff;
- s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "unknown OneNAND boot command %" PRIx64 "\n",
- value);
- }
- break;
-
- case 0xf100 ... 0xf107: /* Start addresses */
- s->addr[offset - 0xf100] = value;
- break;
-
- case 0xf200: /* Start buffer */
- s->bufaddr = (value >> 8) & 0xf;
- if (PAGE_SHIFT == 11)
- s->count = (value & 3) ?: 4;
- else if (PAGE_SHIFT == 10)
- s->count = (value & 1) ?: 2;
- break;
-
- case 0xf220: /* Command */
- if (s->intstatus & (1 << 15))
- break;
- s->command = value;
- onenand_command(s);
- break;
- case 0xf221: /* System Configuration 1 */
- s->config[0] = value;
- onenand_intr_update(s);
- qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
- break;
- case 0xf222: /* System Configuration 2 */
- s->config[1] = value;
- break;
-
- case 0xf241: /* Interrupt */
- s->intstatus &= value;
- if ((1 << 15) & ~s->intstatus)
- s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
- ONEN_ERR_PROG | ONEN_ERR_LOAD);
- onenand_intr_update(s);
- break;
- case 0xf24c: /* Unlock Start Block Address */
- s->unladdr[0] = value & (s->blocks - 1);
- /* For some reason we have to set the end address to by default
- * be same as start because the software forgets to write anything
- * in there. */
- s->unladdr[1] = value & (s->blocks - 1);
- break;
- case 0xf24d: /* Unlock End Block Address */
- s->unladdr[1] = value & (s->blocks - 1);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "write to unknown OneNAND register 0x%x\n",
- offset);
- }
-}
-
-static const MemoryRegionOps onenand_ops = {
- .read = onenand_read,
- .write = onenand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void onenand_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- OneNANDState *s = ONE_NAND(dev);
- uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
- void *ram;
- Error *local_err = NULL;
-
- s->base = (hwaddr)-1;
- s->rdy = NULL;
- s->blocks = size >> BLOCK_SHIFT;
- s->secs = size >> 9;
- s->blockwp = g_malloc(s->blocks);
- s->density_mask = (s->id.dev & 0x08)
- ? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
- memory_region_init_io(&s->iomem, OBJECT(s), &onenand_ops, s, "onenand",
- 0x10000 << s->shift);
- if (!s->blk) {
- s->image = memset(g_malloc(size + (size >> 5)),
- 0xff, size + (size >> 5));
- } else {
- if (!blk_supports_write_perm(s->blk)) {
- error_setg(errp, "Can't use a read-only drive");
- return;
- }
- blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
- BLK_PERM_ALL, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- s->blk_cur = s->blk;
- }
- s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
- 0xff, (64 + 2) << PAGE_SHIFT);
- memory_region_init_ram_nomigrate(&s->ram, OBJECT(s), "onenand.ram",
- 0xc000 << s->shift, &error_fatal);
- vmstate_register_ram_global(&s->ram);
- ram = memory_region_get_ram_ptr(&s->ram);
- s->boot[0] = ram + (0x0000 << s->shift);
- s->boot[1] = ram + (0x8000 << s->shift);
- s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
- s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
- s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
- s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
- onenand_mem_setup(s);
- sysbus_init_irq(sbd, &s->intr);
- sysbus_init_mmio(sbd, &s->container);
- vmstate_register(VMSTATE_IF(dev),
- ((s->shift & 0x7f) << 24)
- | ((s->id.man & 0xff) << 16)
- | ((s->id.dev & 0xff) << 8)
- | (s->id.ver & 0xff),
- &vmstate_onenand, s);
-}
-
-static Property onenand_properties[] = {
- DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
- DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
- DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
- DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
- DEFINE_PROP_DRIVE("drive", OneNANDState, blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void onenand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = onenand_realize;
- dc->reset = onenand_system_reset;
- device_class_set_props(dc, onenand_properties);
-}
-
-static const TypeInfo onenand_info = {
- .name = TYPE_ONE_NAND,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OneNANDState),
- .class_init = onenand_class_init,
-};
-
-static void onenand_register_types(void)
-{
- type_register_static(&onenand_info);
-}
-
-void *onenand_raw_otp(DeviceState *onenand_device)
-{
- OneNANDState *s = ONE_NAND(onenand_device);
-
- return s->otp;
-}
-
-type_init(onenand_register_types)
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 2f3d1dd..168101d 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -41,18 +41,17 @@
#include "hw/block/flash.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/bitops.h"
#include "qemu/host-utils.h"
#include "qemu/log.h"
-#include "qemu/module.h"
#include "qemu/option.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/runstate.h"
+#include "system/blockdev.h"
+#include "system/runstate.h"
#include "trace.h"
#define PFLASH_BE 0
@@ -896,7 +895,7 @@ static void pflash_cfi01_system_reset(DeviceState *dev)
pfl->blk_offset = -1;
}
-static Property pflash_cfi01_properties[] = {
+static const Property pflash_cfi01_properties[] = {
DEFINE_PROP_DRIVE("drive", PFlashCFI01, blk),
/* num-blocks is the number of blocks actually visible to the guest,
* ie the total size of the device divided by the sector length.
@@ -933,34 +932,29 @@ static Property pflash_cfi01_properties[] = {
DEFINE_PROP_STRING("name", PFlashCFI01, name),
DEFINE_PROP_BOOL("old-multiple-chip-handling", PFlashCFI01,
old_multiple_chip_handling, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
+static void pflash_cfi01_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pflash_cfi01_system_reset;
+ device_class_set_legacy_reset(dc, pflash_cfi01_system_reset);
dc->realize = pflash_cfi01_realize;
device_class_set_props(dc, pflash_cfi01_properties);
dc->vmsd = &vmstate_pflash;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
-
-static const TypeInfo pflash_cfi01_info = {
- .name = TYPE_PFLASH_CFI01,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PFlashCFI01),
- .class_init = pflash_cfi01_class_init,
+static const TypeInfo pflash_cfi01_types[] = {
+ {
+ .name = TYPE_PFLASH_CFI01,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PFlashCFI01),
+ .class_init = pflash_cfi01_class_init,
+ },
};
-static void pflash_cfi01_register_types(void)
-{
- type_register_static(&pflash_cfi01_info);
-}
-
-type_init(pflash_cfi01_register_types)
+DEFINE_TYPES(pflash_cfi01_types)
PFlashCFI01 *pflash_cfi01_register(hwaddr base,
const char *name,
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 2314142..3244b69 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -41,7 +41,7 @@
#include "qemu/error-report.h"
#include "qemu/bitmap.h"
#include "qemu/timer.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qemu/host-utils.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
@@ -937,7 +937,7 @@ static void pflash_cfi02_reset(DeviceState *dev)
pflash_reset_state_machine(pfl);
}
-static Property pflash_cfi02_properties[] = {
+static const Property pflash_cfi02_properties[] = {
DEFINE_PROP_DRIVE("drive", PFlashCFI02, blk),
DEFINE_PROP_UINT32("num-blocks", PFlashCFI02, uniform_nb_blocs, 0),
DEFINE_PROP_UINT32("sector-length", PFlashCFI02, uniform_sector_len, 0),
@@ -959,7 +959,6 @@ static Property pflash_cfi02_properties[] = {
DEFINE_PROP_UINT16("unlock-addr0", PFlashCFI02, unlock_addr0, 0),
DEFINE_PROP_UINT16("unlock-addr1", PFlashCFI02, unlock_addr1, 0),
DEFINE_PROP_STRING("name", PFlashCFI02, name),
- DEFINE_PROP_END_OF_LIST(),
};
static void pflash_cfi02_unrealize(DeviceState *dev)
@@ -969,12 +968,12 @@ static void pflash_cfi02_unrealize(DeviceState *dev)
g_free(pfl->sector_erase_map);
}
-static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
+static void pflash_cfi02_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pflash_cfi02_realize;
- dc->reset = pflash_cfi02_reset;
+ device_class_set_legacy_reset(dc, pflash_cfi02_reset);
dc->unrealize = pflash_cfi02_unrealize;
device_class_set_props(dc, pflash_cfi02_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/block/swim.c b/hw/block/swim.c
index 44761c1..ad04736 100644
--- a/hw/block/swim.c
+++ b/hw/block/swim.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "qapi/error.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/block/block.h"
@@ -166,10 +166,9 @@ static const BlockDevOps swim_block_ops = {
.change_media_cb = swim_change_cb,
};
-static Property swim_drive_properties[] = {
+static const Property swim_drive_properties[] = {
DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
- DEFINE_PROP_END_OF_LIST(),
};
static void swim_drive_realize(DeviceState *qdev, Error **errp)
@@ -254,7 +253,7 @@ static void swim_drive_realize(DeviceState *qdev, Error **errp)
blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
}
-static void swim_drive_class_init(ObjectClass *klass, void *data)
+static void swim_drive_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = swim_drive_realize;
@@ -551,12 +550,12 @@ static const VMStateDescription vmstate_sysbus_swim = {
}
};
-static void sysbus_swim_class_init(ObjectClass *oc, void *data)
+static void sysbus_swim_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = sysbus_swim_realize;
- dc->reset = sysbus_swim_reset;
+ device_class_set_legacy_reset(dc, sysbus_swim_reset);
dc->vmsd = &vmstate_sysbus_swim;
}
diff --git a/hw/block/tc58128.c b/hw/block/tc58128.c
deleted file mode 100644
index 0984e37..0000000
--- a/hw/block/tc58128.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * TC58128 NAND EEPROM emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * SPDX-License-Identifier: MIT
- */
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "hw/sh4/sh.h"
-#include "hw/loader.h"
-#include "sysemu/qtest.h"
-#include "qemu/error-report.h"
-
-#define CE1 0x0100
-#define CE2 0x0200
-#define RE 0x0400
-#define WE 0x0800
-#define ALE 0x1000
-#define CLE 0x2000
-#define RDY1 0x4000
-#define RDY2 0x8000
-#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
-
-typedef enum { WAIT, READ1, READ2, READ3 } state_t;
-
-typedef struct {
- uint8_t *flash_contents;
- state_t state;
- uint32_t address;
- uint8_t address_cycle;
-} tc58128_dev;
-
-static tc58128_dev tc58128_devs[2];
-
-#define FLASH_SIZE (16 * MiB)
-
-static void init_dev(tc58128_dev * dev, const char *filename)
-{
- int ret, blocks;
-
- dev->state = WAIT;
- dev->flash_contents = g_malloc(FLASH_SIZE);
- memset(dev->flash_contents, 0xff, FLASH_SIZE);
- if (filename) {
- /* Load flash image skipping the first block */
- ret = load_image_size(filename, dev->flash_contents + 528 * 32,
- FLASH_SIZE - 528 * 32);
- if (ret < 0) {
- if (!qtest_enabled()) {
- error_report("Could not load flash image %s", filename);
- exit(1);
- }
- } else {
- /* Build first block with number of blocks */
- blocks = DIV_ROUND_UP(ret, 528 * 32);
- dev->flash_contents[0] = blocks & 0xff;
- dev->flash_contents[1] = (blocks >> 8) & 0xff;
- dev->flash_contents[2] = (blocks >> 16) & 0xff;
- dev->flash_contents[3] = (blocks >> 24) & 0xff;
- fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
- filename);
- }
- }
-}
-
-static void handle_command(tc58128_dev * dev, uint8_t command)
-{
- switch (command) {
- case 0xff:
- fprintf(stderr, "reset flash device\n");
- dev->state = WAIT;
- break;
- case 0x00:
- fprintf(stderr, "read mode 1\n");
- dev->state = READ1;
- dev->address_cycle = 0;
- break;
- case 0x01:
- fprintf(stderr, "read mode 2\n");
- dev->state = READ2;
- dev->address_cycle = 0;
- break;
- case 0x50:
- fprintf(stderr, "read mode 3\n");
- dev->state = READ3;
- dev->address_cycle = 0;
- break;
- default:
- fprintf(stderr, "unknown flash command 0x%02x\n", command);
- abort();
- }
-}
-
-static void handle_address(tc58128_dev * dev, uint8_t data)
-{
- switch (dev->state) {
- case READ1:
- case READ2:
- case READ3:
- switch (dev->address_cycle) {
- case 0:
- dev->address = data;
- if (dev->state == READ2)
- dev->address |= 0x100;
- else if (dev->state == READ3)
- dev->address |= 0x200;
- break;
- case 1:
- dev->address += data * 528 * 0x100;
- break;
- case 2:
- dev->address += data * 528;
- fprintf(stderr, "address pointer in flash: 0x%08x\n",
- dev->address);
- break;
- default:
- /* Invalid data */
- abort();
- }
- dev->address_cycle++;
- break;
- default:
- abort();
- }
-}
-
-static uint8_t handle_read(tc58128_dev * dev)
-{
-#if 0
- if (dev->address % 0x100000 == 0)
- fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
-#endif
- return dev->flash_contents[dev->address++];
-}
-
-/* We never mark the device as busy, so interrupts cannot be triggered
- XXXXX */
-
-static int tc58128_cb(uint16_t porta, uint16_t portb,
- uint16_t * periph_pdtra, uint16_t * periph_portadir,
- uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
-{
- int dev;
-
- if ((porta & CE1) == 0)
- dev = 0;
- else if ((porta & CE2) == 0)
- dev = 1;
- else
- return 0; /* No device selected */
-
- if ((porta & RE) && (porta & WE)) {
- /* Nothing to do, assert ready and return to input state */
- *periph_portadir &= 0xff00;
- *periph_portadir |= RDY(dev);
- *periph_pdtra |= RDY(dev);
- return 1;
- }
-
- if (porta & CLE) {
- /* Command */
- assert((porta & WE) == 0);
- handle_command(&tc58128_devs[dev], porta & 0x00ff);
- } else if (porta & ALE) {
- assert((porta & WE) == 0);
- handle_address(&tc58128_devs[dev], porta & 0x00ff);
- } else if ((porta & RE) == 0) {
- *periph_portadir |= 0x00ff;
- *periph_pdtra &= 0xff00;
- *periph_pdtra |= handle_read(&tc58128_devs[dev]);
- } else {
- abort();
- }
- return 1;
-}
-
-static sh7750_io_device tc58128 = {
- RE | WE, /* Port A triggers */
- 0, /* Port B triggers */
- tc58128_cb /* Callback */
-};
-
-int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2)
-{
- if (!qtest_enabled()) {
- warn_report_once("The TC58128 flash device is deprecated");
- }
- init_dev(&tc58128_devs[0], zone1);
- init_dev(&tc58128_devs[1], zone2);
- return sh7750_register_io_device(s, &tc58128);
-}
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 5b7f46b..0eebbcd 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -29,8 +29,8 @@
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/runstate.h"
static const int user_feature_bits[] = {
VIRTIO_BLK_F_SIZE_MAX,
@@ -90,27 +90,39 @@ static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
s->blkcfg.wce = blkcfg->wce;
}
+static int vhost_user_blk_sync_config(DeviceState *dev, Error **errp)
+{
+ int ret;
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VHostUserBlk *s = VHOST_USER_BLK(vdev);
+
+ ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
+ vdev->config_len, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ memcpy(vdev->config, &s->blkcfg, vdev->config_len);
+ virtio_notify_config(vdev);
+
+ return 0;
+}
+
static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
{
int ret;
- VirtIODevice *vdev = dev->vdev;
- VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
Error *local_err = NULL;
if (!dev->started) {
return 0;
}
- ret = vhost_dev_get_config(dev, (uint8_t *)&s->blkcfg,
- vdev->config_len, &local_err);
+ ret = vhost_user_blk_sync_config(DEVICE(dev->vdev), &local_err);
if (ret < 0) {
error_report_err(local_err);
return ret;
}
- memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len);
- virtio_notify_config(dev->vdev);
-
return 0;
}
@@ -192,7 +204,7 @@ err_host_notifiers:
return ret;
}
-static void vhost_user_blk_stop(VirtIODevice *vdev)
+static int vhost_user_blk_stop(VirtIODevice *vdev)
{
VHostUserBlk *s = VHOST_USER_BLK(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@@ -200,26 +212,26 @@ static void vhost_user_blk_stop(VirtIODevice *vdev)
int ret;
if (!s->started_vu) {
- return;
+ return 0;
}
s->started_vu = false;
if (!k->set_guest_notifiers) {
- return;
+ return 0;
}
- vhost_dev_stop(&s->dev, vdev, true);
+ ret = vhost_dev_stop(&s->dev, vdev, true);
- ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
- if (ret < 0) {
+ if (k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false) < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
- return;
+ return -1;
}
vhost_dev_disable_notifiers(&s->dev, vdev);
+ return ret;
}
-static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
+static int vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserBlk *s = VHOST_USER_BLK(vdev);
bool should_start = virtio_device_should_start(vdev, status);
@@ -227,11 +239,11 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
int ret;
if (!s->connected) {
- return;
+ return -1;
}
if (vhost_dev_is_started(&s->dev) == should_start) {
- return;
+ return 0;
}
if (should_start) {
@@ -241,9 +253,12 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
qemu_chr_fe_disconnect(&s->chardev);
}
} else {
- vhost_user_blk_stop(vdev);
+ ret = vhost_user_blk_stop(vdev);
+ if (ret < 0) {
+ return ret;
+ }
}
-
+ return 0;
}
static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
@@ -558,7 +573,7 @@ static const VMStateDescription vmstate_vhost_user_blk = {
},
};
-static Property vhost_user_blk_properties[] = {
+static const Property vhost_user_blk_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserBlk, chardev),
DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues,
VHOST_USER_BLK_AUTO_NUM_QUEUES),
@@ -569,16 +584,16 @@ static Property vhost_user_blk_properties[] = {
VIRTIO_BLK_F_DISCARD, true),
DEFINE_PROP_BIT64("write-zeroes", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_WRITE_ZEROES, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vhost_user_blk_class_init(ObjectClass *klass, void *data)
+static void vhost_user_blk_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
device_class_set_props(dc, vhost_user_blk_properties);
dc->vmsd = &vmstate_vhost_user_blk;
+ dc->sync_config = vhost_user_blk_sync_config;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = vhost_user_blk_device_realize;
vdc->unrealize = vhost_user_blk_device_unrealize;
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 73bdfd6..9bab271 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -22,10 +22,10 @@
#include "trace.h"
#include "hw/block/block.h"
#include "hw/qdev-properties.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/block-ram-registrar.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/blockdev.h"
+#include "system/block-ram-registrar.h"
+#include "system/system.h"
+#include "system/runstate.h"
#include "hw/virtio/virtio-blk.h"
#include "scsi/constants.h"
#ifdef __linux__
@@ -33,6 +33,7 @@
#endif
#include "hw/virtio/virtio-bus.h"
#include "migration/qemu-file-types.h"
+#include "hw/virtio/iothread-vq-mapping.h"
#include "hw/virtio/virtio-access.h"
#include "hw/virtio/virtio-blk-common.h"
#include "qemu/coroutine.h"
@@ -50,12 +51,7 @@ static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
req->mr_next = NULL;
}
-static void virtio_blk_free_request(VirtIOBlockReq *req)
-{
- g_free(req);
-}
-
-static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
+void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
{
VirtIOBlock *s = req->dev;
VirtIODevice *vdev = VIRTIO_DEVICE(s);
@@ -93,7 +89,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
if (acct_failed) {
block_acct_failed(blk_get_stats(s->blk), &req->acct);
}
- virtio_blk_free_request(req);
+ g_free(req);
}
blk_error_action(s->blk, action, is_read, error);
@@ -136,7 +132,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
block_acct_done(blk_get_stats(s->blk), &req->acct);
- virtio_blk_free_request(req);
+ g_free(req);
}
}
@@ -151,7 +147,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
block_acct_done(blk_get_stats(s->blk), &req->acct);
- virtio_blk_free_request(req);
+ g_free(req);
}
static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
@@ -169,7 +165,7 @@ static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
if (is_write_zeroes) {
block_acct_done(blk_get_stats(s->blk), &req->acct);
}
- virtio_blk_free_request(req);
+ g_free(req);
}
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *vq)
@@ -214,7 +210,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
fail:
virtio_blk_req_complete(req, status);
- virtio_blk_free_request(req);
+ g_free(req);
}
static inline void submit_requests(VirtIOBlock *s, MultiReqBuffer *mrb,
@@ -612,7 +608,7 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
out:
virtio_blk_req_complete(req, err_status);
- virtio_blk_free_request(req);
+ g_free(req);
g_free(data->zone_report_data.zones);
g_free(data);
}
@@ -661,7 +657,7 @@ static void virtio_blk_handle_zone_report(VirtIOBlockReq *req,
return;
out:
virtio_blk_req_complete(req, err_status);
- virtio_blk_free_request(req);
+ g_free(req);
}
static void virtio_blk_zone_mgmt_complete(void *opaque, int ret)
@@ -677,7 +673,7 @@ static void virtio_blk_zone_mgmt_complete(void *opaque, int ret)
}
virtio_blk_req_complete(req, err_status);
- virtio_blk_free_request(req);
+ g_free(req);
}
static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op)
@@ -700,7 +696,7 @@ static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op)
} else {
if (bs->bl.zone_size > capacity - offset) {
/* The zoned device allows the last smaller zone. */
- len = capacity - bs->bl.zone_size * (bs->bl.nr_zones - 1);
+ len = capacity - bs->bl.zone_size * (bs->bl.nr_zones - 1ull);
} else {
len = bs->bl.zone_size;
}
@@ -719,7 +715,7 @@ static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op)
return 0;
out:
virtio_blk_req_complete(req, err_status);
- virtio_blk_free_request(req);
+ g_free(req);
return err_status;
}
@@ -750,7 +746,7 @@ static void virtio_blk_zone_append_complete(void *opaque, int ret)
out:
virtio_blk_req_complete(req, err_status);
- virtio_blk_free_request(req);
+ g_free(req);
g_free(data);
}
@@ -788,7 +784,7 @@ static int virtio_blk_handle_zone_append(VirtIOBlockReq *req,
out:
virtio_blk_req_complete(req, err_status);
- virtio_blk_free_request(req);
+ g_free(req);
return err_status;
}
@@ -855,7 +851,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
block_acct_invalid(blk_get_stats(s->blk),
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
- virtio_blk_free_request(req);
+ g_free(req);
return 0;
}
@@ -911,7 +907,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
VIRTIO_BLK_ID_BYTES));
iov_from_buf(in_iov, in_num, 0, serial, size);
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
- virtio_blk_free_request(req);
+ g_free(req);
break;
}
case VIRTIO_BLK_T_ZONE_APPEND & ~VIRTIO_BLK_T_OUT:
@@ -943,7 +939,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
if (unlikely(!(type & VIRTIO_BLK_T_OUT) ||
out_len > sizeof(dwz_hdr))) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
- virtio_blk_free_request(req);
+ g_free(req);
return 0;
}
@@ -960,14 +956,24 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
is_write_zeroes);
if (err_status != VIRTIO_BLK_S_OK) {
virtio_blk_req_complete(req, err_status);
- virtio_blk_free_request(req);
+ g_free(req);
}
break;
}
default:
- virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
- virtio_blk_free_request(req);
+ {
+ /*
+ * Give subclasses a chance to handle unknown requests. This way the
+ * class lookup is not in the hot path.
+ */
+ VirtIOBlkClass *vbk = VIRTIO_BLK_GET_CLASS(s);
+ if (!vbk->handle_unknown_request ||
+ !vbk->handle_unknown_request(req, mrb, type)) {
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+ g_free(req);
+ }
+ }
}
return 0;
}
@@ -988,7 +994,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
while ((req = virtio_blk_get_request(s, vq))) {
if (virtio_blk_handle_request(req, &mrb)) {
virtqueue_detach_element(req->vq, &req->elem, 0);
- virtio_blk_free_request(req);
+ g_free(req);
break;
}
}
@@ -1038,7 +1044,7 @@ static void virtio_blk_dma_restart_bh(void *opaque)
while (req) {
next = req->next;
virtqueue_detach_element(req->vq, &req->elem, 0);
- virtio_blk_free_request(req);
+ g_free(req);
req = next;
}
break;
@@ -1060,7 +1066,7 @@ static void virtio_blk_dma_restart_cb(void *opaque, bool running,
VirtIOBlock *s = opaque;
uint16_t num_queues = s->conf.num_queues;
g_autofree VirtIOBlockReq **vq_rq = NULL;
- VirtIOBlockReq *rq;
+ VirtIOBlockReq *rq = NULL;
if (!running) {
return;
@@ -1121,7 +1127,7 @@ static void virtio_blk_reset(VirtIODevice *vdev)
/* No other threads can access req->vq here */
virtqueue_detach_element(req->vq, &req->elem, 0);
- virtio_blk_free_request(req);
+ g_free(req);
}
}
@@ -1264,7 +1270,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
return features;
}
-static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
+static int virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
{
VirtIOBlock *s = VIRTIO_BLK(vdev);
@@ -1273,7 +1279,7 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
}
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return;
+ return 0;
}
/* A guest that supports VIRTIO_BLK_F_CONFIG_WCE must be able to send
@@ -1296,6 +1302,7 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
virtio_vdev_has_feature(vdev,
VIRTIO_BLK_F_WCE));
}
+ return 0;
}
static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
@@ -1418,128 +1425,6 @@ static const BlockDevOps virtio_block_ops = {
.drained_end = virtio_blk_drained_end,
};
-static bool
-validate_iothread_vq_mapping_list(IOThreadVirtQueueMappingList *list,
- uint16_t num_queues, Error **errp)
-{
- g_autofree unsigned long *vqs = bitmap_new(num_queues);
- g_autoptr(GHashTable) iothreads =
- g_hash_table_new(g_str_hash, g_str_equal);
-
- for (IOThreadVirtQueueMappingList *node = list; node; node = node->next) {
- const char *name = node->value->iothread;
- uint16List *vq;
-
- if (!iothread_by_id(name)) {
- error_setg(errp, "IOThread \"%s\" object does not exist", name);
- return false;
- }
-
- if (!g_hash_table_add(iothreads, (gpointer)name)) {
- error_setg(errp,
- "duplicate IOThread name \"%s\" in iothread-vq-mapping",
- name);
- return false;
- }
-
- if (node != list) {
- if (!!node->value->vqs != !!list->value->vqs) {
- error_setg(errp, "either all items in iothread-vq-mapping "
- "must have vqs or none of them must have it");
- return false;
- }
- }
-
- for (vq = node->value->vqs; vq; vq = vq->next) {
- if (vq->value >= num_queues) {
- error_setg(errp, "vq index %u for IOThread \"%s\" must be "
- "less than num_queues %u in iothread-vq-mapping",
- vq->value, name, num_queues);
- return false;
- }
-
- if (test_and_set_bit(vq->value, vqs)) {
- error_setg(errp, "cannot assign vq %u to IOThread \"%s\" "
- "because it is already assigned", vq->value, name);
- return false;
- }
- }
- }
-
- if (list->value->vqs) {
- for (uint16_t i = 0; i < num_queues; i++) {
- if (!test_bit(i, vqs)) {
- error_setg(errp,
- "missing vq %u IOThread assignment in iothread-vq-mapping",
- i);
- return false;
- }
- }
- }
-
- return true;
-}
-
-/**
- * apply_iothread_vq_mapping:
- * @iothread_vq_mapping_list: The mapping of virtqueues to IOThreads.
- * @vq_aio_context: The array of AioContext pointers to fill in.
- * @num_queues: The length of @vq_aio_context.
- * @errp: If an error occurs, a pointer to the area to store the error.
- *
- * Fill in the AioContext for each virtqueue in the @vq_aio_context array given
- * the iothread-vq-mapping parameter in @iothread_vq_mapping_list.
- *
- * Returns: %true on success, %false on failure.
- **/
-static bool apply_iothread_vq_mapping(
- IOThreadVirtQueueMappingList *iothread_vq_mapping_list,
- AioContext **vq_aio_context,
- uint16_t num_queues,
- Error **errp)
-{
- IOThreadVirtQueueMappingList *node;
- size_t num_iothreads = 0;
- size_t cur_iothread = 0;
-
- if (!validate_iothread_vq_mapping_list(iothread_vq_mapping_list,
- num_queues, errp)) {
- return false;
- }
-
- for (node = iothread_vq_mapping_list; node; node = node->next) {
- num_iothreads++;
- }
-
- for (node = iothread_vq_mapping_list; node; node = node->next) {
- IOThread *iothread = iothread_by_id(node->value->iothread);
- AioContext *ctx = iothread_get_aio_context(iothread);
-
- /* Released in virtio_blk_vq_aio_context_cleanup() */
- object_ref(OBJECT(iothread));
-
- if (node->value->vqs) {
- uint16List *vq;
-
- /* Explicit vq:IOThread assignment */
- for (vq = node->value->vqs; vq; vq = vq->next) {
- assert(vq->value < num_queues);
- vq_aio_context[vq->value] = ctx;
- }
- } else {
- /* Round-robin vq:IOThread assignment */
- for (unsigned i = cur_iothread; i < num_queues;
- i += num_iothreads) {
- vq_aio_context[i] = ctx;
- }
- }
-
- cur_iothread++;
- }
-
- return true;
-}
-
/* Context: BQL held */
static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
{
@@ -1567,21 +1452,12 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
error_setg(errp, "ioeventfd is required for iothread");
return false;
}
-
- /*
- * If ioeventfd is (re-)enabled while the guest is running there could
- * be block jobs that can conflict.
- */
- if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
- error_prepend(errp, "cannot start virtio-blk ioeventfd: ");
- return false;
- }
}
s->vq_aio_context = g_new(AioContext *, conf->num_queues);
if (conf->iothread_vq_mapping_list) {
- if (!apply_iothread_vq_mapping(conf->iothread_vq_mapping_list,
+ if (!iothread_vq_mapping_apply(conf->iothread_vq_mapping_list,
s->vq_aio_context,
conf->num_queues,
errp)) {
@@ -1615,12 +1491,7 @@ static void virtio_blk_vq_aio_context_cleanup(VirtIOBlock *s)
assert(!s->ioeventfd_started);
if (conf->iothread_vq_mapping_list) {
- IOThreadVirtQueueMappingList *node;
-
- for (node = conf->iothread_vq_mapping_list; node; node = node->next) {
- IOThread *iothread = iothread_by_id(node->value->iothread);
- object_unref(OBJECT(iothread));
- }
+ iothread_vq_mapping_cleanup(conf->iothread_vq_mapping_list);
}
if (conf->iothread) {
@@ -1932,7 +1803,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
* called after ->start_ioeventfd() has already set blk's AioContext.
*/
s->change =
- qdev_add_vm_change_state_handler(dev, virtio_blk_dma_restart_cb, s);
+ qdev_add_vm_change_state_handler(dev, virtio_blk_dma_restart_cb, NULL, s);
blk_ram_registrar_init(&s->blk_ram_registrar, s->blk);
blk_set_dev_ops(s->blk, &virtio_block_ops, s);
@@ -1985,7 +1856,7 @@ static const VMStateDescription vmstate_virtio_blk = {
},
};
-static Property virtio_blk_properties[] = {
+static const Property virtio_blk_properties[] = {
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf),
DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf),
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf),
@@ -2014,10 +1885,9 @@ static Property virtio_blk_properties[] = {
conf.max_write_zeroes_sectors, BDRV_REQUEST_MAX_SECTORS),
DEFINE_PROP_BOOL("x-enable-wce-if-config-wce", VirtIOBlock,
conf.x_enable_wce_if_config_wce, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_blk_class_init(ObjectClass *klass, void *data)
+static void virtio_blk_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -2044,6 +1914,7 @@ static const TypeInfo virtio_blk_info = {
.instance_size = sizeof(VirtIOBlock),
.instance_init = virtio_blk_instance_init,
.class_init = virtio_blk_class_init,
+ .class_size = sizeof(VirtIOBlkClass),
};
static void virtio_register_types(void)
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index aed1d5c..74de897 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -16,16 +16,16 @@
#include "qapi/qapi-visit-block-core.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/visitor.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qstring.h"
#include "qom/object_interfaces.h"
#include "hw/block/xen_blkif.h"
#include "hw/qdev-properties.h"
#include "hw/xen/xen-block.h"
#include "hw/xen/xen-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/iothread.h"
+#include "system/blockdev.h"
+#include "system/block-backend.h"
+#include "system/iothread.h"
#include "dataplane/xen-block.h"
#include "hw/xen/interface/io/xs_wire.h"
#include "trace.h"
@@ -239,7 +239,8 @@ static void xen_block_connect(XenDevice *xendev, Error **errp)
return;
}
- if (xen_device_frontend_scanf(xendev, "protocol", "%ms", &str) != 1) {
+ str = xen_device_frontend_read(xendev, "protocol");
+ if (!str) {
/* x86 defaults to the 32-bit protocol even for 64-bit guests. */
if (object_dynamic_cast(OBJECT(qdev_get_machine()), "x86-machine")) {
protocol = BLKIF_PROTOCOL_X86_32;
@@ -407,6 +408,8 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
}
xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
+ xen_device_backend_printf(xendev, "mode",
+ (blockdev->info & VDISK_READONLY) ? "r" : "w");
xen_device_frontend_printf(xendev, "virtual-device", "%lu",
vdev->number);
@@ -485,7 +488,7 @@ static char *disk_to_vbd_name(unsigned int disk)
static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
XenBlockVdev *vdev = object_field_prop_ptr(obj, prop);
char *str;
@@ -545,7 +548,7 @@ static int vbd_name_to_disk(const char *name, const char **endp,
static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
XenBlockVdev *vdev = object_field_prop_ptr(obj, prop);
char *str, *p;
const char *end;
@@ -659,14 +662,14 @@ invalid:
*
* https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
*/
-const PropertyInfo xen_block_prop_vdev = {
- .name = "str",
- .description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
+static const PropertyInfo xen_block_prop_vdev = {
+ .type = "str",
+ .description = "Virtual Disk specifier (d*p*/xvd*/hd*/sd*)",
.get = xen_block_get_vdev,
.set = xen_block_set_vdev,
};
-static Property xen_block_props[] = {
+static const Property xen_block_props[] = {
DEFINE_PROP("vdev", XenBlockDevice, props.vdev,
xen_block_prop_vdev, XenBlockVdev),
DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf),
@@ -674,10 +677,9 @@ static Property xen_block_props[] = {
props.max_ring_page_order, 4),
DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread,
TYPE_IOTHREAD, IOThread *),
- DEFINE_PROP_END_OF_LIST()
};
-static void xen_block_class_init(ObjectClass *class, void *data)
+static void xen_block_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
@@ -722,7 +724,7 @@ static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
blockdev->info = blk_supports_write_perm(conf->blk) ? 0 : VDISK_READONLY;
}
-static void xen_disk_class_init(ObjectClass *class, void *data)
+static void xen_disk_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
@@ -769,7 +771,7 @@ static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
blockdev->info = VDISK_READONLY | VDISK_CDROM;
}
-static void xen_cdrom_class_init(ObjectClass *class, void *data)
+static void xen_cdrom_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 4fd74ea..9d517f3 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -11,6 +11,12 @@ config PARALLEL
config PL011
bool
+ # The PL011 has both a Rust and a C implementation
+ select PL011_C if !HAVE_RUST
+ select X_PL011_RUST if HAVE_RUST
+
+config PL011_C
+ bool
config SERIAL
bool
@@ -21,6 +27,10 @@ config SERIAL_ISA
depends on ISA_BUS
select SERIAL
+config SERIAL_MM
+ bool
+ select SERIAL
+
config SERIAL_PCI
bool
default y if PCI_DEVICES
@@ -62,6 +72,9 @@ config RENESAS_SCI
config AVR_USART
bool
+config DIVA_GSP
+ bool
+
config MCHP_PFSOC_MMUART
bool
select SERIAL
@@ -74,3 +87,8 @@ config GOLDFISH_TTY
config SHAKTI_UART
bool
+
+config IP_OCTAL_232
+ bool
+ default y
+ depends on IPACK
diff --git a/hw/char/avr_usart.c b/hw/char/avr_usart.c
index 5bcf9db..fae1521 100644
--- a/hw/char/avr_usart.c
+++ b/hw/char/avr_usart.c
@@ -86,7 +86,7 @@ static void update_char_mask(AVRUsartState *usart)
usart->char_mask = 0b11111111;
break;
default:
- assert(0);
+ g_assert_not_reached();
}
}
@@ -259,9 +259,8 @@ static const MemoryRegionOps avr_usart_ops = {
.impl = {.min_access_size = 1, .max_access_size = 1}
};
-static Property avr_usart_properties[] = {
+static const Property avr_usart_properties[] = {
DEFINE_PROP_CHR("chardev", AVRUsartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void avr_usart_pr(void *opaque, int irq, int level)
@@ -296,11 +295,11 @@ static void avr_usart_realize(DeviceState *dev, Error **errp)
avr_usart_reset(dev);
}
-static void avr_usart_class_init(ObjectClass *klass, void *data)
+static void avr_usart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = avr_usart_reset;
+ device_class_set_legacy_reset(dc, avr_usart_reset);
device_class_set_props(dc, avr_usart_properties);
dc->realize = avr_usart_realize;
}
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index fca2f27..2b397f2 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -98,7 +98,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
* interrupts are active, besides that this cannot occur. At
* present, we choose to prioritise the rx interrupt, since
* the tx fifo is always empty. */
- if (s->read_count != 0) {
+ if ((s->iir & RX_INT) && s->read_count != 0) {
res |= 0x4;
} else {
res |= 0x2;
@@ -221,7 +221,7 @@ static int bcm2835_aux_can_receive(void *opaque)
{
BCM2835AuxState *s = opaque;
- return s->read_count < BCM2835_AUX_RX_FIFO_LEN;
+ return BCM2835_AUX_RX_FIFO_LEN - s->read_count;
}
static void bcm2835_aux_put_fifo(void *opaque, uint8_t value)
@@ -243,7 +243,9 @@ static void bcm2835_aux_put_fifo(void *opaque, uint8_t value)
static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size)
{
- bcm2835_aux_put_fifo(opaque, *buf);
+ for (int i = 0; i < size; i++) {
+ bcm2835_aux_put_fifo(opaque, buf[i]);
+ }
}
static const MemoryRegionOps bcm2835_aux_ops = {
@@ -290,12 +292,11 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
bcm2835_aux_receive, NULL, NULL, s, NULL, true);
}
-static Property bcm2835_aux_props[] = {
+static const Property bcm2835_aux_props[] = {
DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void bcm2835_aux_class_init(ObjectClass *oc, void *data)
+static void bcm2835_aux_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index 77d9a2a..0dfa356 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -617,12 +617,11 @@ static const VMStateDescription vmstate_cadence_uart = {
},
};
-static Property cadence_uart_properties[] = {
+static const Property cadence_uart_properties[] = {
DEFINE_PROP_CHR("chardev", CadenceUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cadence_uart_class_init(ObjectClass *klass, void *data)
+static void cadence_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c
index d07cca1..32090f3 100644
--- a/hw/char/cmsdk-apb-uart.c
+++ b/hw/char/cmsdk-apb-uart.c
@@ -377,19 +377,18 @@ static const VMStateDescription cmsdk_apb_uart_vmstate = {
}
};
-static Property cmsdk_apb_uart_properties[] = {
+static const Property cmsdk_apb_uart_properties[] = {
DEFINE_PROP_CHR("chardev", CMSDKAPBUART, chr),
DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBUART, pclk_frq, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cmsdk_apb_uart_class_init(ObjectClass *klass, void *data)
+static void cmsdk_apb_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cmsdk_apb_uart_realize;
dc->vmsd = &cmsdk_apb_uart_vmstate;
- dc->reset = cmsdk_apb_uart_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_uart_reset);
device_class_set_props(dc, cmsdk_apb_uart_properties);
}
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index fdb04fe..bf44aaf 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -114,14 +114,13 @@ static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
isa->iobase, &s->io);
}
-static Property debugcon_isa_properties[] = {
+static const Property debugcon_isa_properties[] = {
DEFINE_PROP_UINT32("iobase", ISADebugconState, iobase, 0xe9),
DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
DEFINE_PROP_UINT32("readback", ISADebugconState, state.readback, 0xe9),
- DEFINE_PROP_END_OF_LIST(),
};
-static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
+static void debugcon_isa_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index ef2d762..0f6af51 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -172,17 +172,16 @@ static const VMStateDescription vmstate_digic_uart = {
}
};
-static Property digic_uart_properties[] = {
+static const Property digic_uart_properties[] = {
DEFINE_PROP_CHR("chardev", DigicUartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void digic_uart_class_init(ObjectClass *klass, void *data)
+static void digic_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = digic_uart_realize;
- dc->reset = digic_uart_reset;
+ device_class_set_legacy_reset(dc, digic_uart_reset);
dc->vmsd = &vmstate_digic_uart;
device_class_set_props(dc, digic_uart_properties);
}
diff --git a/hw/char/diva-gsp.c b/hw/char/diva-gsp.c
new file mode 100644
index 0000000..e1f0713
--- /dev/null
+++ b/hw/char/diva-gsp.c
@@ -0,0 +1,295 @@
+/*
+ * HP Diva GSP controller
+ *
+ * The Diva PCI boards are Remote Management cards for PA-RISC machines.
+ * They come with built-in 16550A multi UARTs for serial consoles
+ * and a mailbox-like memory area for hardware auto-reboot functionality.
+ * GSP stands for "Guardian Service Processor". Later products were marketed
+ * "Management Processor" (MP).
+ *
+ * Diva cards are multifunctional cards. The first part, the aux port,
+ * is on physical machines not useable but we still try to mimic it here.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2025 Helge Deller <deller@gmx.de>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "hw/char/serial.h"
+#include "hw/irq.h"
+#include "hw/pci/pci_device.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "migration/vmstate.h"
+
+#define PCI_DEVICE_ID_HP_DIVA 0x1048
+/* various DIVA GSP cards: */
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A
+#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B
+#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1
+#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223
+#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226
+#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227
+#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282
+#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290
+#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301
+#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a
+
+
+#define PCI_SERIAL_MAX_PORTS 4
+
+typedef struct PCIDivaSerialState {
+ PCIDevice dev;
+ MemoryRegion membar; /* for serial ports */
+ MemoryRegion mailboxbar; /* for hardware mailbox */
+ uint32_t subvendor;
+ uint32_t ports;
+ char *name[PCI_SERIAL_MAX_PORTS];
+ SerialState state[PCI_SERIAL_MAX_PORTS];
+ uint32_t level[PCI_SERIAL_MAX_PORTS];
+ qemu_irq *irqs;
+ bool disable;
+} PCIDivaSerialState;
+
+static void diva_pci_exit(PCIDevice *dev)
+{
+ PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ SerialState *s;
+ int i;
+
+ for (i = 0; i < pci->ports; i++) {
+ s = pci->state + i;
+ qdev_unrealize(DEVICE(s));
+ memory_region_del_subregion(&pci->membar, &s->io);
+ g_free(pci->name[i]);
+ }
+ qemu_free_irqs(pci->irqs, pci->ports);
+}
+
+static void multi_serial_irq_mux(void *opaque, int n, int level)
+{
+ PCIDivaSerialState *pci = opaque;
+ int i, pending = 0;
+
+ pci->level[n] = level;
+ for (i = 0; i < pci->ports; i++) {
+ if (pci->level[i]) {
+ pending = 1;
+ }
+ }
+ pci_set_irq(&pci->dev, pending);
+}
+
+struct diva_info {
+ unsigned int nports:4; /* number of serial ports */
+ unsigned int omask:12; /* offset mask: BIT(1) -> offset 8 */
+};
+
+static struct diva_info diva_get_diva_info(PCIDeviceClass *pc)
+{
+ switch (pc->subsystem_id) {
+ case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
+ case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
+ return (struct diva_info) { .nports = 1,
+ .omask = BIT(0) };
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
+ return (struct diva_info) { .nports = 2,
+ .omask = BIT(0) | BIT(1) };
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
+ case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
+ case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
+ return (struct diva_info) { .nports = 3,
+ .omask = BIT(0) | BIT(1) | BIT(2) };
+ case PCI_DEVICE_ID_HP_DIVA_EVEREST: /* e.g. in rp3410 */
+ return (struct diva_info) { .nports = 3,
+ .omask = BIT(0) | BIT(2) | BIT(7) };
+ case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+ return (struct diva_info) { .nports = 4,
+ .omask = BIT(0) | BIT(1) | BIT(2) | BIT(7) };
+ }
+ g_assert_not_reached();
+}
+
+
+static void diva_pci_realize(PCIDevice *dev, Error **errp)
+{
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ SerialState *s;
+ struct diva_info di = diva_get_diva_info(pc);
+ size_t i, offset = 0;
+ size_t portmask = di.omask;
+
+ pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */
+ pci->dev.config[PCI_INTERRUPT_PIN] = 1;
+ memory_region_init(&pci->membar, OBJECT(pci), "serial_ports", 4096);
+ pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->membar);
+ pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, di.nports);
+
+ for (i = 0; i < di.nports; i++) {
+ s = pci->state + i;
+ if (!qdev_realize(DEVICE(s), NULL, errp)) {
+ diva_pci_exit(dev);
+ return;
+ }
+ s->irq = pci->irqs[i];
+ pci->name[i] = g_strdup_printf("uart #%zu", i + 1);
+ memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
+ pci->name[i], 8);
+
+ /* calculate offset of given port based on bitmask */
+ while ((portmask & BIT(0)) == 0) {
+ offset += 8;
+ portmask >>= 1;
+ }
+ memory_region_add_subregion(&pci->membar, offset, &s->io);
+ offset += 8;
+ portmask >>= 1;
+ pci->ports++;
+ }
+
+ /* mailbox bar */
+ memory_region_init(&pci->mailboxbar, OBJECT(pci), "mailbox", 128 * KiB);
+ pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &pci->mailboxbar);
+}
+
+static const VMStateDescription vmstate_pci_diva = {
+ .name = "pci-diva-serial",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, PCIDivaSerialState),
+ VMSTATE_STRUCT_ARRAY(state, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS,
+ 0, vmstate_serial, SerialState),
+ VMSTATE_UINT32_ARRAY(level, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS),
+ VMSTATE_BOOL(disable, PCIDivaSerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property diva_serial_properties[] = {
+ DEFINE_PROP_BOOL("disable", PCIDivaSerialState, disable, false),
+ DEFINE_PROP_CHR("chardev1", PCIDivaSerialState, state[0].chr),
+ DEFINE_PROP_CHR("chardev2", PCIDivaSerialState, state[1].chr),
+ DEFINE_PROP_CHR("chardev3", PCIDivaSerialState, state[2].chr),
+ DEFINE_PROP_CHR("chardev4", PCIDivaSerialState, state[3].chr),
+ DEFINE_PROP_UINT32("subvendor", PCIDivaSerialState, subvendor,
+ PCI_DEVICE_ID_HP_DIVA_TOSCA1),
+};
+
+static void diva_serial_class_initfn(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+ pc->realize = diva_pci_realize;
+ pc->exit = diva_pci_exit;
+ pc->vendor_id = PCI_VENDOR_ID_HP;
+ pc->device_id = PCI_DEVICE_ID_HP_DIVA;
+ pc->subsystem_vendor_id = PCI_VENDOR_ID_HP;
+ pc->subsystem_id = PCI_DEVICE_ID_HP_DIVA_TOSCA1;
+ pc->revision = 3;
+ pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+ dc->vmsd = &vmstate_pci_diva;
+ device_class_set_props(dc, diva_serial_properties);
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static void diva_serial_init(Object *o)
+{
+ PCIDevice *dev = PCI_DEVICE(o);
+ PCIDivaSerialState *pms = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ struct diva_info di = diva_get_diva_info(PCI_DEVICE_GET_CLASS(dev));
+ size_t i;
+
+ for (i = 0; i < di.nports; i++) {
+ object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIAL);
+ }
+}
+
+
+/* Diva-aux is the driver for portion 0 of the multifunction PCI device */
+
+struct DivaAuxState {
+ PCIDevice dev;
+ MemoryRegion mem;
+ qemu_irq irq;
+};
+
+#define TYPE_DIVA_AUX "diva-aux"
+OBJECT_DECLARE_SIMPLE_TYPE(DivaAuxState, DIVA_AUX)
+
+static void diva_aux_realize(PCIDevice *dev, Error **errp)
+{
+ DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev);
+
+ pci->dev.config[PCI_CLASS_PROG] = 0x02;
+ pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ pci->irq = pci_allocate_irq(&pci->dev);
+
+ memory_region_init(&pci->mem, OBJECT(pci), "mem", 16);
+ pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->mem);
+}
+
+static void diva_aux_exit(PCIDevice *dev)
+{
+ DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev);
+ qemu_free_irq(pci->irq);
+}
+
+static void diva_aux_class_initfn(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+ pc->realize = diva_aux_realize;
+ pc->exit = diva_aux_exit;
+ pc->vendor_id = PCI_VENDOR_ID_HP;
+ pc->device_id = PCI_DEVICE_ID_HP_DIVA_AUX;
+ pc->subsystem_vendor_id = PCI_VENDOR_ID_HP;
+ pc->subsystem_id = 0x1291;
+ pc->revision = 1;
+ pc->class_id = PCI_CLASS_COMMUNICATION_MULTISERIAL;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->user_creatable = false;
+}
+
+static void diva_aux_init(Object *o)
+{
+}
+
+static const TypeInfo diva_aux_info = {
+ .name = TYPE_DIVA_AUX,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(DivaAuxState),
+ .instance_init = diva_aux_init,
+ .class_init = diva_aux_class_initfn,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+
+
+static const TypeInfo diva_serial_pci_info = {
+ .name = "diva-gsp",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDivaSerialState),
+ .instance_init = diva_serial_init,
+ .class_init = diva_serial_class_initfn,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+static void diva_pci_register_type(void)
+{
+ type_register_static(&diva_serial_pci_info);
+ type_register_static(&diva_aux_info);
+}
+
+type_init(diva_pci_register_type)
diff --git a/hw/char/escc.c b/hw/char/escc.c
index d450d70..afe4ca4 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -287,6 +287,7 @@ static void escc_reset_chn(ESCCChannelState *s)
s->rxint = s->txint = 0;
s->rxint_under_svc = s->txint_under_svc = 0;
s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
+ s->sunmouse_dx = s->sunmouse_dy = s->sunmouse_buttons = 0;
clear_queue(s);
}
@@ -952,53 +953,96 @@ static void handle_kbd_command(ESCCChannelState *s, int val)
}
}
-static void sunmouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
+static void sunmouse_handle_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- ESCCChannelState *s = opaque;
- int ch;
+ ESCCChannelState *s = (ESCCChannelState *)dev;
+ InputMoveEvent *move;
+ InputBtnEvent *btn;
+ static const int bmap[INPUT_BUTTON__MAX] = {
+ [INPUT_BUTTON_LEFT] = 0x4,
+ [INPUT_BUTTON_MIDDLE] = 0x2,
+ [INPUT_BUTTON_RIGHT] = 0x1,
+ };
+
+ switch (evt->type) {
+ case INPUT_EVENT_KIND_REL:
+ move = evt->u.rel.data;
+ if (move->axis == INPUT_AXIS_X) {
+ s->sunmouse_dx += move->value;
+ } else if (move->axis == INPUT_AXIS_Y) {
+ s->sunmouse_dy -= move->value;
+ }
+ break;
- trace_escc_sunmouse_event(dx, dy, buttons_state);
- ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+ case INPUT_EVENT_KIND_BTN:
+ btn = evt->u.btn.data;
+ if (bmap[btn->button]) {
+ if (btn->down) {
+ s->sunmouse_buttons |= bmap[btn->button];
+ } else {
+ s->sunmouse_buttons &= ~bmap[btn->button];
+ }
+ /* Indicate we have a supported button event */
+ s->sunmouse_buttons |= 0x80;
+ }
+ break;
- if (buttons_state & MOUSE_EVENT_LBUTTON) {
- ch ^= 0x4;
- }
- if (buttons_state & MOUSE_EVENT_MBUTTON) {
- ch ^= 0x2;
+ default:
+ /* keep gcc happy */
+ break;
}
- if (buttons_state & MOUSE_EVENT_RBUTTON) {
- ch ^= 0x1;
+}
+
+static void sunmouse_sync(DeviceState *dev)
+{
+ ESCCChannelState *s = (ESCCChannelState *)dev;
+ int ch;
+
+ if (s->sunmouse_dx == 0 && s->sunmouse_dy == 0 &&
+ (s->sunmouse_buttons & 0x80) == 0) {
+ /* Nothing to do after button event filter */
+ return;
}
+ /* Clear our button event flag */
+ s->sunmouse_buttons &= ~0x80;
+ trace_escc_sunmouse_event(s->sunmouse_dx, s->sunmouse_dy,
+ s->sunmouse_buttons);
+ ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+ ch ^= s->sunmouse_buttons;
put_queue(s, ch);
- ch = dx;
-
+ ch = s->sunmouse_dx;
if (ch > 127) {
ch = 127;
} else if (ch < -127) {
ch = -127;
}
-
put_queue(s, ch & 0xff);
+ s->sunmouse_dx -= ch;
- ch = -dy;
-
+ ch = s->sunmouse_dy;
if (ch > 127) {
ch = 127;
} else if (ch < -127) {
ch = -127;
}
-
put_queue(s, ch & 0xff);
+ s->sunmouse_dy -= ch;
/* MSC protocol specifies two extra motion bytes */
-
put_queue(s, 0);
put_queue(s, 0);
}
+static const QemuInputHandler sunmouse_handler = {
+ .name = "QEMU Sun Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+ .event = sunmouse_handle_event,
+ .sync = sunmouse_sync,
+};
+
static void escc_init1(Object *obj)
{
ESCCState *s = ESCC(obj);
@@ -1036,8 +1080,8 @@ static void escc_realize(DeviceState *dev, Error **errp)
}
if (s->chn[0].type == escc_mouse) {
- qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
- "QEMU Sun Mouse");
+ s->chn[0].hs = qemu_input_handler_register((DeviceState *)(&s->chn[0]),
+ &sunmouse_handler);
}
if (s->chn[1].type == escc_kbd) {
s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]),
@@ -1045,7 +1089,7 @@ static void escc_realize(DeviceState *dev, Error **errp)
}
}
-static Property escc_properties[] = {
+static const Property escc_properties[] = {
DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0),
DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0),
DEFINE_PROP_BOOL("bit_swap", ESCCState, bit_swap, false),
@@ -1055,14 +1099,13 @@ static Property escc_properties[] = {
DEFINE_PROP_CHR("chrB", ESCCState, chn[0].chr),
DEFINE_PROP_CHR("chrA", ESCCState, chn[1].chr),
DEFINE_PROP_STRING("chnA-sunkbd-layout", ESCCState, chn[1].sunkbd_layout),
- DEFINE_PROP_END_OF_LIST(),
};
-static void escc_class_init(ObjectClass *klass, void *data)
+static void escc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = escc_reset;
+ device_class_set_legacy_reset(dc, escc_reset);
dc->realize = escc_realize;
dc->vmsd = &vmstate_escc;
device_class_set_props(dc, escc_properties);
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
deleted file mode 100644
index 8d6422d..0000000
--- a/hw/char/etraxfs_ser.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * QEMU ETRAX System Emulator
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/sysbus.h"
-#include "chardev/char-fe.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define D(x)
-
-#define RW_TR_CTRL (0x00 / 4)
-#define RW_TR_DMA_EN (0x04 / 4)
-#define RW_REC_CTRL (0x08 / 4)
-#define RW_DOUT (0x1c / 4)
-#define RS_STAT_DIN (0x20 / 4)
-#define R_STAT_DIN (0x24 / 4)
-#define RW_INTR_MASK (0x2c / 4)
-#define RW_ACK_INTR (0x30 / 4)
-#define R_INTR (0x34 / 4)
-#define R_MASKED_INTR (0x38 / 4)
-#define R_MAX (0x3c / 4)
-
-#define STAT_DAV 16
-#define STAT_TR_IDLE 22
-#define STAT_TR_RDY 24
-
-#define TYPE_ETRAX_FS_SERIAL "etraxfs-serial"
-typedef struct ETRAXSerial ETRAXSerial;
-DECLARE_INSTANCE_CHECKER(ETRAXSerial, ETRAX_SERIAL,
- TYPE_ETRAX_FS_SERIAL)
-
-struct ETRAXSerial {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- CharBackend chr;
- qemu_irq irq;
-
- int pending_tx;
-
- uint8_t rx_fifo[16];
- unsigned int rx_fifo_pos;
- unsigned int rx_fifo_len;
-
- /* Control registers. */
- uint32_t regs[R_MAX];
-};
-
-static void ser_update_irq(ETRAXSerial *s)
-{
-
- if (s->rx_fifo_len) {
- s->regs[R_INTR] |= 8;
- } else {
- s->regs[R_INTR] &= ~8;
- }
-
- s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
- qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
-}
-
-static uint64_t
-ser_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXSerial *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- case R_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- case RS_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- s->rx_fifo_len--;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- default:
- r = s->regs[addr];
- D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr, r));
- break;
- }
- return r;
-}
-
-static void
-ser_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXSerial *s = opaque;
- uint32_t value = val64;
- unsigned char ch = val64;
-
- D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr, value));
- addr >>= 2;
- switch (addr)
- {
- case RW_DOUT:
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, &ch, 1);
- s->regs[R_INTR] |= 3;
- s->pending_tx = 1;
- s->regs[addr] = value;
- break;
- case RW_ACK_INTR:
- if (s->pending_tx) {
- value &= ~1;
- s->pending_tx = 0;
- D(qemu_log("fixedup value=%x r_intr=%x\n",
- value, s->regs[R_INTR]));
- }
- s->regs[addr] = value;
- s->regs[R_INTR] &= ~value;
- D(printf("r_intr=%x\n", s->regs[R_INTR]));
- break;
- default:
- s->regs[addr] = value;
- break;
- }
- ser_update_irq(s);
-}
-
-static const MemoryRegionOps ser_ops = {
- .read = ser_read,
- .write = ser_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static Property etraxfs_ser_properties[] = {
- DEFINE_PROP_CHR("chardev", ETRAXSerial, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_receive(void *opaque, const uint8_t *buf, int size)
-{
- ETRAXSerial *s = opaque;
- int i;
-
- /* Got a byte. */
- if (s->rx_fifo_len >= 16) {
- D(qemu_log("WARNING: UART dropped char.\n"));
- return;
- }
-
- for (i = 0; i < size; i++) {
- s->rx_fifo[s->rx_fifo_pos] = buf[i];
- s->rx_fifo_pos++;
- s->rx_fifo_pos &= 15;
- s->rx_fifo_len++;
- }
-
- ser_update_irq(s);
-}
-
-static int serial_can_receive(void *opaque)
-{
- ETRAXSerial *s = opaque;
-
- /* Is the receiver enabled? */
- if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
- return 0;
- }
-
- return sizeof(s->rx_fifo) - s->rx_fifo_len;
-}
-
-static void serial_event(void *opaque, QEMUChrEvent event)
-{
-
-}
-
-static void etraxfs_ser_reset(DeviceState *d)
-{
- ETRAXSerial *s = ETRAX_SERIAL(d);
-
- /* transmitter begins ready and idle. */
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
-
- s->regs[RW_REC_CTRL] = 0x10000;
-
-}
-
-static void etraxfs_ser_init(Object *obj)
-{
- ETRAXSerial *s = ETRAX_SERIAL(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->mmio, obj, &ser_ops, s,
- "etraxfs-serial", R_MAX * 4);
- sysbus_init_mmio(dev, &s->mmio);
-}
-
-static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
-{
- ETRAXSerial *s = ETRAX_SERIAL(dev);
-
- qemu_chr_fe_set_handlers(&s->chr,
- serial_can_receive, serial_receive,
- serial_event, NULL, s, NULL, true);
-}
-
-static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = etraxfs_ser_reset;
- device_class_set_props(dc, etraxfs_ser_properties);
- dc->realize = etraxfs_ser_realize;
-}
-
-static const TypeInfo etraxfs_ser_info = {
- .name = TYPE_ETRAX_FS_SERIAL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXSerial),
- .instance_init = etraxfs_ser_init,
- .class_init = etraxfs_ser_class_init,
-};
-
-static void etraxfs_serial_register_types(void)
-{
- type_register_static(&etraxfs_ser_info);
-}
-
-type_init(etraxfs_serial_register_types)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 8cdd42e..6521b4c 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -704,20 +704,19 @@ static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
NULL, s, NULL, true);
}
-static Property exynos4210_uart_properties[] = {
+static const Property exynos4210_uart_properties[] = {
DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
- DEFINE_PROP_END_OF_LIST(),
};
-static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
+static void exynos4210_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = exynos4210_uart_realize;
- dc->reset = exynos4210_uart_reset;
+ device_class_set_legacy_reset(dc, exynos4210_uart_reset);
device_class_set_props(dc, exynos4210_uart_properties);
dc->vmsd = &vmstate_exynos4210_uart;
}
diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c
index c2e1f65..a37408a 100644
--- a/hw/char/goldfish_tty.c
+++ b/hw/char/goldfish_tty.c
@@ -15,8 +15,8 @@
#include "chardev/char-fe.h"
#include "qemu/log.h"
#include "trace.h"
-#include "exec/address-spaces.h"
-#include "sysemu/dma.h"
+#include "system/address-spaces.h"
+#include "system/dma.h"
#include "hw/char/goldfish_tty.h"
#define GOLDFISH_TTY_VERSION 1
@@ -241,9 +241,8 @@ static const VMStateDescription vmstate_goldfish_tty = {
}
};
-static Property goldfish_tty_properties[] = {
+static const Property goldfish_tty_properties[] = {
DEFINE_PROP_CHR("chardev", GoldfishTTYState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void goldfish_tty_instance_init(Object *obj)
@@ -257,12 +256,12 @@ static void goldfish_tty_instance_init(Object *obj)
sysbus_init_irq(dev, &s->irq);
}
-static void goldfish_tty_class_init(ObjectClass *oc, void *data)
+static void goldfish_tty_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, goldfish_tty_properties);
- dc->reset = goldfish_tty_reset;
+ device_class_set_legacy_reset(dc, goldfish_tty_reset);
dc->realize = goldfish_tty_realize;
dc->unrealize = goldfish_tty_unrealize;
dc->vmsd = &vmstate_goldfish_tty;
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 515b65b..81c26e3 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -277,17 +277,16 @@ static void grlib_apbuart_reset(DeviceState *d)
uart->current = 0;
}
-static Property grlib_apbuart_properties[] = {
+static const Property grlib_apbuart_properties[] = {
DEFINE_PROP_CHR("chrdev", UART, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
+static void grlib_apbuart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = grlib_apbuart_realize;
- dc->reset = grlib_apbuart_reset;
+ device_class_set_legacy_reset(dc, grlib_apbuart_reset);
device_class_set_props(dc, grlib_apbuart_properties);
}
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index 63aae6d..d6f0d18 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -508,9 +508,8 @@ static const VMStateDescription vmstate_ibex_uart = {
}
};
-static Property ibex_uart_properties[] = {
+static const Property ibex_uart_properties[] = {
DEFINE_PROP_CHR("chardev", IbexUartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void ibex_uart_init(Object *obj)
@@ -543,11 +542,11 @@ static void ibex_uart_realize(DeviceState *dev, Error **errp)
s, NULL, true);
}
-static void ibex_uart_class_init(ObjectClass *klass, void *data)
+static void ibex_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ibex_uart_reset;
+ device_class_set_legacy_reset(dc, ibex_uart_reset);
dc->realize = ibex_uart_realize;
dc->vmsd = &vmstate_ibex_uart;
device_class_set_props(dc, ibex_uart_properties);
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index ba37be6..509b014 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -27,6 +27,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/fifo32.h"
+#include "trace.h"
#ifndef DEBUG_IMX_UART
#define DEBUG_IMX_UART 0
@@ -159,6 +160,7 @@ static void imx_serial_reset(IMXSerialState *s)
s->ucr3 = 0x700;
s->ubmr = 0;
s->ubrc = 4;
+ s->ufcr = BIT(11) | BIT(0);
fifo32_reset(&s->rx_fifo);
timer_del(&s->ageing_timer);
@@ -184,10 +186,10 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
unsigned size)
{
IMXSerialState *s = (IMXSerialState *)opaque;
+ Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
uint32_t c, rx_used;
uint8_t rxtl = s->ufcr & TL_MASK;
-
- DPRINTF("read(offset=0x%" HWADDR_PRIx ")\n", offset);
+ uint64_t value;
switch (offset >> 2) {
case 0x0: /* URXD */
@@ -208,49 +210,67 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
imx_serial_rx_fifo_ageing_timer_restart(s);
qemu_chr_fe_accept_input(&s->chr);
}
- return c;
+ value = c;
+ break;
case 0x20: /* UCR1 */
- return s->ucr1;
+ value = s->ucr1;
+ break;
case 0x21: /* UCR2 */
- return s->ucr2;
+ value = s->ucr2;
+ break;
case 0x25: /* USR1 */
- return s->usr1;
+ value = s->usr1;
+ break;
case 0x26: /* USR2 */
- return s->usr2;
+ value = s->usr2;
+ break;
case 0x2A: /* BRM Modulator */
- return s->ubmr;
+ value = s->ubmr;
+ break;
case 0x2B: /* Baud Rate Count */
- return s->ubrc;
+ value = s->ubrc;
+ break;
case 0x2d: /* Test register */
- return s->uts1;
+ value = s->uts1;
+ break;
case 0x24: /* UFCR */
- return s->ufcr;
+ value = s->ufcr;
+ break;
case 0x2c:
- return s->onems;
+ value = s->onems;
+ break;
case 0x22: /* UCR3 */
- return s->ucr3;
+ value = s->ucr3;
+ break;
case 0x23: /* UCR4 */
- return s->ucr4;
+ value = s->ucr4;
+ break;
case 0x29: /* BRM Incremental */
- return 0x0; /* TODO */
+ value = 0x0; /* TODO */
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
- return 0;
+ value = 0;
+ break;
}
+
+ trace_imx_serial_read(chr ? chr->label : "NODEV", offset, value);
+
+ return value;
}
static void imx_serial_write(void *opaque, hwaddr offset,
@@ -260,8 +280,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
unsigned char ch;
- DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
- offset, (unsigned int)value, chr ? chr->label : "NODEV");
+ trace_imx_serial_write(chr ? chr->label : "NODEV", offset, value);
switch (offset >> 2) {
case 0x10: /* UTXD */
@@ -367,27 +386,30 @@ static void imx_serial_write(void *opaque, hwaddr offset,
static int imx_can_receive(void *opaque)
{
IMXSerialState *s = (IMXSerialState *)opaque;
- return s->ucr2 & UCR2_RXEN && fifo32_num_used(&s->rx_fifo) < FIFO_SIZE;
+
+ return s->ucr2 & UCR2_RXEN ? fifo32_num_free(&s->rx_fifo) : 0;
}
static void imx_put_data(void *opaque, uint32_t value)
{
IMXSerialState *s = (IMXSerialState *)opaque;
+ Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
uint8_t rxtl = s->ufcr & TL_MASK;
- DPRINTF("received char\n");
+ trace_imx_serial_put_data(chr ? chr->label : "NODEV", value);
+
imx_serial_rx_fifo_push(s, value);
if (fifo32_num_used(&s->rx_fifo) >= rxtl) {
s->usr1 |= USR1_RRDY;
}
-
- imx_serial_rx_fifo_ageing_timer_restart(s);
-
s->usr2 |= USR2_RDR;
s->uts1 &= ~UTS1_RXEMPTY;
if (value & URXD_BRK) {
s->usr2 |= USR2_BRCD;
}
+
+ imx_serial_rx_fifo_ageing_timer_restart(s);
+
imx_update(s);
}
@@ -396,7 +418,10 @@ static void imx_receive(void *opaque, const uint8_t *buf, int size)
IMXSerialState *s = (IMXSerialState *)opaque;
s->usr2 |= USR2_WAKE;
- imx_put_data(opaque, *buf);
+
+ for (int i = 0; i < size; i++) {
+ imx_put_data(opaque, buf[i]);
+ }
}
static void imx_event(void *opaque, QEMUChrEvent event)
@@ -438,18 +463,17 @@ static void imx_serial_init(Object *obj)
sysbus_init_irq(sbd, &s->irq);
}
-static Property imx_serial_properties[] = {
+static const Property imx_serial_properties[] = {
DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void imx_serial_class_init(ObjectClass *klass, void *data)
+static void imx_serial_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_serial_realize;
dc->vmsd = &vmstate_imx_serial;
- dc->reset = imx_serial_reset_at_boot;
+ device_class_set_legacy_reset(dc, imx_serial_reset_at_boot);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->desc = "i.MX series UART";
device_class_set_props(dc, imx_serial_properties);
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 64be522..752c6c8 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -184,9 +184,9 @@ static void update_irq(IPOctalState *dev, unsigned block)
unsigned intno = block / 2;
if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) {
- qemu_irq_raise(idev->irq[intno]);
+ qemu_irq_raise(&idev->irq[intno]);
} else {
- qemu_irq_lower(idev->irq[intno]);
+ qemu_irq_lower(&idev->irq[intno]);
}
}
@@ -558,7 +558,7 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
}
}
-static Property ipoctal_properties[] = {
+static const Property ipoctal_properties[] = {
DEFINE_PROP_CHR("chardev0", IPOctalState, ch[0].dev),
DEFINE_PROP_CHR("chardev1", IPOctalState, ch[1].dev),
DEFINE_PROP_CHR("chardev2", IPOctalState, ch[2].dev),
@@ -567,10 +567,9 @@ static Property ipoctal_properties[] = {
DEFINE_PROP_CHR("chardev5", IPOctalState, ch[5].dev),
DEFINE_PROP_CHR("chardev6", IPOctalState, ch[6].dev),
DEFINE_PROP_CHR("chardev7", IPOctalState, ch[7].dev),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ipoctal_class_init(ObjectClass *klass, void *data)
+static void ipoctal_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass);
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index f9cbc9b..87bfcbe 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -17,6 +17,8 @@
#include "chardev/char-fe.h"
#include "qom/object.h"
+#define FIFO_DEPTH 4
+
struct mcf_uart_state {
SysBusDevice parent_obj;
@@ -27,7 +29,7 @@ struct mcf_uart_state {
uint8_t imr;
uint8_t bg1;
uint8_t bg2;
- uint8_t fifo[4];
+ uint8_t fifo[FIFO_DEPTH];
uint8_t tb;
int current_mr;
int fifo_len;
@@ -247,14 +249,16 @@ static void mcf_uart_reset(DeviceState *dev)
static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
{
/* Break events overwrite the last byte if the fifo is full. */
- if (s->fifo_len == 4)
+ if (s->fifo_len == FIFO_DEPTH) {
s->fifo_len--;
+ }
s->fifo[s->fifo_len] = data;
s->fifo_len++;
s->sr |= MCF_UART_RxRDY;
- if (s->fifo_len == 4)
+ if (s->fifo_len == FIFO_DEPTH) {
s->sr |= MCF_UART_FFULL;
+ }
mcf_uart_update(s);
}
@@ -277,14 +281,16 @@ static int mcf_uart_can_receive(void *opaque)
{
mcf_uart_state *s = (mcf_uart_state *)opaque;
- return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
+ return s->rx_enabled ? FIFO_DEPTH - s->fifo_len : 0;
}
static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
{
mcf_uart_state *s = (mcf_uart_state *)opaque;
- mcf_uart_push_byte(s, buf[0]);
+ for (int i = 0; i < size; i++) {
+ mcf_uart_push_byte(s, buf[i]);
+ }
}
static const MemoryRegionOps mcf_uart_ops = {
@@ -312,17 +318,16 @@ static void mcf_uart_realize(DeviceState *dev, Error **errp)
mcf_uart_event, NULL, s, NULL, true);
}
-static Property mcf_uart_properties[] = {
+static const Property mcf_uart_properties[] = {
DEFINE_PROP_CHR("chardev", mcf_uart_state, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mcf_uart_class_init(ObjectClass *oc, void *data)
+static void mcf_uart_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mcf_uart_realize;
- dc->reset = mcf_uart_reset;
+ device_class_set_legacy_reset(dc, mcf_uart_reset);
device_class_set_props(dc, mcf_uart_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/char/mchp_pfsoc_mmuart.c b/hw/char/mchp_pfsoc_mmuart.c
index e7908bb..6149f9d 100644
--- a/hw/char/mchp_pfsoc_mmuart.c
+++ b/hw/char/mchp_pfsoc_mmuart.c
@@ -121,12 +121,12 @@ static const VMStateDescription mchp_pfsoc_mmuart_vmstate = {
}
};
-static void mchp_pfsoc_mmuart_class_init(ObjectClass *oc, void *data)
+static void mchp_pfsoc_mmuart_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mchp_pfsoc_mmuart_realize;
- dc->reset = mchp_pfsoc_mmuart_reset;
+ device_class_set_legacy_reset(dc, mchp_pfsoc_mmuart_reset);
dc->vmsd = &mchp_pfsoc_mmuart_vmstate;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/char/meson.build b/hw/char/meson.build
index e5b13b6..4e439da 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -1,25 +1,26 @@
system_ss.add(when: 'CONFIG_CADENCE', if_true: files('cadence_uart.c'))
system_ss.add(when: 'CONFIG_CMSDK_APB_UART', if_true: files('cmsdk-apb-uart.c'))
system_ss.add(when: 'CONFIG_ESCC', if_true: files('escc.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_ser.c'))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_apbuart.c'))
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_uart.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c'))
-system_ss.add(when: 'CONFIG_IPACK', if_true: files('ipoctal232.c'))
+system_ss.add(when: 'CONFIG_IP_OCTAL_232', if_true: files('ipoctal232.c'))
system_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c'))
system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugcon.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_uart.c'))
system_ss.add(when: 'CONFIG_PARALLEL', if_true: files('parallel.c'))
-system_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c'))
+system_ss.add(when: 'CONFIG_PL011_C', if_true: files('pl011.c'))
system_ss.add(when: 'CONFIG_SCLPCONSOLE', if_true: files('sclpconsole.c', 'sclpconsole-lm.c'))
system_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c'))
system_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c'))
+system_ss.add(when: 'CONFIG_SERIAL_MM', if_true: files('serial-mm.c'))
system_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c'))
system_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c'))
system_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c'))
system_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c'))
system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_console.c'))
system_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c'))
+system_ss.add(when: 'CONFIG_DIVA_GSP', if_true: files('diva-gsp.c'))
system_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c'))
diff --git a/hw/char/nrf51_uart.c b/hw/char/nrf51_uart.c
index c2cd6bb..41d4234 100644
--- a/hw/char/nrf51_uart.c
+++ b/hw/char/nrf51_uart.c
@@ -304,16 +304,15 @@ static const VMStateDescription nrf51_uart_vmstate = {
}
};
-static Property nrf51_uart_properties[] = {
+static const Property nrf51_uart_properties[] = {
DEFINE_PROP_CHR("chardev", NRF51UARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nrf51_uart_class_init(ObjectClass *klass, void *data)
+static void nrf51_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = nrf51_uart_reset;
+ device_class_set_legacy_reset(dc, nrf51_uart_reset);
dc->realize = nrf51_uart_realize;
device_class_set_props(dc, nrf51_uart_properties);
dc->vmsd = &nrf51_uart_vmstate;
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
index c2ef4c1..8cbf6ce 100644
--- a/hw/char/omap_uart.c
+++ b/hw/char/omap_uart.c
@@ -20,15 +20,14 @@
#include "qemu/osdep.h"
#include "chardev/char.h"
#include "hw/arm/omap.h"
-#include "hw/char/serial.h"
-#include "exec/address-spaces.h"
+#include "hw/char/serial-mm.h"
+#include "system/address-spaces.h"
/* UARTs */
struct omap_uart_s {
MemoryRegion iomem;
hwaddr base;
SerialMM *serial; /* TODO */
- struct omap_target_agent_s *ta;
omap_clk fclk;
qemu_irq irq;
@@ -36,8 +35,6 @@ struct omap_uart_s {
uint8_t syscontrol;
uint8_t wkup;
uint8_t cfps;
- uint8_t mdr[2];
- uint8_t scr;
uint8_t clksel;
};
@@ -66,113 +63,3 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
DEVICE_NATIVE_ENDIAN);
return s;
}
-
-static uint64_t omap_uart_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_uart_s *s = opaque;
-
- if (size == 4) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- return s->mdr[0];
- case 0x24: /* MDR2 */
- return s->mdr[1];
- case 0x40: /* SCR */
- return s->scr;
- case 0x44: /* SSR */
- return 0x0;
- case 0x48: /* EBLR (OMAP2) */
- return s->eblr;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- return s->clksel;
- case 0x50: /* MVR */
- return 0x30;
- case 0x54: /* SYSC (OMAP2) */
- return s->syscontrol;
- case 0x58: /* SYSS (OMAP2) */
- return 1;
- case 0x5c: /* WER (OMAP2) */
- return s->wkup;
- case 0x60: /* CFPS (OMAP2) */
- return s->cfps;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_uart_s *s = opaque;
-
- if (size == 4) {
- omap_badwidth_write8(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- s->mdr[0] = value & 0x7f;
- break;
- case 0x24: /* MDR2 */
- s->mdr[1] = value & 0xff;
- break;
- case 0x40: /* SCR */
- s->scr = value & 0xff;
- break;
- case 0x48: /* EBLR (OMAP2) */
- s->eblr = value & 0xff;
- break;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- s->clksel = value & 1;
- break;
- case 0x44: /* SSR */
- case 0x50: /* MVR */
- case 0x58: /* SYSS (OMAP2) */
- OMAP_RO_REG(addr);
- break;
- case 0x54: /* SYSC (OMAP2) */
- s->syscontrol = value & 0x1d;
- if (value & 2) {
- omap_uart_reset(s);
- }
- break;
- case 0x5c: /* WER (OMAP2) */
- s->wkup = value & 0x7f;
- break;
- case 0x60: /* CFPS (OMAP2) */
- s->cfps = value & 0xff;
- break;
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_uart_ops = {
- .read = omap_uart_read,
- .write = omap_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
- struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, Chardev *chr)
-{
- hwaddr base = omap_l4_attach(ta, 0, NULL);
- struct omap_uart_s *s = omap_uart_init(base, irq,
- fclk, iclk, txdma, rxdma, label, chr);
-
- memory_region_init_io(&s->iomem, NULL, &omap_uart_ops, s, "omap.uart", 0x100);
-
- s->ta = ta;
-
- memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
-
- return s;
-}
diff --git a/hw/char/parallel-isa.c b/hw/char/parallel-isa.c
index a5ce6ee..b6dfb6c 100644
--- a/hw/char/parallel-isa.c
+++ b/hw/char/parallel-isa.c
@@ -10,7 +10,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
#include "hw/char/parallel-isa.h"
diff --git a/hw/char/parallel.c b/hw/char/parallel.c
index c394635..8732e4e 100644
--- a/hw/char/parallel.c
+++ b/hw/char/parallel.c
@@ -33,8 +33,8 @@
#include "migration/vmstate.h"
#include "hw/char/parallel-isa.h"
#include "hw/char/parallel.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
+#include "system/reset.h"
+#include "system/system.h"
#include "trace.h"
#include "qom/object.h"
@@ -603,15 +603,14 @@ bool parallel_mm_init(MemoryRegion *address_space,
return true;
}
-static Property parallel_isa_properties[] = {
+static const Property parallel_isa_properties[] = {
DEFINE_PROP_UINT32("index", ISAParallelState, index, -1),
DEFINE_PROP_UINT32("iobase", ISAParallelState, iobase, -1),
DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7),
DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
+static void parallel_isa_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
@@ -628,7 +627,7 @@ static const TypeInfo parallel_isa_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(ISAParallelState),
.class_init = parallel_isa_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index f8078aa..01335d9 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -85,13 +85,16 @@ DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr)
#define CR_OUT1 (1 << 12)
#define CR_RTS (1 << 11)
#define CR_DTR (1 << 10)
+#define CR_RXE (1 << 9)
+#define CR_TXE (1 << 8)
#define CR_LBE (1 << 7)
+#define CR_UARTEN (1 << 0)
/* Integer Baud Rate Divider, UARTIBRD */
-#define IBRD_MASK 0x3f
+#define IBRD_MASK 0xffff
/* Fractional Baud Rate Divider, UARTFBRD */
-#define FBRD_MASK 0xffff
+#define FBRD_MASK 0x3f
static const unsigned char pl011_id_arm[8] =
{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
@@ -138,6 +141,11 @@ static void pl011_update(PL011State *s)
}
}
+static bool pl011_loopback_enabled(PL011State *s)
+{
+ return !!(s->cr & CR_LBE);
+}
+
static bool pl011_is_fifo_enabled(PL011State *s)
{
return (s->lcr & LCR_FEN) != 0;
@@ -149,41 +157,127 @@ static inline unsigned pl011_get_fifo_depth(PL011State *s)
return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1;
}
-static inline void pl011_reset_fifo(PL011State *s)
+static inline void pl011_reset_rx_fifo(PL011State *s)
{
s->read_count = 0;
s->read_pos = 0;
/* Reset FIFO flags */
- s->flags &= ~(PL011_FLAG_RXFF | PL011_FLAG_TXFF);
- s->flags |= PL011_FLAG_RXFE | PL011_FLAG_TXFE;
+ s->flags &= ~PL011_FLAG_RXFF;
+ s->flags |= PL011_FLAG_RXFE;
+}
+
+static inline void pl011_reset_tx_fifo(PL011State *s)
+{
+ /* Reset FIFO flags */
+ s->flags &= ~PL011_FLAG_TXFF;
+ s->flags |= PL011_FLAG_TXFE;
+}
+
+static void pl011_fifo_rx_put(void *opaque, uint32_t value)
+{
+ PL011State *s = (PL011State *)opaque;
+ int slot;
+ unsigned pipe_depth;
+
+ pipe_depth = pl011_get_fifo_depth(s);
+ slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
+ s->read_fifo[slot] = value;
+ s->read_count++;
+ s->flags &= ~PL011_FLAG_RXFE;
+ trace_pl011_fifo_rx_put(value, s->read_count, pipe_depth);
+ if (s->read_count == pipe_depth) {
+ trace_pl011_fifo_rx_full();
+ s->flags |= PL011_FLAG_RXFF;
+ }
+ if (s->read_count == s->read_trigger) {
+ s->int_level |= INT_RX;
+ pl011_update(s);
+ }
+}
+
+static void pl011_loopback_tx(PL011State *s, uint32_t value)
+{
+ if (!pl011_loopback_enabled(s)) {
+ return;
+ }
+
+ /*
+ * Caveat:
+ *
+ * In real hardware, TX loopback happens at the serial-bit level
+ * and then reassembled by the RX logics back into bytes and placed
+ * into the RX fifo. That is, loopback happens after TX fifo.
+ *
+ * Because the real hardware TX fifo is time-drained at the frame
+ * rate governed by the configured serial format, some loopback
+ * bytes in TX fifo may still be able to get into the RX fifo
+ * that could be full at times while being drained at software
+ * pace.
+ *
+ * In such scenario, the RX draining pace is the major factor
+ * deciding which loopback bytes get into the RX fifo, unless
+ * hardware flow-control is enabled.
+ *
+ * For simplicity, the above described is not emulated.
+ */
+ pl011_fifo_rx_put(s, value);
+}
+
+static void pl011_write_txdata(PL011State *s, uint8_t data)
+{
+ if (!(s->cr & CR_UARTEN)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "PL011 data written to disabled UART\n");
+ }
+ if (!(s->cr & CR_TXE)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "PL011 data written to disabled TX UART\n");
+ }
+
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &data, 1);
+ pl011_loopback_tx(s, data);
+ s->int_level |= INT_TX;
+ pl011_update(s);
+}
+
+static uint32_t pl011_read_rxdata(PL011State *s)
+{
+ uint32_t c;
+ unsigned fifo_depth = pl011_get_fifo_depth(s);
+
+ s->flags &= ~PL011_FLAG_RXFF;
+ c = s->read_fifo[s->read_pos];
+ if (s->read_count > 0) {
+ s->read_count--;
+ s->read_pos = (s->read_pos + 1) & (fifo_depth - 1);
+ }
+ if (s->read_count == 0) {
+ s->flags |= PL011_FLAG_RXFE;
+ }
+ if (s->read_count == s->read_trigger - 1) {
+ s->int_level &= ~INT_RX;
+ }
+ trace_pl011_read_fifo(s->read_count, fifo_depth);
+ s->rsr = c >> 8;
+ pl011_update(s);
+ qemu_chr_fe_accept_input(&s->chr);
+ return c;
}
static uint64_t pl011_read(void *opaque, hwaddr offset,
unsigned size)
{
PL011State *s = (PL011State *)opaque;
- uint32_t c;
uint64_t r;
switch (offset >> 2) {
case 0: /* UARTDR */
- s->flags &= ~PL011_FLAG_RXFF;
- c = s->read_fifo[s->read_pos];
- if (s->read_count > 0) {
- s->read_count--;
- s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
- }
- if (s->read_count == 0) {
- s->flags |= PL011_FLAG_RXFE;
- }
- if (s->read_count == s->read_trigger - 1)
- s->int_level &= ~ INT_RX;
- trace_pl011_read_fifo(s->read_count);
- s->rsr = c >> 8;
- pl011_update(s);
- qemu_chr_fe_accept_input(&s->chr);
- r = c;
+ r = pl011_read_rxdata(s);
break;
case 1: /* UARTRSR */
r = s->rsr;
@@ -268,11 +362,6 @@ static void pl011_trace_baudrate_change(const PL011State *s)
s->ibrd, s->fbrd);
}
-static bool pl011_loopback_enabled(PL011State *s)
-{
- return !!(s->cr & CR_LBE);
-}
-
static void pl011_loopback_mdmctrl(PL011State *s)
{
uint32_t cr, fr, il;
@@ -314,36 +403,6 @@ static void pl011_loopback_mdmctrl(PL011State *s)
pl011_update(s);
}
-static void pl011_put_fifo(void *opaque, uint32_t value);
-
-static void pl011_loopback_tx(PL011State *s, uint32_t value)
-{
- if (!pl011_loopback_enabled(s)) {
- return;
- }
-
- /*
- * Caveat:
- *
- * In real hardware, TX loopback happens at the serial-bit level
- * and then reassembled by the RX logics back into bytes and placed
- * into the RX fifo. That is, loopback happens after TX fifo.
- *
- * Because the real hardware TX fifo is time-drained at the frame
- * rate governed by the configured serial format, some loopback
- * bytes in TX fifo may still be able to get into the RX fifo
- * that could be full at times while being drained at software
- * pace.
- *
- * In such scenario, the RX draining pace is the major factor
- * deciding which loopback bytes get into the RX fifo, unless
- * hardware flow-control is enabled.
- *
- * For simplicity, the above described is not emulated.
- */
- pl011_put_fifo(s, value);
-}
-
static void pl011_loopback_break(PL011State *s, int brk_enable)
{
if (brk_enable) {
@@ -361,14 +420,8 @@ static void pl011_write(void *opaque, hwaddr offset,
switch (offset >> 2) {
case 0: /* UARTDR */
- /* ??? Check if transmitter is enabled. */
ch = value;
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, &ch, 1);
- pl011_loopback_tx(s, ch);
- s->int_level |= INT_TX;
- pl011_update(s);
+ pl011_write_txdata(s, ch);
break;
case 1: /* UARTRSR/UARTECR */
s->rsr = 0;
@@ -390,7 +443,8 @@ static void pl011_write(void *opaque, hwaddr offset,
case 11: /* UARTLCR_H */
/* Reset the FIFO state on FIFO enable or disable */
if ((s->lcr ^ value) & LCR_FEN) {
- pl011_reset_fifo(s);
+ pl011_reset_rx_fifo(s);
+ pl011_reset_tx_fifo(s);
}
if ((s->lcr ^ value) & LCR_BRK) {
int break_enable = value & LCR_BRK;
@@ -433,37 +487,26 @@ static void pl011_write(void *opaque, hwaddr offset,
static int pl011_can_receive(void *opaque)
{
PL011State *s = (PL011State *)opaque;
- int r;
-
- r = s->read_count < pl011_get_fifo_depth(s);
- trace_pl011_can_receive(s->lcr, s->read_count, r);
- return r;
-}
+ unsigned fifo_depth = pl011_get_fifo_depth(s);
+ unsigned fifo_available = fifo_depth - s->read_count;
-static void pl011_put_fifo(void *opaque, uint32_t value)
-{
- PL011State *s = (PL011State *)opaque;
- int slot;
- unsigned pipe_depth;
+ /*
+ * In theory we should check the UART and RX enable bits here and
+ * return 0 if they are not set (so the guest can't receive data
+ * until you have enabled the UART). In practice we suspect there
+ * is at least some guest code out there which has been tested only
+ * on QEMU and which never bothers to enable the UART because we
+ * historically never enforced that. So we effectively keep the
+ * UART continuously enabled regardless of the enable bits.
+ */
- pipe_depth = pl011_get_fifo_depth(s);
- slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
- s->read_fifo[slot] = value;
- s->read_count++;
- s->flags &= ~PL011_FLAG_RXFE;
- trace_pl011_put_fifo(value, s->read_count);
- if (s->read_count == pipe_depth) {
- trace_pl011_put_fifo_full();
- s->flags |= PL011_FLAG_RXFF;
- }
- if (s->read_count == s->read_trigger) {
- s->int_level |= INT_RX;
- pl011_update(s);
- }
+ trace_pl011_can_receive(s->lcr, s->read_count, fifo_depth, fifo_available);
+ return fifo_available;
}
static void pl011_receive(void *opaque, const uint8_t *buf, int size)
{
+ trace_pl011_receive(size);
/*
* In loopback mode, the RX input signal is internally disconnected
* from the entire receiving logics; thus, all inputs are ignored,
@@ -473,13 +516,15 @@ static void pl011_receive(void *opaque, const uint8_t *buf, int size)
return;
}
- pl011_put_fifo(opaque, *buf);
+ for (int i = 0; i < size; i++) {
+ pl011_fifo_rx_put(opaque, buf[i]);
+ }
}
static void pl011_event(void *opaque, QEMUChrEvent event)
{
if (event == CHR_EVENT_BREAK && !pl011_loopback_enabled(opaque)) {
- pl011_put_fifo(opaque, DR_BE);
+ pl011_fifo_rx_put(opaque, DR_BE);
}
}
@@ -549,7 +594,7 @@ static const VMStateDescription vmstate_pl011 = {
.minimum_version_id = 2,
.post_load = pl011_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(readbuff, PL011State),
+ VMSTATE_UNUSED(sizeof(uint32_t)),
VMSTATE_UINT32(flags, PL011State),
VMSTATE_UINT32(lcr, PL011State),
VMSTATE_UINT32(rsr, PL011State),
@@ -573,10 +618,9 @@ static const VMStateDescription vmstate_pl011 = {
}
};
-static Property pl011_properties[] = {
+static const Property pl011_properties[] = {
DEFINE_PROP_CHR("chardev", PL011State, chr),
DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
- DEFINE_PROP_END_OF_LIST(),
};
static void pl011_init(Object *obj)
@@ -621,15 +665,16 @@ static void pl011_reset(DeviceState *dev)
s->ifl = 0x12;
s->cr = 0x300;
s->flags = 0;
- pl011_reset_fifo(s);
+ pl011_reset_rx_fifo(s);
+ pl011_reset_tx_fifo(s);
}
-static void pl011_class_init(ObjectClass *oc, void *data)
+static void pl011_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = pl011_realize;
- dc->reset = pl011_reset;
+ device_class_set_legacy_reset(dc, pl011_reset);
dc->vmsd = &vmstate_pl011;
device_class_set_props(dc, pl011_properties);
}
diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c
index 5cb7335..b9d0ed1 100644
--- a/hw/char/renesas_sci.c
+++ b/hw/char/renesas_sci.c
@@ -319,19 +319,18 @@ static const VMStateDescription vmstate_rsci = {
}
};
-static Property rsci_properties[] = {
+static const Property rsci_properties[] = {
DEFINE_PROP_UINT64("input-freq", RSCIState, input_freq, 0),
DEFINE_PROP_CHR("chardev", RSCIState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void rsci_class_init(ObjectClass *klass, void *data)
+static void rsci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = rsci_realize;
dc->vmsd = &vmstate_rsci;
- dc->reset = rsci_reset;
+ device_class_set_legacy_reset(dc, rsci_reset);
device_class_set_props(dc, rsci_properties);
}
diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c
index 9bef60d..c884be5 100644
--- a/hw/char/riscv_htif.c
+++ b/hw/char/riscv_htif.c
@@ -24,23 +24,15 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "hw/char/riscv_htif.h"
-#include "hw/char/serial.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "exec/tswap.h"
-#include "sysemu/dma.h"
-#include "sysemu/runstate.h"
-
-#define RISCV_DEBUG_HTIF 0
-#define HTIF_DEBUG(fmt, ...) \
- do { \
- if (RISCV_DEBUG_HTIF) { \
- qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\
- } \
- } while (0)
+#include "system/dma.h"
+#include "system/runstate.h"
+#include "trace.h"
#define HTIF_DEV_SHIFT 56
#define HTIF_CMD_SHIFT 48
@@ -160,8 +152,7 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
uint64_t payload = val_written & 0xFFFFFFFFFFFFULL;
int resp = 0;
- HTIF_DEBUG("mtohost write: device: %d cmd: %d what: %02" PRIx64
- " -payload: %016" PRIx64 "\n", device, cmd, payload & 0xFF, payload);
+ trace_htif_uart_write_to_host(device, cmd, payload);
/*
* Currently, there is a fixed mapping of devices:
@@ -213,12 +204,16 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
} else {
uint64_t syscall[8];
cpu_physical_memory_read(payload, syscall, sizeof(syscall));
- if (tswap64(syscall[0]) == PK_SYS_WRITE &&
- tswap64(syscall[1]) == HTIF_DEV_CONSOLE &&
- tswap64(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
+ if (le64_to_cpu(syscall[0]) == PK_SYS_WRITE &&
+ le64_to_cpu(syscall[1]) == HTIF_DEV_CONSOLE &&
+ le64_to_cpu(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
uint8_t ch;
- cpu_physical_memory_read(tswap64(syscall[2]), &ch, 1);
- qemu_chr_fe_write(&s->chr, &ch, 1);
+ cpu_physical_memory_read(le64_to_cpu(syscall[2]), &ch, 1);
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
resp = 0x100 | (uint8_t)payload;
} else {
qemu_log_mask(LOG_UNIMP,
@@ -237,15 +232,18 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
return;
} else if (cmd == HTIF_CONSOLE_CMD_PUTC) {
uint8_t ch = (uint8_t)payload;
- qemu_chr_fe_write(&s->chr, &ch, 1);
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
resp = 0x100 | (uint8_t)payload;
} else {
qemu_log("HTIF device %d: unknown command\n", device);
}
} else {
qemu_log("HTIF unknown device or command\n");
- HTIF_DEBUG("device: %d cmd: %d what: %02" PRIx64
- " payload: %016" PRIx64, device, cmd, payload & 0xFF, payload);
+ trace_htif_uart_unknown_device_command(device, cmd, payload);
}
/*
* Latest bbl does not set fromhost to 0 if there is a value in tohost.
@@ -317,6 +315,11 @@ static void htif_mm_write(void *opaque, hwaddr addr,
static const MemoryRegionOps htif_mm_ops = {
.read = htif_mm_read,
.write = htif_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
};
HTIFState *htif_mm_init(MemoryRegion *address_space, Chardev *chr,
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 7719f43..3e40d5e 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -214,7 +214,7 @@ static int process_mdb(SCLPEvent *event, MDBO *mdbo)
{
int rc;
int len;
- uint8_t buffer[SIZE_BUFFER];
+ QEMU_UNINITIALIZED uint8_t buffer[SIZE_BUFFER];
len = be16_to_cpu(mdbo->length);
len -= sizeof(mdbo->length) + sizeof(mdbo->type)
@@ -333,20 +333,19 @@ static void console_reset(DeviceState *dev)
scon->write_errors = 0;
}
-static Property console_properties[] = {
+static const Property console_properties[] = {
DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr),
DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0),
DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void console_class_init(ObjectClass *klass, void *data)
+static void console_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
device_class_set_props(dc, console_properties);
- dc->reset = console_reset;
+ device_class_set_legacy_reset(dc, console_reset);
dc->vmsd = &vmstate_sclplmconsole;
ec->init = console_init;
ec->get_send_mask = send_mask;
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index 5d630b0..95e3045 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -251,18 +251,17 @@ static void console_reset(DeviceState *dev)
scon->notify = false;
}
-static Property console_properties[] = {
+static const Property console_properties[] = {
DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void console_class_init(ObjectClass *klass, void *data)
+static void console_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
device_class_set_props(dc, console_properties);
- dc->reset = console_reset;
+ device_class_set_legacy_reset(dc, console_reset);
dc->vmsd = &vmstate_sclpconsole;
ec->init = console_init;
ec->get_send_mask = send_mask;
diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
index 329b352..0ea59a3 100644
--- a/hw/char/serial-isa.c
+++ b/hw/char/serial-isa.c
@@ -26,9 +26,10 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -112,14 +113,13 @@ static const VMStateDescription vmstate_isa_serial = {
}
};
-static Property serial_isa_properties[] = {
+static const Property serial_isa_properties[] = {
DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
DEFINE_PROP_UINT32("iobase", ISASerialState, iobase, -1),
DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void serial_isa_class_initfn(ObjectClass *klass, void *data)
+static void serial_isa_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
@@ -146,7 +146,7 @@ static const TypeInfo serial_isa_info = {
.instance_size = sizeof(ISASerialState),
.instance_init = serial_isa_initfn,
.class_init = serial_isa_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/char/serial-mm.c b/hw/char/serial-mm.c
new file mode 100644
index 0000000..13aba78
--- /dev/null
+++ b/hw/char/serial-mm.c
@@ -0,0 +1,156 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/serial-mm.h"
+#include "exec/cpu-common.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+
+static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+ SerialMM *s = SERIAL_MM(opaque);
+ return serial_io_ops.read(&s->serial, addr >> s->regshift, 1);
+}
+
+static void serial_mm_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ SerialMM *s = SERIAL_MM(opaque);
+ value &= 255;
+ serial_io_ops.write(&s->serial, addr >> s->regshift, value, 1);
+}
+
+static const MemoryRegionOps serial_mm_ops[3] = {
+ [DEVICE_NATIVE_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+ [DEVICE_LITTLE_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+ [DEVICE_BIG_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+};
+
+static void serial_mm_realize(DeviceState *dev, Error **errp)
+{
+ SerialMM *smm = SERIAL_MM(dev);
+ SerialState *s = &smm->serial;
+
+ if (!qdev_realize(DEVICE(s), NULL, errp)) {
+ return;
+ }
+
+ memory_region_init_io(&s->io, OBJECT(dev),
+ &serial_mm_ops[smm->endianness], smm, "serial",
+ 8 << smm->regshift);
+ sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
+ sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
+}
+
+static const VMStateDescription vmstate_serial_mm = {
+ .name = "serial",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT(serial, SerialMM, 0, vmstate_serial, SerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+SerialMM *serial_mm_init(MemoryRegion *address_space,
+ hwaddr base, int regshift,
+ qemu_irq irq, int baudbase,
+ Chardev *chr, enum device_endian end)
+{
+ SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM));
+ MemoryRegion *mr;
+
+ qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
+ qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
+ qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
+ qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
+ qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
+ memory_region_add_subregion(address_space, base, mr);
+
+ return smm;
+}
+
+static void serial_mm_instance_init(Object *o)
+{
+ SerialMM *smm = SERIAL_MM(o);
+
+ object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL);
+
+ qdev_alias_all_properties(DEVICE(&smm->serial), o);
+}
+
+static const Property serial_mm_properties[] = {
+ /*
+ * Set the spacing between adjacent memory-mapped UART registers.
+ * Each register will be at (1 << regshift) bytes after the previous one.
+ */
+ DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
+ DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
+};
+
+static void serial_mm_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ device_class_set_props(dc, serial_mm_properties);
+ dc->realize = serial_mm_realize;
+ dc->vmsd = &vmstate_serial_mm;
+}
+
+static const TypeInfo types[] = {
+ {
+ .name = TYPE_SERIAL_MM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = serial_mm_class_init,
+ .instance_init = serial_mm_instance_init,
+ .instance_size = sizeof(SerialMM),
+ },
+};
+
+DEFINE_TYPES(types)
diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c
index 28b2757..13df272 100644
--- a/hw/char/serial-pci-multi.c
+++ b/hw/char/serial-pci-multi.c
@@ -45,8 +45,7 @@ typedef struct PCIMultiSerialState {
char *name[PCI_SERIAL_MAX_PORTS];
SerialState state[PCI_SERIAL_MAX_PORTS];
uint32_t level[PCI_SERIAL_MAX_PORTS];
- qemu_irq *irqs;
- uint8_t prog_if;
+ IRQState irqs[PCI_SERIAL_MAX_PORTS];
} PCIMultiSerialState;
static void multi_serial_pci_exit(PCIDevice *dev)
@@ -61,7 +60,6 @@ static void multi_serial_pci_exit(PCIDevice *dev)
memory_region_del_subregion(&pci->iobar, &s->io);
g_free(pci->name[i]);
}
- qemu_free_irqs(pci->irqs, pci->ports);
}
static void multi_serial_irq_mux(void *opaque, int n, int level)
@@ -98,11 +96,10 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
SerialState *s;
size_t i, nports = multi_serial_get_port_count(pc);
- pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
- pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */
+ pci->dev.config[PCI_INTERRUPT_PIN] = 1;
memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nports);
pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
- pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, nports);
for (i = 0; i < nports; i++) {
s = pci->state + i;
@@ -110,7 +107,7 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
multi_serial_pci_exit(dev);
return;
}
- s->irq = pci->irqs[i];
+ s->irq = &pci->irqs[i];
pci->name[i] = g_strdup_printf("uart #%zu", i + 1);
memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
pci->name[i], 8);
@@ -132,23 +129,20 @@ static const VMStateDescription vmstate_pci_multi_serial = {
}
};
-static Property multi_2x_serial_pci_properties[] = {
+static const Property multi_2x_serial_pci_properties[] = {
DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr),
DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr),
- DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02),
- DEFINE_PROP_END_OF_LIST(),
};
-static Property multi_4x_serial_pci_properties[] = {
+static const Property multi_4x_serial_pci_properties[] = {
DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr),
DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr),
DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr),
DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr),
- DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02),
- DEFINE_PROP_END_OF_LIST(),
};
-static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+static void multi_2x_serial_pci_class_initfn(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
@@ -163,7 +157,8 @@ static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
-static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+static void multi_4x_serial_pci_class_initfn(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
@@ -185,6 +180,7 @@ static void multi_serial_init(Object *o)
size_t i, nports = multi_serial_get_port_count(PCI_DEVICE_GET_CLASS(dev));
for (i = 0; i < nports; i++) {
+ qemu_init_irq(&pms->irqs[i], multi_serial_irq_mux, pms, i);
object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIAL);
}
}
@@ -195,7 +191,7 @@ static const TypeInfo multi_2x_serial_pci_info = {
.instance_size = sizeof(PCIMultiSerialState),
.instance_init = multi_serial_init,
.class_init = multi_2x_serial_pci_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -207,7 +203,7 @@ static const TypeInfo multi_4x_serial_pci_info = {
.instance_size = sizeof(PCIMultiSerialState),
.instance_init = multi_serial_init,
.class_init = multi_4x_serial_pci_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c
index f8a1a94..46efabc 100644
--- a/hw/char/serial-pci.c
+++ b/hw/char/serial-pci.c
@@ -38,7 +38,6 @@
struct PCISerialState {
PCIDevice dev;
SerialState state;
- uint8_t prog_if;
};
#define TYPE_PCI_SERIAL "pci-serial"
@@ -53,8 +52,8 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp)
return;
}
- pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
- pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */
+ pci->dev.config[PCI_INTERRUPT_PIN] = 1;
s->irq = pci_allocate_irq(&pci->dev);
memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8);
@@ -81,12 +80,7 @@ static const VMStateDescription vmstate_pci_serial = {
}
};
-static Property serial_pci_properties[] = {
- DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_pci_class_initfn(ObjectClass *klass, void *data)
+static void serial_pci_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
@@ -97,7 +91,6 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data)
pc->revision = 1;
pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
dc->vmsd = &vmstate_pci_serial;
- device_class_set_props(dc, serial_pci_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
@@ -116,7 +109,7 @@ static const TypeInfo serial_pci_info = {
.instance_size = sizeof(PCISerialState),
.instance_init = serial_pci_init,
.class_init = serial_pci_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/char/serial.c b/hw/char/serial.c
index d8b2db5..03fec3f 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -31,8 +31,8 @@
#include "chardev/char-serial.h"
#include "qapi/error.h"
#include "qemu/timer.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/qdev-properties.h"
@@ -951,13 +951,6 @@ static void serial_unrealize(DeviceState *dev)
qemu_unregister_reset(serial_reset, s);
}
-/* Change the main reference oscillator frequency. */
-void serial_set_frequency(SerialState *s, uint32_t frequency)
-{
- s->baudbase = frequency;
- serial_update_parameters(s);
-}
-
const MemoryRegionOps serial_io_ops = {
.read = serial_ioport_read,
.write = serial_ioport_write,
@@ -971,14 +964,13 @@ const MemoryRegionOps serial_io_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static Property serial_properties[] = {
+static const Property serial_properties[] = {
DEFINE_PROP_CHR("chardev", SerialState, chr),
DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200),
DEFINE_PROP_BOOL("wakeup", SerialState, wakeup, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void serial_class_init(ObjectClass *klass, void* data)
+static void serial_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -996,135 +988,9 @@ static const TypeInfo serial_info = {
.class_init = serial_class_init,
};
-/* Memory mapped interface */
-static uint64_t serial_mm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SerialMM *s = SERIAL_MM(opaque);
- return serial_ioport_read(&s->serial, addr >> s->regshift, 1);
-}
-
-static void serial_mm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SerialMM *s = SERIAL_MM(opaque);
- value &= 255;
- serial_ioport_write(&s->serial, addr >> s->regshift, value, 1);
-}
-
-static const MemoryRegionOps serial_mm_ops[3] = {
- [DEVICE_NATIVE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
- [DEVICE_LITTLE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
- [DEVICE_BIG_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
-};
-
-static void serial_mm_realize(DeviceState *dev, Error **errp)
-{
- SerialMM *smm = SERIAL_MM(dev);
- SerialState *s = &smm->serial;
-
- if (!qdev_realize(DEVICE(s), NULL, errp)) {
- return;
- }
-
- memory_region_init_io(&s->io, OBJECT(dev),
- &serial_mm_ops[smm->endianness], smm, "serial",
- 8 << smm->regshift);
- sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
- sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
-}
-
-static const VMStateDescription vmstate_serial_mm = {
- .name = "serial",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_STRUCT(serial, SerialMM, 0, vmstate_serial, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-SerialMM *serial_mm_init(MemoryRegion *address_space,
- hwaddr base, int regshift,
- qemu_irq irq, int baudbase,
- Chardev *chr, enum device_endian end)
-{
- SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM));
- MemoryRegion *mr;
-
- qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
- qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
- qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
- qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
- qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
- memory_region_add_subregion(address_space, base, mr);
-
- return smm;
-}
-
-static void serial_mm_instance_init(Object *o)
-{
- SerialMM *smm = SERIAL_MM(o);
-
- object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL);
-
- qdev_alias_all_properties(DEVICE(&smm->serial), o);
-}
-
-static Property serial_mm_properties[] = {
- /*
- * Set the spacing between adjacent memory-mapped UART registers.
- * Each register will be at (1 << regshift) bytes after the
- * previous one.
- */
- DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
- DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_mm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- device_class_set_props(dc, serial_mm_properties);
- dc->realize = serial_mm_realize;
- dc->vmsd = &vmstate_serial_mm;
-}
-
-static const TypeInfo serial_mm_info = {
- .name = TYPE_SERIAL_MM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .class_init = serial_mm_class_init,
- .instance_init = serial_mm_instance_init,
- .instance_size = sizeof(SerialMM),
-};
-
static void serial_register_types(void)
{
type_register_static(&serial_info);
- type_register_static(&serial_mm_info);
}
type_init(serial_register_types)
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 355886e..30447fa 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -78,10 +78,6 @@ struct SHSerialState {
qemu_irq bri;
};
-typedef struct {} SHSerialStateClass;
-
-OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE)
-
static void sh_serial_clear_fifo(SHSerialState *s)
{
memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
@@ -320,7 +316,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
static int sh_serial_can_receive(SHSerialState *s)
{
- return s->scr & (1 << 4);
+ return s->scr & (1 << 4) ? SH_RX_FIFO_LENGTH - s->rx_head : 0;
}
static void sh_serial_receive_break(SHSerialState *s)
@@ -353,22 +349,20 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
if (s->feat & SH_SERIAL_FEAT_SCIF) {
int i;
for (i = 0; i < size; i++) {
- if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
- s->rx_fifo[s->rx_head++] = buf[i];
- if (s->rx_head == SH_RX_FIFO_LENGTH) {
- s->rx_head = 0;
- }
- s->rx_cnt++;
- if (s->rx_cnt >= s->rtrg) {
- s->flags |= SH_SERIAL_FLAG_RDF;
- if (s->scr & (1 << 6) && s->rxi) {
- timer_del(&s->fifo_timeout_timer);
- qemu_set_irq(s->rxi, 1);
- }
- } else {
- timer_mod(&s->fifo_timeout_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
+ s->rx_fifo[s->rx_head++] = buf[i];
+ if (s->rx_head == SH_RX_FIFO_LENGTH) {
+ s->rx_head = 0;
+ }
+ s->rx_cnt++;
+ if (s->rx_cnt >= s->rtrg) {
+ s->flags |= SH_SERIAL_FLAG_RDF;
+ if (s->scr & (1 << 6) && s->rxi) {
+ timer_del(&s->fifo_timeout_timer);
+ qemu_set_irq(s->rxi, 1);
}
+ } else {
+ timer_mod(&s->fifo_timeout_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
}
}
} else {
@@ -436,30 +430,37 @@ static void sh_serial_realize(DeviceState *d, Error **errp)
s->etu = NANOSECONDS_PER_SECOND / 9600;
}
-static void sh_serial_finalize(Object *obj)
+static void sh_serial_unrealize(DeviceState *dev)
{
- SHSerialState *s = SH_SERIAL(obj);
+ SHSerialState *s = SH_SERIAL(dev);
timer_del(&s->fifo_timeout_timer);
}
-static void sh_serial_init(Object *obj)
-{
-}
-
-static Property sh_serial_properties[] = {
+static const Property sh_serial_properties[] = {
DEFINE_PROP_CHR("chardev", SHSerialState, chr),
DEFINE_PROP_UINT8("features", SHSerialState, feat, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void sh_serial_class_init(ObjectClass *oc, void *data)
+static void sh_serial_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, sh_serial_properties);
dc->realize = sh_serial_realize;
- dc->reset = sh_serial_reset;
+ dc->unrealize = sh_serial_unrealize;
+ device_class_set_legacy_reset(dc, sh_serial_reset);
/* Reason: part of SuperH CPU/SoC, needs to be wired up */
dc->user_creatable = false;
}
+
+static const TypeInfo sh_serial_types[] = {
+ {
+ .name = TYPE_SH_SERIAL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SHSerialState),
+ .class_init = sh_serial_class_init,
+ },
+};
+
+DEFINE_TYPES(sh_serial_types)
diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c
index 98b142c..6e216ed 100644
--- a/hw/char/shakti_uart.c
+++ b/hw/char/shakti_uart.c
@@ -157,15 +157,14 @@ static void shakti_uart_instance_init(Object *obj)
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio);
}
-static Property shakti_uart_properties[] = {
+static const Property shakti_uart_properties[] = {
DEFINE_PROP_CHR("chardev", ShaktiUartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void shakti_uart_class_init(ObjectClass *klass, void *data)
+static void shakti_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = shakti_uart_reset;
+ device_class_set_legacy_reset(dc, shakti_uart_reset);
dc->realize = shakti_uart_realize;
device_class_set_props(dc, shakti_uart_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c
index 7fc6787..0fc89e7 100644
--- a/hw/char/sifive_uart.c
+++ b/hw/char/sifive_uart.c
@@ -26,6 +26,8 @@
#include "hw/char/sifive_uart.h"
#include "hw/qdev-properties-system.h"
+#define TX_INTERRUPT_TRIGGER_DELAY_NS 100
+
/*
* Not yet implemented:
*
@@ -64,6 +66,72 @@ static void sifive_uart_update_irq(SiFiveUARTState *s)
}
}
+static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
+ void *opaque)
+{
+ SiFiveUARTState *s = opaque;
+ int ret;
+ const uint8_t *characters;
+ uint32_t numptr = 0;
+
+ /* instant drain the fifo when there's no back-end */
+ if (!qemu_chr_fe_backend_connected(&s->chr)) {
+ fifo8_reset(&s->tx_fifo);
+ return G_SOURCE_REMOVE;
+ }
+
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ return G_SOURCE_REMOVE;
+ }
+
+ /* Don't pop the FIFO in case the write fails */
+ characters = fifo8_peek_bufptr(&s->tx_fifo,
+ fifo8_num_used(&s->tx_fifo), &numptr);
+ ret = qemu_chr_fe_write(&s->chr, characters, numptr);
+
+ if (ret >= 0) {
+ /* We wrote the data, actually pop the fifo */
+ fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
+ }
+
+ if (!fifo8_is_empty(&s->tx_fifo)) {
+ guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+ sifive_uart_xmit, s);
+ if (!r) {
+ fifo8_reset(&s->tx_fifo);
+ return G_SOURCE_REMOVE;
+ }
+ }
+
+ /* Clear the TX Full bit */
+ if (!fifo8_is_full(&s->tx_fifo)) {
+ s->txfifo &= ~SIFIVE_UART_TXFIFO_FULL;
+ }
+
+ sifive_uart_update_irq(s);
+ return G_SOURCE_REMOVE;
+}
+
+static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
+ int size)
+{
+ uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ if (size > fifo8_num_free(&s->tx_fifo)) {
+ size = fifo8_num_free(&s->tx_fifo);
+ qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
+ }
+
+ fifo8_push_all(&s->tx_fifo, buf, size);
+
+ if (fifo8_is_full(&s->tx_fifo)) {
+ s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
+ }
+
+ timer_mod(s->fifo_trigger_handle, current_time +
+ TX_INTERRUPT_TRIGGER_DELAY_NS);
+}
+
static uint64_t
sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
{
@@ -82,7 +150,7 @@ sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
return 0x80000000;
case SIFIVE_UART_TXFIFO:
- return 0; /* Should check tx fifo */
+ return s->txfifo;
case SIFIVE_UART_IE:
return s->ie;
case SIFIVE_UART_IP:
@@ -106,12 +174,11 @@ sifive_uart_write(void *opaque, hwaddr addr,
{
SiFiveUARTState *s = opaque;
uint32_t value = val64;
- unsigned char ch = value;
+ uint8_t ch = value;
switch (addr) {
case SIFIVE_UART_TXFIFO:
- qemu_chr_fe_write(&s->chr, &ch, 1);
- sifive_uart_update_irq(s);
+ sifive_uart_write_tx_fifo(s, &ch, 1);
return;
case SIFIVE_UART_IE:
s->ie = val64;
@@ -131,6 +198,13 @@ sifive_uart_write(void *opaque, hwaddr addr,
__func__, (int)addr, (int)value);
}
+static void fifo_trigger_update(void *opaque)
+{
+ SiFiveUARTState *s = opaque;
+
+ sifive_uart_xmit(NULL, G_IO_OUT, s);
+}
+
static const MemoryRegionOps sifive_uart_ops = {
.read = sifive_uart_read,
.write = sifive_uart_write,
@@ -177,9 +251,25 @@ static int sifive_uart_be_change(void *opaque)
return 0;
}
-static Property sifive_uart_properties[] = {
+static void sifive_uart_reset_enter(Object *obj, ResetType type)
+{
+ SiFiveUARTState *s = SIFIVE_UART(obj);
+
+ s->txfifo = 0;
+ s->ie = 0;
+ s->ip = 0;
+ s->txctrl = 0;
+ s->rxctrl = 0;
+ s->div = 0;
+
+ s->rx_fifo_len = 0;
+
+ memset(s->rx_fifo, 0, SIFIVE_UART_RX_FIFO_SIZE);
+ fifo8_reset(&s->tx_fifo);
+}
+
+static const Property sifive_uart_properties[] = {
DEFINE_PROP_CHR("chardev", SiFiveUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void sifive_uart_init(Object *obj)
@@ -197,21 +287,24 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
{
SiFiveUARTState *s = SIFIVE_UART(dev);
- qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
- sifive_uart_event, sifive_uart_be_change, s,
- NULL, true);
+ fifo8_create(&s->tx_fifo, SIFIVE_UART_TX_FIFO_SIZE);
+
+ s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ fifo_trigger_update, s);
+
+ if (qemu_chr_fe_backend_connected(&s->chr)) {
+ qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
+ sifive_uart_event, sifive_uart_be_change, s,
+ NULL, true);
+ }
}
-static void sifive_uart_reset_enter(Object *obj, ResetType type)
+static void sifive_uart_unrealize(DeviceState *dev)
{
- SiFiveUARTState *s = SIFIVE_UART(obj);
- s->ie = 0;
- s->ip = 0;
- s->txctrl = 0;
- s->rxctrl = 0;
- s->div = 0;
- s->rx_fifo_len = 0;
+ SiFiveUARTState *s = SIFIVE_UART(dev);
+
+ fifo8_destroy(&s->tx_fifo);
}
static void sifive_uart_reset_hold(Object *obj, ResetType type)
@@ -222,8 +315,8 @@ static void sifive_uart_reset_hold(Object *obj, ResetType type)
static const VMStateDescription vmstate_sifive_uart = {
.name = TYPE_SIFIVE_UART,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(rx_fifo, SiFiveUARTState,
SIFIVE_UART_RX_FIFO_SIZE),
@@ -233,17 +326,21 @@ static const VMStateDescription vmstate_sifive_uart = {
VMSTATE_UINT32(txctrl, SiFiveUARTState),
VMSTATE_UINT32(rxctrl, SiFiveUARTState),
VMSTATE_UINT32(div, SiFiveUARTState),
+ VMSTATE_UINT32(txfifo, SiFiveUARTState),
+ VMSTATE_FIFO8(tx_fifo, SiFiveUARTState),
+ VMSTATE_TIMER_PTR(fifo_trigger_handle, SiFiveUARTState),
VMSTATE_END_OF_LIST()
},
};
-static void sifive_uart_class_init(ObjectClass *oc, void *data)
+static void sifive_uart_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
dc->realize = sifive_uart_realize;
+ dc->unrealize = sifive_uart_unrealize;
dc->vmsd = &vmstate_sifive_uart;
rc->phases.enter = sifive_uart_reset_enter;
rc->phases.hold = sifive_uart_reset_hold;
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 3e23d9c..fc8ea60 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -163,10 +163,9 @@ void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev)
qdev_realize_and_unref(dev, &bus->bus, &error_fatal);
}
-static Property spapr_vty_properties[] = {
+static const Property spapr_vty_properties[] = {
DEFINE_SPAPR_PROPERTIES(SpaprVioVty, sdev),
DEFINE_PROP_CHR("chardev", SpaprVioVty, chardev),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_spapr_vty = {
@@ -183,7 +182,7 @@ static const VMStateDescription vmstate_spapr_vty = {
},
};
-static void spapr_vty_class_init(ObjectClass *klass, void *data)
+static void spapr_vty_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 8753afe..45c3064 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -30,17 +30,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
-#ifndef STM_USART_ERR_DEBUG
-#define STM_USART_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(lvl, fmt, args...) do { \
- if (STM_USART_ERR_DEBUG >= lvl) { \
- qemu_log("%s: " fmt, __func__, ## args); \
- } \
-} while (0)
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+#include "trace.h"
static int stm32f2xx_usart_can_receive(void *opaque)
{
@@ -67,10 +57,11 @@ static void stm32f2xx_update_irq(STM32F2XXUsartState *s)
static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
{
STM32F2XXUsartState *s = opaque;
+ DeviceState *d = DEVICE(s);
if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
/* USART not enabled - drop the chars */
- DB_PRINT("Dropping the chars\n");
+ trace_stm32f2xx_usart_drop(d->id);
return;
}
@@ -79,7 +70,7 @@ static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
stm32f2xx_update_irq(s);
- DB_PRINT("Receiving: %c\n", s->usart_dr);
+ trace_stm32f2xx_usart_receive(d->id, *buf);
}
static void stm32f2xx_usart_reset(DeviceState *dev)
@@ -101,49 +92,55 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
unsigned int size)
{
STM32F2XXUsartState *s = opaque;
- uint64_t retvalue;
-
- DB_PRINT("Read 0x%"HWADDR_PRIx"\n", addr);
+ DeviceState *d = DEVICE(s);
+ uint64_t retvalue = 0;
switch (addr) {
case USART_SR:
retvalue = s->usart_sr;
qemu_chr_fe_accept_input(&s->chr);
- return retvalue;
+ break;
case USART_DR:
- DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
retvalue = s->usart_dr & 0x3FF;
s->usart_sr &= ~USART_SR_RXNE;
qemu_chr_fe_accept_input(&s->chr);
stm32f2xx_update_irq(s);
- return retvalue;
+ break;
case USART_BRR:
- return s->usart_brr;
+ retvalue = s->usart_brr;
+ break;
case USART_CR1:
- return s->usart_cr1;
+ retvalue = s->usart_cr1;
+ break;
case USART_CR2:
- return s->usart_cr2;
+ retvalue = s->usart_cr2;
+ break;
case USART_CR3:
- return s->usart_cr3;
+ retvalue = s->usart_cr3;
+ break;
case USART_GTPR:
- return s->usart_gtpr;
+ retvalue = s->usart_gtpr;
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
return 0;
}
- return 0;
+ trace_stm32f2xx_usart_read(d->id, size, addr, retvalue);
+
+ return retvalue;
}
static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
uint64_t val64, unsigned int size)
{
STM32F2XXUsartState *s = opaque;
+ DeviceState *d = DEVICE(s);
uint32_t value = val64;
unsigned char ch;
- DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr);
+ trace_stm32f2xx_usart_write(d->id, size, addr, val64);
switch (addr) {
case USART_SR:
@@ -199,9 +196,8 @@ static const MemoryRegionOps stm32f2xx_usart_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static Property stm32f2xx_usart_properties[] = {
+static const Property stm32f2xx_usart_properties[] = {
DEFINE_PROP_CHR("chardev", STM32F2XXUsartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void stm32f2xx_usart_init(Object *obj)
@@ -224,11 +220,11 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
s, NULL, true);
}
-static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
+static void stm32f2xx_usart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_usart_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_usart_reset);
device_class_set_props(dc, stm32f2xx_usart_properties);
dc->realize = stm32f2xx_usart_realize;
}
diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
index fc5dcac..afbe4ba 100644
--- a/hw/char/stm32l4x5_usart.c
+++ b/hw/char/stm32l4x5_usart.c
@@ -154,6 +154,21 @@ REG32(RDR, 0x24)
REG32(TDR, 0x28)
FIELD(TDR, TDR, 0, 9)
+static void stm32l4x5_update_isr(Stm32l4x5UsartBaseState *s)
+{
+ if (s->cr1 & R_CR1_TE_MASK) {
+ s->isr |= R_ISR_TEACK_MASK;
+ } else {
+ s->isr &= ~R_ISR_TEACK_MASK;
+ }
+
+ if (s->cr1 & R_CR1_RE_MASK) {
+ s->isr |= R_ISR_REACK_MASK;
+ } else {
+ s->isr &= ~R_ISR_REACK_MASK;
+ }
+}
+
static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
{
if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) ||
@@ -456,6 +471,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
case A_CR1:
s->cr1 = value;
stm32l4x5_update_params(s);
+ stm32l4x5_update_isr(s);
stm32l4x5_update_irq(s);
return;
case A_CR2:
@@ -518,9 +534,8 @@ static const MemoryRegionOps stm32l4x5_usart_base_ops = {
},
};
-static Property stm32l4x5_usart_base_properties[] = {
+static const Property stm32l4x5_usart_base_properties[] = {
DEFINE_PROP_CHR("chardev", Stm32l4x5UsartBaseState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void stm32l4x5_usart_base_init(Object *obj)
@@ -579,7 +594,8 @@ static void stm32l4x5_usart_base_realize(DeviceState *dev, Error **errp)
s, NULL, true);
}
-static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
+static void stm32l4x5_usart_base_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -590,21 +606,21 @@ static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_stm32l4x5_usart_base;
}
-static void stm32l4x5_usart_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5_usart_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
subc->type = STM32L4x5_USART;
}
-static void stm32l4x5_uart_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5_uart_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
subc->type = STM32L4x5_UART;
}
-static void stm32l4x5_lpuart_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5_lpuart_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c
index 82e85fa..d950c17 100644
--- a/hw/char/terminal3270.c
+++ b/hw/char/terminal3270.c
@@ -283,9 +283,8 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd)
return (retval <= 0) ? 0 : get_cds(t)->count;
}
-static Property terminal_properties[] = {
+static const Property terminal_properties[] = {
DEFINE_PROP_CHR("chardev", Terminal3270, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription terminal3270_vmstate = {
@@ -293,7 +292,7 @@ static const VMStateDescription terminal3270_vmstate = {
.unmigratable = 1,
};
-static void terminal_class_init(ObjectClass *klass, void *data)
+static void terminal_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass);
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 8875758..05a3303 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -52,15 +52,21 @@ escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x"
escc_kbd_command(int val) "Command %d"
escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=0x%01x"
+# imx_serial.c
+imx_serial_read(const char *chrname, uint64_t addr, uint64_t value) "%s:[0x%03" PRIu64 "] -> 0x%08" PRIx64
+imx_serial_write(const char *chrname, uint64_t addr, uint64_t value) "%s:[0x%03" PRIu64 "] <- 0x%08" PRIx64
+imx_serial_put_data(const char *chrname, uint32_t value) "%s: 0x%" PRIx32
+
# pl011.c
pl011_irq_state(int level) "irq state %d"
pl011_read(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s"
-pl011_read_fifo(int read_count) "FIFO read, read_count now %d"
+pl011_read_fifo(unsigned rx_fifo_used, size_t rx_fifo_depth) "RX FIFO read, used %u/%zu"
pl011_write(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s"
-pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
-pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d"
-pl011_put_fifo_full(void) "FIFO now full, RXFF set"
+pl011_can_receive(uint32_t lcr, unsigned rx_fifo_used, size_t rx_fifo_depth, unsigned rx_fifo_available) "LCR 0x%02x, RX FIFO used %u/%zu, can_receive %u chars"
+pl011_fifo_rx_put(uint32_t c, unsigned read_count, size_t rx_fifo_depth) "RX FIFO push char [0x%02x] %d/%zu depth used"
+pl011_fifo_rx_full(void) "RX FIFO now full, RXFF set"
pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
+pl011_receive(int size) "recv %d chars"
# cmsdk-apb-uart.c
cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
@@ -125,3 +131,13 @@ xen_console_unrealize(unsigned int idx) "idx %u"
xen_console_realize(unsigned int idx, const char *chrdev) "idx %u chrdev %s"
xen_console_device_create(unsigned int idx) "idx %u"
xen_console_device_destroy(unsigned int idx) "idx %u"
+
+# stm32f2xx_usart.c
+stm32f2xx_usart_read(char *id, unsigned size, uint64_t ofs, uint64_t val) " %s size %d ofs 0x%02" PRIx64 " -> 0x%02" PRIx64
+stm32f2xx_usart_write(char *id, unsigned size, uint64_t ofs, uint64_t val) "%s size %d ofs 0x%02" PRIx64 " <- 0x%02" PRIx64
+stm32f2xx_usart_drop(char *id) " %s dropping the chars"
+stm32f2xx_usart_receive(char *id, uint8_t chr) " %s receiving '%c'"
+
+# riscv_htif.c
+htif_uart_write_to_host(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
+htif_uart_unknown_device_command(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index dbe0b28..0932a35 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -261,7 +261,7 @@ static void virtconsole_unrealize(DeviceState *dev)
}
}
-static void virtconsole_class_init(ObjectClass *klass, void *data)
+static void virtconsole_class_init(ObjectClass *klass, const void *data)
{
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
@@ -274,12 +274,11 @@ static const TypeInfo virtconsole_info = {
.class_init = virtconsole_class_init,
};
-static Property virtserialport_properties[] = {
+static const Property virtserialport_properties[] = {
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtserialport_class_init(ObjectClass *klass, void *data)
+static void virtserialport_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 2094d21..673c50f 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -622,7 +622,7 @@ static void guest_reset(VirtIOSerial *vser)
}
}
-static void set_status(VirtIODevice *vdev, uint8_t status)
+static int set_status(VirtIODevice *vdev, uint8_t status)
{
VirtIOSerial *vser;
VirtIOSerialPort *port;
@@ -650,6 +650,7 @@ static void set_status(VirtIODevice *vdev, uint8_t status)
vsc->enable_backend(port, vdev->vm_running);
}
}
+ return 0;
}
static void vser_reset(VirtIODevice *vdev)
@@ -835,13 +836,12 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
-static Property virtser_props[] = {
+static const Property virtser_props[] = {
DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
- DEFINE_PROP_END_OF_LIST()
};
-static void virtser_bus_class_init(ObjectClass *klass, void *data)
+static void virtser_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
k->print_dev = virtser_bus_dev_print;
@@ -1093,7 +1093,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
QLIST_INSERT_HEAD(&vserdevices.devices, vser, next);
}
-static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
+static void virtio_serial_port_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
@@ -1153,15 +1153,14 @@ static const VMStateDescription vmstate_virtio_console = {
},
};
-static Property virtio_serial_properties[] = {
+static const Property virtio_serial_properties[] = {
DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports,
31),
DEFINE_PROP_BIT64("emergency-write", VirtIOSerial, host_features,
VIRTIO_CONSOLE_F_EMERG_WRITE, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_serial_class_init(ObjectClass *klass, void *data)
+static void virtio_serial_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -1190,7 +1189,7 @@ static const TypeInfo virtio_device_info = {
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOSerial),
.class_init = virtio_serial_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 683c92a..9c34a55 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -25,7 +25,7 @@
#include <termios.h>
#include "qapi/error.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "chardev/char-fe.h"
#include "hw/xen/xen-backend.h"
#include "hw/xen/xen-bus-helper.h"
@@ -367,28 +367,28 @@ static char *xen_console_get_name(XenDevice *xendev, Error **errp)
if (con->dev == -1) {
XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
- char fe_path[XENSTORE_ABS_PATH_MAX + 1];
int idx = (xen_mode == XEN_EMULATE) ? 0 : 1;
+ Error *local_err = NULL;
char *value;
/* Theoretically we could go up to INT_MAX here but that's overkill */
while (idx < 100) {
if (!idx) {
- snprintf(fe_path, sizeof(fe_path),
- "/local/domain/%u/console", xendev->frontend_id);
+ value = xs_node_read(xenbus->xsh, XBT_NULL, NULL, &local_err,
+ "/local/domain/%u/console",
+ xendev->frontend_id);
} else {
- snprintf(fe_path, sizeof(fe_path),
- "/local/domain/%u/device/console/%u",
- xendev->frontend_id, idx);
+ value = xs_node_read(xenbus->xsh, XBT_NULL, NULL, &local_err,
+ "/local/domain/%u/device/console/%u",
+ xendev->frontend_id, idx);
}
- value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL);
if (!value) {
if (errno == ENOENT) {
con->dev = idx;
+ error_free(local_err);
goto found;
}
- error_setg(errp, "cannot read %s: %s", fe_path,
- strerror(errno));
+ error_propagate(errp, local_err);
return NULL;
}
free(value);
@@ -487,13 +487,12 @@ static char *xen_console_get_frontend_path(XenDevice *xendev, Error **errp)
}
-static Property xen_console_properties[] = {
+static const Property xen_console_properties[] = {
DEFINE_PROP_CHR("chardev", XenConsole, chr),
DEFINE_PROP_INT32("idx", XenConsole, dev, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xen_console_class_init(ObjectClass *class, void *data)
+static void xen_console_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
@@ -551,7 +550,8 @@ static void xen_console_device_create(XenBackendInstance *backend,
goto fail;
}
- if (xs_node_scanf(xsh, XBT_NULL, fe, "type", errp, "%ms", &type) != 1) {
+ type = xs_node_read(xsh, XBT_NULL, NULL, errp, "%s/%s", fe, "type");
+ if (!type) {
error_prepend(errp, "failed to read console device type: ");
goto fail;
}
@@ -569,7 +569,8 @@ static void xen_console_device_create(XenBackendInstance *backend,
snprintf(label, sizeof(label), "xencons%ld", number);
- if (xs_node_scanf(xsh, XBT_NULL, fe, "output", NULL, "%ms", &output) == 1) {
+ output = xs_node_read(xsh, XBT_NULL, NULL, errp, "%s/%s", fe, "output");
+ if (output) {
/*
* FIXME: sure we want to support implicit
* muxed monitors here?
@@ -580,19 +581,27 @@ static void xen_console_device_create(XenBackendInstance *backend,
output);
goto fail;
}
- } else if (number) {
- cd = serial_hd(number);
- if (!cd) {
- error_prepend(errp, "console: No serial device #%ld found: ",
- number);
- goto fail;
- }
+ } else if (errno != ENOENT) {
+ error_prepend(errp, "console: No valid chardev found: ");
+ goto fail;
} else {
- /* No 'output' node on primary console: use null. */
- cd = qemu_chr_new(label, "null", NULL);
- if (!cd) {
- error_setg(errp, "console: failed to create null device");
- goto fail;
+ error_free(*errp);
+ *errp = NULL;
+
+ if (number) {
+ cd = serial_hd(number);
+ if (!cd) {
+ error_setg(errp, "console: No serial device #%ld found",
+ number);
+ goto fail;
+ }
+ } else {
+ /* No 'output' node on primary console: use null. */
+ cd = qemu_chr_new(label, "null", NULL);
+ if (!cd) {
+ error_setg(errp, "console: failed to create null device");
+ goto fail;
+ }
}
}
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 180bb97..8008171 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qapi/error.h"
#include "hw/char/xilinx_uartlite.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
@@ -57,6 +58,7 @@
struct XilinxUARTLite {
SysBusDevice parent_obj;
+ EndianMode model_endianness;
MemoryRegion mmio;
CharBackend chr;
qemu_irq irq;
@@ -166,19 +168,22 @@ uart_write(void *opaque, hwaddr addr,
uart_update_irq(s);
}
-static const MemoryRegionOps uart_ops = {
- .read = uart_read,
- .write = uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4
- }
+static const MemoryRegionOps uart_ops[2] = {
+ [0 ... 1] = {
+ .read = uart_read,
+ .write = uart_write,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+ },
+ [0].endianness = DEVICE_LITTLE_ENDIAN,
+ [1].endianness = DEVICE_BIG_ENDIAN,
};
-static Property xilinx_uartlite_properties[] = {
+static const Property xilinx_uartlite_properties[] = {
+ DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XilinxUARTLite, model_endianness),
DEFINE_PROP_CHR("chardev", XilinxUARTLite, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void uart_rx(void *opaque, const uint8_t *buf, int size)
@@ -215,6 +220,15 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
{
XilinxUARTLite *s = XILINX_UARTLITE(dev);
+ if (s->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
+ error_setg(errp, TYPE_XILINX_UARTLITE " property 'endianness'"
+ " must be set to 'big' or 'little'");
+ return;
+ }
+
+ memory_region_init_io(&s->mmio, OBJECT(dev),
+ &uart_ops[s->model_endianness == ENDIAN_MODE_BIG],
+ s, "xlnx.xps-uartlite", R_MAX * 4);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
uart_event, NULL, s, NULL, true);
}
@@ -224,17 +238,14 @@ static void xilinx_uartlite_init(Object *obj)
XilinxUARTLite *s = XILINX_UARTLITE(obj);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
- memory_region_init_io(&s->mmio, obj, &uart_ops, s,
- "xlnx.xps-uartlite", R_MAX * 4);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
-static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
+static void xilinx_uartlite_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xilinx_uartlite_reset;
+ device_class_set_legacy_reset(dc, xilinx_uartlite_reset);
dc->realize = xilinx_uartlite_realize;
device_class_set_props(dc, xilinx_uartlite_properties);
}
diff --git a/hw/core/Kconfig b/hw/core/Kconfig
index 24411f5..d1bdf76 100644
--- a/hw/core/Kconfig
+++ b/hw/core/Kconfig
@@ -34,3 +34,7 @@ config REGISTER
config SPLIT_IRQ
bool
+
+config EIF
+ bool
+ depends on LIBCBOR && GNUTLS
diff --git a/hw/core/bus.c b/hw/core/bus.c
index b9d8949..bddfc22 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -232,7 +232,7 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev)
return g_strdup(object_get_typename(OBJECT(dev)));
}
-static void bus_class_init(ObjectClass *class, void *data)
+static void bus_class_init(ObjectClass *class, const void *data)
{
BusClass *bc = BUS_CLASS(class);
ResettableClass *rc = RESETTABLE_CLASS(class);
@@ -260,7 +260,7 @@ static const TypeInfo bus_info = {
.instance_init = qbus_initfn,
.instance_finalize = qbus_finalize,
.class_init = bus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_RESETTABLE_INTERFACE },
{ }
},
diff --git a/hw/core/clock.c b/hw/core/clock.c
index e212865..9c90676 100644
--- a/hw/core/clock.c
+++ b/hw/core/clock.c
@@ -13,6 +13,8 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
+#include "qapi/visitor.h"
+#include "system/qtest.h"
#include "hw/clock.h"
#include "trace.h"
@@ -42,16 +44,12 @@ Clock *clock_new(Object *parent, const char *name)
void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque,
unsigned int events)
{
+ assert(OBJECT(clk)->parent);
clk->callback = cb;
clk->callback_opaque = opaque;
clk->callback_events = events;
}
-void clock_clear_callback(Clock *clk)
-{
- clock_set_callback(clk, NULL, NULL, 0);
-}
-
bool clock_set(Clock *clk, uint64_t period)
{
if (clk->period == period) {
@@ -158,6 +156,25 @@ bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
return true;
}
+static void clock_period_prop_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ Clock *clk = CLOCK(obj);
+ uint64_t period = clock_get(clk);
+ visit_type_uint64(v, name, &period, errp);
+}
+
+static void clock_unparent(Object *obj)
+{
+ /*
+ * Callback are registered by the parent, which might die anytime after
+ * it's unparented the children. Avoid having a callback to a deleted
+ * object in case the clock is still referenced somewhere else (eg: by
+ * a clock output).
+ */
+ clock_set_callback(CLOCK(obj), NULL, NULL, 0);
+}
+
static void clock_initfn(Object *obj)
{
Clock *clk = CLOCK(obj);
@@ -166,6 +183,11 @@ static void clock_initfn(Object *obj)
clk->divider = 1;
QLIST_INIT(&clk->children);
+
+ if (qtest_enabled()) {
+ object_property_add(obj, "qtest-clock-period", "uint64",
+ clock_period_prop_get, NULL, NULL, NULL);
+ }
}
static void clock_finalizefn(Object *obj)
@@ -184,11 +206,17 @@ static void clock_finalizefn(Object *obj)
g_free(clk->canonical_path);
}
+static void clock_class_init(ObjectClass *klass, const void *data)
+{
+ klass->unparent = clock_unparent;
+}
+
static const TypeInfo clock_info = {
.name = TYPE_CLOCK,
.parent = TYPE_OBJECT,
.instance_size = sizeof(Clock),
.instance_init = clock_initfn,
+ .class_init = clock_class_init,
.instance_finalize = clock_finalizefn,
};
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 7982ecd..39e674a 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -21,12 +21,16 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/core/cpu.h"
-#include "sysemu/hw_accel.h"
+#include "system/hw_accel.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
+#include "qemu/lockcnt.h"
+#include "qemu/error-report.h"
+#include "qemu/qemu-print.h"
+#include "qemu/target-info.h"
#include "exec/log.h"
#include "exec/gdbstub.h"
-#include "sysemu/tcg.h"
+#include "system/tcg.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "trace.h"
@@ -39,9 +43,7 @@ CPUState *cpu_by_arch_id(int64_t id)
CPUState *cpu;
CPU_FOREACH(cpu) {
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->get_arch_id(cpu) == id) {
+ if (cpu->cc->get_arch_id(cpu) == id) {
return cpu;
}
}
@@ -100,11 +102,9 @@ static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
void cpu_dump_state(CPUState *cpu, FILE *f, int flags)
{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->dump_state) {
+ if (cpu->cc->dump_state) {
cpu_synchronize_state(cpu);
- cc->dump_state(cpu, f, flags);
+ cpu->cc->dump_state(cpu, f, flags);
}
}
@@ -118,11 +118,10 @@ void cpu_reset(CPUState *cpu)
static void cpu_common_reset_hold(Object *obj, ResetType type)
{
CPUState *cpu = CPU(obj);
- CPUClass *cc = CPU_GET_CLASS(cpu);
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", cpu->cpu_index);
- log_cpu_state(cpu, cc->reset_dump_flags);
+ log_cpu_state(cpu, cpu->cc->reset_dump_flags);
}
cpu->interrupt_request = 0;
@@ -138,11 +137,6 @@ static void cpu_common_reset_hold(Object *obj, ResetType type)
cpu_exec_reset_hold(cpu);
}
-static bool cpu_common_has_work(CPUState *cs)
-{
- return false;
-}
-
ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
{
ObjectClass *oc;
@@ -161,6 +155,21 @@ ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
return NULL;
}
+char *cpu_model_from_type(const char *typename)
+{
+ g_autofree char *suffix = g_strdup_printf("-%s", target_cpu_type());
+
+ if (!object_class_by_name(typename)) {
+ return NULL;
+ }
+
+ if (g_str_has_suffix(typename, suffix)) {
+ return g_strndup(typename, strlen(typename) - strlen(suffix));
+ }
+
+ return g_strdup(typename);
+}
+
static void cpu_common_parse_features(const char *typename, char *features,
Error **errp)
{
@@ -192,6 +201,49 @@ static void cpu_common_parse_features(const char *typename, char *features,
}
}
+const char *parse_cpu_option(const char *cpu_option)
+{
+ ObjectClass *oc;
+ CPUClass *cc;
+ gchar **model_pieces;
+ const char *cpu_type;
+
+ model_pieces = g_strsplit(cpu_option, ",", 2);
+ if (!model_pieces[0]) {
+ error_report("-cpu option cannot be empty");
+ exit(1);
+ }
+
+ oc = cpu_class_by_name(target_cpu_type(), model_pieces[0]);
+ if (oc == NULL) {
+ error_report("unable to find CPU model '%s'", model_pieces[0]);
+ g_strfreev(model_pieces);
+ exit(EXIT_FAILURE);
+ }
+
+ cpu_type = object_class_get_name(oc);
+ cc = CPU_CLASS(oc);
+ cc->parse_features(cpu_type, model_pieces[1], &error_fatal);
+ g_strfreev(model_pieces);
+ return cpu_type;
+}
+
+bool cpu_exec_realizefn(CPUState *cpu, Error **errp)
+{
+ if (!accel_cpu_common_realize(cpu, errp)) {
+ return false;
+ }
+
+ gdb_init_cpu(cpu);
+
+ /* Wait until cpu initialization complete before exposing cpu. */
+ cpu_list_add(cpu);
+
+ cpu_vmstate_register(cpu);
+
+ return true;
+}
+
static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cpu = CPU(dev);
@@ -233,18 +285,34 @@ static void cpu_common_unrealizefn(DeviceState *dev)
cpu_exec_unrealizefn(cpu);
}
+void cpu_exec_unrealizefn(CPUState *cpu)
+{
+ cpu_vmstate_unregister(cpu);
+
+ cpu_list_remove(cpu);
+ /*
+ * Now that the vCPU has been removed from the RCU list, we can call
+ * accel_cpu_common_unrealize, which may free fields using call_rcu.
+ */
+ accel_cpu_common_unrealize(cpu);
+}
+
static void cpu_common_initfn(Object *obj)
{
CPUState *cpu = CPU(obj);
- gdb_init_cpu(cpu);
+ cpu_exec_class_post_init(CPU_GET_CLASS(obj));
+
+ /* cache the cpu class for the hotpath */
+ cpu->cc = CPU_GET_CLASS(cpu);
+
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
+ cpu->as = NULL;
+ cpu->num_ases = 0;
/* user-mode doesn't have configurable SMP topology */
/* the default value is changed by qemu_init_vcpu() for system-mode */
- cpu->nr_cores = 1;
cpu->nr_threads = 1;
- cpu->cflags_next_tb = -1;
/* allocate storage for thread info, initialise condition variables */
cpu->thread = g_new0(QemuThread, 1);
@@ -298,7 +366,7 @@ static int64_t cpu_common_get_arch_id(CPUState *cpu)
return cpu->cpu_index;
}
-static void cpu_common_class_init(ObjectClass *klass, void *data)
+static void cpu_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -306,7 +374,6 @@ static void cpu_common_class_init(ObjectClass *klass, void *data)
k->parse_features = cpu_common_parse_features;
k->get_arch_id = cpu_common_get_arch_id;
- k->has_work = cpu_common_has_work;
k->gdb_read_register = cpu_common_gdb_read_register;
k->gdb_write_register = cpu_common_gdb_write_register;
set_bit(DEVICE_CATEGORY_CPU, dc->categories);
@@ -338,3 +405,32 @@ static void cpu_register_types(void)
}
type_init(cpu_register_types)
+
+static void cpu_list_entry(gpointer data, gpointer user_data)
+{
+ CPUClass *cc = CPU_CLASS(OBJECT_CLASS(data));
+ const char *typename = object_class_get_name(OBJECT_CLASS(data));
+ g_autofree char *model = cpu_model_from_type(typename);
+
+ if (cc->deprecation_note) {
+ qemu_printf(" %s (deprecated)\n", model);
+ } else {
+ qemu_printf(" %s\n", model);
+ }
+}
+
+void list_cpus(void)
+{
+ CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type()));
+
+ if (cc->list_cpus) {
+ cc->list_cpus();
+ } else {
+ GSList *list;
+
+ list = object_class_get_list_sorted(TYPE_CPU, false);
+ qemu_printf("Available CPUs:\n");
+ g_slist_foreach(list, cpu_list_entry, NULL);
+ g_slist_free(list);
+ }
+}
diff --git a/hw/core/cpu-sysemu.c b/hw/core/cpu-sysemu.c
deleted file mode 100644
index 2a9a2a4..0000000
--- a/hw/core/cpu-sysemu.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * QEMU CPU model (system emulation specific)
- *
- * Copyright (c) 2012-2014 SUSE LINUX Products GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see
- * <http://www.gnu.org/licenses/gpl-2.0.html>
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "exec/tswap.h"
-#include "hw/core/sysemu-cpu-ops.h"
-
-bool cpu_paging_enabled(const CPUState *cpu)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->get_paging_enabled) {
- return cc->sysemu_ops->get_paging_enabled(cpu);
- }
-
- return false;
-}
-
-bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
- Error **errp)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->get_memory_mapping) {
- return cc->sysemu_ops->get_memory_mapping(cpu, list, errp);
- }
-
- error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
- return false;
-}
-
-hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
- MemTxAttrs *attrs)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->get_phys_page_attrs_debug) {
- return cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs);
- }
- /* Fallback for CPUs which don't implement the _attrs_ hook */
- *attrs = MEMTXATTRS_UNSPECIFIED;
- return cc->sysemu_ops->get_phys_page_debug(cpu, addr);
-}
-
-hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
-{
- MemTxAttrs attrs = {};
-
- return cpu_get_phys_page_attrs_debug(cpu, addr, &attrs);
-}
-
-int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs)
-{
- int ret = 0;
-
- if (cpu->cc->sysemu_ops->asidx_from_attrs) {
- ret = cpu->cc->sysemu_ops->asidx_from_attrs(cpu, attrs);
- assert(ret < cpu->num_ases && ret >= 0);
- }
- return ret;
-}
-
-int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
- void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf32_qemunote) {
- return 0;
- }
- return (*cc->sysemu_ops->write_elf32_qemunote)(f, cpu, opaque);
-}
-
-int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
- int cpuid, void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf32_note) {
- return -1;
- }
- return (*cc->sysemu_ops->write_elf32_note)(f, cpu, cpuid, opaque);
-}
-
-int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
- void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf64_qemunote) {
- return 0;
- }
- return (*cc->sysemu_ops->write_elf64_qemunote)(f, cpu, opaque);
-}
-
-int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
- int cpuid, void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf64_note) {
- return -1;
- }
- return (*cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque);
-}
-
-bool cpu_virtio_is_big_endian(CPUState *cpu)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->virtio_is_big_endian) {
- return cc->sysemu_ops->virtio_is_big_endian(cpu);
- }
- return target_words_bigendian();
-}
-
-GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
- GuestPanicInformation *res = NULL;
-
- if (cc->sysemu_ops->get_crash_info) {
- res = cc->sysemu_ops->get_crash_info(cpu);
- }
- return res;
-}
diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c
new file mode 100644
index 0000000..3c84176
--- /dev/null
+++ b/hw/core/cpu-system.c
@@ -0,0 +1,305 @@
+/*
+ * QEMU CPU model (system specific)
+ *
+ * Copyright (c) 2012-2014 SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "system/address-spaces.h"
+#include "exec/cputlb.h"
+#include "system/memory.h"
+#include "exec/tb-flush.h"
+#include "exec/tswap.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "hw/core/sysemu-cpu-ops.h"
+#include "migration/vmstate.h"
+#include "system/tcg.h"
+
+bool cpu_has_work(CPUState *cpu)
+{
+ return cpu->cc->sysemu_ops->has_work(cpu);
+}
+
+bool cpu_paging_enabled(const CPUState *cpu)
+{
+ if (cpu->cc->sysemu_ops->get_paging_enabled) {
+ return cpu->cc->sysemu_ops->get_paging_enabled(cpu);
+ }
+
+ return false;
+}
+
+bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
+ Error **errp)
+{
+ if (cpu->cc->sysemu_ops->get_memory_mapping) {
+ return cpu->cc->sysemu_ops->get_memory_mapping(cpu, list, errp);
+ }
+
+ error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
+ return false;
+}
+
+hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
+ MemTxAttrs *attrs)
+{
+ hwaddr paddr;
+
+ if (cpu->cc->sysemu_ops->get_phys_page_attrs_debug) {
+ paddr = cpu->cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr,
+ attrs);
+ } else {
+ /* Fallback for CPUs which don't implement the _attrs_ hook */
+ *attrs = MEMTXATTRS_UNSPECIFIED;
+ paddr = cpu->cc->sysemu_ops->get_phys_page_debug(cpu, addr);
+ }
+ /* Indicate that this is a debug access. */
+ attrs->debug = 1;
+ return paddr;
+}
+
+hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
+{
+ MemTxAttrs attrs = {};
+
+ return cpu_get_phys_page_attrs_debug(cpu, addr, &attrs);
+}
+
+int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs)
+{
+ int ret = 0;
+
+ if (cpu->cc->sysemu_ops->asidx_from_attrs) {
+ ret = cpu->cc->sysemu_ops->asidx_from_attrs(cpu, attrs);
+ assert(ret < cpu->num_ases && ret >= 0);
+ }
+ return ret;
+}
+
+int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
+ void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf32_qemunote) {
+ return 0;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf32_qemunote)(f, cpu, opaque);
+}
+
+int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
+ int cpuid, void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf32_note) {
+ return -1;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf32_note)(f, cpu, cpuid, opaque);
+}
+
+int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
+ void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf64_qemunote) {
+ return 0;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf64_qemunote)(f, cpu, opaque);
+}
+
+int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
+ int cpuid, void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf64_note) {
+ return -1;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque);
+}
+
+bool cpu_virtio_is_big_endian(CPUState *cpu)
+{
+ if (cpu->cc->sysemu_ops->virtio_is_big_endian) {
+ return cpu->cc->sysemu_ops->virtio_is_big_endian(cpu);
+ }
+ return target_big_endian();
+}
+
+GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
+{
+ GuestPanicInformation *res = NULL;
+
+ if (cpu->cc->sysemu_ops->get_crash_info) {
+ res = cpu->cc->sysemu_ops->get_crash_info(cpu);
+ }
+ return res;
+}
+
+static const Property cpu_system_props[] = {
+ /*
+ * Create a memory property for system CPU object, so users can
+ * wire up its memory. The default if no link is set up is to use
+ * the system address space.
+ */
+ DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+};
+
+static bool cpu_get_start_powered_off(Object *obj, Error **errp)
+{
+ CPUState *cpu = CPU(obj);
+ return cpu->start_powered_off;
+}
+
+static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
+{
+ CPUState *cpu = CPU(obj);
+ cpu->start_powered_off = value;
+}
+
+void cpu_class_init_props(DeviceClass *dc)
+{
+ ObjectClass *oc = OBJECT_CLASS(dc);
+
+ /*
+ * We can't use DEFINE_PROP_BOOL in the Property array for this
+ * property, because we want this to be settable after realize.
+ */
+ object_class_property_add_bool(oc, "start-powered-off",
+ cpu_get_start_powered_off,
+ cpu_set_start_powered_off);
+
+ device_class_set_props(dc, cpu_system_props);
+}
+
+void cpu_exec_class_post_init(CPUClass *cc)
+{
+ /* Check mandatory SysemuCPUOps handlers */
+ g_assert(cc->sysemu_ops->has_work);
+}
+
+void cpu_exec_initfn(CPUState *cpu)
+{
+ cpu->memory = get_system_memory();
+ object_ref(OBJECT(cpu->memory));
+}
+
+static int cpu_common_post_load(void *opaque, int version_id)
+{
+ if (tcg_enabled()) {
+ CPUState *cpu = opaque;
+
+ /*
+ * 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
+ * version_id is increased.
+ */
+ cpu->interrupt_request &= ~0x01;
+
+ tlb_flush(cpu);
+
+ /*
+ * loadvm has just updated the content of RAM, bypassing the
+ * usual mechanisms that ensure we flush TBs for writes to
+ * memory we've translated code from. So we must flush all TBs,
+ * which will now be stale.
+ */
+ tb_flush(cpu);
+ }
+
+ return 0;
+}
+
+static int cpu_common_pre_load(void *opaque)
+{
+ CPUState *cpu = opaque;
+
+ cpu->exception_index = -1;
+
+ return 0;
+}
+
+static bool cpu_common_exception_index_needed(void *opaque)
+{
+ CPUState *cpu = opaque;
+
+ return tcg_enabled() && cpu->exception_index != -1;
+}
+
+static const VMStateDescription vmstate_cpu_common_exception_index = {
+ .name = "cpu_common/exception_index",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpu_common_exception_index_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_INT32(exception_index, CPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool cpu_common_crash_occurred_needed(void *opaque)
+{
+ CPUState *cpu = opaque;
+
+ return cpu->crash_occurred;
+}
+
+static const VMStateDescription vmstate_cpu_common_crash_occurred = {
+ .name = "cpu_common/crash_occurred",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpu_common_crash_occurred_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BOOL(crash_occurred, CPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+const VMStateDescription vmstate_cpu_common = {
+ .name = "cpu_common",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_load = cpu_common_pre_load,
+ .post_load = cpu_common_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(halted, CPUState),
+ VMSTATE_UINT32(interrupt_request, CPUState),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_cpu_common_exception_index,
+ &vmstate_cpu_common_crash_occurred,
+ NULL
+ }
+};
+
+void cpu_vmstate_register(CPUState *cpu)
+{
+ if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
+ vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
+ }
+ if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
+ vmstate_register(NULL, cpu->cpu_index,
+ cpu->cc->sysemu_ops->legacy_vmsd, cpu);
+ }
+}
+
+void cpu_vmstate_unregister(CPUState *cpu)
+{
+ if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
+ vmstate_unregister(NULL, cpu->cc->sysemu_ops->legacy_vmsd, cpu);
+ }
+ if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
+ vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
+ }
+}
diff --git a/hw/core/cpu-user.c b/hw/core/cpu-user.c
new file mode 100644
index 0000000..7176791
--- /dev/null
+++ b/hw/core/cpu-user.c
@@ -0,0 +1,49 @@
+/*
+ * QEMU CPU model (user specific)
+ *
+ * Copyright (c) Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "hw/core/cpu.h"
+#include "migration/vmstate.h"
+
+static const Property cpu_user_props[] = {
+ /*
+ * Create a property for the user-only object, so users can
+ * adjust prctl(PR_SET_UNALIGN) from the command-line.
+ * Has no effect if the target does not support the feature.
+ */
+ DEFINE_PROP_BOOL("prctl-unalign-sigbus", CPUState,
+ prctl_unalign_sigbus, false),
+};
+
+void cpu_class_init_props(DeviceClass *dc)
+{
+ device_class_set_props(dc, cpu_user_props);
+}
+
+void cpu_exec_class_post_init(CPUClass *cc)
+{
+ /* nothing to do */
+}
+
+void cpu_exec_initfn(CPUState *cpu)
+{
+ /* nothing to do */
+}
+
+void cpu_vmstate_register(CPUState *cpu)
+{
+ assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
+ qdev_get_vmsd(DEVICE(cpu))->unmigratable);
+}
+
+void cpu_vmstate_unregister(CPUState *cpu)
+{
+ /* nothing to do */
+}
diff --git a/hw/core/eif.c b/hw/core/eif.c
new file mode 100644
index 0000000..513caec
--- /dev/null
+++ b/hw/core/eif.c
@@ -0,0 +1,709 @@
+/*
+ * EIF (Enclave Image Format) related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "qapi/error.h"
+#include "crypto/hash.h"
+#include "crypto/x509-utils.h"
+#include <zlib.h> /* for crc32 */
+#include <cbor.h>
+
+#include "hw/core/eif.h"
+
+#define MAX_SECTIONS 32
+
+/* members are ordered according to field order in .eif file */
+typedef struct EifHeader {
+ uint8_t magic[4]; /* must be .eif in ascii i.e., [46, 101, 105, 102] */
+ uint16_t version;
+ uint16_t flags;
+ uint64_t default_memory;
+ uint64_t default_cpus;
+ uint16_t reserved;
+ uint16_t section_cnt;
+ uint64_t section_offsets[MAX_SECTIONS];
+ uint64_t section_sizes[MAX_SECTIONS];
+ uint32_t unused;
+ uint32_t eif_crc32;
+} QEMU_PACKED EifHeader;
+
+/* members are ordered according to field order in .eif file */
+typedef struct EifSectionHeader {
+ /*
+ * 0 = invalid, 1 = kernel, 2 = cmdline, 3 = ramdisk, 4 = signature,
+ * 5 = metadata
+ */
+ uint16_t section_type;
+ uint16_t flags;
+ uint64_t section_size;
+} QEMU_PACKED EifSectionHeader;
+
+enum EifSectionTypes {
+ EIF_SECTION_INVALID = 0,
+ EIF_SECTION_KERNEL = 1,
+ EIF_SECTION_CMDLINE = 2,
+ EIF_SECTION_RAMDISK = 3,
+ EIF_SECTION_SIGNATURE = 4,
+ EIF_SECTION_METADATA = 5,
+ EIF_SECTION_MAX = 6,
+};
+
+static const char *section_type_to_string(uint16_t type)
+{
+ const char *str;
+ switch (type) {
+ case EIF_SECTION_INVALID:
+ str = "invalid";
+ break;
+ case EIF_SECTION_KERNEL:
+ str = "kernel";
+ break;
+ case EIF_SECTION_CMDLINE:
+ str = "cmdline";
+ break;
+ case EIF_SECTION_RAMDISK:
+ str = "ramdisk";
+ break;
+ case EIF_SECTION_SIGNATURE:
+ str = "signature";
+ break;
+ case EIF_SECTION_METADATA:
+ str = "metadata";
+ break;
+ default:
+ str = "unknown";
+ break;
+ }
+
+ return str;
+}
+
+static bool read_eif_header(FILE *f, EifHeader *header, uint32_t *crc,
+ Error **errp)
+{
+ size_t got;
+ size_t header_size = sizeof(*header);
+
+ got = fread(header, 1, header_size, f);
+ if (got != header_size) {
+ error_setg(errp, "Failed to read EIF header");
+ return false;
+ }
+
+ if (memcmp(header->magic, ".eif", 4) != 0) {
+ error_setg(errp, "Invalid EIF image. Magic mismatch.");
+ return false;
+ }
+
+ /* Exclude header->eif_crc32 field from CRC calculation */
+ *crc = crc32(*crc, (uint8_t *)header, header_size - 4);
+
+ header->version = be16_to_cpu(header->version);
+ header->flags = be16_to_cpu(header->flags);
+ header->default_memory = be64_to_cpu(header->default_memory);
+ header->default_cpus = be64_to_cpu(header->default_cpus);
+ header->reserved = be16_to_cpu(header->reserved);
+ header->section_cnt = be16_to_cpu(header->section_cnt);
+
+ for (int i = 0; i < MAX_SECTIONS; ++i) {
+ header->section_offsets[i] = be64_to_cpu(header->section_offsets[i]);
+ }
+
+ for (int i = 0; i < MAX_SECTIONS; ++i) {
+ header->section_sizes[i] = be64_to_cpu(header->section_sizes[i]);
+ if (header->section_sizes[i] > SSIZE_MAX) {
+ error_setg(errp, "Invalid EIF image. Section size out of bounds");
+ return false;
+ }
+ }
+
+ header->unused = be32_to_cpu(header->unused);
+ header->eif_crc32 = be32_to_cpu(header->eif_crc32);
+ return true;
+}
+
+static bool read_eif_section_header(FILE *f, EifSectionHeader *section_header,
+ uint32_t *crc, Error **errp)
+{
+ size_t got;
+ size_t section_header_size = sizeof(*section_header);
+
+ got = fread(section_header, 1, section_header_size, f);
+ if (got != section_header_size) {
+ error_setg(errp, "Failed to read EIF section header");
+ return false;
+ }
+
+ *crc = crc32(*crc, (uint8_t *)section_header, section_header_size);
+
+ section_header->section_type = be16_to_cpu(section_header->section_type);
+ section_header->flags = be16_to_cpu(section_header->flags);
+ section_header->section_size = be64_to_cpu(section_header->section_size);
+ return true;
+}
+
+/*
+ * Upon success, the caller is responsible for unlinking and freeing *tmp_path.
+ */
+static bool get_tmp_file(const char *template, char **tmp_path, Error **errp)
+{
+ int tmp_fd;
+
+ *tmp_path = NULL;
+ tmp_fd = g_file_open_tmp(template, tmp_path, NULL);
+ if (tmp_fd < 0 || *tmp_path == NULL) {
+ error_setg(errp, "Failed to create temporary file for template %s",
+ template);
+ return false;
+ }
+
+ close(tmp_fd);
+ return true;
+}
+
+static void safe_fclose(FILE *f)
+{
+ if (f) {
+ fclose(f);
+ }
+}
+
+static void safe_unlink(char *f)
+{
+ if (f) {
+ unlink(f);
+ }
+}
+
+/*
+ * Upon success, the caller is reponsible for unlinking and freeing *kernel_path
+ */
+static bool read_eif_kernel(FILE *f, uint64_t size, char **kernel_path,
+ QCryptoHash *hash0, QCryptoHash *hash1,
+ uint32_t *crc, Error **errp)
+{
+ size_t got;
+ FILE *tmp_file = NULL;
+ uint8_t *kernel = g_try_malloc(size);
+ if (!kernel) {
+ error_setg(errp, "Out of memory reading kernel section");
+ goto cleanup;
+ }
+
+ *kernel_path = NULL;
+ if (!get_tmp_file("eif-kernel-XXXXXX", kernel_path, errp)) {
+ goto cleanup;
+ }
+
+ tmp_file = fopen(*kernel_path, "wb");
+ if (tmp_file == NULL) {
+ error_setg_errno(errp, errno, "Failed to open temporary file %s",
+ *kernel_path);
+ goto cleanup;
+ }
+
+ got = fread(kernel, 1, size, f);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF kernel section data");
+ goto cleanup;
+ }
+
+ got = fwrite(kernel, 1, size, tmp_file);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to write EIF kernel section data to temporary"
+ " file");
+ goto cleanup;
+ }
+
+ *crc = crc32(*crc, kernel, size);
+ if (qcrypto_hash_update(hash0, (char *)kernel, size, errp) != 0 ||
+ qcrypto_hash_update(hash1, (char *)kernel, size, errp) != 0) {
+ goto cleanup;
+ }
+ g_free(kernel);
+ fclose(tmp_file);
+
+ return true;
+
+ cleanup:
+ safe_fclose(tmp_file);
+
+ safe_unlink(*kernel_path);
+ g_free(*kernel_path);
+ *kernel_path = NULL;
+
+ g_free(kernel);
+ return false;
+}
+
+static bool read_eif_cmdline(FILE *f, uint64_t size, char *cmdline,
+ QCryptoHash *hash0, QCryptoHash *hash1,
+ uint32_t *crc, Error **errp)
+{
+ size_t got = fread(cmdline, 1, size, f);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF cmdline section data");
+ return false;
+ }
+
+ *crc = crc32(*crc, (uint8_t *)cmdline, size);
+ if (qcrypto_hash_update(hash0, cmdline, size, errp) != 0 ||
+ qcrypto_hash_update(hash1, cmdline, size, errp) != 0) {
+ return false;
+ }
+ return true;
+}
+
+static bool read_eif_ramdisk(FILE *eif, FILE *initrd, uint64_t size,
+ QCryptoHash *hash0, QCryptoHash *h, uint32_t *crc,
+ Error **errp)
+{
+ size_t got;
+ bool ret = false;
+ uint8_t *ramdisk = g_try_malloc(size);
+ if (!ramdisk) {
+ error_setg(errp, "Out of memory reading initrd section");
+ goto cleanup;
+ }
+
+ got = fread(ramdisk, 1, size, eif);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF ramdisk section data");
+ goto cleanup;
+ }
+
+ got = fwrite(ramdisk, 1, size, initrd);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to write EIF ramdisk data to temporary file");
+ goto cleanup;
+ }
+
+ *crc = crc32(*crc, ramdisk, size);
+ if (qcrypto_hash_update(hash0, (char *)ramdisk, size, errp) != 0 ||
+ qcrypto_hash_update(h, (char *)ramdisk, size, errp) != 0) {
+ goto cleanup;
+ }
+ ret = true;
+
+ cleanup:
+ g_free(ramdisk);
+ return ret;
+}
+
+static bool get_signature_fingerprint_sha384(FILE *eif, uint64_t size,
+ uint8_t *sha384,
+ uint32_t *crc,
+ Error **errp)
+{
+ size_t got;
+ g_autofree uint8_t *sig = NULL;
+ g_autofree uint8_t *cert = NULL;
+ cbor_item_t *item = NULL;
+ cbor_item_t *pcr0 = NULL;
+ size_t len;
+ size_t hash_len = QCRYPTO_HASH_DIGEST_LEN_SHA384;
+ struct cbor_pair *pair;
+ struct cbor_load_result result;
+ bool ret = false;
+
+ sig = g_try_malloc(size);
+ if (!sig) {
+ error_setg(errp, "Out of memory reading signature section");
+ goto cleanup;
+ }
+
+ got = fread(sig, 1, size, eif);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF signature section data");
+ goto cleanup;
+ }
+
+ *crc = crc32(*crc, sig, size);
+
+ item = cbor_load(sig, size, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ error_setg(errp, "Failed to load signature section data as CBOR");
+ goto cleanup;
+ }
+ if (!cbor_isa_array(item) || cbor_array_size(item) < 1) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ pcr0 = cbor_array_get(item, 0);
+ if (!pcr0) {
+ error_setg(errp, "Failed to get PCR0 signature");
+ goto cleanup;
+ }
+ if (!cbor_isa_map(pcr0) || cbor_map_size(pcr0) != 2) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ pair = cbor_map_handle(pcr0);
+ if (!cbor_isa_string(pair->key) || cbor_string_length(pair->key) != 19 ||
+ memcmp(cbor_string_handle(pair->key), "signing_certificate", 19) != 0) {
+ error_setg(errp, "Invalid signautre CBOR");
+ goto cleanup;
+ }
+ if (!cbor_isa_array(pair->value)) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ len = cbor_array_size(pair->value);
+ if (len == 0) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ cert = g_try_malloc(len);
+ if (!cert) {
+ error_setg(errp, "Out of memory reading signature section");
+ goto cleanup;
+ }
+
+ for (int i = 0; i < len; ++i) {
+ cbor_item_t *tmp = cbor_array_get(pair->value, i);
+ if (!tmp) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ if (!cbor_isa_uint(tmp) || cbor_int_get_width(tmp) != CBOR_INT_8) {
+ cbor_decref(&tmp);
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ cert[i] = cbor_get_uint8(tmp);
+ cbor_decref(&tmp);
+ }
+
+ if (qcrypto_get_x509_cert_fingerprint(cert, len, QCRYPTO_HASH_ALGO_SHA384,
+ sha384, &hash_len, errp)) {
+ goto cleanup;
+ }
+
+ ret = true;
+
+ cleanup:
+ if (pcr0) {
+ cbor_decref(&pcr0);
+ }
+ if (item) {
+ cbor_decref(&item);
+ }
+ return ret;
+}
+
+/* Expects file to have offset 0 before this function is called */
+static long get_file_size(FILE *f, Error **errp)
+{
+ long size;
+
+ if (fseek(f, 0, SEEK_END) != 0) {
+ error_setg_errno(errp, errno, "Failed to seek to the end of file");
+ return -1;
+ }
+
+ size = ftell(f);
+ if (size == -1) {
+ error_setg_errno(errp, errno, "Failed to get offset");
+ return -1;
+ }
+
+ if (fseek(f, 0, SEEK_SET) != 0) {
+ error_setg_errno(errp, errno, "Failed to seek back to the start");
+ return -1;
+ }
+
+ return size;
+}
+
+static bool get_SHA384_hash(QCryptoHash *h, uint8_t *hash, Error **errp)
+{
+ size_t hash_len = QCRYPTO_HASH_DIGEST_LEN_SHA384;
+ return qcrypto_hash_finalize_bytes(h, &hash, &hash_len, errp) == 0;
+}
+
+/*
+ * Upon success, the caller is reponsible for unlinking and freeing
+ * *kernel_path, *initrd_path and freeing *cmdline.
+ */
+bool read_eif_file(const char *eif_path, const char *machine_initrd,
+ char **kernel_path, char **initrd_path, char **cmdline,
+ uint8_t *image_hash, uint8_t *bootstrap_hash,
+ uint8_t *app_hash, uint8_t *fingerprint_hash,
+ bool *signature_found, Error **errp)
+{
+ FILE *f = NULL;
+ FILE *machine_initrd_f = NULL;
+ FILE *initrd_path_f = NULL;
+ long machine_initrd_size;
+ uint32_t crc = 0;
+ EifHeader eif_header;
+ bool seen_sections[EIF_SECTION_MAX] = {false};
+ /* kernel + ramdisks + cmdline SHA384 hash */
+ g_autoptr(QCryptoHash) hash0 = NULL;
+ /* kernel + boot ramdisk + cmdline SHA384 hash */
+ g_autoptr(QCryptoHash) hash1 = NULL;
+ /* application ramdisk(s) SHA384 hash */
+ g_autoptr(QCryptoHash) hash2 = NULL;
+
+ *signature_found = false;
+ *kernel_path = *initrd_path = *cmdline = NULL;
+
+ hash0 = qcrypto_hash_new(QCRYPTO_HASH_ALGO_SHA384, errp);
+ if (!hash0) {
+ goto cleanup;
+ }
+ hash1 = qcrypto_hash_new(QCRYPTO_HASH_ALGO_SHA384, errp);
+ if (!hash1) {
+ goto cleanup;
+ }
+ hash2 = qcrypto_hash_new(QCRYPTO_HASH_ALGO_SHA384, errp);
+ if (!hash2) {
+ goto cleanup;
+ }
+
+ f = fopen(eif_path, "rb");
+ if (f == NULL) {
+ error_setg_errno(errp, errno, "Failed to open %s", eif_path);
+ goto cleanup;
+ }
+
+ if (!read_eif_header(f, &eif_header, &crc, errp)) {
+ goto cleanup;
+ }
+
+ if (eif_header.version < 4) {
+ error_setg(errp, "Expected EIF version 4 or greater");
+ goto cleanup;
+ }
+
+ if (eif_header.flags != 0) {
+ error_setg(errp, "Expected EIF flags to be 0");
+ goto cleanup;
+ }
+
+ if (eif_header.section_cnt > MAX_SECTIONS) {
+ error_setg(errp, "EIF header section count must not be greater than "
+ "%d but found %d", MAX_SECTIONS, eif_header.section_cnt);
+ goto cleanup;
+ }
+
+ for (int i = 0; i < eif_header.section_cnt; ++i) {
+ EifSectionHeader hdr;
+ uint16_t section_type;
+
+ if (eif_header.section_offsets[i] > OFF_MAX) {
+ error_setg(errp, "Invalid EIF image. Section offset out of bounds");
+ goto cleanup;
+ }
+ if (fseek(f, eif_header.section_offsets[i], SEEK_SET) != 0) {
+ error_setg_errno(errp, errno, "Failed to offset to %" PRIu64 " in EIF file",
+ eif_header.section_offsets[i]);
+ goto cleanup;
+ }
+
+ if (!read_eif_section_header(f, &hdr, &crc, errp)) {
+ goto cleanup;
+ }
+
+ if (hdr.flags != 0) {
+ error_setg(errp, "Expected EIF section header flags to be 0");
+ goto cleanup;
+ }
+
+ if (eif_header.section_sizes[i] != hdr.section_size) {
+ error_setg(errp, "EIF section size mismatch between header and "
+ "section header: header %" PRIu64 ", section header %" PRIu64,
+ eif_header.section_sizes[i],
+ hdr.section_size);
+ goto cleanup;
+ }
+
+ section_type = hdr.section_type;
+
+ switch (section_type) {
+ case EIF_SECTION_KERNEL:
+ if (seen_sections[EIF_SECTION_KERNEL]) {
+ error_setg(errp, "Invalid EIF image. More than 1 kernel "
+ "section");
+ goto cleanup;
+ }
+
+ if (!read_eif_kernel(f, hdr.section_size, kernel_path, hash0,
+ hash1, &crc, errp)) {
+ goto cleanup;
+ }
+
+ break;
+ case EIF_SECTION_CMDLINE:
+ {
+ uint64_t size;
+ if (seen_sections[EIF_SECTION_CMDLINE]) {
+ error_setg(errp, "Invalid EIF image. More than 1 cmdline "
+ "section");
+ goto cleanup;
+ }
+ size = hdr.section_size;
+ *cmdline = g_try_malloc(size + 1);
+ if (!*cmdline) {
+ error_setg(errp, "Out of memory reading command line section");
+ goto cleanup;
+ }
+ if (!read_eif_cmdline(f, size, *cmdline, hash0, hash1, &crc,
+ errp)) {
+ goto cleanup;
+ }
+ (*cmdline)[size] = '\0';
+
+ break;
+ }
+ case EIF_SECTION_RAMDISK:
+ {
+ QCryptoHash *h = hash2;
+ if (!seen_sections[EIF_SECTION_RAMDISK]) {
+ /*
+ * If this is the first time we are seeing a ramdisk section,
+ * we need to:
+ * 1) hash it into bootstrap (hash1) instead of app (hash2)
+ * along with image (hash0)
+ * 2) create the initrd temporary file.
+ */
+ h = hash1;
+ if (!get_tmp_file("eif-initrd-XXXXXX", initrd_path, errp)) {
+ goto cleanup;
+ }
+ initrd_path_f = fopen(*initrd_path, "wb");
+ if (initrd_path_f == NULL) {
+ error_setg_errno(errp, errno, "Failed to open file %s",
+ *initrd_path);
+ goto cleanup;
+ }
+ }
+
+ if (!read_eif_ramdisk(f, initrd_path_f, hdr.section_size, hash0, h,
+ &crc, errp)) {
+ goto cleanup;
+ }
+
+ break;
+ }
+ case EIF_SECTION_SIGNATURE:
+ *signature_found = true;
+ if (!get_signature_fingerprint_sha384(f, hdr.section_size,
+ fingerprint_hash, &crc,
+ errp)) {
+ goto cleanup;
+ }
+ break;
+ default:
+ /* other sections including invalid or unknown sections */
+ {
+ uint8_t *buf;
+ size_t got;
+ uint64_t size = hdr.section_size;
+ buf = g_try_malloc(size);
+ if (!buf) {
+ error_setg(errp, "Out of memory reading unknown section");
+ goto cleanup;
+ }
+ got = fread(buf, 1, size, f);
+ if ((uint64_t) got != size) {
+ g_free(buf);
+ error_setg(errp, "Failed to read EIF %s section data",
+ section_type_to_string(section_type));
+ goto cleanup;
+ }
+ crc = crc32(crc, buf, size);
+ g_free(buf);
+ break;
+ }
+ }
+
+ if (section_type < EIF_SECTION_MAX) {
+ seen_sections[section_type] = true;
+ }
+ }
+
+ if (!seen_sections[EIF_SECTION_KERNEL]) {
+ error_setg(errp, "Invalid EIF image. No kernel section.");
+ goto cleanup;
+ }
+ if (!seen_sections[EIF_SECTION_CMDLINE]) {
+ error_setg(errp, "Invalid EIF image. No cmdline section.");
+ goto cleanup;
+ }
+ if (!seen_sections[EIF_SECTION_RAMDISK]) {
+ error_setg(errp, "Invalid EIF image. No ramdisk section.");
+ goto cleanup;
+ }
+
+ if (eif_header.eif_crc32 != crc) {
+ error_setg(errp, "CRC mismatch. Expected %u but header has %u.",
+ crc, eif_header.eif_crc32);
+ goto cleanup;
+ }
+
+ /*
+ * Let's append the initrd file from "-initrd" option if any. Although
+ * we pass the crc pointer to read_eif_ramdisk, it is not useful anymore.
+ * We have already done the crc mismatch check above this code.
+ */
+ if (machine_initrd) {
+ machine_initrd_f = fopen(machine_initrd, "rb");
+ if (machine_initrd_f == NULL) {
+ error_setg_errno(errp, errno, "Failed to open initrd file %s",
+ machine_initrd);
+ goto cleanup;
+ }
+
+ machine_initrd_size = get_file_size(machine_initrd_f, errp);
+ if (machine_initrd_size == -1) {
+ goto cleanup;
+ }
+
+ if (!read_eif_ramdisk(machine_initrd_f, initrd_path_f,
+ machine_initrd_size, hash0, hash2, &crc, errp)) {
+ goto cleanup;
+ }
+ }
+
+ if (!get_SHA384_hash(hash0, image_hash, errp)) {
+ goto cleanup;
+ }
+ if (!get_SHA384_hash(hash1, bootstrap_hash, errp)) {
+ goto cleanup;
+ }
+ if (!get_SHA384_hash(hash2, app_hash, errp)) {
+ goto cleanup;
+ }
+
+ fclose(f);
+ fclose(initrd_path_f);
+ safe_fclose(machine_initrd_f);
+ return true;
+
+ cleanup:
+ safe_fclose(f);
+ safe_fclose(initrd_path_f);
+ safe_fclose(machine_initrd_f);
+
+ safe_unlink(*kernel_path);
+ g_free(*kernel_path);
+ *kernel_path = NULL;
+
+ safe_unlink(*initrd_path);
+ g_free(*initrd_path);
+ *initrd_path = NULL;
+
+ g_free(*cmdline);
+ *cmdline = NULL;
+
+ return false;
+}
diff --git a/hw/core/eif.h b/hw/core/eif.h
new file mode 100644
index 0000000..fed3cb5
--- /dev/null
+++ b/hw/core/eif.h
@@ -0,0 +1,22 @@
+/*
+ * EIF (Enclave Image Format) related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#ifndef HW_CORE_EIF_H
+#define HW_CORE_EIF_H
+
+bool read_eif_file(const char *eif_path, const char *machine_initrd,
+ char **kernel_path, char **initrd_path,
+ char **kernel_cmdline, uint8_t *image_sha384,
+ uint8_t *bootstrap_sha384, uint8_t *app_sha384,
+ uint8_t *fingerprint_sha384, bool *signature_found,
+ Error **errp);
+
+#endif
+
diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c
index ea8628b..e72bbde 100644
--- a/hw/core/generic-loader.c
+++ b/hw/core/generic-loader.c
@@ -31,9 +31,8 @@
*/
#include "qemu/osdep.h"
-#include "exec/tswap.h"
-#include "sysemu/dma.h"
-#include "sysemu/reset.h"
+#include "system/dma.h"
+#include "system/reset.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
@@ -48,11 +47,8 @@ static void generic_loader_reset(void *opaque)
GenericLoaderState *s = GENERIC_LOADER(opaque);
if (s->set_pc) {
- CPUClass *cc = CPU_GET_CLASS(s->cpu);
cpu_reset(s->cpu);
- if (cc) {
- cc->set_pc(s->cpu, s->addr);
- }
+ cpu_set_pc(s->cpu, s->addr);
}
if (s->data_len) {
@@ -66,7 +62,6 @@ static void generic_loader_realize(DeviceState *dev, Error **errp)
{
GenericLoaderState *s = GENERIC_LOADER(dev);
hwaddr entry;
- int big_endian;
ssize_t size = 0;
s->set_pc = false;
@@ -134,14 +129,12 @@ static void generic_loader_realize(DeviceState *dev, Error **errp)
s->cpu = first_cpu;
}
- big_endian = target_words_bigendian();
-
if (s->file) {
AddressSpace *as = s->cpu ? s->cpu->as : NULL;
if (!s->force_raw) {
size = load_elf_as(s->file, NULL, NULL, NULL, &entry, NULL, NULL,
- NULL, big_endian, 0, 0, 0, as);
+ NULL, ELFDATANONE, 0, 0, 0, as);
if (size < 0) {
size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL,
@@ -179,7 +172,7 @@ static void generic_loader_unrealize(DeviceState *dev)
qemu_unregister_reset(generic_loader_reset, dev);
}
-static Property generic_loader_props[] = {
+static const Property generic_loader_props[] = {
DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0),
DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0),
DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0),
@@ -187,10 +180,9 @@ static Property generic_loader_props[] = {
DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE),
DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false),
DEFINE_PROP_STRING("file", GenericLoaderState, file),
- DEFINE_PROP_END_OF_LIST(),
};
-static void generic_loader_class_init(ObjectClass *klass, void *data)
+static void generic_loader_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/gpio.c b/hw/core/gpio.c
index 80d07a6..6e32a8e 100644
--- a/hw/core/gpio.c
+++ b/hw/core/gpio.c
@@ -121,8 +121,7 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
name ? name : "unnamed-gpio-out", n);
if (input_pin && !OBJECT(input_pin)->parent) {
/* We need a name for object_property_set_link to work */
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
+ object_property_add_child(machine_get_container("unattached"),
"non-qdev-gpio[*]", OBJECT(input_pin));
}
object_property_set_link(OBJECT(dev), propname,
diff --git a/hw/core/guest-loader.c b/hw/core/guest-loader.c
index 391c875..3db89d7 100644
--- a/hw/core/guest-loader.c
+++ b/hw/core/guest-loader.c
@@ -26,13 +26,13 @@
#include "qemu/osdep.h"
#include "hw/core/cpu.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "guest-loader.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/boards.h"
/*
@@ -111,15 +111,14 @@ static void guest_loader_realize(DeviceState *dev, Error **errp)
loader_insert_platform_data(s, size, errp);
}
-static Property guest_loader_props[] = {
+static const Property guest_loader_props[] = {
DEFINE_PROP_UINT64("addr", GuestLoaderState, addr, 0),
DEFINE_PROP_STRING("kernel", GuestLoaderState, kernel),
DEFINE_PROP_STRING("bootargs", GuestLoaderState, args),
DEFINE_PROP_STRING("initrd", GuestLoaderState, initrd),
- DEFINE_PROP_END_OF_LIST(),
};
-static void guest_loader_class_init(ObjectClass *klass, void *data)
+static void guest_loader_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/irq.c b/hw/core/irq.c
index 3f14e2d..6dd8d47 100644
--- a/hw/core/irq.c
+++ b/hw/core/irq.c
@@ -26,16 +26,6 @@
#include "hw/irq.h"
#include "qom/object.h"
-OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ)
-
-struct IRQState {
- Object parent_obj;
-
- qemu_irq_handler handler;
- void *opaque;
- int n;
-};
-
void qemu_set_irq(qemu_irq irq, int level)
{
if (!irq)
@@ -44,6 +34,29 @@ void qemu_set_irq(qemu_irq irq, int level)
irq->handler(irq->opaque, irq->n, level);
}
+static void init_irq_fields(IRQState *irq, qemu_irq_handler handler,
+ void *opaque, int n)
+{
+ irq->handler = handler;
+ irq->opaque = opaque;
+ irq->n = n;
+}
+
+void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque,
+ int n)
+{
+ object_initialize(irq, sizeof(*irq), TYPE_IRQ);
+ init_irq_fields(irq, handler, opaque, n);
+}
+
+void qemu_init_irqs(IRQState irq[], size_t count,
+ qemu_irq_handler handler, void *opaque)
+{
+ for (size_t i = 0; i < count; i++) {
+ qemu_init_irq(&irq[i], handler, opaque, i);
+ }
+}
+
qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
void *opaque, int n)
{
@@ -67,13 +80,8 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
qemu_irq qemu_allocate_irq(qemu_irq_handler handler, void *opaque, int n)
{
- IRQState *irq;
-
- irq = IRQ(object_new(TYPE_IRQ));
- irq->handler = handler;
- irq->opaque = opaque;
- irq->n = n;
-
+ IRQState *irq = IRQ(object_new(TYPE_IRQ));
+ init_irq_fields(irq, handler, opaque, n);
return irq;
}
diff --git a/hw/core/loader-fit.c b/hw/core/loader-fit.c
index 7ccc9d5..2dea485 100644
--- a/hw/core/loader-fit.c
+++ b/hw/core/loader-fit.c
@@ -20,20 +20,20 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/units.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/loader.h"
#include "hw/loader-fit.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include <libfdt.h>
#include <zlib.h>
#define FIT_LOADER_MAX_PATH (128)
-static const void *fit_load_image_alloc(const void *itb, const char *name,
- int *poff, size_t *psz, Error **errp)
+static void *fit_load_image_alloc(const void *itb, const char *name,
+ int *poff, size_t *psz, Error **errp)
{
const void *data;
const char *comp;
@@ -80,11 +80,11 @@ static const void *fit_load_image_alloc(const void *itb, const char *name,
return NULL;
}
- data = g_realloc(uncomp_data, uncomp_len);
+ uncomp_data = g_realloc(uncomp_data, uncomp_len);
if (psz) {
*psz = uncomp_len;
}
- return data;
+ return uncomp_data;
}
error_setg(errp, "unknown compression '%s'", comp);
@@ -177,13 +177,12 @@ out:
static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
int cfg, void *opaque, const void *match_data,
- hwaddr kernel_end, Error **errp)
+ hwaddr kernel_end, void **pfdt, Error **errp)
{
ERRP_GUARD();
Error *err = NULL;
const char *name;
- const void *data;
- const void *load_data;
+ void *data;
hwaddr load_addr;
int img_off;
size_t sz;
@@ -194,7 +193,7 @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
return 0;
}
- load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
+ data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
if (!data) {
error_prepend(errp, "unable to load FDT image from FIT: ");
return -EINVAL;
@@ -211,19 +210,23 @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
}
if (ldr->fdt_filter) {
- load_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
+ void *filtered_data;
+
+ filtered_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
+ if (filtered_data != data) {
+ g_free(data);
+ data = filtered_data;
+ }
}
load_addr = ldr->addr_to_phys(opaque, load_addr);
- sz = fdt_totalsize(load_data);
- rom_add_blob_fixed(name, load_data, sz, load_addr);
+ sz = fdt_totalsize(data);
+ rom_add_blob_fixed(name, data, sz, load_addr);
- ret = 0;
+ *pfdt = data;
+ return 0;
out:
g_free((void *) data);
- if (data != load_data) {
- g_free((void *) load_data);
- }
return ret;
}
@@ -259,7 +262,8 @@ out:
return ret;
}
-int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
+int load_fit(const struct fit_loader *ldr, const char *filename,
+ void **pfdt, void *opaque)
{
Error *err = NULL;
const struct fit_loader_match *match;
@@ -323,7 +327,7 @@ int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
goto out;
}
- ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end,
+ ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end, pfdt,
&err);
if (ret) {
error_report_err(err);
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 31593a1..e7056ba 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -51,17 +51,18 @@
#include "trace.h"
#include "hw/hw.h"
#include "disas/disas.h"
+#include "migration/cpr.h"
#include "migration/vmstate.h"
#include "monitor/monitor.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
+#include "system/reset.h"
+#include "system/system.h"
#include "uboot_image.h"
#include "hw/loader.h"
#include "hw/nvram/fw_cfg.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/boards.h"
#include "qemu/cutils.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "tcg/debuginfo.h"
#include <zlib.h>
@@ -144,7 +145,7 @@ ssize_t load_image_mr(const char *filename, MemoryRegion *mr)
{
ssize_t size;
- if (!memory_access_is_direct(mr, false)) {
+ if (!memory_access_is_direct(mr, false, MEMTXATTRS_UNSPECIFIED)) {
/* Can only load an image into RAM or ROM */
return -1;
}
@@ -225,7 +226,7 @@ static void bswap_ahdr(struct exec *e)
ssize_t load_aout(const char *filename, hwaddr addr, int max_sz,
- int bswap_needed, hwaddr target_page_size)
+ bool big_endian, hwaddr target_page_size)
{
int fd;
ssize_t size, ret;
@@ -240,7 +241,7 @@ ssize_t load_aout(const char *filename, hwaddr addr, int max_sz,
if (size < 0)
goto fail;
- if (bswap_needed) {
+ if (big_endian != HOST_BIG_ENDIAN) {
bswap_ahdr(&e);
}
@@ -409,11 +410,11 @@ ssize_t load_elf(const char *filename,
uint64_t (*elf_note_fn)(void *, void *, bool),
uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
- uint64_t *highaddr, uint32_t *pflags, int big_endian,
+ uint64_t *highaddr, uint32_t *pflags, int elf_data_order,
int elf_machine, int clear_lsb, int data_swab)
{
return load_elf_as(filename, elf_note_fn, translate_fn, translate_opaque,
- pentry, lowaddr, highaddr, pflags, big_endian,
+ pentry, lowaddr, highaddr, pflags, elf_data_order,
elf_machine, clear_lsb, data_swab, NULL);
}
@@ -422,29 +423,15 @@ ssize_t load_elf_as(const char *filename,
uint64_t (*elf_note_fn)(void *, void *, bool),
uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
- uint64_t *highaddr, uint32_t *pflags, int big_endian,
+ uint64_t *highaddr, uint32_t *pflags, int elf_data_order,
int elf_machine, int clear_lsb, int data_swab,
AddressSpace *as)
{
- return load_elf_ram(filename, elf_note_fn, translate_fn, translate_opaque,
- pentry, lowaddr, highaddr, pflags, big_endian,
- elf_machine, clear_lsb, data_swab, as, true);
-}
-
-/* return < 0 if error, otherwise the number of bytes loaded in memory */
-ssize_t load_elf_ram(const char *filename,
- uint64_t (*elf_note_fn)(void *, void *, bool),
- uint64_t (*translate_fn)(void *, uint64_t),
- void *translate_opaque, uint64_t *pentry,
- uint64_t *lowaddr, uint64_t *highaddr, uint32_t *pflags,
- int big_endian, int elf_machine, int clear_lsb,
- int data_swab, AddressSpace *as, bool load_rom)
-{
return load_elf_ram_sym(filename, elf_note_fn,
translate_fn, translate_opaque,
- pentry, lowaddr, highaddr, pflags, big_endian,
+ pentry, lowaddr, highaddr, pflags, elf_data_order,
elf_machine, clear_lsb, data_swab, as,
- load_rom, NULL);
+ true, NULL);
}
/* return < 0 if error, otherwise the number of bytes loaded in memory */
@@ -453,11 +440,12 @@ ssize_t load_elf_ram_sym(const char *filename,
uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry,
uint64_t *lowaddr, uint64_t *highaddr,
- uint32_t *pflags, int big_endian, int elf_machine,
+ uint32_t *pflags, int elf_data_order, int elf_machine,
int clear_lsb, int data_swab,
AddressSpace *as, bool load_rom, symbol_fn_t sym_cb)
{
- int fd, data_order, target_data_order, must_swab;
+ const int host_data_order = HOST_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
+ int fd, must_swab;
ssize_t ret = ELF_LOAD_FAILED;
uint8_t e_ident[EI_NIDENT];
@@ -475,23 +463,14 @@ ssize_t load_elf_ram_sym(const char *filename,
ret = ELF_LOAD_NOT_ELF;
goto fail;
}
-#if HOST_BIG_ENDIAN
- data_order = ELFDATA2MSB;
-#else
- data_order = ELFDATA2LSB;
-#endif
- must_swab = data_order != e_ident[EI_DATA];
- if (big_endian) {
- target_data_order = ELFDATA2MSB;
- } else {
- target_data_order = ELFDATA2LSB;
- }
- if (target_data_order != e_ident[EI_DATA]) {
+ if (elf_data_order != ELFDATANONE && elf_data_order != e_ident[EI_DATA]) {
ret = ELF_LOAD_WRONG_ENDIAN;
goto fail;
}
+ must_swab = host_data_order != e_ident[EI_DATA];
+
lseek(fd, 0, SEEK_SET);
if (e_ident[EI_CLASS] == ELFCLASS64) {
ret = load_elf64(filename, fd, elf_note_fn,
@@ -886,11 +865,11 @@ struct linux_efi_zboot_header {
*
* If the image is not a Linux EFI zboot image, do nothing and return success.
*/
-ssize_t unpack_efi_zboot_image(uint8_t **buffer, int *size)
+ssize_t unpack_efi_zboot_image(uint8_t **buffer, ssize_t *size)
{
const struct linux_efi_zboot_header *header;
uint8_t *data = NULL;
- int ploff, plsize;
+ ssize_t ploff, plsize;
ssize_t bytes;
/* ignore if this is too small to be a EFI zboot image */
@@ -1051,7 +1030,9 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name, bool ro)
vmstate_register_ram_global(rom->mr);
data = memory_region_get_ram_ptr(rom->mr);
- memcpy(data, rom->data, rom->datasize);
+ if (!cpr_is_incoming()) {
+ memcpy(data, rom->data, rom->datasize);
+ }
return data;
}
@@ -1352,20 +1333,6 @@ void rom_set_fw(FWCfgState *f)
fw_cfg = f;
}
-void rom_set_order_override(int order)
-{
- if (!fw_cfg)
- return;
- fw_cfg_set_order_override(fw_cfg, order);
-}
-
-void rom_reset_order_override(void)
-{
- if (!fw_cfg)
- return;
- fw_cfg_reset_order_override(fw_cfg);
-}
-
void rom_transaction_begin(void)
{
Rom *rom;
@@ -1429,7 +1396,7 @@ typedef struct RomSec {
* work, but this way saves a little work later by avoiding
* dealing with "gaps" of 0 length.
*/
-static gint sort_secs(gconstpointer a, gconstpointer b)
+static gint sort_secs(gconstpointer a, gconstpointer b, gpointer d)
{
RomSec *ra = (RomSec *) a;
RomSec *rb = (RomSec *) b;
@@ -1482,7 +1449,7 @@ RomGap rom_find_largest_gap_between(hwaddr base, size_t size)
/* sentinel */
secs = add_romsec_to_list(secs, base + size, 1);
- secs = g_list_sort(secs, sort_secs);
+ secs = g_list_sort_with_data(secs, sort_secs, NULL);
for (it = g_list_first(secs); it; it = g_list_next(it)) {
cand = (RomSec *) it->data;
diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
index 8701f00..c6325cd 100644
--- a/hw/core/machine-hmp-cmds.c
+++ b/hw/core/machine-hmp-cmds.c
@@ -19,10 +19,10 @@
#include "qapi/error.h"
#include "qapi/qapi-builtin-visit.h"
#include "qapi/qapi-commands-machine.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/string-output-visitor.h"
#include "qemu/error-report.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#include "hw/boards.h"
void hmp_info_cpus(Monitor *mon, const QDict *qdict)
diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
index 130217d..d82043e 100644
--- a/hw/core/machine-qmp-cmds.c
+++ b/hw/core/machine-qmp-cmds.c
@@ -15,16 +15,18 @@
#include "qapi/error.h"
#include "qapi/qapi-builtin-visit.h"
#include "qapi/qapi-commands-machine.h"
-#include "qapi/qmp/qobject.h"
+#include "qobject/qobject.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/type-helpers.h"
#include "qemu/uuid.h"
+#include "qemu/target-info.h"
#include "qom/qom-qobject.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/numa.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/hostmem.h"
+#include "system/hw_accel.h"
+#include "system/numa.h"
+#include "system/runstate.h"
+#include "system/system.h"
+#include "hw/s390x/storage-keys.h"
/*
* fast means: we NEVER interrupt vCPU threads to retrieve
@@ -72,6 +74,7 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
for (el = machines; el; el = el->next) {
MachineClass *mc = el->data;
+ const char *default_cpu_type = machine_class_default_cpu_type(mc);
MachineInfo *info;
info = g_malloc0(sizeof(*info));
@@ -90,8 +93,8 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
info->numa_mem_supported = mc->numa_mem_supported;
info->deprecated = !!mc->deprecation_reason;
info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi");
- if (mc->default_cpu_type) {
- info->default_cpu_type = g_strdup(mc->default_cpu_type);
+ if (default_cpu_type) {
+ info->default_cpu_type = g_strdup(default_cpu_type);
}
if (mc->default_ram_id) {
info->default_ram_id = g_strdup(mc->default_ram_id);
@@ -132,9 +135,9 @@ CurrentMachineParams *qmp_query_current_machine(Error **errp)
return params;
}
-TargetInfo *qmp_query_target(Error **errp)
+QemuTargetInfo *qmp_query_target(Error **errp)
{
- TargetInfo *info = g_malloc0(sizeof(*info));
+ QemuTargetInfo *info = g_malloc0(sizeof(*info));
info->arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1,
&error_abort);
@@ -406,3 +409,16 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
info->guid = qemu_uuid_unparse_strdup(&vms->guid);
return info;
}
+
+void qmp_dump_skeys(const char *filename, Error **errp)
+{
+ ObjectClass *mc = object_get_class(qdev_get_machine());
+ ObjectClass *oc = object_class_dynamic_cast(mc, TYPE_DUMP_SKEYS_INTERFACE);
+
+ if (!oc) {
+ error_setg(errp, "Storage keys information not available"
+ " for this architecture");
+ return;
+ }
+ DUMP_SKEYS_INTERFACE_CLASS(oc)->qmp_dump_skeys(filename, errp);
+}
diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c
index 5d8d7ed..0be0ac0 100644
--- a/hw/core/machine-smp.c
+++ b/hw/core/machine-smp.c
@@ -261,6 +261,82 @@ void machine_parse_smp_config(MachineState *ms,
}
}
+static bool machine_check_topo_support(MachineState *ms,
+ CpuTopologyLevel topo,
+ Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if ((topo == CPU_TOPOLOGY_LEVEL_MODULE && !mc->smp_props.modules_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_CLUSTER && !mc->smp_props.clusters_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_DIE && !mc->smp_props.dies_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_BOOK && !mc->smp_props.books_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_DRAWER && !mc->smp_props.drawers_supported)) {
+ error_setg(errp,
+ "Invalid topology level: %s. "
+ "The topology level is not supported by this machine",
+ CpuTopologyLevel_str(topo));
+ return false;
+ }
+
+ return true;
+}
+
+bool machine_parse_smp_cache(MachineState *ms,
+ const SmpCachePropertiesList *caches,
+ Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const SmpCachePropertiesList *node;
+ DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX);
+
+ bitmap_zero(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX);
+ for (node = caches; node; node = node->next) {
+ /* Prohibit users from repeating settings. */
+ if (test_bit(node->value->cache, caches_bitmap)) {
+ error_setg(errp,
+ "Invalid cache properties: %s. "
+ "The cache properties are duplicated",
+ CacheLevelAndType_str(node->value->cache));
+ return false;
+ }
+
+ machine_set_cache_topo_level(ms, node->value->cache,
+ node->value->topology);
+ set_bit(node->value->cache, caches_bitmap);
+ }
+
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ const SmpCacheProperties *props = &ms->smp_cache.props[i];
+
+ /*
+ * Reject non "default" topology level if the cache isn't
+ * supported by the machine.
+ */
+ if (props->topology != CPU_TOPOLOGY_LEVEL_DEFAULT &&
+ !mc->smp_props.cache_supported[props->cache]) {
+ error_setg(errp,
+ "%s cache topology not supported by this machine",
+ CacheLevelAndType_str(props->cache));
+ return false;
+ }
+
+ if (props->topology == CPU_TOPOLOGY_LEVEL_THREAD) {
+ error_setg(errp,
+ "%s level cache not supported by this machine",
+ CpuTopologyLevel_str(props->topology));
+ return false;
+ }
+
+ if (!machine_check_topo_support(ms, props->topology, errp)) {
+ return false;
+ }
+ }
+
+ mc->smp_props.has_caches = true;
+ return true;
+}
+
unsigned int machine_topo_get_cores_per_socket(const MachineState *ms)
{
return ms->smp.cores * ms->smp.modules * ms->smp.clusters * ms->smp.dies;
@@ -270,3 +346,63 @@ unsigned int machine_topo_get_threads_per_socket(const MachineState *ms)
{
return ms->smp.threads * machine_topo_get_cores_per_socket(ms);
}
+
+CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms,
+ CacheLevelAndType cache)
+{
+ return ms->smp_cache.props[cache].topology;
+}
+
+void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache,
+ CpuTopologyLevel level)
+{
+ ms->smp_cache.props[cache].topology = level;
+}
+
+/*
+ * When both cache1 and cache2 are configured with specific topology levels
+ * (not default level), is cache1's topology level higher than cache2?
+ */
+static bool smp_cache_topo_cmp(const SmpCache *smp_cache,
+ CacheLevelAndType cache1,
+ CacheLevelAndType cache2)
+{
+ /*
+ * Before comparing, the "default" topology level should be replaced
+ * with the specific level.
+ */
+ assert(smp_cache->props[cache1].topology != CPU_TOPOLOGY_LEVEL_DEFAULT);
+
+ return smp_cache->props[cache1].topology > smp_cache->props[cache2].topology;
+}
+
+/*
+ * Currently, we have no way to expose the arch-specific default cache model
+ * because the cache model is sometimes related to the CPU model (e.g., i386).
+ *
+ * We can only check the correctness of the cache topology after the arch loads
+ * the user-configured cache model from MachineState and consumes the special
+ * "default" level by replacing it with the specific level.
+ */
+bool machine_check_smp_cache(const MachineState *ms, Error **errp)
+{
+ if (smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L1D,
+ CACHE_LEVEL_AND_TYPE_L2) ||
+ smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L1I,
+ CACHE_LEVEL_AND_TYPE_L2)) {
+ error_setg(errp,
+ "Invalid smp cache topology. "
+ "L2 cache topology level shouldn't be lower than L1 cache");
+ return false;
+ }
+
+ if (smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L2,
+ CACHE_LEVEL_AND_TYPE_L3)) {
+ error_setg(errp,
+ "Invalid smp cache topology. "
+ "L3 cache topology level shouldn't be lower than L2 cache");
+ return false;
+ }
+
+ return true;
+}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 27dcda0..e869821 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -11,36 +11,61 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qemu/accel.h"
-#include "sysemu/replay.h"
+#include "system/replay.h"
#include "hw/boards.h"
#include "hw/loader.h"
+#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-machine.h"
+#include "qapi/qapi-commands-machine.h"
#include "qemu/madvise.h"
#include "qom/object_interfaces.h"
-#include "sysemu/cpus.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/xen.h"
-#include "sysemu/qtest.h"
+#include "system/cpus.h"
+#include "system/system.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/xen.h"
+#include "system/qtest.h"
#include "hw/pci/pci_bridge.h"
#include "hw/mem/nvdimm.h"
#include "migration/global_state.h"
-#include "exec/confidential-guest-support.h"
+#include "system/confidential-guest-support.h"
#include "hw/virtio/virtio-pci.h"
#include "hw/virtio/virtio-net.h"
#include "hw/virtio/virtio-iommu.h"
#include "audio/audio.h"
+GlobalProperty hw_compat_10_0[] = {
+ { "scsi-hd", "dpofua", "off" },
+};
+const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0);
+
+GlobalProperty hw_compat_9_2[] = {
+ { "arm-cpu", "backcompat-pauth-default-use-qarma5", "true"},
+ { "virtio-balloon-pci", "vectors", "0" },
+ { "virtio-balloon-pci-transitional", "vectors", "0" },
+ { "virtio-balloon-pci-non-transitional", "vectors", "0" },
+ { "virtio-mem-pci", "vectors", "0" },
+ { "migration", "multifd-clean-tls-termination", "false" },
+ { "migration", "send-switchover-start", "off"},
+ { "vfio-pci", "x-migration-multifd-transfer", "off" },
+};
+const size_t hw_compat_9_2_len = G_N_ELEMENTS(hw_compat_9_2);
+
+GlobalProperty hw_compat_9_1[] = {
+ { TYPE_PCI_DEVICE, "x-pcie-ext-tag", "false" },
+};
+const size_t hw_compat_9_1_len = G_N_ELEMENTS(hw_compat_9_1);
+
GlobalProperty hw_compat_9_0[] = {
- {"arm-cpu", "backcompat-cntfrq", "true" },
+ { "arm-cpu", "backcompat-cntfrq", "true" },
{ "scsi-hd", "migrate-emulated-scsi-request", "false" },
{ "scsi-cd", "migrate-emulated-scsi-request", "false" },
- {"vfio-pci", "skip-vsc-check", "false" },
+ { "vfio-pci", "skip-vsc-check", "false" },
{ "virtio-pci", "x-pcie-pm-no-soft-reset", "off" },
- {"sd-card", "spec_version", "2" },
+ { "sd-card", "spec_version", "2" },
};
const size_t hw_compat_9_0_len = G_N_ELEMENTS(hw_compat_9_0);
@@ -260,51 +285,6 @@ GlobalProperty hw_compat_2_6[] = {
};
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
-GlobalProperty hw_compat_2_5[] = {
- { "isa-fdc", "fallback", "144" },
- { "pvscsi", "x-old-pci-configuration", "on" },
- { "pvscsi", "x-disable-pcie", "on" },
- { "vmxnet3", "x-old-msi-offsets", "on" },
- { "vmxnet3", "x-disable-pcie", "on" },
-};
-const size_t hw_compat_2_5_len = G_N_ELEMENTS(hw_compat_2_5);
-
-GlobalProperty hw_compat_2_4[] = {
- { "e1000", "extra_mac_registers", "off" },
- { "virtio-pci", "x-disable-pcie", "on" },
- { "virtio-pci", "migrate-extra", "off" },
- { "fw_cfg_mem", "dma_enabled", "off" },
- { "fw_cfg_io", "dma_enabled", "off" }
-};
-const size_t hw_compat_2_4_len = G_N_ELEMENTS(hw_compat_2_4);
-
-GlobalProperty hw_compat_2_3[] = {
- { "virtio-blk-pci", "any_layout", "off" },
- { "virtio-balloon-pci", "any_layout", "off" },
- { "virtio-serial-pci", "any_layout", "off" },
- { "virtio-9p-pci", "any_layout", "off" },
- { "virtio-rng-pci", "any_layout", "off" },
- { TYPE_PCI_DEVICE, "x-pcie-lnksta-dllla", "off" },
- { "migration", "send-configuration", "off" },
- { "migration", "send-section-footer", "off" },
- { "migration", "store-global-state", "off" },
-};
-const size_t hw_compat_2_3_len = G_N_ELEMENTS(hw_compat_2_3);
-
-GlobalProperty hw_compat_2_2[] = {};
-const size_t hw_compat_2_2_len = G_N_ELEMENTS(hw_compat_2_2);
-
-GlobalProperty hw_compat_2_1[] = {
- { "intel-hda", "old_msi_addr", "on" },
- { "VGA", "qemu-extended-regs", "off" },
- { "secondary-vga", "qemu-extended-regs", "off" },
- { "virtio-scsi-pci", "any_layout", "off" },
- { "usb-mouse", "usb_version", "1" },
- { "usb-kbd", "usb_version", "1" },
- { "virtio-pci", "virtio-pci-bus-master-bug-migration", "on" },
-};
-const size_t hw_compat_2_1_len = G_N_ELEMENTS(hw_compat_2_1);
-
MachineState *current_machine;
static char *machine_get_kernel(Object *obj, Error **errp)
@@ -322,6 +302,21 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp)
ms->kernel_filename = g_strdup(value);
}
+static char *machine_get_shim(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return g_strdup(ms->shim_filename);
+}
+
+static void machine_set_shim(Object *obj, const char *value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ g_free(ms->shim_filename);
+ ms->shim_filename = g_strdup(value);
+}
+
static char *machine_get_initrd(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -457,6 +452,22 @@ static void machine_set_mem_merge(Object *obj, bool value, Error **errp)
ms->mem_merge = value;
}
+#ifdef CONFIG_POSIX
+static bool machine_get_aux_ram_share(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return ms->aux_ram_share;
+}
+
+static void machine_set_aux_ram_share(Object *obj, bool value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ ms->aux_ram_share = value;
+}
+#endif
+
static bool machine_get_usb(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -618,11 +629,19 @@ static void machine_set_mem(Object *obj, Visitor *v, const char *name,
mem->size = mc->fixup_ram_size(mem->size);
}
if ((ram_addr_t)mem->size != mem->size) {
- error_setg(errp, "ram size too large");
+ error_setg(errp, "ram size %llu exceeds permitted maximum %llu",
+ (unsigned long long)mem->size,
+ (unsigned long long)RAM_ADDR_MAX);
goto out_free;
}
if (mem->has_max_size) {
+ if ((ram_addr_t)mem->max_size != mem->max_size) {
+ error_setg(errp, "ram size %llu exceeds permitted maximum %llu",
+ (unsigned long long)mem->max_size,
+ (unsigned long long)RAM_ADDR_MAX);
+ goto out_free;
+ }
if (mem->max_size < mem->size) {
error_setg(errp, "invalid value of maxmem: "
"maximum memory size (0x%" PRIx64 ") must be at least "
@@ -929,6 +948,40 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name,
machine_parse_smp_config(ms, config, errp);
}
+static void machine_get_smp_cache(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ SmpCache *cache = &ms->smp_cache;
+ SmpCachePropertiesList *head = NULL;
+ SmpCachePropertiesList **tail = &head;
+
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ SmpCacheProperties *node = g_new(SmpCacheProperties, 1);
+
+ node->cache = cache->props[i].cache;
+ node->topology = cache->props[i].topology;
+ QAPI_LIST_APPEND(tail, node);
+ }
+
+ visit_type_SmpCachePropertiesList(v, name, &head, errp);
+ qapi_free_SmpCachePropertiesList(head);
+}
+
+static void machine_set_smp_cache(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ SmpCachePropertiesList *caches;
+
+ if (!visit_type_SmpCachePropertiesList(v, name, &caches, errp)) {
+ return;
+ }
+
+ machine_parse_smp_cache(ms, caches, errp);
+ qapi_free_SmpCachePropertiesList(caches);
+}
+
static void machine_get_boot(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -998,7 +1051,40 @@ void machine_add_audiodev_property(MachineClass *mc)
"Audiodev to use for default machine devices");
}
-static void machine_class_init(ObjectClass *oc, void *data)
+static bool create_default_memdev(MachineState *ms, const char *path,
+ Error **errp)
+{
+ Object *obj;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ bool r = false;
+
+ obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM);
+ if (path) {
+ if (!object_property_set_str(obj, "mem-path", path, errp)) {
+ goto out;
+ }
+ }
+ if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
+ goto out;
+ }
+ object_property_add_child(object_get_objects_root(), mc->default_ram_id,
+ obj);
+ /* Ensure backend's memory region name is equal to mc->default_ram_id */
+ if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id",
+ false, errp)) {
+ goto out;
+ }
+ if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
+ goto out;
+ }
+ r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
+
+out:
+ object_unref(obj);
+ return r;
+}
+
+static void machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1017,11 +1103,18 @@ static void machine_class_init(ObjectClass *oc, void *data)
*/
mc->numa_mem_align_shift = 23;
+ mc->create_default_memdev = create_default_memdev;
+
object_class_property_add_str(oc, "kernel",
machine_get_kernel, machine_set_kernel);
object_class_property_set_description(oc, "kernel",
"Linux kernel image file");
+ object_class_property_add_str(oc, "shim",
+ machine_get_shim, machine_set_shim);
+ object_class_property_set_description(oc, "shim",
+ "shim.efi file");
+
object_class_property_add_str(oc, "initrd",
machine_get_initrd, machine_set_initrd);
object_class_property_set_description(oc, "initrd",
@@ -1054,6 +1147,11 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "smp",
"CPU topology");
+ object_class_property_add(oc, "smp-cache", "SmpCachePropertiesWrapper",
+ machine_get_smp_cache, machine_set_smp_cache, NULL, NULL);
+ object_class_property_set_description(oc, "smp-cache",
+ "Cache properties list for SMP machine");
+
object_class_property_add(oc, "phandle-start", "int",
machine_get_phandle_start, machine_set_phandle_start,
NULL, NULL);
@@ -1075,6 +1173,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "mem-merge",
"Enable/disable memory merge support");
+#ifdef CONFIG_POSIX
+ object_class_property_add_bool(oc, "aux-ram-share",
+ machine_get_aux_ram_share,
+ machine_set_aux_ram_share);
+#endif
+
object_class_property_add_bool(oc, "usb",
machine_get_usb, machine_set_usb);
object_class_property_set_description(oc, "usb",
@@ -1123,7 +1227,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
"Memory size configuration");
}
-static void machine_class_base_init(ObjectClass *oc, void *data)
+static void machine_class_base_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->max_cpus = mc->max_cpus ?: 1;
@@ -1144,9 +1248,6 @@ static void machine_initfn(Object *obj)
MachineState *ms = MACHINE(obj);
MachineClass *mc = MACHINE_GET_CLASS(obj);
- container_get(obj, "/peripheral");
- container_get(obj, "/peripheral-anon");
-
ms->dump_guest_core = true;
ms->mem_merge = (QEMU_MADV_MERGEABLE != QEMU_MADV_INVALID);
ms->enable_graphics = true;
@@ -1192,6 +1293,11 @@ static void machine_initfn(Object *obj)
ms->smp.cores = 1;
ms->smp.threads = 1;
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ ms->smp_cache.props[i].cache = (CacheLevelAndType)i;
+ ms->smp_cache.props[i].topology = CPU_TOPOLOGY_LEVEL_DEFAULT;
+ }
+
machine_copy_boot_config(ms, &(BootConfiguration){ 0 });
}
@@ -1410,38 +1516,6 @@ MemoryRegion *machine_consume_memdev(MachineState *machine,
return ret;
}
-static bool create_default_memdev(MachineState *ms, const char *path, Error **errp)
-{
- Object *obj;
- MachineClass *mc = MACHINE_GET_CLASS(ms);
- bool r = false;
-
- obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM);
- if (path) {
- if (!object_property_set_str(obj, "mem-path", path, errp)) {
- goto out;
- }
- }
- if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
- goto out;
- }
- object_property_add_child(object_get_objects_root(), mc->default_ram_id,
- obj);
- /* Ensure backend's memory region name is equal to mc->default_ram_id */
- if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id",
- false, errp)) {
- goto out;
- }
- if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
- goto out;
- }
- r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
-
-out:
- object_unref(obj);
- return r;
-}
-
const char *machine_class_default_cpu_type(MachineClass *mc)
{
if (mc->valid_cpu_types && !mc->valid_cpu_types[1]) {
@@ -1545,7 +1619,9 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
machine_class->default_ram_id);
return;
}
- if (!create_default_memdev(current_machine, mem_path, errp)) {
+
+ if (!machine_class->create_default_memdev(current_machine, mem_path,
+ errp)) {
return;
}
}
@@ -1610,6 +1686,22 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify)
notifier_remove(notify);
}
+static void handle_machine_dumpdtb(MachineState *ms)
+{
+ if (!ms->dumpdtb) {
+ return;
+ }
+#ifdef CONFIG_FDT
+ qmp_dumpdtb(ms->dumpdtb, &error_fatal);
+ exit(0);
+#else
+ error_report("This machine doesn't have an FDT");
+ error_printf("(this machine type definitely doesn't use FDT, and "
+ "this QEMU doesn't have FDT support compiled in)\n");
+ exit(1);
+#endif
+}
+
void qdev_machine_creation_done(void)
{
cpu_synchronize_all_post_init();
@@ -1639,6 +1731,12 @@ void qdev_machine_creation_done(void)
notifier_list_notify(&machine_init_done_notifiers, NULL);
+ /*
+ * If the user used -machine dumpdtb=file.dtb to request that we
+ * dump the DTB to a file, do it now, and exit.
+ */
+ handle_machine_dumpdtb(current_machine);
+
if (rom_check_and_register_reset() != 0) {
exit(1);
}
diff --git a/hw/core/meson.build b/hw/core/meson.build
index a3d9bab..b5a545a 100644
--- a/hw/core/meson.build
+++ b/hw/core/meson.build
@@ -24,9 +24,10 @@ system_ss.add(when: 'CONFIG_REGISTER', if_true: files('register.c'))
system_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c'))
system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c'))
system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c'))
+system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls])
system_ss.add(files(
- 'cpu-sysemu.c',
+ 'cpu-system.c',
'fw-path-provider.c',
'gpio.c',
'hotplug.c',
@@ -45,3 +46,7 @@ system_ss.add(files(
'vm-change-state-handler.c',
'clock-vmstate.c',
))
+user_ss.add(files(
+ 'cpu-user.c',
+ 'qdev-user.c',
+))
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index f586a4b..a6e477a 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/boards.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/core/cpu.h"
static void machine_none_init(MachineState *mch)
@@ -53,7 +53,6 @@ static void machine_none_machine_init(MachineClass *mc)
mc->no_parallel = 1;
mc->no_floppy = 1;
mc->no_cdrom = 1;
- mc->no_sdcard = 1;
}
DEFINE_MACHINE("none", machine_none_machine_init)
diff --git a/hw/core/numa.c b/hw/core/numa.c
index f8ce332..218576f 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -24,15 +24,15 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/numa.h"
+#include "system/hostmem.h"
+#include "system/numa.h"
#include "exec/cpu-common.h"
#include "exec/ramlist.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/opts-visitor.h"
#include "qapi/qapi-visit-machine.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#include "hw/core/cpu.h"
#include "hw/mem/pc-dimm.h"
#include "hw/boards.h"
@@ -249,7 +249,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
lb_data.initiator = node->initiator;
lb_data.target = node->target;
- if (node->data_type <= HMATLB_DATA_TYPE_WRITE_LATENCY) {
+ if (node->data_type <= HMAT_LB_DATA_TYPE_WRITE_LATENCY) {
/* Input latency data */
if (!node->has_latency) {
@@ -313,7 +313,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
numa_info[node->target].lb_info_provided |= BIT(0);
}
lb_data.data = node->latency;
- } else if (node->data_type >= HMATLB_DATA_TYPE_ACCESS_BANDWIDTH) {
+ } else if (node->data_type >= HMAT_LB_DATA_TYPE_ACCESS_BANDWIDTH) {
/* Input bandwidth data */
if (!node->has_bandwidth) {
error_setg(errp, "Missing 'bandwidth' option");
@@ -380,7 +380,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
}
lb_data.data = node->bandwidth;
} else {
- assert(0);
+ g_assert_not_reached();
}
g_array_append_val(hmat_lb->list, lb_data);
diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c
index 13907df..3942c70 100644
--- a/hw/core/or-irq.c
+++ b/hw/core/or-irq.c
@@ -115,16 +115,15 @@ static const VMStateDescription vmstate_or_irq = {
},
};
-static Property or_irq_properties[] = {
+static const Property or_irq_properties[] = {
DEFINE_PROP_UINT16("num-lines", OrIRQState, num_lines, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void or_irq_class_init(ObjectClass *klass, void *data)
+static void or_irq_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = or_irq_reset;
+ device_class_set_legacy_reset(dc, or_irq_reset);
device_class_set_props(dc, or_irq_properties);
dc->realize = or_irq_realize;
dc->vmsd = &vmstate_or_irq;
diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c
index b8487b2..6950063 100644
--- a/hw/core/platform-bus.c
+++ b/hw/core/platform-bus.c
@@ -145,9 +145,12 @@ static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
* the target device's memory region
*/
for (off = 0; off < pbus->mmio_size; off += alignment) {
- if (!memory_region_find(&pbus->mmio, off, size).mr) {
+ MemoryRegion *mr = memory_region_find(&pbus->mmio, off, size).mr;
+ if (!mr) {
found_region = true;
break;
+ } else {
+ memory_region_unref(mr);
}
}
@@ -201,13 +204,12 @@ static void platform_bus_realize(DeviceState *dev, Error **errp)
plaform_bus_refresh_irqs(pbus);
}
-static Property platform_bus_properties[] = {
+static const Property platform_bus_properties[] = {
DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void platform_bus_class_init(ObjectClass *klass, void *data)
+static void platform_bus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 1d8964d..0aeb10f 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -11,8 +11,8 @@
#include "migration/vmstate.h"
#include "qemu/host-utils.h"
#include "exec/replay-core.h"
-#include "sysemu/cpu-timers.h"
-#include "sysemu/qtest.h"
+#include "exec/icount.h"
+#include "system/qtest.h"
#include "block/aio.h"
#include "hw/clock.h"
diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c
index 8279957..dacafa4 100644
--- a/hw/core/qdev-clock.c
+++ b/hw/core/qdev-clock.c
@@ -22,7 +22,7 @@
* Add a new clock in a device
*/
static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name,
- bool output, Clock *clk)
+ bool alias, bool output, Clock *clk)
{
NamedClockList *ncl;
@@ -38,39 +38,8 @@ static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name,
*/
ncl = g_new0(NamedClockList, 1);
ncl->name = g_strdup(name);
+ ncl->alias = alias;
ncl->output = output;
- ncl->alias = (clk != NULL);
-
- /*
- * Trying to create a clock whose name clashes with some other
- * clock or property is a bug in the caller and we will abort().
- */
- if (clk == NULL) {
- clk = CLOCK(object_new(TYPE_CLOCK));
- object_property_add_child(OBJECT(dev), name, OBJECT(clk));
- if (output) {
- /*
- * Remove object_new()'s initial reference.
- * Note that for inputs, the reference created by object_new()
- * will be deleted in qdev_finalize_clocklist().
- */
- object_unref(OBJECT(clk));
- }
- } else {
- object_property_add_link(OBJECT(dev), name,
- object_get_typename(OBJECT(clk)),
- (Object **) &ncl->clock,
- NULL, OBJ_PROP_LINK_STRONG);
- /*
- * Since the link property has the OBJ_PROP_LINK_STRONG flag, the clk
- * object reference count gets decremented on property deletion.
- * However object_property_add_link does not increment it since it
- * doesn't know the linked object. Increment it here to ensure the
- * aliased clock stays alive during this device life-time.
- */
- object_ref(OBJECT(clk));
- }
-
ncl->clock = clk;
QLIST_INSERT_HEAD(&dev->clocks, ncl, node);
@@ -84,14 +53,11 @@ void qdev_finalize_clocklist(DeviceState *dev)
QLIST_FOREACH_SAFE(ncl, &dev->clocks, node, ncl_next) {
QLIST_REMOVE(ncl, node);
- if (!ncl->output && !ncl->alias) {
+ if (!ncl->alias) {
/*
* We kept a reference on the input clock to ensure it lives up to
- * this point so we can safely remove the callback.
- * It avoids having a callback to a deleted object if ncl->clock
- * is still referenced somewhere else (eg: by a clock output).
+ * this point; it is used by the monitor to show the frequency.
*/
- clock_clear_callback(ncl->clock);
object_unref(OBJECT(ncl->clock));
}
g_free(ncl->name);
@@ -101,29 +67,25 @@ void qdev_finalize_clocklist(DeviceState *dev)
Clock *qdev_init_clock_out(DeviceState *dev, const char *name)
{
- NamedClockList *ncl;
-
- assert(name);
-
- ncl = qdev_init_clocklist(dev, name, true, NULL);
+ Clock *clk = CLOCK(object_new(TYPE_CLOCK));
+ object_property_add_child(OBJECT(dev), name, OBJECT(clk));
- return ncl->clock;
+ qdev_init_clocklist(dev, name, false, true, clk);
+ return clk;
}
Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
ClockCallback *callback, void *opaque,
unsigned int events)
{
- NamedClockList *ncl;
-
- assert(name);
-
- ncl = qdev_init_clocklist(dev, name, false, NULL);
+ Clock *clk = CLOCK(object_new(TYPE_CLOCK));
+ object_property_add_child(OBJECT(dev), name, OBJECT(clk));
+ qdev_init_clocklist(dev, name, false, false, clk);
if (callback) {
- clock_set_callback(ncl->clock, callback, opaque, events);
+ clock_set_callback(clk, callback, opaque, events);
}
- return ncl->clock;
+ return clk;
}
void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks)
@@ -194,15 +156,25 @@ Clock *qdev_get_clock_out(DeviceState *dev, const char *name)
Clock *qdev_alias_clock(DeviceState *dev, const char *name,
DeviceState *alias_dev, const char *alias_name)
{
- NamedClockList *ncl;
-
- assert(name && alias_name);
+ NamedClockList *ncl = qdev_get_clocklist(dev, name);
+ Clock *clk = ncl->clock;
- ncl = qdev_get_clocklist(dev, name);
+ ncl = qdev_init_clocklist(alias_dev, alias_name, true, ncl->output, clk);
- qdev_init_clocklist(alias_dev, alias_name, ncl->output, ncl->clock);
+ object_property_add_link(OBJECT(alias_dev), alias_name,
+ TYPE_CLOCK,
+ (Object **) &ncl->clock,
+ NULL, OBJ_PROP_LINK_STRONG);
+ /*
+ * Since the link property has the OBJ_PROP_LINK_STRONG flag, the clk
+ * object reference count gets decremented on property deletion.
+ * However object_property_add_link does not increment it since it
+ * doesn't know the linked object. Increment it here to ensure the
+ * aliased clock stays alive during this device life-time.
+ */
+ object_ref(OBJECT(clk));
- return ncl->clock;
+ return clk;
}
void qdev_connect_clock_in(DeviceState *dev, const char *name, Clock *source)
diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c
index d495d0e..ff176dc 100644
--- a/hw/core/qdev-hotplug.c
+++ b/hw/core/qdev-hotplug.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "hw/qdev-core.h"
#include "hw/boards.h"
+#include "qapi/error.h"
HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
{
@@ -30,12 +31,48 @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
return NULL;
}
-bool qdev_hotplug_allowed(DeviceState *dev, Error **errp)
+static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus,
+ Error **errp)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ if (!dc->hotpluggable) {
+ error_setg(errp, "Device '%s' does not support hotplugging",
+ object_get_typename(OBJECT(dev)));
+ return false;
+ }
+
+ if (bus) {
+ if (!qbus_is_hotpluggable(bus)) {
+ error_setg(errp, "Bus '%s' does not support hotplugging",
+ bus->name);
+ return false;
+ }
+ } else {
+ if (!qdev_get_machine_hotplug_handler(dev)) {
+ /*
+ * No bus, no machine hotplug handler --> device is not hotpluggable
+ */
+ error_setg(errp,
+ "Device '%s' can not be hotplugged on this machine",
+ object_get_typename(OBJECT(dev)));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp)
{
MachineState *machine;
MachineClass *mc;
Object *m_obj = qdev_get_machine();
+ if (!qdev_hotplug_unplug_allowed_common(dev, bus, errp)) {
+ return false;
+ }
+
if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
machine = MACHINE(m_obj);
mc = MACHINE_GET_CLASS(machine);
@@ -47,6 +84,12 @@ bool qdev_hotplug_allowed(DeviceState *dev, Error **errp)
return true;
}
+bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp)
+{
+ return !qdev_unplug_blocked(dev, errp) &&
+ qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp);
+}
+
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
{
if (dev->parent_bus) {
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index f13350b..24e145d 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -29,8 +29,8 @@
#include "audio/audio.h"
#include "chardev/char-fe.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
#include "net/net.h"
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
@@ -58,13 +58,39 @@ static bool check_prop_still_unset(Object *obj, const char *name,
return false;
}
+bool qdev_prop_sanitize_s390x_loadparm(uint8_t *loadparm, const char *str,
+ Error **errp)
+{
+ int i, len;
+
+ len = strlen(str);
+ if (len > 8) {
+ error_setg(errp, "'loadparm' can only contain up to 8 characters");
+ return false;
+ }
+
+ for (i = 0; i < len; i++) {
+ uint8_t c = qemu_toupper(str[i]); /* mimic HMC */
+
+ if (qemu_isalnum(c) || c == '.' || c == ' ') {
+ loadparm[i] = c;
+ } else {
+ error_setg(errp,
+ "invalid character in 'loadparm': '%c' (ASCII 0x%02x)",
+ c, c);
+ return false;
+ }
+ }
+
+ return true;
+}
/* --- drive --- */
static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
void **ptr = object_field_prop_ptr(obj, prop);
const char *value;
char *p;
@@ -90,7 +116,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name,
void *opaque, bool iothread, Error **errp)
{
DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
+ const Property *prop = opaque;
void **ptr = object_field_prop_ptr(obj, prop);
char *str;
BlockBackend *blk;
@@ -119,6 +145,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name,
if (ctx != bdrv_get_aio_context(bs)) {
error_setg(errp, "Different aio context is not supported for new "
"node");
+ return;
}
blk_replace_bs(blk, bs, errp);
@@ -199,7 +226,7 @@ static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
static void release_drive(Object *obj, const char *name, void *opaque)
{
DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
+ const Property *prop = opaque;
BlockBackend **ptr = object_field_prop_ptr(obj, prop);
if (*ptr) {
@@ -209,7 +236,7 @@ static void release_drive(Object *obj, const char *name, void *opaque)
}
const PropertyInfo qdev_prop_drive = {
- .name = "str",
+ .type = "str",
.description = "Node name or ID of a block device to use as a backend",
.realized_set_allowed = true,
.get = get_drive,
@@ -218,7 +245,7 @@ const PropertyInfo qdev_prop_drive = {
};
const PropertyInfo qdev_prop_drive_iothread = {
- .name = "str",
+ .type = "str",
.description = "Node name or ID of a block device to use as a backend",
.realized_set_allowed = true,
.get = get_drive,
@@ -243,7 +270,7 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
ERRP_GUARD();
- Property *prop = opaque;
+ const Property *prop = opaque;
CharBackend *be = object_field_prop_ptr(obj, prop);
Chardev *s;
char *str;
@@ -279,14 +306,14 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
static void release_chr(Object *obj, const char *name, void *opaque)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
CharBackend *be = object_field_prop_ptr(obj, prop);
qemu_chr_fe_deinit(be, false);
}
const PropertyInfo qdev_prop_chr = {
- .name = "str",
+ .type = "str",
.description = "ID of a chardev to use as a backend",
.get = get_chr,
.set = set_chr,
@@ -303,7 +330,7 @@ const PropertyInfo qdev_prop_chr = {
static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
MACAddr *mac = object_field_prop_ptr(obj, prop);
char buffer[2 * 6 + 5 + 1];
char *p = buffer;
@@ -318,7 +345,7 @@ static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
MACAddr *mac = object_field_prop_ptr(obj, prop);
int i, pos;
char *str;
@@ -360,7 +387,7 @@ inval:
}
const PropertyInfo qdev_prop_macaddr = {
- .name = "str",
+ .type = "str",
.description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
.get = get_mac,
.set = set_mac,
@@ -380,7 +407,7 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
static void get_netdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
@@ -391,7 +418,7 @@ static void get_netdev(Object *obj, Visitor *v, const char *name,
static void set_netdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
NetClientState **ncs = peers_ptr->ncs;
NetClientState *peers[MAX_QUEUE_NUM];
@@ -448,7 +475,7 @@ out:
}
const PropertyInfo qdev_prop_netdev = {
- .name = "str",
+ .type = "str",
.description = "ID of a netdev to use as a backend",
.get = get_netdev,
.set = set_netdev,
@@ -459,7 +486,7 @@ const PropertyInfo qdev_prop_netdev = {
static void get_audiodev(Object *obj, Visitor *v, const char* name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
char *p = g_strdup(audio_get_id(card));
@@ -470,7 +497,7 @@ static void get_audiodev(Object *obj, Visitor *v, const char* name,
static void set_audiodev(Object *obj, Visitor *v, const char* name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
AudioState *state;
g_autofree char *str = NULL;
@@ -486,7 +513,7 @@ static void set_audiodev(Object *obj, Visitor *v, const char* name,
}
const PropertyInfo qdev_prop_audiodev = {
- .name = "str",
+ .type = "str",
.description = "ID of an audiodev to use as a backend",
/* release done on shutdown */
.get = get_audiodev,
@@ -552,7 +579,7 @@ static void qdev_propinfo_set_losttickpolicy(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int *ptr = object_field_prop_ptr(obj, prop);
int value;
@@ -576,7 +603,8 @@ static void qdev_propinfo_set_losttickpolicy(Object *obj, Visitor *v,
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
const PropertyInfo qdev_prop_losttickpolicy = {
- .name = "LostTickPolicy",
+ .type = "LostTickPolicy",
+ .description = "Policy for handling lost ticks (discard/delay/slew)",
.enum_table = &LostTickPolicy_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_losttickpolicy,
@@ -588,25 +616,21 @@ const PropertyInfo qdev_prop_losttickpolicy = {
static void set_blocksize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
uint64_t value;
- Error *local_err = NULL;
if (!visit_type_size(v, name, &value, errp)) {
return;
}
- check_block_size(dev->id ? : "", name, value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!check_block_size(name, value, errp)) {
return;
}
*ptr = value;
}
const PropertyInfo qdev_prop_blocksize = {
- .name = "size",
+ .type = "size",
.description = "A power of two between " MIN_BLOCK_SIZE_STR
" and " MAX_BLOCK_SIZE_STR,
.get = qdev_propinfo_get_size32,
@@ -619,9 +643,8 @@ const PropertyInfo qdev_prop_blocksize = {
QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
const PropertyInfo qdev_prop_blockdev_on_error = {
- .name = "BlockdevOnError",
- .description = "Error handling policy, "
- "report/ignore/enospc/stop/auto",
+ .type = "BlockdevOnError",
+ .description = "Error handling policy (report/ignore/enospc/stop/auto)",
.enum_table = &BlockdevOnError_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -633,9 +656,9 @@ const PropertyInfo qdev_prop_blockdev_on_error = {
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
const PropertyInfo qdev_prop_bios_chs_trans = {
- .name = "BiosAtaTranslation",
- .description = "Logical CHS translation algorithm, "
- "auto/none/lba/large/rechs",
+ .type = "BiosAtaTranslation",
+ .description = "Logical CHS translation algorithm "
+ " (auto/none/lba/large/rechs)",
.enum_table = &BiosAtaTranslation_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -645,9 +668,8 @@ const PropertyInfo qdev_prop_bios_chs_trans = {
/* --- FDC default drive types */
const PropertyInfo qdev_prop_fdc_drive_type = {
- .name = "FdcDriveType",
- .description = "FDC drive type, "
- "144/288/120/none/auto",
+ .type = "FloppyDriveType",
+ .description = "Floppy drive type (144/288/120/none/auto)",
.enum_table = &FloppyDriveType_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -657,9 +679,9 @@ const PropertyInfo qdev_prop_fdc_drive_type = {
/* --- MultiFDCompression --- */
const PropertyInfo qdev_prop_multifd_compression = {
- .name = "MultiFDCompression",
- .description = "multifd_compression values, "
- "none/zlib/zstd/qpl/uadk",
+ .type = "MultiFDCompression",
+ .description = "multifd_compression values"
+ " (none/zlib/zstd/qpl/uadk/qatzip)",
.enum_table = &MultiFDCompression_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -671,9 +693,8 @@ const PropertyInfo qdev_prop_multifd_compression = {
QEMU_BUILD_BUG_ON(sizeof(MigMode) != sizeof(int));
const PropertyInfo qdev_prop_mig_mode = {
- .name = "MigMode",
- .description = "mig_mode values, "
- "normal,cpr-reboot",
+ .type = "MigMode",
+ .description = "Migration mode (normal/cpr-reboot)",
.enum_table = &MigMode_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -685,9 +706,8 @@ const PropertyInfo qdev_prop_mig_mode = {
QEMU_BUILD_BUG_ON(sizeof(GranuleMode) != sizeof(int));
const PropertyInfo qdev_prop_granule_mode = {
- .name = "GranuleMode",
- .description = "granule_mode values, "
- "4k, 8k, 16k, 64k, host",
+ .type = "GranuleMode",
+ .description = "Granule page size (4k/8k/16k/64k/host)",
.enum_table = &GranuleMode_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -695,9 +715,8 @@ const PropertyInfo qdev_prop_granule_mode = {
};
const PropertyInfo qdev_prop_zero_page_detection = {
- .name = "ZeroPageDetection",
- .description = "zero_page_detection values, "
- "none,legacy,multifd",
+ .type = "ZeroPageDetection",
+ .description = "Zero page detection (none/legacy/multifd)",
.enum_table = &ZeroPageDetection_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -715,7 +734,7 @@ const PropertyInfo qdev_prop_zero_page_detection = {
static void get_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
ReservedRegion *rr = object_field_prop_ptr(obj, prop);
char buffer[64];
char *p = buffer;
@@ -731,7 +750,7 @@ static void get_reserved_region(Object *obj, Visitor *v, const char *name,
static void set_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
ReservedRegion *rr = object_field_prop_ptr(obj, prop);
const char *endptr;
uint64_t lob, upb;
@@ -775,11 +794,10 @@ separator_error:
error_setg(errp, "reserved region fields must be separated with ':'");
out:
g_free(str);
- return;
}
const PropertyInfo qdev_prop_reserved_region = {
- .name = "reserved_region",
+ .type = "str",
.description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
.get = get_reserved_region,
.set = set_reserved_region,
@@ -793,43 +811,61 @@ const PropertyInfo qdev_prop_reserved_region = {
static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
+ g_autofree GenericAlternate *alt;
int32_t value, *ptr = object_field_prop_ptr(obj, prop);
unsigned int slot, fn, n;
- char *str;
+ g_autofree char *str = NULL;
+
+ if (!visit_start_alternate(v, name, &alt, sizeof(*alt), errp)) {
+ return;
+ }
+
+ switch (alt->type) {
+ case QTYPE_QSTRING:
+ if (!visit_type_str(v, name, &str, errp)) {
+ goto out;
+ }
- if (!visit_type_str(v, name, &str, NULL)) {
+ if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
+ fn = 0;
+ if (sscanf(str, "%x%n", &slot, &n) != 1) {
+ goto invalid;
+ }
+ }
+ if (str[n] != '\0' || fn > 7 || slot > 31) {
+ goto invalid;
+ }
+ *ptr = slot << 3 | fn;
+ break;
+
+ case QTYPE_QNUM:
if (!visit_type_int32(v, name, &value, errp)) {
- return;
+ goto out;
}
if (value < -1 || value > 255) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
name ? name : "null", "a value between -1 and 255");
- return;
+ goto out;
}
*ptr = value;
- return;
- }
+ break;
- if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
- fn = 0;
- if (sscanf(str, "%x%n", &slot, &n) != 1) {
- goto invalid;
- }
- }
- if (str[n] != '\0' || fn > 7 || slot > 31) {
- goto invalid;
+ default:
+ error_setg(errp, "Invalid parameter type for '%s', expected int or str",
+ name ? name : "null");
+ goto out;
}
- *ptr = slot << 3 | fn;
- g_free(str);
- return;
+
+ goto out;
invalid:
error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
- g_free(str);
+out:
+ visit_end_alternate(v, (void **) &alt);
}
-static int print_pci_devfn(Object *obj, Property *prop, char *dest,
+static int print_pci_devfn(Object *obj, const Property *prop, char *dest,
size_t len)
{
int32_t *ptr = object_field_prop_ptr(obj, prop);
@@ -842,7 +878,7 @@ static int print_pci_devfn(Object *obj, Property *prop, char *dest,
}
const PropertyInfo qdev_prop_pci_devfn = {
- .name = "int32",
+ .type = "str",
.description = "Slot and optional function number, example: 06.0 or 06",
.print = print_pci_devfn,
.get = qdev_propinfo_get_int32,
@@ -855,7 +891,7 @@ const PropertyInfo qdev_prop_pci_devfn = {
static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
char buffer[] = "ffff:ff:ff.f";
char *p = buffer;
@@ -881,7 +917,7 @@ static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
char *str, *p;
char *e;
@@ -948,8 +984,8 @@ inval:
}
const PropertyInfo qdev_prop_pci_host_devaddr = {
- .name = "str",
- .description = "Address (bus/device/function) of "
+ .type = "str",
+ .description = "Address (bus:device.function) of "
"the host device, example: 04:10.0",
.get = get_pci_host_devaddr,
.set = set_pci_host_devaddr,
@@ -958,7 +994,7 @@ const PropertyInfo qdev_prop_pci_host_devaddr = {
/* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
const PropertyInfo qdev_prop_off_auto_pcibar = {
- .name = "OffAutoPCIBAR",
+ .type = "OffAutoPCIBAR",
.description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
.enum_table = &OffAutoPCIBAR_lookup,
.get = qdev_propinfo_get_enum,
@@ -971,7 +1007,7 @@ const PropertyInfo qdev_prop_off_auto_pcibar = {
static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
int speed;
@@ -1005,7 +1041,7 @@ static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
int speed;
@@ -1040,7 +1076,7 @@ static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_pcie_link_speed = {
- .name = "PCIELinkSpeed",
+ .type = "PCIELinkSpeed",
.description = "2_5/5/8/16/32/64",
.enum_table = &PCIELinkSpeed_lookup,
.get = get_prop_pcielinkspeed,
@@ -1053,7 +1089,7 @@ const PropertyInfo qdev_prop_pcie_link_speed = {
static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
int width;
@@ -1090,7 +1126,7 @@ static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
int width;
@@ -1128,7 +1164,7 @@ static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_pcie_link_width = {
- .name = "PCIELinkWidth",
+ .type = "PCIELinkWidth",
.description = "1/2/4/8/12/16/32",
.enum_table = &PCIELinkWidth_lookup,
.get = get_prop_pcielinkwidth,
@@ -1141,7 +1177,7 @@ const PropertyInfo qdev_prop_pcie_link_width = {
static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QemuUUID *uuid = object_field_prop_ptr(obj, prop);
char buffer[UUID_STR_LEN];
char *p = buffer;
@@ -1156,7 +1192,7 @@ static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QemuUUID *uuid = object_field_prop_ptr(obj, prop);
char *str;
@@ -1178,7 +1214,7 @@ static void set_default_uuid_auto(ObjectProperty *op, const Property *prop)
}
const PropertyInfo qdev_prop_uuid = {
- .name = "str",
+ .type = "str",
.description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
"\" for random value (default)",
.get = get_uuid,
@@ -1188,12 +1224,12 @@ const PropertyInfo qdev_prop_uuid = {
/* --- s390 cpu entitlement policy --- */
-QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));
+QEMU_BUILD_BUG_ON(sizeof(S390CpuEntitlement) != sizeof(int));
const PropertyInfo qdev_prop_cpus390entitlement = {
- .name = "CpuS390Entitlement",
- .description = "low/medium (default)/high",
- .enum_table = &CpuS390Entitlement_lookup,
+ .type = "S390CpuEntitlement",
+ .description = "auto/low/medium/high (default medium)",
+ .enum_table = &S390CpuEntitlement_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
@@ -1236,10 +1272,30 @@ static void release_iothread_vq_mapping_list(Object *obj,
}
const PropertyInfo qdev_prop_iothread_vq_mapping_list = {
- .name = "IOThreadVirtQueueMappingList",
+ .type = "IOThreadVirtQueueMappingList",
.description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", "
"\"vqs\":[1,2,3,...]},...]",
.get = get_iothread_vq_mapping_list,
.set = set_iothread_vq_mapping_list,
.release = release_iothread_vq_mapping_list,
};
+
+/* --- Endian modes */
+
+const PropertyInfo qdev_prop_endian_mode = {
+ .type = "EndianMode",
+ .description = "Endian mode, big/little/unspecified",
+ .enum_table = &EndianMode_lookup,
+ .get = qdev_propinfo_get_enum,
+ .set = qdev_propinfo_set_enum,
+ .set_default_value = qdev_propinfo_set_default_value_enum,
+};
+
+const PropertyInfo qdev_prop_vmapple_virtio_blk_variant = {
+ .type = "VMAppleVirtioBlkVariant",
+ .description = "unspecified/root/aux",
+ .enum_table = &VMAppleVirtioBlkVariant_lookup,
+ .get = qdev_propinfo_get_enum,
+ .set = qdev_propinfo_set_enum,
+ .set_default_value = qdev_propinfo_set_default_value_enum,
+};
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 86a5835..147b3ff 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -2,7 +2,7 @@
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qapi/qapi-types-misc.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qemu/ctype.h"
#include "qemu/error-report.h"
#include "qapi/visitor.h"
@@ -51,7 +51,7 @@ void qdev_prop_allow_set_link_before_realize(const Object *obj,
}
}
-void *object_field_prop_ptr(Object *obj, Property *prop)
+void *object_field_prop_ptr(Object *obj, const Property *prop)
{
void *ptr = obj;
ptr += prop->offset;
@@ -61,7 +61,7 @@ void *object_field_prop_ptr(Object *obj, Property *prop)
static void field_prop_get(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
return prop->info->get(obj, v, name, opaque, errp);
}
@@ -78,7 +78,7 @@ static ObjectPropertyAccessor *field_prop_getter(const PropertyInfo *info)
static void field_prop_set(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
if (!qdev_prop_allow_set(obj, name, prop->info, errp)) {
return;
@@ -100,7 +100,7 @@ static ObjectPropertyAccessor *field_prop_setter(const PropertyInfo *info)
void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int *ptr = object_field_prop_ptr(obj, prop);
visit_type_enum(v, name, ptr, prop->info->enum_table, errp);
@@ -109,7 +109,7 @@ void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name,
void qdev_propinfo_set_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int *ptr = object_field_prop_ptr(obj, prop);
visit_type_enum(v, name, ptr, prop->info->enum_table, errp);
@@ -122,22 +122,15 @@ void qdev_propinfo_set_default_value_enum(ObjectProperty *op,
qapi_enum_lookup(prop->info->enum_table, prop->defval.i));
}
-const PropertyInfo qdev_prop_enum = {
- .name = "enum",
- .get = qdev_propinfo_get_enum,
- .set = qdev_propinfo_set_enum,
- .set_default_value = qdev_propinfo_set_default_value_enum,
-};
-
/* Bit */
-static uint32_t qdev_get_prop_mask(Property *prop)
+static uint32_t qdev_get_prop_mask(const Property *prop)
{
assert(prop->info == &qdev_prop_bit);
return 0x1 << prop->bitnr;
}
-static void bit_prop_set(Object *obj, Property *props, bool val)
+static void bit_prop_set(Object *obj, const Property *props, bool val)
{
uint32_t *p = object_field_prop_ptr(obj, props);
uint32_t mask = qdev_get_prop_mask(props);
@@ -151,7 +144,7 @@ static void bit_prop_set(Object *obj, Property *props, bool val)
static void prop_get_bit(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *p = object_field_prop_ptr(obj, prop);
bool value = (*p & qdev_get_prop_mask(prop)) != 0;
@@ -161,7 +154,7 @@ static void prop_get_bit(Object *obj, Visitor *v, const char *name,
static void prop_set_bit(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool value;
if (!visit_type_bool(v, name, &value, errp)) {
@@ -176,7 +169,7 @@ static void set_default_value_bool(ObjectProperty *op, const Property *prop)
}
const PropertyInfo qdev_prop_bit = {
- .name = "bool",
+ .type = "bool",
.description = "on/off",
.get = prop_get_bit,
.set = prop_set_bit,
@@ -185,13 +178,13 @@ const PropertyInfo qdev_prop_bit = {
/* Bit64 */
-static uint64_t qdev_get_prop_mask64(Property *prop)
+static uint64_t qdev_get_prop_mask64(const Property *prop)
{
assert(prop->info == &qdev_prop_bit64);
return 0x1ull << prop->bitnr;
}
-static void bit64_prop_set(Object *obj, Property *props, bool val)
+static void bit64_prop_set(Object *obj, const Property *props, bool val)
{
uint64_t *p = object_field_prop_ptr(obj, props);
uint64_t mask = qdev_get_prop_mask64(props);
@@ -205,7 +198,7 @@ static void bit64_prop_set(Object *obj, Property *props, bool val)
static void prop_get_bit64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *p = object_field_prop_ptr(obj, prop);
bool value = (*p & qdev_get_prop_mask64(prop)) != 0;
@@ -215,7 +208,7 @@ static void prop_get_bit64(Object *obj, Visitor *v, const char *name,
static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool value;
if (!visit_type_bool(v, name, &value, errp)) {
@@ -225,7 +218,7 @@ static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_bit64 = {
- .name = "bool",
+ .type = "bool",
.description = "on/off",
.get = prop_get_bit64,
.set = prop_set_bit64,
@@ -237,7 +230,7 @@ const PropertyInfo qdev_prop_bit64 = {
static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool *ptr = object_field_prop_ptr(obj, prop);
visit_type_bool(v, name, ptr, errp);
@@ -246,14 +239,15 @@ static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool *ptr = object_field_prop_ptr(obj, prop);
visit_type_bool(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_bool = {
- .name = "bool",
+ .type = "bool",
+ .description = "on/off",
.get = get_bool,
.set = set_bool,
.set_default_value = set_default_value_bool,
@@ -264,7 +258,7 @@ const PropertyInfo qdev_prop_bool = {
static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint8_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint8(v, name, ptr, errp);
@@ -273,7 +267,7 @@ static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint8_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint8(v, name, ptr, errp);
@@ -292,7 +286,7 @@ void qdev_propinfo_set_default_value_uint(ObjectProperty *op,
}
const PropertyInfo qdev_prop_uint8 = {
- .name = "uint8",
+ .type = "uint8",
.get = get_uint8,
.set = set_uint8,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -303,7 +297,7 @@ const PropertyInfo qdev_prop_uint8 = {
static void get_uint16(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint16_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint16(v, name, ptr, errp);
@@ -312,14 +306,14 @@ static void get_uint16(Object *obj, Visitor *v, const char *name,
static void set_uint16(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint16_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint16(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_uint16 = {
- .name = "uint16",
+ .type = "uint16",
.get = get_uint16,
.set = set_uint16,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -330,7 +324,7 @@ const PropertyInfo qdev_prop_uint16 = {
static void get_uint32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint32(v, name, ptr, errp);
@@ -339,7 +333,7 @@ static void get_uint32(Object *obj, Visitor *v, const char *name,
static void set_uint32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint32(v, name, ptr, errp);
@@ -348,7 +342,7 @@ static void set_uint32(Object *obj, Visitor *v, const char *name,
void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int32(v, name, ptr, errp);
@@ -357,21 +351,21 @@ void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int32(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_uint32 = {
- .name = "uint32",
+ .type = "uint32",
.get = get_uint32,
.set = set_uint32,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
const PropertyInfo qdev_prop_int32 = {
- .name = "int32",
+ .type = "int32",
.get = qdev_propinfo_get_int32,
.set = set_int32,
.set_default_value = qdev_propinfo_set_default_value_int,
@@ -382,7 +376,7 @@ const PropertyInfo qdev_prop_int32 = {
static void get_uint64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint64(v, name, ptr, errp);
@@ -391,7 +385,7 @@ static void get_uint64(Object *obj, Visitor *v, const char *name,
static void set_uint64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint64(v, name, ptr, errp);
@@ -400,7 +394,7 @@ static void set_uint64(Object *obj, Visitor *v, const char *name,
static void get_int64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int64(v, name, ptr, errp);
@@ -409,21 +403,21 @@ static void get_int64(Object *obj, Visitor *v, const char *name,
static void set_int64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int64(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_uint64 = {
- .name = "uint64",
+ .type = "uint64",
.get = get_uint64,
.set = set_uint64,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
const PropertyInfo qdev_prop_int64 = {
- .name = "int64",
+ .type = "int64",
.get = get_int64,
.set = set_int64,
.set_default_value = qdev_propinfo_set_default_value_int,
@@ -432,7 +426,7 @@ const PropertyInfo qdev_prop_int64 = {
static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint64(v, name, ptr, errp);
@@ -443,23 +437,60 @@ static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_uint64_checkmask = {
- .name = "uint64",
+ .type = "uint64",
.get = get_uint64,
.set = set_uint64_checkmask,
};
+/* --- pointer-size integer --- */
+
+static void get_usize(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ const Property *prop = opaque;
+
+#if HOST_LONG_BITS == 32
+ uint32_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint32(v, name, ptr, errp);
+#else
+ uint64_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint64(v, name, ptr, errp);
+#endif
+}
+
+static void set_usize(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ const Property *prop = opaque;
+
+#if HOST_LONG_BITS == 32
+ uint32_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint32(v, name, ptr, errp);
+#else
+ uint64_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint64(v, name, ptr, errp);
+#endif
+}
+
+const PropertyInfo qdev_prop_usize = {
+ .type = "usize",
+ .get = get_usize,
+ .set = set_usize,
+ .set_default_value = qdev_propinfo_set_default_value_uint,
+};
+
/* --- string --- */
static void release_string(Object *obj, const char *name, void *opaque)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
g_free(*(char **)object_field_prop_ptr(obj, prop));
}
static void get_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
char **ptr = object_field_prop_ptr(obj, prop);
if (!*ptr) {
@@ -473,7 +504,7 @@ static void get_string(Object *obj, Visitor *v, const char *name,
static void set_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
char **ptr = object_field_prop_ptr(obj, prop);
char *str;
@@ -485,7 +516,7 @@ static void set_string(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_string = {
- .name = "str",
+ .type = "str",
.release = release_string,
.get = get_string,
.set = set_string,
@@ -494,7 +525,7 @@ const PropertyInfo qdev_prop_string = {
/* --- on/off/auto --- */
const PropertyInfo qdev_prop_on_off_auto = {
- .name = "OnOffAuto",
+ .type = "OnOffAuto",
.description = "on/off/auto",
.enum_table = &OnOffAuto_lookup,
.get = qdev_propinfo_get_enum,
@@ -507,7 +538,7 @@ const PropertyInfo qdev_prop_on_off_auto = {
void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
uint64_t value = *ptr;
@@ -517,7 +548,7 @@ void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
uint64_t value;
@@ -537,7 +568,7 @@ static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque,
}
const PropertyInfo qdev_prop_size32 = {
- .name = "size",
+ .type = "size",
.get = qdev_propinfo_get_size32,
.set = set_size32,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -557,7 +588,7 @@ struct ArrayElementList {
* specific element of the array. Arrays are backed by an uint32_t length field
* and an element array. @elem points at an element in this element array.
*/
-static Property array_elem_prop(Object *obj, Property *parent_prop,
+static Property array_elem_prop(Object *obj, const Property *parent_prop,
const char *name, char *elem)
{
return (Property) {
@@ -582,7 +613,7 @@ static Property array_elem_prop(Object *obj, Property *parent_prop,
*/
static void release_prop_array(Object *obj, const char *name, void *opaque)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
char *elem = *arrayptr;
@@ -609,7 +640,7 @@ static void set_prop_array(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
ERRP_GUARD();
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
ArrayElementList *list, *elem, *next;
@@ -685,7 +716,7 @@ static void get_prop_array(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
ERRP_GUARD();
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
char *elemptr = *arrayptr;
@@ -740,7 +771,7 @@ static void default_prop_array(ObjectProperty *op, const Property *prop)
}
const PropertyInfo qdev_prop_array = {
- .name = "list",
+ .type = "list",
.get = get_prop_array,
.set = set_prop_array,
.release = release_prop_array,
@@ -749,29 +780,26 @@ const PropertyInfo qdev_prop_array = {
/* --- public helpers --- */
-static Property *qdev_prop_walk(Property *props, const char *name)
+static const Property *qdev_prop_walk(DeviceClass *cls, const char *name)
{
- if (!props) {
- return NULL;
- }
- while (props->name) {
- if (strcmp(props->name, name) == 0) {
- return props;
+ for (int i = 0, n = cls->props_count_; i < n; ++i) {
+ const Property *prop = &cls->props_[i];
+ if (strcmp(prop->name, name) == 0) {
+ return prop;
}
- props++;
}
return NULL;
}
-static Property *qdev_prop_find(DeviceState *dev, const char *name)
+static const Property *qdev_prop_find(DeviceState *dev, const char *name)
{
ObjectClass *class;
- Property *prop;
+ const Property *prop;
/* device properties */
class = object_get_class(OBJECT(dev));
do {
- prop = qdev_prop_walk(DEVICE_CLASS(class)->props_, name);
+ prop = qdev_prop_walk(DEVICE_CLASS(class), name);
if (prop) {
return prop;
}
@@ -840,7 +868,7 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
{
- Property *prop;
+ const Property *prop;
prop = qdev_prop_find(dev, name);
object_property_set_str(OBJECT(dev), name,
@@ -931,7 +959,7 @@ void qdev_prop_set_globals(DeviceState *dev)
static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_size(v, name, ptr, errp);
@@ -940,14 +968,14 @@ static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_size(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_size(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_size = {
- .name = "size",
+ .type = "size",
.get = get_size,
.set = set_size,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -956,7 +984,7 @@ const PropertyInfo qdev_prop_size = {
/* --- object link property --- */
static ObjectProperty *create_link_property(ObjectClass *oc, const char *name,
- Property *prop)
+ const Property *prop)
{
return object_class_property_add_link(oc, name, prop->link_type,
prop->offset,
@@ -965,22 +993,22 @@ static ObjectProperty *create_link_property(ObjectClass *oc, const char *name,
}
const PropertyInfo qdev_prop_link = {
- .name = "link",
+ .type = "link",
.create = create_link_property,
};
-void qdev_property_add_static(DeviceState *dev, Property *prop)
+void qdev_property_add_static(DeviceState *dev, const Property *prop)
{
Object *obj = OBJECT(dev);
ObjectProperty *op;
assert(!prop->info->create);
- op = object_property_add(obj, prop->name, prop->info->name,
+ op = object_property_add(obj, prop->name, prop->info->type,
field_prop_getter(prop->info),
field_prop_setter(prop->info),
prop->info->release,
- prop);
+ (Property *)prop);
object_property_set_description(obj, prop->name,
prop->info->description);
@@ -994,7 +1022,7 @@ void qdev_property_add_static(DeviceState *dev, Property *prop)
}
static void qdev_class_add_property(DeviceClass *klass, const char *name,
- Property *prop)
+ const Property *prop)
{
ObjectClass *oc = OBJECT_CLASS(klass);
ObjectProperty *op;
@@ -1003,11 +1031,11 @@ static void qdev_class_add_property(DeviceClass *klass, const char *name,
op = prop->info->create(oc, name, prop);
} else {
op = object_class_property_add(oc,
- name, prop->info->name,
+ name, prop->info->type,
field_prop_getter(prop->info),
field_prop_setter(prop->info),
prop->info->release,
- prop);
+ (Property *)prop);
}
if (prop->set_default) {
prop->info->set_default_value(op, prop);
@@ -1023,7 +1051,7 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
char buffer[1024];
char *ptr = buffer;
@@ -1046,7 +1074,7 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v,
* Do not use this in new code! QOM Properties added through this interface
* will be given names in the "legacy" namespace.
*/
-static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop)
+static void qdev_class_add_legacy_property(DeviceClass *dc, const Property *prop)
{
g_autofree char *name = NULL;
@@ -1058,15 +1086,21 @@ static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop)
name = g_strdup_printf("legacy-%s", prop->name);
object_class_property_add(OBJECT_CLASS(dc), name, "str",
prop->info->print ? qdev_get_legacy_property : prop->info->get,
- NULL, NULL, prop);
+ NULL, NULL, (Property *)prop);
}
-void device_class_set_props(DeviceClass *dc, Property *props)
+void device_class_set_props_n(DeviceClass *dc, const Property *props, size_t n)
{
- Property *prop;
+ /* We used a hole in DeviceClass because that's still a lot. */
+ assert(n <= UINT16_MAX);
+ assert(n != 0);
dc->props_ = props;
- for (prop = props; prop && prop->name; prop++) {
+ dc->props_count_ = n;
+
+ for (size_t i = 0; i < n; ++i) {
+ const Property *prop = &props[i];
+ assert(prop->name);
qdev_class_add_legacy_property(dc, prop);
qdev_class_add_property(dc, prop->name, prop);
}
diff --git a/hw/core/qdev-user.c b/hw/core/qdev-user.c
new file mode 100644
index 0000000..3d421d8
--- /dev/null
+++ b/hw/core/qdev-user.c
@@ -0,0 +1,19 @@
+/*
+ * QDev helpers specific to user emulation.
+ *
+ * Copyright 2025 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "qom/object.h"
+#include "hw/qdev-core.h"
+
+void qdev_create_fake_machine(void)
+{
+ Object *fake_machine_obj;
+
+ fake_machine_obj = object_property_add_new_container(object_get_root(),
+ "machine");
+ object_property_add_new_container(fake_machine_obj, "unattached");
+}
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index f3a996f..f600226 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -28,7 +28,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qapi-events-qdev.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
@@ -146,31 +146,16 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp)
DeviceState *qdev_new(const char *name)
{
- ObjectClass *oc = object_class_by_name(name);
-#ifdef CONFIG_MODULES
- if (!oc) {
- int rv = module_load_qom(name, &error_fatal);
- if (rv > 0) {
- oc = object_class_by_name(name);
- } else {
- error_report("could not find a module for type '%s'", name);
- exit(1);
- }
- }
-#endif
- if (!oc) {
- error_report("unknown type '%s'", name);
- abort();
- }
return DEVICE(object_new(name));
}
DeviceState *qdev_try_new(const char *name)
{
- if (!module_object_class_by_name(name)) {
+ ObjectClass *oc = module_object_class_by_name(name);
+ if (!oc) {
return NULL;
}
- return DEVICE(object_new(name));
+ return DEVICE(object_new_with_class(oc));
}
static QTAILQ_HEAD(, DeviceListener) device_listeners
@@ -491,8 +476,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
if (!obj->parent) {
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
+ object_property_add_child(machine_get_container("unattached"),
name, obj);
unattached_parent = true;
g_free(name);
@@ -706,11 +690,10 @@ static void device_finalize(Object *obj)
dev->canonical_path = NULL;
}
- qobject_unref(dev->opts);
g_free(dev->id);
}
-static void device_class_base_init(ObjectClass *class, void *data)
+static void device_class_base_init(ObjectClass *class, const void *data)
{
DeviceClass *klass = DEVICE_CLASS(class);
@@ -718,6 +701,7 @@ static void device_class_base_init(ObjectClass *class, void *data)
* so do not propagate them to the subclasses.
*/
klass->props_ = NULL;
+ klass->props_count_ = 0;
}
static void device_unparent(Object *obj)
@@ -747,58 +731,7 @@ device_vmstate_if_get_id(VMStateIf *obj)
return qdev_get_dev_path(dev);
}
-/**
- * device_phases_reset:
- * Transition reset method for devices to allow moving
- * smoothly from legacy reset method to multi-phases
- */
-static void device_phases_reset(DeviceState *dev)
-{
- ResettableClass *rc = RESETTABLE_GET_CLASS(dev);
-
- if (rc->phases.enter) {
- rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.hold) {
- rc->phases.hold(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.exit) {
- rc->phases.exit(OBJECT(dev), RESET_TYPE_COLD);
- }
-}
-
-static void device_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
-
- /*
- * This will call either @device_phases_reset (for multi-phases transitioned
- * devices) or a device's specific method for not-yet transitioned devices.
- * In both case, it does not reset children.
- */
- if (dc->reset) {
- dc->reset(DEVICE(obj));
- }
-}
-
-/**
- * device_get_transitional_reset:
- * check if the device's class is ready for multi-phase
- */
-static ResettableTrFunction device_get_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
- if (dc->reset != device_phases_reset) {
- /*
- * dc->reset has been overridden by a subclass,
- * the device is not ready for multi phase yet.
- */
- return device_transitional_reset;
- }
- return NULL;
-}
-
-static void device_class_init(ObjectClass *class, void *data)
+static void device_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
VMStateIfClass *vc = VMSTATE_IF_CLASS(class);
@@ -819,20 +752,12 @@ static void device_class_init(ObjectClass *class, void *data)
rc->child_foreach = device_reset_child_foreach;
/*
- * @device_phases_reset is put as the default reset method below, allowing
- * to do the multi-phase transition from base classes to leaf classes. It
- * allows a legacy-reset Device class to extend a multi-phases-reset
- * Device class for the following reason:
- * + If a base class B has been moved to multi-phase, then it does not
- * override this default reset method and may have defined phase methods.
- * + A child class C (extending class B) which uses
- * device_class_set_parent_reset() (or similar means) to override the
- * reset method will still work as expected. @device_phases_reset function
- * will be registered as the parent reset method and effectively call
- * parent reset phases.
+ * A NULL legacy_reset implies a three-phase reset device. Devices can
+ * only be reset using three-phase aware mechanisms, but we still support
+ * for transitional purposes leaf classes which set the old legacy_reset
+ * method via device_class_set_legacy_reset().
*/
- dc->reset = device_phases_reset;
- rc->get_transitional_function = device_get_transitional_reset;
+ dc->legacy_reset = NULL;
object_class_property_add_bool(class, "realized",
device_get_realized, device_set_realized);
@@ -844,12 +769,30 @@ static void device_class_init(ObjectClass *class, void *data)
offsetof(DeviceState, parent_bus), NULL, 0);
}
-void device_class_set_parent_reset(DeviceClass *dc,
- DeviceReset dev_reset,
- DeviceReset *parent_reset)
+static void do_legacy_reset(Object *obj, ResetType type)
{
- *parent_reset = dc->reset;
- dc->reset = dev_reset;
+ DeviceClass *dc = DEVICE_GET_CLASS(obj);
+
+ dc->legacy_reset(DEVICE(obj));
+}
+
+void device_class_set_legacy_reset(DeviceClass *dc, DeviceReset dev_reset)
+{
+ /*
+ * A legacy DeviceClass::reset has identical semantics to the
+ * three-phase "hold" method, with no "enter" or "exit"
+ * behaviour. Classes that use this legacy function must be leaf
+ * classes that do not chain up to their parent class reset.
+ * There is no mechanism for resetting a device that does not
+ * use the three-phase APIs, so the only place which calls
+ * the legacy_reset hook is do_legacy_reset().
+ */
+ ResettableClass *rc = RESETTABLE_CLASS(dc);
+
+ rc->phases.enter = NULL;
+ rc->phases.hold = do_legacy_reset;
+ rc->phases.exit = NULL;
+ dc->legacy_reset = dev_reset;
}
void device_class_set_parent_realize(DeviceClass *dc,
@@ -873,12 +816,28 @@ Object *qdev_get_machine(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get(object_get_root(), "/machine");
+ dev = object_resolve_path_component(object_get_root(), "machine");
+ /*
+ * Any call to this function before machine is created is treated
+ * as a programming error as of now.
+ */
+ assert(dev);
}
return dev;
}
+Object *machine_get_container(const char *name)
+{
+ Object *container, *machine;
+
+ machine = qdev_get_machine();
+ container = object_resolve_path_component(machine, name);
+ assert(object_dynamic_cast(container, TYPE_CONTAINER));
+
+ return container;
+}
+
char *qdev_get_human_name(DeviceState *dev)
{
g_assert(dev != NULL);
@@ -911,7 +870,7 @@ static const TypeInfo device_type_info = {
.class_init = device_class_init,
.abstract = true,
.class_size = sizeof(DeviceClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_VMSTATE_IF },
{ TYPE_RESETTABLE_INTERFACE },
{ }
diff --git a/hw/core/register.c b/hw/core/register.c
index 95b0150..8f63d9f 100644
--- a/hw/core/register.c
+++ b/hw/core/register.c
@@ -319,7 +319,7 @@ void register_finalize_block(RegisterInfoArray *r_array)
g_free(r_array);
}
-static void register_class_init(ObjectClass *oc, void *data)
+static void register_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/core/reset.c b/hw/core/reset.c
index 58dfc8d..65f82fa 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -24,7 +24,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/resettable.h"
#include "hw/core/resetcontainer.h"
@@ -84,7 +84,7 @@ static void legacy_reset_finalize(Object *obj)
{
}
-static void legacy_reset_class_init(ObjectClass *klass, void *data)
+static void legacy_reset_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -170,11 +170,8 @@ void qemu_unregister_resettable(Object *obj)
resettable_container_remove(get_root_reset_container(), obj);
}
-void qemu_devices_reset(ShutdownCause reason)
+void qemu_devices_reset(ResetType type)
{
- ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ?
- RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD;
-
/* Reset the simulation */
resettable_reset(OBJECT(get_root_reset_container()), type);
}
diff --git a/hw/core/resetcontainer.c b/hw/core/resetcontainer.c
index e4ece68..5ff1700 100644
--- a/hw/core/resetcontainer.c
+++ b/hw/core/resetcontainer.c
@@ -68,7 +68,8 @@ static void resettable_container_finalize(Object *obj)
{
}
-static void resettable_container_class_init(ObjectClass *klass, void *data)
+static void resettable_container_class_init(ObjectClass *klass,
+ const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/core/resettable.c b/hw/core/resettable.c
index 6dd3e3d..5cdb4a4 100644
--- a/hw/core/resettable.c
+++ b/hw/core/resettable.c
@@ -93,20 +93,6 @@ static void resettable_child_foreach(ResettableClass *rc, Object *obj,
}
}
-/**
- * resettable_get_tr_func:
- * helper to fetch transitional reset callback if any.
- */
-static ResettableTrFunction resettable_get_tr_func(ResettableClass *rc,
- Object *obj)
-{
- ResettableTrFunction tr_func = NULL;
- if (rc->get_transitional_function) {
- tr_func = rc->get_transitional_function(obj);
- }
- return tr_func;
-}
-
static void resettable_phase_enter(Object *obj, void *opaque, ResetType type)
{
ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
@@ -146,7 +132,7 @@ static void resettable_phase_enter(Object *obj, void *opaque, ResetType type)
if (action_needed) {
trace_resettable_phase_enter_exec(obj, obj_typename, type,
!!rc->phases.enter);
- if (rc->phases.enter && !resettable_get_tr_func(rc, obj)) {
+ if (rc->phases.enter) {
rc->phases.enter(obj, type);
}
s->hold_phase_pending = true;
@@ -171,12 +157,8 @@ static void resettable_phase_hold(Object *obj, void *opaque, ResetType type)
/* exec hold phase */
if (s->hold_phase_pending) {
s->hold_phase_pending = false;
- ResettableTrFunction tr_func = resettable_get_tr_func(rc, obj);
trace_resettable_phase_hold_exec(obj, obj_typename, !!rc->phases.hold);
- if (tr_func) {
- trace_resettable_transitional_function(obj, obj_typename);
- tr_func(obj);
- } else if (rc->phases.hold) {
+ if (rc->phases.hold) {
rc->phases.hold(obj, type);
}
}
@@ -199,7 +181,7 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type)
assert(s->count > 0);
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)) {
+ if (rc->phases.exit) {
rc->phases.exit(obj, type);
}
}
diff --git a/hw/core/split-irq.c b/hw/core/split-irq.c
index 3b90af2..f8b4875 100644
--- a/hw/core/split-irq.c
+++ b/hw/core/split-irq.c
@@ -59,12 +59,11 @@ static void split_irq_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out(dev, s->out_irq, s->num_lines);
}
-static Property split_irq_properties[] = {
+static const Property split_irq_properties[] = {
DEFINE_PROP_UINT16("num-lines", SplitIRQ, num_lines, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void split_irq_class_init(ObjectClass *klass, void *data)
+static void split_irq_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c
index eebcd28..c339a27 100644
--- a/hw/core/sysbus-fdt.c
+++ b/hw/core/sysbus-fdt.c
@@ -29,13 +29,15 @@
#endif
#include "hw/core/sysbus-fdt.h"
#include "qemu/error-report.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/tpm.h"
+#include "system/device_tree.h"
+#include "system/tpm.h"
#include "hw/platform-bus.h"
#include "hw/vfio/vfio-platform.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
#include "hw/vfio/vfio-amd-xgbe.h"
+#include "hw/vfio/vfio-region.h"
#include "hw/display/ramfb.h"
+#include "hw/uefi/var-service-api.h"
#include "hw/arm/fdt.h"
/*
@@ -471,6 +473,28 @@ static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque)
}
#endif
+static int add_uefi_vars_node(SysBusDevice *sbdev, void *opaque)
+{
+ PlatformBusFDTData *data = opaque;
+ PlatformBusDevice *pbus = data->pbus;
+ const char *parent_node = data->pbus_node_name;
+ void *fdt = data->fdt;
+ uint64_t mmio_base;
+ char *nodename;
+
+ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
+ nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
+ UEFI_VARS_FDT_NODE, mmio_base);
+ qemu_fdt_add_subnode(fdt, nodename);
+ qemu_fdt_setprop_string(fdt, nodename,
+ "compatible", UEFI_VARS_FDT_COMPAT);
+ qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
+ 1, mmio_base,
+ 1, UEFI_VARS_REGS_SIZE);
+ g_free(nodename);
+ return 0;
+}
+
static int no_fdt_node(SysBusDevice *sbdev, void *opaque)
{
return 0;
@@ -495,6 +519,7 @@ static const BindingEntry bindings[] = {
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
#endif
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
+ TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
TYPE_BINDING("", NULL), /* last element */
};
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index ad34fb7..e71367a 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -19,10 +19,9 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu/module.h"
#include "hw/sysbus.h"
#include "monitor/monitor.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
static char *sysbus_get_fw_dev_path(DeviceState *dev);
@@ -65,14 +64,14 @@ void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque)
};
/* Loop through all sysbus devices that were spawned outside the machine */
- container = container_get(qdev_get_machine(), "/peripheral");
+ container = machine_get_container("peripheral");
find_sysbus_device(container, &find);
- container = container_get(qdev_get_machine(), "/peripheral-anon");
+ container = machine_get_container("peripheral-anon");
find_sysbus_device(container, &find);
}
-static void system_bus_class_init(ObjectClass *klass, void *data)
+static void system_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
@@ -80,13 +79,6 @@ static void system_bus_class_init(ObjectClass *klass, void *data)
k->get_fw_dev_path = sysbus_get_fw_dev_path;
}
-static const TypeInfo system_bus_info = {
- .name = TYPE_SYSTEM_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(BusState),
- .class_init = system_bus_class_init,
-};
-
/* Check whether an IRQ source exists */
bool sysbus_has_irq(SysBusDevice *dev, int n)
{
@@ -154,16 +146,6 @@ static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
}
}
-void sysbus_mmio_unmap(SysBusDevice *dev, int n)
-{
- assert(n >= 0 && n < dev->num_mmio);
-
- if (dev->mmio[n].addr != (hwaddr)-1) {
- memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
- dev->mmio[n].addr = (hwaddr)-1;
- }
-}
-
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
{
sysbus_mmio_map_common(dev, n, addr, false, 0);
@@ -298,7 +280,7 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev)
return g_strdup(qdev_fw_name(dev));
}
-static void sysbus_device_class_init(ObjectClass *klass, void *data)
+static void sysbus_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = sysbus_device_realize;
@@ -316,15 +298,6 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data)
k->user_creatable = false;
}
-static const TypeInfo sysbus_device_type_info = {
- .name = TYPE_SYS_BUS_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .abstract = true,
- .class_size = sizeof(SysBusDeviceClass),
- .class_init = sysbus_device_class_init,
-};
-
static BusState *main_system_bus;
static void main_system_bus_create(void)
@@ -333,8 +306,8 @@ static void main_system_bus_create(void)
* assign main_system_bus before qbus_init()
* in order to make "if (bus != sysbus_get_default())" work
*/
- main_system_bus = g_malloc0(system_bus_info.instance_size);
- qbus_init(main_system_bus, system_bus_info.instance_size,
+ main_system_bus = g_new0(BusState, 1);
+ qbus_init(main_system_bus, sizeof(BusState),
TYPE_SYSTEM_BUS, NULL, "main-system-bus");
OBJECT(main_system_bus)->free = g_free;
}
@@ -347,10 +320,36 @@ BusState *sysbus_get_default(void)
return main_system_bus;
}
-static void sysbus_register_types(void)
+static void dynamic_sysbus_device_class_init(ObjectClass *klass,
+ const void *data)
{
- type_register_static(&system_bus_info);
- type_register_static(&sysbus_device_type_info);
+ DeviceClass *k = DEVICE_CLASS(klass);
+
+ k->user_creatable = true;
+ k->hotpluggable = false;
}
-type_init(sysbus_register_types)
+static const TypeInfo sysbus_types[] = {
+ {
+ .name = TYPE_SYSTEM_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(BusState),
+ .class_init = system_bus_class_init,
+ },
+ {
+ .name = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .abstract = true,
+ .class_size = sizeof(SysBusDeviceClass),
+ .class_init = sysbus_device_class_init,
+ },
+ {
+ .name = TYPE_DYNAMIC_SYS_BUS_DEVICE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = dynamic_sysbus_device_class_init,
+ .abstract = true,
+ }
+};
+
+DEFINE_TYPES(sysbus_types)
diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h
index 18ac293..e4dcfb0 100644
--- a/hw/core/uboot_image.h
+++ b/hw/core/uboot_image.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* (C) Copyright 2008 Semihalf
*
diff --git a/hw/core/vm-change-state-handler.c b/hw/core/vm-change-state-handler.c
index 8e26392..99c642b 100644
--- a/hw/core/vm-change-state-handler.c
+++ b/hw/core/vm-change-state-handler.c
@@ -17,7 +17,7 @@
#include "qemu/osdep.h"
#include "hw/qdev-core.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
static int qdev_get_dev_tree_depth(DeviceState *dev)
{
@@ -40,6 +40,7 @@ static int qdev_get_dev_tree_depth(DeviceState *dev)
* qdev_add_vm_change_state_handler:
* @dev: the device that owns this handler
* @cb: the callback function to be invoked
+ * @cb_ret: the callback function with return value to be invoked
* @opaque: user data passed to the callback function
*
* This function works like qemu_add_vm_change_state_handler() except callbacks
@@ -50,25 +51,30 @@ static int qdev_get_dev_tree_depth(DeviceState *dev)
* controller's callback is invoked before the children on its bus when the VM
* starts running. The order is reversed when the VM stops running.
*
+ * Note that the parameter `cb` and `cb_ret` are mutually exclusive.
+ *
* Returns: an entry to be freed with qemu_del_vm_change_state_handler()
*/
VMChangeStateEntry *qdev_add_vm_change_state_handler(DeviceState *dev,
VMChangeStateHandler *cb,
+ VMChangeStateHandlerWithRet *cb_ret,
void *opaque)
{
- return qdev_add_vm_change_state_handler_full(dev, cb, NULL, opaque);
+ assert(!cb || !cb_ret);
+ return qdev_add_vm_change_state_handler_full(dev, cb, NULL, cb_ret, opaque);
}
/*
* Exactly like qdev_add_vm_change_state_handler() but passes a prepare_cb
- * argument too.
+ * and the cb_ret arguments too.
*/
VMChangeStateEntry *qdev_add_vm_change_state_handler_full(
- DeviceState *dev, VMChangeStateHandler *cb,
- VMChangeStateHandler *prepare_cb, void *opaque)
+ DeviceState *dev, VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb,
+ VMChangeStateHandlerWithRet *cb_ret, void *opaque)
{
int depth = qdev_get_dev_tree_depth(dev);
- return qemu_add_vm_change_state_handler_prio_full(cb, prepare_cb, opaque,
- depth);
+ assert(!cb || !cb_ret);
+ return qemu_add_vm_change_state_handler_prio_full(cb, prepare_cb, cb_ret,
+ opaque, depth);
}
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index 967d8d3..bd36dd9 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -24,7 +24,7 @@
#include "hw/cpu/a15mpcore.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_arm.h"
#include "target/arm/gtimer.h"
@@ -58,6 +58,11 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
bool has_el2 = false;
Object *cpuobj;
+ if (s->num_irq < 32 || s->num_irq > 256) {
+ error_setg(errp, "Property 'num-irq' must be between 32 and 256");
+ return;
+ }
+
gicdev = DEVICE(&s->gic);
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
@@ -144,19 +149,19 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
}
}
-static Property a15mp_priv_properties[] = {
+static const Property a15mp_priv_properties[] = {
DEFINE_PROP_UINT32("num-cpu", A15MPPrivState, num_cpu, 1),
- /* The Cortex-A15MP may have anything from 0 to 224 external interrupt
- * IRQ lines (with another 32 internal). We default to 128+32, which
- * is the number provided by the Cortex-A15MP test chip in the
- * Versatile Express A15 development board.
- * Other boards may differ and should set this property appropriately.
+ /*
+ * The Cortex-A15MP may have anything from 0 to 224 external interrupt
+ * lines, plus always 32 internal IRQs. This property sets the total
+ * of internal + external, so the valid range is from 32 to 256.
+ * The board model must set this to whatever the configuration
+ * used for the CPU on that board or SoC is.
*/
- DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 160),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 0),
};
-static void a15mp_priv_class_init(ObjectClass *klass, void *data)
+static void a15mp_priv_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -165,17 +170,14 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data)
/* We currently have no saveable state */
}
-static const TypeInfo a15mp_priv_info = {
- .name = TYPE_A15MPCORE_PRIV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(A15MPPrivState),
- .instance_init = a15mp_priv_initfn,
- .class_init = a15mp_priv_class_init,
+static const TypeInfo a15mp_types[] = {
+ {
+ .name = TYPE_A15MPCORE_PRIV,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(A15MPPrivState),
+ .instance_init = a15mp_priv_initfn,
+ .class_init = a15mp_priv_class_init,
+ },
};
-static void a15mp_register_types(void)
-{
- type_register_static(&a15mp_priv_info);
-}
-
-type_init(a15mp_register_types)
+DEFINE_TYPES(a15mp_types)
diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c
index c30ef72..64bebbd 100644
--- a/hw/cpu/a9mpcore.c
+++ b/hw/cpu/a9mpcore.c
@@ -56,6 +56,11 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
CPUState *cpu0;
Object *cpuobj;
+ if (s->num_irq < 32 || s->num_irq > 256) {
+ error_setg(errp, "Property 'num-irq' must be between 32 and 256");
+ return;
+ }
+
cpu0 = qemu_get_cpu(0);
cpuobj = OBJECT(cpu0);
if (strcmp(object_get_typename(cpuobj), ARM_CPU_TYPE_NAME("cortex-a9"))) {
@@ -158,19 +163,19 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
}
}
-static Property a9mp_priv_properties[] = {
+static const Property a9mp_priv_properties[] = {
DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1),
- /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
- * IRQ lines (with another 32 internal). We default to 64+32, which
- * is the number provided by the Cortex-A9MP test chip in the
- * Realview PBX-A9 and Versatile Express A9 development boards.
- * Other boards may differ and should set this property appropriately.
+ /*
+ * The Cortex-A9MP may have anything from 0 to 224 external interrupt
+ * lines, plus always 32 internal IRQs. This property sets the total
+ * of internal + external, so the valid range is from 32 to 256.
+ * The board model must set this to whatever the configuration
+ * used for the CPU on that board or SoC is.
*/
- DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 96),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 0),
};
-static void a9mp_priv_class_init(ObjectClass *klass, void *data)
+static void a9mp_priv_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -178,17 +183,14 @@ static void a9mp_priv_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, a9mp_priv_properties);
}
-static const TypeInfo a9mp_priv_info = {
- .name = TYPE_A9MPCORE_PRIV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(A9MPPrivState),
- .instance_init = a9mp_priv_initfn,
- .class_init = a9mp_priv_class_init,
+static const TypeInfo a9mp_types[] = {
+ {
+ .name = TYPE_A9MPCORE_PRIV,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(A9MPPrivState),
+ .instance_init = a9mp_priv_initfn,
+ .class_init = a9mp_priv_class_init,
+ },
};
-static void a9mp_register_types(void)
-{
- type_register_static(&a9mp_priv_info);
-}
-
-type_init(a9mp_register_types)
+DEFINE_TYPES(a9mp_types)
diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c
index 89c4e35..01772e7 100644
--- a/hw/cpu/arm11mpcore.c
+++ b/hw/cpu/arm11mpcore.c
@@ -131,7 +131,7 @@ static void mpcore_priv_initfn(Object *obj)
object_initialize_child(obj, "wdtimer", &s->wdtimer, TYPE_ARM_MPTIMER);
}
-static Property mpcore_priv_properties[] = {
+static const Property mpcore_priv_properties[] = {
DEFINE_PROP_UINT32("num-cpu", ARM11MPCorePriveState, num_cpu, 1),
/* The ARM11 MPCORE TRM says the on-chip controller may have
* anything from 0 to 224 external interrupt IRQ lines (with another
@@ -142,10 +142,9 @@ static Property mpcore_priv_properties[] = {
* has more IRQ lines than the kernel expects.
*/
DEFINE_PROP_UINT32("num-irq", ARM11MPCorePriveState, num_irq, 64),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mpcore_priv_class_init(ObjectClass *klass, void *data)
+static void mpcore_priv_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -153,17 +152,14 @@ static void mpcore_priv_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, mpcore_priv_properties);
}
-static const TypeInfo mpcore_priv_info = {
- .name = TYPE_ARM11MPCORE_PRIV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ARM11MPCorePriveState),
- .instance_init = mpcore_priv_initfn,
- .class_init = mpcore_priv_class_init,
+static const TypeInfo arm11mp_types[] = {
+ {
+ .name = TYPE_ARM11MPCORE_PRIV,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ARM11MPCorePriveState),
+ .instance_init = mpcore_priv_initfn,
+ .class_init = mpcore_priv_class_init,
+ },
};
-static void arm11mpcore_register_types(void)
-{
- type_register_static(&mpcore_priv_info);
-}
-
-type_init(arm11mpcore_register_types)
+DEFINE_TYPES(arm11mp_types)
diff --git a/hw/cpu/cluster.c b/hw/cpu/cluster.c
index 61289a8..ef3b3d1 100644
--- a/hw/cpu/cluster.c
+++ b/hw/cpu/cluster.c
@@ -25,9 +25,8 @@
#include "hw/qdev-properties.h"
#include "qapi/error.h"
-static Property cpu_cluster_properties[] = {
+static const Property cpu_cluster_properties[] = {
DEFINE_PROP_UINT32("cluster-id", CPUClusterState, cluster_id, 0),
- DEFINE_PROP_END_OF_LIST()
};
typedef struct CallbackData {
@@ -73,7 +72,7 @@ static void cpu_cluster_realize(DeviceState *dev, Error **errp)
assert(cbdata.cpu_count > 0);
}
-static void cpu_cluster_class_init(ObjectClass *klass, void *data)
+static void cpu_cluster_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/cpu/core.c b/hw/cpu/core.c
index 495a5c3..5cb2e9a 100644
--- a/hw/cpu/core.c
+++ b/hw/cpu/core.c
@@ -77,7 +77,7 @@ static void cpu_core_instance_init(Object *obj)
}
}
-static void cpu_core_class_init(ObjectClass *oc, void *data)
+static void cpu_core_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/cpu/realview_mpcore.c b/hw/cpu/realview_mpcore.c
index 72c792e..099b71a 100644
--- a/hw/cpu/realview_mpcore.c
+++ b/hw/cpu/realview_mpcore.c
@@ -14,7 +14,6 @@
#include "hw/cpu/arm11mpcore.h"
#include "hw/intc/realview_gic.h"
#include "hw/irq.h"
-#include "hw/qdev-properties.h"
#include "qom/object.h"
#define TYPE_REALVIEW_MPCORE_RIRQ "realview_mpcore"
@@ -68,7 +67,6 @@ static void realview_mpcore_realize(DeviceState *dev, Error **errp)
int n;
int i;
- qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->priv), errp)) {
return;
}
@@ -100,6 +98,7 @@ static void mpcore_rirq_init(Object *obj)
int i;
object_initialize_child(obj, "a11priv", &s->priv, TYPE_ARM11MPCORE_PRIV);
+ object_property_add_alias(obj, "num-cpu", OBJECT(&s->priv), "num-cpu");
privbusdev = SYS_BUS_DEVICE(&s->priv);
sysbus_init_mmio(sbd, sysbus_mmio_get_region(privbusdev, 0));
@@ -108,30 +107,21 @@ static void mpcore_rirq_init(Object *obj)
}
}
-static Property mpcore_rirq_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
+static void mpcore_rirq_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = realview_mpcore_realize;
- device_class_set_props(dc, mpcore_rirq_properties);
}
-static const TypeInfo mpcore_rirq_info = {
- .name = TYPE_REALVIEW_MPCORE_RIRQ,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mpcore_rirq_state),
- .instance_init = mpcore_rirq_init,
- .class_init = mpcore_rirq_class_init,
+static const TypeInfo realview_mpcore_types[] = {
+ {
+ .name = TYPE_REALVIEW_MPCORE_RIRQ,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mpcore_rirq_state),
+ .instance_init = mpcore_rirq_init,
+ .class_init = mpcore_rirq_class_init,
+ },
};
-static void realview_mpcore_register_types(void)
-{
- type_register_static(&mpcore_rirq_info);
-}
-
-type_init(realview_mpcore_register_types)
+DEFINE_TYPES(realview_mpcore_types)
diff --git a/hw/cris/Kconfig b/hw/cris/Kconfig
deleted file mode 100644
index 26c7eef..0000000
--- a/hw/cris/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-config AXIS
- bool
- default y
- depends on CRIS
- select ETRAXFS
- select PFLASH_CFI02
- select NAND
-
-config ETRAXFS
- bool
- select PTIMER
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
deleted file mode 100644
index 5556634..0000000
--- a/hw/cris/axis_dev88.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * QEMU model for the AXIS devboard 88.
- *
- * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "hw/boards.h"
-#include "hw/cris/etraxfs.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "boot.h"
-#include "sysemu/qtest.h"
-#include "sysemu/sysemu.h"
-
-#define D(x)
-#define DNAND(x)
-
-struct nand_state_t
-{
- DeviceState *nand;
- MemoryRegion iomem;
- unsigned int rdy:1;
- unsigned int ale:1;
- unsigned int cle:1;
- unsigned int ce:1;
-};
-
-static struct nand_state_t nand_state;
-static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct nand_state_t *s = opaque;
- uint32_t r;
- int rdy;
-
- r = nand_getio(s->nand);
- nand_getpins(s->nand, &rdy);
- s->rdy = rdy;
-
- DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
- return r;
-}
-
-static void
-nand_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- struct nand_state_t *s = opaque;
- int rdy;
-
- DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value));
- nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
- nand_setio(s->nand, value);
- nand_getpins(s->nand, &rdy);
- s->rdy = rdy;
-}
-
-static const MemoryRegionOps nand_ops = {
- .read = nand_read,
- .write = nand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct tempsensor_t
-{
- unsigned int shiftreg;
- unsigned int count;
- enum {
- ST_OUT, ST_IN, ST_Z
- } state;
-
- uint16_t regs[3];
-};
-
-static void tempsensor_clkedge(struct tempsensor_t *s,
- unsigned int clk, unsigned int data_in)
-{
- D(printf("%s clk=%d state=%d sr=%x\n", __func__,
- clk, s->state, s->shiftreg));
- if (s->count == 0) {
- s->count = 16;
- s->state = ST_OUT;
- }
- switch (s->state) {
- case ST_OUT:
- /* Output reg is clocked at negedge. */
- if (!clk) {
- s->count--;
- s->shiftreg <<= 1;
- if (s->count == 0) {
- s->shiftreg = 0;
- s->state = ST_IN;
- s->count = 16;
- }
- }
- break;
- case ST_Z:
- if (clk) {
- s->count--;
- if (s->count == 0) {
- s->shiftreg = 0;
- s->state = ST_OUT;
- s->count = 16;
- }
- }
- break;
- case ST_IN:
- /* Indata is sampled at posedge. */
- if (clk) {
- s->count--;
- s->shiftreg <<= 1;
- s->shiftreg |= data_in & 1;
- if (s->count == 0) {
- D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
- s->regs[0] = s->shiftreg;
- s->state = ST_OUT;
- s->count = 16;
-
- if ((s->regs[0] & 0xff) == 0) {
- /* 25 degrees celsius. */
- s->shiftreg = 0x0b9f;
- } else if ((s->regs[0] & 0xff) == 0xff) {
- /* Sensor ID, 0x8100 LM70. */
- s->shiftreg = 0x8100;
- } else
- printf("Invalid tempsens state %x\n", s->regs[0]);
- }
- }
- break;
- }
-}
-
-
-#define RW_PA_DOUT 0x00
-#define R_PA_DIN 0x01
-#define RW_PA_OE 0x02
-#define RW_PD_DOUT 0x10
-#define R_PD_DIN 0x11
-#define RW_PD_OE 0x12
-
-static struct gpio_state_t
-{
- MemoryRegion iomem;
- struct nand_state_t *nand;
- struct tempsensor_t tempsensor;
- uint32_t regs[0x5c / 4];
-} gpio_state;
-
-static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct gpio_state_t *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- case R_PA_DIN:
- r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
-
- /* Encode pins from the nand. */
- r |= s->nand->rdy << 7;
- break;
- case R_PD_DIN:
- r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
-
- /* Encode temp sensor pins. */
- r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
- break;
-
- default:
- r = s->regs[addr];
- break;
- }
- return r;
- D(printf("%s %x=%x\n", __func__, addr, r));
-}
-
-static void gpio_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- struct gpio_state_t *s = opaque;
- D(printf("%s %x=%x\n", __func__, addr, (unsigned)value));
-
- addr >>= 2;
- switch (addr)
- {
- case RW_PA_DOUT:
- /* Decode nand pins. */
- s->nand->ale = !!(value & (1 << 6));
- s->nand->cle = !!(value & (1 << 5));
- s->nand->ce = !!(value & (1 << 4));
-
- s->regs[addr] = value;
- break;
-
- case RW_PD_DOUT:
- /* Temp sensor clk. */
- if ((s->regs[addr] ^ value) & 2)
- tempsensor_clkedge(&s->tempsensor, !!(value & 2),
- !!(value & 16));
- s->regs[addr] = value;
- break;
-
- default:
- s->regs[addr] = value;
- break;
- }
-}
-
-static const MemoryRegionOps gpio_ops = {
- .read = gpio_read,
- .write = gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-#define INTMEM_SIZE (128 * KiB)
-
-static struct cris_load_info li;
-
-static
-void axisdev88_init(MachineState *machine)
-{
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- CRISCPU *cpu;
- DeviceState *dev;
- SysBusDevice *s;
- DriveInfo *nand;
- qemu_irq irq[30], nmi[2];
- void *etraxfs_dmac;
- struct etraxfs_dma_client *dma_eth;
- int i;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
-
- /* init CPUs */
- cpu = CRIS_CPU(cpu_create(machine->cpu_type));
-
- memory_region_add_subregion(address_space_mem, 0x40000000, machine->ram);
-
- /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the
- internal memory. */
- memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram",
- INTMEM_SIZE, &error_fatal);
- memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
-
- /* Attach a NAND flash to CS1. */
- nand = drive_get(IF_MTD, 0, 0);
- nand_state.nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- NAND_MFR_STMICRO, 0x39);
- memory_region_init_io(&nand_state.iomem, NULL, &nand_ops, &nand_state,
- "nand", 0x05000000);
- memory_region_add_subregion(address_space_mem, 0x10000000,
- &nand_state.iomem);
-
- gpio_state.nand = &nand_state;
- memory_region_init_io(&gpio_state.iomem, NULL, &gpio_ops, &gpio_state,
- "gpio", 0x5c);
- memory_region_add_subregion(address_space_mem, 0x3001a000,
- &gpio_state.iomem);
-
-
- dev = qdev_new("etraxfs-pic");
- s = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, 0x3001c000);
- sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ));
- sysbus_connect_irq(s, 1, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_NMI));
- for (i = 0; i < 30; i++) {
- irq[i] = qdev_get_gpio_in(dev, i);
- }
- nmi[0] = qdev_get_gpio_in(dev, 30);
- nmi[1] = qdev_get_gpio_in(dev, 31);
-
- etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
- for (i = 0; i < 10; i++) {
- /* On ETRAX, odd numbered channels are inputs. */
- etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
- }
-
- /* Add the two ethernet blocks. */
- dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels. */
-
- etraxfs_eth_init(0x30034000, 1, &dma_eth[0], &dma_eth[1]);
- /* The DMA Connector block is missing, hardwire things for now. */
- etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
-
- if (qemu_find_nic_info("etraxfs-eth", true, "fseth")) {
- etraxfs_eth_init(0x30036000, 2, &dma_eth[2], &dma_eth[3]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
- }
-
- /* 2 timers. */
- sysbus_create_varargs("etraxfs-timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
- sysbus_create_varargs("etraxfs-timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
-
- for (i = 0; i < 4; i++) {
- etraxfs_ser_create(0x30026000 + i * 0x2000, irq[0x14 + i], serial_hd(i));
- }
-
- if (kernel_filename) {
- li.image_filename = kernel_filename;
- li.cmdline = kernel_cmdline;
- li.ram_size = machine->ram_size;
- cris_load_image(cpu, &li);
- } else if (!qtest_enabled()) {
- fprintf(stderr, "Kernel image must be specified\n");
- exit(1);
- }
-}
-
-static void axisdev88_machine_init(MachineClass *mc)
-{
- mc->desc = "AXIS devboard 88";
- mc->init = axisdev88_init;
- mc->is_default = true;
- mc->default_cpu_type = CRIS_CPU_TYPE_NAME("crisv32");
- mc->default_ram_id = "axisdev88.ram";
-}
-
-DEFINE_MACHINE("axis-dev88", axisdev88_machine_init)
diff --git a/hw/cris/boot.c b/hw/cris/boot.c
deleted file mode 100644
index 9fa09cf..0000000
--- a/hw/cris/boot.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * CRIS image loading.
- *
- * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "boot.h"
-#include "qemu/cutils.h"
-#include "sysemu/reset.h"
-
-static void main_cpu_reset(void *opaque)
-{
- CRISCPU *cpu = opaque;
- CPUCRISState *env = &cpu->env;
- struct cris_load_info *li;
-
- li = env->load_info;
-
- cpu_reset(CPU(cpu));
-
- if (!li) {
- /* nothing more to do. */
- return;
- }
-
- env->pc = li->entry;
-
- if (li->image_filename) {
- env->regs[8] = 0x56902387; /* RAM boot magic. */
- env->regs[9] = 0x40004000 + li->image_size;
- }
-
- if (li->cmdline) {
- /* Let the kernel know we are modifying the cmdline. */
- env->regs[10] = 0x87109563;
- env->regs[11] = 0x40000000;
- }
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return addr - 0x80000000LL;
-}
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li)
-{
- CPUCRISState *env = &cpu->env;
- uint64_t entry;
- int kcmdline_len;
- int image_size;
-
- env->load_info = li;
- /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
- devboard SDK. */
- image_size = load_elf(li->image_filename, NULL,
- translate_kernel_address, NULL,
- &entry, NULL, NULL, NULL, 0, EM_CRIS, 0, 0);
- li->entry = entry;
- if (image_size < 0) {
- /* Takes a kimage from the axis devboard SDK. */
- image_size = load_image_targphys(li->image_filename, 0x40004000,
- li->ram_size);
- li->entry = 0x40004000;
- }
-
- if (image_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- li->image_filename);
- exit(1);
- }
-
- if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) {
- if (kcmdline_len > 256) {
- fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
- exit(1);
- }
- pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline);
- }
- qemu_register_reset(main_cpu_reset, cpu);
-}
diff --git a/hw/cris/boot.h b/hw/cris/boot.h
deleted file mode 100644
index 9f1e0e3..0000000
--- a/hw/cris/boot.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef HW_CRIS_BOOT_H
-#define HW_CRIS_BOOT_H
-
-struct cris_load_info
-{
- const char *image_filename;
- const char *cmdline;
- int image_size;
- ram_addr_t ram_size;
-
- hwaddr entry;
-};
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li);
-
-#endif
diff --git a/hw/cris/meson.build b/hw/cris/meson.build
deleted file mode 100644
index dc808a4..0000000
--- a/hw/cris/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-cris_ss = ss.source_set()
-cris_ss.add(files('boot.c'))
-cris_ss.add(when: 'CONFIG_AXIS', if_true: files('axis_dev88.c'))
-
-hw_arch += {'cris': cris_ss}
diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c
index cd116c0..4738959 100644
--- a/hw/cxl/cxl-component-utils.c
+++ b/hw/cxl/cxl-component-utils.c
@@ -243,8 +243,13 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 1);
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY,
POISON_ON_ERR_CAP, 0);
- ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 3_6_12_WAY, 0);
- ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 16_WAY, 0);
+ if (type == CXL2_TYPE3_DEVICE) {
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 3_6_12_WAY, 1);
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 16_WAY, 1);
+ } else {
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 3_6_12_WAY, 0);
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 16_WAY, 0);
+ }
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, UIO, 0);
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY,
UIO_DECODER_COUNT, 0);
diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c
index 035d034..e150d74 100644
--- a/hw/cxl/cxl-device-utils.c
+++ b/hw/cxl/cxl-device-utils.c
@@ -95,11 +95,15 @@ static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size)
}
if (offset == A_CXL_DEV_MAILBOX_STS) {
uint64_t status_reg = cxl_dstate->mbox_reg_state64[offset / size];
- if (cci->bg.complete_pct) {
- status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, BG_OP,
- 0);
- cxl_dstate->mbox_reg_state64[offset / size] = status_reg;
- }
+ int bgop;
+
+ qemu_mutex_lock(&cci->bg.lock);
+ bgop = !(cci->bg.complete_pct == 100 || cci->bg.aborted);
+
+ status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, BG_OP,
+ bgop);
+ cxl_dstate->mbox_reg_state64[offset / size] = status_reg;
+ qemu_mutex_unlock(&cci->bg.lock);
}
return cxl_dstate->mbox_reg_state64[offset / size];
default:
@@ -352,10 +356,8 @@ static void device_reg_init_common(CXLDeviceState *cxl_dstate)
}
}
-static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate)
+static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate, int msi_n)
{
- const uint8_t msi_n = 9;
-
/* 2048 payload size */
ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT);
@@ -382,7 +384,7 @@ static void memdev_reg_init_common(CXLDeviceState *cxl_dstate)
cxl_dstate->memdev_status = memdev_status_reg;
}
-void cxl_device_register_init_t3(CXLType3Dev *ct3d)
+void cxl_device_register_init_t3(CXLType3Dev *ct3d, int msi_n)
{
CXLDeviceState *cxl_dstate = &ct3d->cxl_dstate;
uint64_t *cap_h = cxl_dstate->caps_reg_state64;
@@ -398,7 +400,7 @@ void cxl_device_register_init_t3(CXLType3Dev *ct3d)
device_reg_init_common(cxl_dstate);
cxl_device_cap_init(cxl_dstate, MAILBOX, 2, CXL_DEV_MAILBOX_VERSION);
- mailbox_reg_init_common(cxl_dstate);
+ mailbox_reg_init_common(cxl_dstate, msi_n);
cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000,
CXL_MEM_DEV_STATUS_VERSION);
@@ -408,7 +410,7 @@ void cxl_device_register_init_t3(CXLType3Dev *ct3d)
CXL_MAILBOX_MAX_PAYLOAD_SIZE);
}
-void cxl_device_register_init_swcci(CSWMBCCIDev *sw)
+void cxl_device_register_init_swcci(CSWMBCCIDev *sw, int msi_n)
{
CXLDeviceState *cxl_dstate = &sw->cxl_dstate;
uint64_t *cap_h = cxl_dstate->caps_reg_state64;
@@ -423,7 +425,7 @@ void cxl_device_register_init_swcci(CSWMBCCIDev *sw)
device_reg_init_common(cxl_dstate);
cxl_device_cap_init(cxl_dstate, MAILBOX, 2, 1);
- mailbox_reg_init_common(cxl_dstate);
+ mailbox_reg_init_common(cxl_dstate, msi_n);
cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000, 1);
memdev_reg_init_common(cxl_dstate);
diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c
index e9f2543..e010163 100644
--- a/hw/cxl/cxl-host.c
+++ b/hw/cxl/cxl-host.c
@@ -10,7 +10,7 @@
#include "qemu/bitmap.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#include "hw/boards.h"
#include "qapi/qapi-visit-machine.h"
@@ -67,8 +67,6 @@ static void cxl_fixed_memory_window_config(CXLState *cxl_state,
cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows,
g_steal_pointer(&fw));
-
- return;
}
void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp)
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 3ebbd32..299f232 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -7,6 +7,8 @@
* COPYING file in the top-level directory.
*/
+#include <math.h>
+
#include "qemu/osdep.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
@@ -19,13 +21,18 @@
#include "qemu/log.h"
#include "qemu/units.h"
#include "qemu/uuid.h"
-#include "sysemu/hostmem.h"
+#include "system/hostmem.h"
#include "qemu/range.h"
#define CXL_CAPACITY_MULTIPLIER (256 * MiB)
#define CXL_DC_EVENT_LOG_SIZE 8
#define CXL_NUM_EXTENTS_SUPPORTED 512
#define CXL_NUM_TAGS_SUPPORTED 0
+#define CXL_ALERTS_LIFE_USED_WARN_THRESH (1 << 0)
+#define CXL_ALERTS_OVER_TEMP_WARN_THRESH (1 << 1)
+#define CXL_ALERTS_UNDER_TEMP_WARN_THRESH (1 << 2)
+#define CXL_ALERTS_COR_VMEM_ERR_WARN_THRESH (1 << 3)
+#define CXL_ALERTS_COR_PMEM_ERR_WARN_THRESH (1 << 4)
/*
* How to add a new command, example. The command set FOO, with cmd BAR.
@@ -56,6 +63,9 @@ enum {
INFOSTAT = 0x00,
#define IS_IDENTIFY 0x1
#define BACKGROUND_OPERATION_STATUS 0x2
+ #define GET_RESPONSE_MSG_LIMIT 0x3
+ #define SET_RESPONSE_MSG_LIMIT 0x4
+ #define BACKGROUND_OPERATION_ABORT 0x5
EVENTS = 0x01,
#define GET_RECORDS 0x0
#define CLEAR_RECORDS 0x1
@@ -81,9 +91,13 @@ enum {
#define GET_PARTITION_INFO 0x0
#define GET_LSA 0x2
#define SET_LSA 0x3
+ HEALTH_INFO_ALERTS = 0x42,
+ #define GET_ALERT_CONFIG 0x1
+ #define SET_ALERT_CONFIG 0x2
SANITIZE = 0x44,
#define OVERWRITE 0x0
#define SECURE_ERASE 0x1
+ #define MEDIA_OPERATIONS 0x2
PERSISTENT_MEM = 0x45,
#define GET_SECURITY_STATE 0x0
MEDIA_AND_POISON = 0x43,
@@ -151,6 +165,9 @@ static CXLRetCode cmd_tunnel_management_cmd(const struct cxl_cmd *cmd,
in = (void *)payload_in;
out = (void *)payload_out;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
/* Enough room for minimum sized message - no payload */
if (in->size < sizeof(in->ccimessage)) {
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
@@ -266,6 +283,12 @@ static CXLRetCode cmd_events_clear_records(const struct cxl_cmd *cmd,
CXLClearEventPayload *pl;
pl = (CXLClearEventPayload *)payload_in;
+
+ if (len_in < sizeof(*pl) ||
+ len_in < sizeof(*pl) + sizeof(*pl->handle) * pl->nr_recs) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
*len_out = 0;
return cxl_event_clear_records(cxlds, pl);
}
@@ -374,7 +397,7 @@ static CXLRetCode cmd_infostat_identify(const struct cxl_cmd *cmd,
uint16_t pcie_subsys_vid;
uint16_t pcie_subsys_id;
uint64_t sn;
- uint8_t max_message_size;
+ uint8_t max_message_size;
uint8_t component_type;
} QEMU_PACKED *is_identify;
QEMU_BUILD_BUG_ON(sizeof(*is_identify) != 18);
@@ -403,12 +426,58 @@ static CXLRetCode cmd_infostat_identify(const struct cxl_cmd *cmd,
is_identify->component_type = 0x3; /* Type 3 */
}
- /* TODO: Allow this to vary across different CCIs */
- is_identify->max_message_size = 9; /* 512 bytes - MCTP_CXL_MAILBOX_BYTES */
+ is_identify->max_message_size = (uint8_t)log2(cci->payload_max);
*len_out = sizeof(*is_identify);
return CXL_MBOX_SUCCESS;
}
+/* CXL r3.1 section 8.2.9.1.3: Get Response Message Limit (Opcode 0003h) */
+static CXLRetCode cmd_get_response_msg_limit(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint8_t rsp_limit;
+ } QEMU_PACKED *get_rsp_msg_limit = (void *)payload_out;
+ QEMU_BUILD_BUG_ON(sizeof(*get_rsp_msg_limit) != 1);
+
+ get_rsp_msg_limit->rsp_limit = (uint8_t)log2(cci->payload_max);
+
+ *len_out = sizeof(*get_rsp_msg_limit);
+ return CXL_MBOX_SUCCESS;
+}
+
+/* CXL r3.1 section 8.2.9.1.4: Set Response Message Limit (Opcode 0004h) */
+static CXLRetCode cmd_set_response_msg_limit(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint8_t rsp_limit;
+ } QEMU_PACKED *in = (void *)payload_in;
+ QEMU_BUILD_BUG_ON(sizeof(*in) != 1);
+ struct {
+ uint8_t rsp_limit;
+ } QEMU_PACKED *out = (void *)payload_out;
+ QEMU_BUILD_BUG_ON(sizeof(*out) != 1);
+
+ if (in->rsp_limit < 8 || in->rsp_limit > 10) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ cci->payload_max = 1 << in->rsp_limit;
+ out->rsp_limit = in->rsp_limit;
+
+ *len_out = sizeof(*out);
+ return CXL_MBOX_SUCCESS;
+}
+
static void cxl_set_dsp_active_bm(PCIBus *b, PCIDevice *d,
void *private)
{
@@ -521,6 +590,9 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
in = (struct cxl_fmapi_get_phys_port_state_req_pl *)payload_in;
out = (struct cxl_fmapi_get_phys_port_state_resp_pl *)payload_out;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
/* Check if what was requested can fit */
if (sizeof(*out) + sizeof(*out->ports) * in->num_ports > cci->payload_max) {
return CXL_MBOX_INVALID_INPUT;
@@ -624,6 +696,41 @@ static CXLRetCode cmd_infostat_bg_op_sts(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
+/*
+ * CXL r3.1 Section 8.2.9.1.5:
+ * Request Abort Background Operation (Opcode 0005h)
+ */
+static CXLRetCode cmd_infostat_bg_op_abort(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ int bg_set = cci->bg.opcode >> 8;
+ int bg_cmd = cci->bg.opcode & 0xff;
+ const struct cxl_cmd *bg_c = &cci->cxl_cmd_set[bg_set][bg_cmd];
+
+ if (!(bg_c->effect & CXL_MBOX_BACKGROUND_OPERATION_ABORT)) {
+ return CXL_MBOX_REQUEST_ABORT_NOTSUP;
+ }
+
+ qemu_mutex_lock(&cci->bg.lock);
+ if (cci->bg.runtime) {
+ /* operation is near complete, let it finish */
+ if (cci->bg.complete_pct < 85) {
+ timer_del(cci->bg.timer);
+ cci->bg.ret_code = CXL_MBOX_ABORTED;
+ cci->bg.starttime = 0;
+ cci->bg.runtime = 0;
+ cci->bg.aborted = true;
+ }
+ }
+ qemu_mutex_unlock(&cci->bg.lock);
+
+ return CXL_MBOX_SUCCESS;
+}
+
#define CXL_FW_SLOTS 2
#define CXL_FW_SIZE 0x02000000 /* 32 mb */
@@ -649,9 +756,9 @@ static CXLRetCode cmd_firmware_update_get_info(const struct cxl_cmd *cmd,
} QEMU_PACKED *fw_info;
QEMU_BUILD_BUG_ON(sizeof(*fw_info) != 0x50);
- if ((cxl_dstate->vmem_size < CXL_CAPACITY_MULTIPLIER) ||
- (cxl_dstate->pmem_size < CXL_CAPACITY_MULTIPLIER) ||
- (ct3d->dc.total_capacity < CXL_CAPACITY_MULTIPLIER)) {
+ if (!QEMU_IS_ALIGNED(cxl_dstate->vmem_size, CXL_CAPACITY_MULTIPLIER) ||
+ !QEMU_IS_ALIGNED(cxl_dstate->pmem_size, CXL_CAPACITY_MULTIPLIER) ||
+ !QEMU_IS_ALIGNED(ct3d->dc.total_capacity, CXL_CAPACITY_MULTIPLIER)) {
return CXL_MBOX_INTERNAL_ERROR;
}
@@ -699,6 +806,10 @@ static CXLRetCode cmd_firmware_update_transfer(const struct cxl_cmd *cmd,
} QEMU_PACKED *fw_transfer = (void *)payload_in;
size_t offset, length;
+ if (len < sizeof(*fw_transfer)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
if (fw_transfer->action == CXL_FW_XFER_ACTION_ABORT) {
/*
* At this point there aren't any on-going transfers
@@ -927,24 +1038,28 @@ static CXLRetCode cmd_logs_get_log(const struct cxl_cmd *cmd,
get_log = (void *)payload_in;
+ if (get_log->length > cci->payload_max) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) {
+ return CXL_MBOX_INVALID_LOG;
+ }
+
/*
* CXL r3.1 Section 8.2.9.5.2: Get Log (Opcode 0401h)
* The device shall return Invalid Input if the Offset or Length
* fields attempt to access beyond the size of the log as reported by Get
- * Supported Logs.
+ * Supported Log.
*
- * The CEL buffer is large enough to fit all commands in the emulation, so
- * the only possible failure would be if the mailbox itself isn't big
- * enough.
+ * Only valid for there to be one entry per opcode, but the length + offset
+ * may still be greater than that if the inputs are not valid and so access
+ * beyond the end of cci->cel_log.
*/
- if (get_log->offset + get_log->length > cci->payload_max) {
+ if ((uint64_t)get_log->offset + get_log->length >= sizeof(cci->cel_log)) {
return CXL_MBOX_INVALID_INPUT;
}
- if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) {
- return CXL_MBOX_INVALID_LOG;
- }
-
/* Store off everything to local variables so we can wipe out the payload */
*len_out = get_log->length;
@@ -1133,10 +1248,8 @@ static CXLRetCode cmd_features_get_supported(const struct cxl_cmd *cmd,
(struct CXLSupportedFeatureEntry) {
.uuid = ecs_uuid,
.feat_index = index,
- .get_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSReadAttrs),
- .set_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSWriteAttrs),
+ .get_feat_size = sizeof(CXLMemECSReadAttrs),
+ .set_feat_size = sizeof(CXLMemECSWriteAttrs),
.attr_flags = CXL_FEAT_ENTRY_ATTR_FLAG_CHANGABLE,
.get_feat_version = CXL_ECS_GET_FEATURE_VERSION,
.set_feat_version = CXL_ECS_SET_FEATURE_VERSION,
@@ -1204,13 +1317,10 @@ static CXLRetCode cmd_features_get_feature(const struct cxl_cmd *cmd,
(uint8_t *)&ct3d->patrol_scrub_attrs + get_feature->offset,
bytes_to_copy);
} else if (qemu_uuid_is_equal(&get_feature->uuid, &ecs_uuid)) {
- if (get_feature->offset >= CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSReadAttrs)) {
+ if (get_feature->offset >= sizeof(CXLMemECSReadAttrs)) {
return CXL_MBOX_INVALID_INPUT;
}
- bytes_to_copy = CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSReadAttrs) -
- get_feature->offset;
+ bytes_to_copy = sizeof(CXLMemECSReadAttrs) - get_feature->offset;
bytes_to_copy = MIN(bytes_to_copy, get_feature->count);
memcpy(payload_out,
(uint8_t *)&ct3d->ecs_attrs + get_feature->offset,
@@ -1243,6 +1353,9 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
CXLType3Dev *ct3d;
uint16_t count;
+ if (len_in < sizeof(*hdr)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
if (!object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) {
return CXL_MBOX_UNSUPPORTED;
@@ -1270,6 +1383,10 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
set_feat_info->data_offset = hdr->offset;
bytes_to_copy = len_in - sizeof(CXLSetFeatureInHeader);
+ if (bytes_to_copy == 0) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) {
if (hdr->version != CXL_MEMDEV_PS_SET_FEATURE_VERSION) {
return CXL_MBOX_UNSUPPORTED;
@@ -1277,6 +1394,11 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
ps_set_feature = (void *)payload_in;
ps_write_attrs = &ps_set_feature->feat_data;
+
+ if ((uint32_t)hdr->offset + bytes_to_copy >
+ sizeof(ct3d->patrol_scrub_wr_attrs)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
memcpy((uint8_t *)&ct3d->patrol_scrub_wr_attrs + hdr->offset,
ps_write_attrs,
bytes_to_copy);
@@ -1299,18 +1421,22 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
ecs_set_feature = (void *)payload_in;
ecs_write_attrs = ecs_set_feature->feat_data;
- memcpy((uint8_t *)ct3d->ecs_wr_attrs + hdr->offset,
+
+ if ((uint32_t)hdr->offset + bytes_to_copy >
+ sizeof(ct3d->ecs_wr_attrs)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+ memcpy((uint8_t *)&ct3d->ecs_wr_attrs + hdr->offset,
ecs_write_attrs,
bytes_to_copy);
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
data_transfer_flag == CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER) {
+ ct3d->ecs_attrs.ecs_log_cap = ct3d->ecs_wr_attrs.ecs_log_cap;
for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
- ct3d->ecs_attrs[count].ecs_log_cap =
- ct3d->ecs_wr_attrs[count].ecs_log_cap;
- ct3d->ecs_attrs[count].ecs_config =
- ct3d->ecs_wr_attrs[count].ecs_config & 0x1F;
+ ct3d->ecs_attrs.fru_attrs[count].ecs_config =
+ ct3d->ecs_wr_attrs.fru_attrs[count].ecs_config & 0x1F;
}
}
} else {
@@ -1324,7 +1450,7 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) {
memset(&ct3d->patrol_scrub_wr_attrs, 0, set_feat_info->data_size);
} else if (qemu_uuid_is_equal(&hdr->uuid, &ecs_uuid)) {
- memset(ct3d->ecs_wr_attrs, 0, set_feat_info->data_size);
+ memset(&ct3d->ecs_wr_attrs, 0, set_feat_info->data_size);
}
set_feat_info->data_transfer_flag = 0;
set_feat_info->data_saved_across_reset = false;
@@ -1445,7 +1571,7 @@ static CXLRetCode cmd_ccls_get_lsa(const struct cxl_cmd *cmd,
} QEMU_PACKED *get_lsa;
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d);
- uint32_t offset, length;
+ uint64_t offset, length;
get_lsa = (void *)payload_in;
offset = get_lsa->offset;
@@ -1479,8 +1605,8 @@ static CXLRetCode cmd_ccls_set_lsa(const struct cxl_cmd *cmd,
const size_t hdr_len = offsetof(struct set_lsa_pl, data);
*len_out = 0;
- if (!len_in) {
- return CXL_MBOX_SUCCESS;
+ if (len_in < hdr_len) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
}
if (set_lsa_payload->offset + len_in > cvc->get_lsa_size(ct3d) + hdr_len) {
@@ -1492,6 +1618,97 @@ static CXLRetCode cmd_ccls_set_lsa(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
+/* CXL r3.2 Section 8.2.10.9.3.2 Get Alert Configuration (Opcode 4201h) */
+static CXLRetCode cmd_get_alert_config(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLAlertConfig *out = (CXLAlertConfig *)payload_out;
+
+ memcpy(out, &ct3d->alert_config, sizeof(ct3d->alert_config));
+ *len_out = sizeof(ct3d->alert_config);
+
+ return CXL_MBOX_SUCCESS;
+}
+
+/* CXL r3.2 Section 8.2.10.9.3.3 Set Alert Configuration (Opcode 4202h) */
+static CXLRetCode cmd_set_alert_config(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLAlertConfig *alert_config = &ct3d->alert_config;
+ struct {
+ uint8_t valid_alert_actions;
+ uint8_t enable_alert_actions;
+ uint8_t life_used_warn_thresh;
+ uint8_t rsvd;
+ uint16_t over_temp_warn_thresh;
+ uint16_t under_temp_warn_thresh;
+ uint16_t cor_vmem_err_warn_thresh;
+ uint16_t cor_pmem_err_warn_thresh;
+ } QEMU_PACKED *in = (void *)payload_in;
+
+ if (in->valid_alert_actions & CXL_ALERTS_LIFE_USED_WARN_THRESH) {
+ /*
+ * CXL r3.2 Table 8-149 The life used warning threshold shall be
+ * less than the life used critical alert value.
+ */
+ if (in->life_used_warn_thresh >=
+ alert_config->life_used_crit_alert_thresh) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ alert_config->life_used_warn_thresh = in->life_used_warn_thresh;
+ alert_config->enable_alerts |= CXL_ALERTS_LIFE_USED_WARN_THRESH;
+ }
+
+ if (in->valid_alert_actions & CXL_ALERTS_OVER_TEMP_WARN_THRESH) {
+ /*
+ * CXL r3.2 Table 8-149 The Device Over-Temperature Warning Threshold
+ * shall be less than the the Device Over-Temperature Critical
+ * Alert Threshold.
+ */
+ if (in->over_temp_warn_thresh >=
+ alert_config->over_temp_crit_alert_thresh) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ alert_config->over_temp_warn_thresh = in->over_temp_warn_thresh;
+ alert_config->enable_alerts |= CXL_ALERTS_OVER_TEMP_WARN_THRESH;
+ }
+
+ if (in->valid_alert_actions & CXL_ALERTS_UNDER_TEMP_WARN_THRESH) {
+ /*
+ * CXL r3.2 Table 8-149 The Device Under-Temperature Warning Threshold
+ * shall be higher than the the Device Under-Temperature Critical
+ * Alert Threshold.
+ */
+ if (in->under_temp_warn_thresh <=
+ alert_config->under_temp_crit_alert_thresh) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ alert_config->under_temp_warn_thresh = in->under_temp_warn_thresh;
+ alert_config->enable_alerts |= CXL_ALERTS_UNDER_TEMP_WARN_THRESH;
+ }
+
+ if (in->valid_alert_actions & CXL_ALERTS_COR_VMEM_ERR_WARN_THRESH) {
+ alert_config->cor_vmem_err_warn_thresh = in->cor_vmem_err_warn_thresh;
+ alert_config->enable_alerts |= CXL_ALERTS_COR_VMEM_ERR_WARN_THRESH;
+ }
+
+ if (in->valid_alert_actions & CXL_ALERTS_COR_PMEM_ERR_WARN_THRESH) {
+ alert_config->cor_pmem_err_warn_thresh = in->cor_pmem_err_warn_thresh;
+ alert_config->enable_alerts |= CXL_ALERTS_COR_PMEM_ERR_WARN_THRESH;
+ }
+ return CXL_MBOX_SUCCESS;
+}
+
/* Perform the actual device zeroing */
static void __do_sanitization(CXLType3Dev *ct3d)
{
@@ -1522,34 +1739,10 @@ static void __do_sanitization(CXLType3Dev *ct3d)
cxl_discard_all_event_records(&ct3d->cxl_dstate);
}
-/*
- * CXL r3.1 Section 8.2.9.9.5.1: Sanitize (Opcode 4400h)
- *
- * Once the Sanitize command has started successfully, the device shall be
- * placed in the media disabled state. If the command fails or is interrupted
- * by a reset or power failure, it shall remain in the media disabled state
- * until a successful Sanitize command has been completed. During this state:
- *
- * 1. Memory writes to the device will have no effect, and all memory reads
- * will return random values (no user data returned, even for locations that
- * the failed Sanitize operation didn’t sanitize yet).
- *
- * 2. Mailbox commands shall still be processed in the disabled state, except
- * that commands that access Sanitized areas shall fail with the Media Disabled
- * error code.
- */
-static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd,
- uint8_t *payload_in,
- size_t len_in,
- uint8_t *payload_out,
- size_t *len_out,
- CXLCCI *cci)
+static int get_sanitize_duration(uint64_t total_mem)
{
- CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
- uint64_t total_mem; /* in Mb */
- int secs;
+ int secs = 0;
- total_mem = (ct3d->cxl_dstate.vmem_size + ct3d->cxl_dstate.pmem_size) >> 20;
if (total_mem <= 512) {
secs = 4;
} else if (total_mem <= 1024) {
@@ -1578,6 +1771,39 @@ static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd,
secs = 240 * 60; /* max 4 hrs */
}
+ return secs;
+}
+
+/*
+ * CXL r3.1 Section 8.2.9.9.5.1: Sanitize (Opcode 4400h)
+ *
+ * Once the Sanitize command has started successfully, the device shall be
+ * placed in the media disabled state. If the command fails or is interrupted
+ * by a reset or power failure, it shall remain in the media disabled state
+ * until a successful Sanitize command has been completed. During this state:
+ *
+ * 1. Memory writes to the device will have no effect, and all memory reads
+ * will return random values (no user data returned, even for locations that
+ * the failed Sanitize operation didn’t sanitize yet).
+ *
+ * 2. Mailbox commands shall still be processed in the disabled state, except
+ * that commands that access Sanitized areas shall fail with the Media Disabled
+ * error code.
+ */
+static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ uint64_t total_mem; /* in Mb */
+ int secs;
+
+ total_mem = (ct3d->cxl_dstate.vmem_size + ct3d->cxl_dstate.pmem_size) >> 20;
+ secs = get_sanitize_duration(total_mem);
+
/* EBUSY other bg cmds as of now */
cci->bg.runtime = secs * 1000UL;
*len_out = 0;
@@ -1588,6 +1814,324 @@ static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd,
return CXL_MBOX_BG_STARTED;
}
+struct dpa_range_list_entry {
+ uint64_t starting_dpa;
+ uint64_t length;
+} QEMU_PACKED;
+
+struct CXLSanitizeInfo {
+ uint32_t dpa_range_count;
+ uint8_t fill_value;
+ struct dpa_range_list_entry dpa_range_list[];
+} QEMU_PACKED;
+
+static uint64_t get_vmr_size(CXLType3Dev *ct3d, MemoryRegion **vmr)
+{
+ MemoryRegion *mr;
+ if (ct3d->hostvmem) {
+ mr = host_memory_backend_get_memory(ct3d->hostvmem);
+ if (vmr) {
+ *vmr = mr;
+ }
+ return memory_region_size(mr);
+ }
+ return 0;
+}
+
+static uint64_t get_pmr_size(CXLType3Dev *ct3d, MemoryRegion **pmr)
+{
+ MemoryRegion *mr;
+ if (ct3d->hostpmem) {
+ mr = host_memory_backend_get_memory(ct3d->hostpmem);
+ if (pmr) {
+ *pmr = mr;
+ }
+ return memory_region_size(mr);
+ }
+ return 0;
+}
+
+static uint64_t get_dc_size(CXLType3Dev *ct3d, MemoryRegion **dc_mr)
+{
+ MemoryRegion *mr;
+ if (ct3d->dc.host_dc) {
+ mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
+ if (dc_mr) {
+ *dc_mr = mr;
+ }
+ return memory_region_size(mr);
+ }
+ return 0;
+}
+
+static int validate_dpa_addr(CXLType3Dev *ct3d, uint64_t dpa_addr,
+ size_t length)
+{
+ uint64_t vmr_size, pmr_size, dc_size;
+
+ if ((dpa_addr % CXL_CACHE_LINE_SIZE) ||
+ (length % CXL_CACHE_LINE_SIZE) ||
+ (length <= 0)) {
+ return -EINVAL;
+ }
+
+ vmr_size = get_vmr_size(ct3d, NULL);
+ pmr_size = get_pmr_size(ct3d, NULL);
+ dc_size = get_dc_size(ct3d, NULL);
+
+ if (dpa_addr + length > vmr_size + pmr_size + dc_size) {
+ return -EINVAL;
+ }
+
+ if (dpa_addr > vmr_size + pmr_size) {
+ if (!ct3_test_region_block_backed(ct3d, dpa_addr, length)) {
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+static int sanitize_range(CXLType3Dev *ct3d, uint64_t dpa_addr, size_t length,
+ uint8_t fill_value)
+{
+
+ uint64_t vmr_size, pmr_size;
+ AddressSpace *as = NULL;
+ MemTxAttrs mem_attrs = {};
+
+ vmr_size = get_vmr_size(ct3d, NULL);
+ pmr_size = get_pmr_size(ct3d, NULL);
+
+ if (dpa_addr < vmr_size) {
+ as = &ct3d->hostvmem_as;
+ } else if (dpa_addr < vmr_size + pmr_size) {
+ as = &ct3d->hostpmem_as;
+ } else {
+ if (!ct3_test_region_block_backed(ct3d, dpa_addr, length)) {
+ return -ENODEV;
+ }
+ as = &ct3d->dc.host_dc_as;
+ }
+
+ return address_space_set(as, dpa_addr, fill_value, length, mem_attrs);
+}
+
+/* Perform the actual device zeroing */
+static void __do_sanitize(CXLType3Dev *ct3d)
+{
+ struct CXLSanitizeInfo *san_info = ct3d->media_op_sanitize;
+ int dpa_range_count = san_info->dpa_range_count;
+ int rc = 0;
+ int i;
+
+ for (i = 0; i < dpa_range_count; i++) {
+ rc = sanitize_range(ct3d, san_info->dpa_range_list[i].starting_dpa,
+ san_info->dpa_range_list[i].length,
+ san_info->fill_value);
+ if (rc) {
+ goto exit;
+ }
+ }
+exit:
+ g_free(ct3d->media_op_sanitize);
+ ct3d->media_op_sanitize = NULL;
+ return;
+}
+
+enum {
+ MEDIA_OP_CLASS_GENERAL = 0x0,
+ #define MEDIA_OP_GEN_SUBC_DISCOVERY 0x0
+ MEDIA_OP_CLASS_SANITIZE = 0x1,
+ #define MEDIA_OP_SAN_SUBC_SANITIZE 0x0
+ #define MEDIA_OP_SAN_SUBC_ZERO 0x1
+};
+
+struct media_op_supported_list_entry {
+ uint8_t media_op_class;
+ uint8_t media_op_subclass;
+};
+
+struct media_op_discovery_out_pl {
+ uint64_t dpa_range_granularity;
+ uint16_t total_supported_operations;
+ uint16_t num_of_supported_operations;
+ struct media_op_supported_list_entry entry[];
+} QEMU_PACKED;
+
+static const struct media_op_supported_list_entry media_op_matrix[] = {
+ { MEDIA_OP_CLASS_GENERAL, MEDIA_OP_GEN_SUBC_DISCOVERY },
+ { MEDIA_OP_CLASS_SANITIZE, MEDIA_OP_SAN_SUBC_SANITIZE },
+ { MEDIA_OP_CLASS_SANITIZE, MEDIA_OP_SAN_SUBC_ZERO },
+};
+
+static CXLRetCode media_operations_discovery(uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out)
+{
+ struct {
+ uint8_t media_operation_class;
+ uint8_t media_operation_subclass;
+ uint8_t rsvd[2];
+ uint32_t dpa_range_count;
+ struct {
+ uint16_t start_index;
+ uint16_t num_ops;
+ } discovery_osa;
+ } QEMU_PACKED *media_op_in_disc_pl = (void *)payload_in;
+ struct media_op_discovery_out_pl *media_out_pl =
+ (struct media_op_discovery_out_pl *)payload_out;
+ int num_ops, start_index, i;
+ int count = 0;
+
+ if (len_in < sizeof(*media_op_in_disc_pl)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
+ num_ops = media_op_in_disc_pl->discovery_osa.num_ops;
+ start_index = media_op_in_disc_pl->discovery_osa.start_index;
+
+ /*
+ * As per spec CXL r3.2 8.2.10.9.5.3 dpa_range_count should be zero and
+ * start index should not exceed the total number of entries for discovery
+ * sub class command.
+ */
+ if (media_op_in_disc_pl->dpa_range_count ||
+ start_index > ARRAY_SIZE(media_op_matrix)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ media_out_pl->dpa_range_granularity = CXL_CACHE_LINE_SIZE;
+ media_out_pl->total_supported_operations =
+ ARRAY_SIZE(media_op_matrix);
+ if (num_ops > 0) {
+ for (i = start_index; i < start_index + num_ops; i++) {
+ media_out_pl->entry[count].media_op_class =
+ media_op_matrix[i].media_op_class;
+ media_out_pl->entry[count].media_op_subclass =
+ media_op_matrix[i].media_op_subclass;
+ count++;
+ if (count == num_ops) {
+ break;
+ }
+ }
+ }
+
+ media_out_pl->num_of_supported_operations = count;
+ *len_out = sizeof(*media_out_pl) + count * sizeof(*media_out_pl->entry);
+ return CXL_MBOX_SUCCESS;
+}
+
+static CXLRetCode media_operations_sanitize(CXLType3Dev *ct3d,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ uint8_t fill_value,
+ CXLCCI *cci)
+{
+ struct media_operations_sanitize {
+ uint8_t media_operation_class;
+ uint8_t media_operation_subclass;
+ uint8_t rsvd[2];
+ uint32_t dpa_range_count;
+ struct dpa_range_list_entry dpa_range_list[];
+ } QEMU_PACKED *media_op_in_sanitize_pl = (void *)payload_in;
+ uint32_t dpa_range_count = media_op_in_sanitize_pl->dpa_range_count;
+ uint64_t total_mem = 0;
+ size_t dpa_range_list_size;
+ int secs = 0, i;
+
+ if (dpa_range_count == 0) {
+ return CXL_MBOX_SUCCESS;
+ }
+
+ dpa_range_list_size = dpa_range_count * sizeof(struct dpa_range_list_entry);
+ if (len_in < (sizeof(*media_op_in_sanitize_pl) + dpa_range_list_size)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
+ for (i = 0; i < dpa_range_count; i++) {
+ uint64_t start_dpa =
+ media_op_in_sanitize_pl->dpa_range_list[i].starting_dpa;
+ uint64_t length = media_op_in_sanitize_pl->dpa_range_list[i].length;
+
+ if (validate_dpa_addr(ct3d, start_dpa, length)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ total_mem += length;
+ }
+ ct3d->media_op_sanitize = g_malloc0(sizeof(struct CXLSanitizeInfo) +
+ dpa_range_list_size);
+
+ ct3d->media_op_sanitize->dpa_range_count = dpa_range_count;
+ ct3d->media_op_sanitize->fill_value = fill_value;
+ memcpy(ct3d->media_op_sanitize->dpa_range_list,
+ media_op_in_sanitize_pl->dpa_range_list,
+ dpa_range_list_size);
+ secs = get_sanitize_duration(total_mem >> 20);
+
+ /* EBUSY other bg cmds as of now */
+ cci->bg.runtime = secs * 1000UL;
+ *len_out = 0;
+ /*
+ * media op sanitize is targeted so no need to disable media or
+ * clear event logs
+ */
+ return CXL_MBOX_BG_STARTED;
+}
+
+static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint8_t media_operation_class;
+ uint8_t media_operation_subclass;
+ uint8_t rsvd[2];
+ uint32_t dpa_range_count;
+ } QEMU_PACKED *media_op_in_common_pl = (void *)payload_in;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ uint8_t media_op_cl = 0;
+ uint8_t media_op_subclass = 0;
+
+ if (len_in < sizeof(*media_op_in_common_pl)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
+ media_op_cl = media_op_in_common_pl->media_operation_class;
+ media_op_subclass = media_op_in_common_pl->media_operation_subclass;
+
+ switch (media_op_cl) {
+ case MEDIA_OP_CLASS_GENERAL:
+ if (media_op_subclass != MEDIA_OP_GEN_SUBC_DISCOVERY) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ return media_operations_discovery(payload_in, len_in, payload_out,
+ len_out);
+ case MEDIA_OP_CLASS_SANITIZE:
+ switch (media_op_subclass) {
+ case MEDIA_OP_SAN_SUBC_SANITIZE:
+ return media_operations_sanitize(ct3d, payload_in, len_in,
+ payload_out, len_out, 0xF,
+ cci);
+ case MEDIA_OP_SAN_SUBC_ZERO:
+ return media_operations_sanitize(ct3d, payload_in, len_in,
+ payload_out, len_out, 0,
+ cci);
+ default:
+ return CXL_MBOX_UNSUPPORTED;
+ }
+ default:
+ return CXL_MBOX_UNSUPPORTED;
+ }
+}
+
static CXLRetCode cmd_get_security_state(const struct cxl_cmd *cmd,
uint8_t *payload_in,
size_t len_in,
@@ -2076,7 +2620,7 @@ static CXLRetCode cmd_media_get_scan_media_results(const struct cxl_cmd *cmd,
start = ROUND_DOWN(ent->start, 64ull);
stop = ROUND_DOWN(ent->start, 64ull) + ent->length;
- stq_le_p(&out->records[i].addr, start | (ent->type & 0x7));
+ stq_le_p(&out->records[i].addr, start);
stl_le_p(&out->records[i].length, (stop - start) / CXL_CACHE_LINE_SIZE);
i++;
@@ -2233,6 +2777,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd,
stw_le_p(&out_rec->shared_seq, ent->shared_seq);
record_done++;
+ out_rec++;
if (record_done == record_count) {
break;
}
@@ -2470,11 +3015,20 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
uint64_t dpa, len;
CXLRetCode ret;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
if (in->num_entries_updated == 0) {
cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
return CXL_MBOX_SUCCESS;
}
+ if (len_in <
+ sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
/* Adding extents causes exceeding device's extent tracking ability. */
if (in->num_entries_updated + ct3d->dc.total_extent_count >
CXL_NUM_EXTENTS_SUPPORTED) {
@@ -2629,10 +3183,19 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd,
uint32_t updated_list_size;
CXLRetCode ret;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
if (in->num_entries_updated == 0) {
return CXL_MBOX_INVALID_INPUT;
}
+ if (len_in <
+ sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
ret = cxl_detect_malformed_extent_list(ct3d, in);
if (ret != CXL_MBOX_SUCCESS) {
return ret;
@@ -2665,6 +3228,8 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd,
}
static const struct cxl_cmd cxl_cmd_set[256][256] = {
+ [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT",
+ cmd_infostat_bg_op_abort, 0, 0 },
[EVENTS][GET_RECORDS] = { "EVENTS_GET_RECORDS",
cmd_events_get_records, 1, 0 },
[EVENTS][CLEAR_RECORDS] = { "EVENTS_CLEAR_RECORDS",
@@ -2677,9 +3242,11 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = {
[FIRMWARE_UPDATE][GET_INFO] = { "FIRMWARE_UPDATE_GET_INFO",
cmd_firmware_update_get_info, 0, 0 },
[FIRMWARE_UPDATE][TRANSFER] = { "FIRMWARE_UPDATE_TRANSFER",
- cmd_firmware_update_transfer, ~0, CXL_MBOX_BACKGROUND_OPERATION },
+ cmd_firmware_update_transfer, ~0,
+ CXL_MBOX_BACKGROUND_OPERATION | CXL_MBOX_BACKGROUND_OPERATION_ABORT },
[FIRMWARE_UPDATE][ACTIVATE] = { "FIRMWARE_UPDATE_ACTIVATE",
- cmd_firmware_update_activate, 2, CXL_MBOX_BACKGROUND_OPERATION },
+ cmd_firmware_update_activate, 2,
+ CXL_MBOX_BACKGROUND_OPERATION | CXL_MBOX_BACKGROUND_OPERATION_ABORT },
[TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 },
[TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set,
8, CXL_MBOX_IMMEDIATE_POLICY_CHANGE },
@@ -2705,9 +3272,20 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = {
[CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 8, 0 },
[CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa,
~0, CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | CXL_MBOX_IMMEDIATE_DATA_CHANGE },
+ [HEALTH_INFO_ALERTS][GET_ALERT_CONFIG] = {
+ "HEALTH_INFO_ALERTS_GET_ALERT_CONFIG",
+ cmd_get_alert_config, 0, 0 },
+ [HEALTH_INFO_ALERTS][SET_ALERT_CONFIG] = {
+ "HEALTH_INFO_ALERTS_SET_ALERT_CONFIG",
+ cmd_set_alert_config, 12, CXL_MBOX_IMMEDIATE_POLICY_CHANGE },
[SANITIZE][OVERWRITE] = { "SANITIZE_OVERWRITE", cmd_sanitize_overwrite, 0,
(CXL_MBOX_IMMEDIATE_DATA_CHANGE |
CXL_MBOX_SECURITY_STATE_CHANGE |
+ CXL_MBOX_BACKGROUND_OPERATION |
+ CXL_MBOX_BACKGROUND_OPERATION_ABORT)},
+ [SANITIZE][MEDIA_OPERATIONS] = { "MEDIA_OPERATIONS", cmd_media_operations,
+ ~0,
+ (CXL_MBOX_IMMEDIATE_DATA_CHANGE |
CXL_MBOX_BACKGROUND_OPERATION)},
[PERSISTENT_MEM][GET_SECURITY_STATE] = { "GET_SECURITY_STATE",
cmd_get_security_state, 0, 0 },
@@ -2721,7 +3299,8 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = {
"MEDIA_AND_POISON_GET_SCAN_MEDIA_CAPABILITIES",
cmd_media_get_scan_media_capabilities, 16, 0 },
[MEDIA_AND_POISON][SCAN_MEDIA] = { "MEDIA_AND_POISON_SCAN_MEDIA",
- cmd_media_scan_media, 17, CXL_MBOX_BACKGROUND_OPERATION },
+ cmd_media_scan_media, 17,
+ (CXL_MBOX_BACKGROUND_OPERATION | CXL_MBOX_BACKGROUND_OPERATION_ABORT)},
[MEDIA_AND_POISON][GET_SCAN_MEDIA_RESULTS] = {
"MEDIA_AND_POISON_GET_SCAN_MEDIA_RESULTS",
cmd_media_get_scan_media_results, 0, 0 },
@@ -2745,6 +3324,8 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
[INFOSTAT][IS_IDENTIFY] = { "IDENTIFY", cmd_infostat_identify, 0, 0 },
[INFOSTAT][BACKGROUND_OPERATION_STATUS] = { "BACKGROUND_OPERATION_STATUS",
cmd_infostat_bg_op_sts, 0, 0 },
+ [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT",
+ cmd_infostat_bg_op_abort, 0, 0 },
[TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 },
[TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8,
CXL_MBOX_IMMEDIATE_POLICY_CHANGE },
@@ -2831,6 +3412,7 @@ int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
cci->bg.opcode = (set << 8) | cmd;
cci->bg.complete_pct = 0;
+ cci->bg.aborted = false;
cci->bg.ret_code = 0;
now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
@@ -2844,10 +3426,12 @@ int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
static void bg_timercb(void *opaque)
{
CXLCCI *cci = opaque;
- uint64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
- uint64_t total_time = cci->bg.starttime + cci->bg.runtime;
+ uint64_t now, total_time;
+
+ qemu_mutex_lock(&cci->bg.lock);
- assert(cci->bg.runtime > 0);
+ now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+ total_time = cci->bg.starttime + cci->bg.runtime;
if (now >= total_time) { /* we are done */
uint16_t ret = CXL_MBOX_SUCCESS;
@@ -2866,6 +3450,12 @@ static void bg_timercb(void *opaque)
cxl_dev_enable_media(&ct3d->cxl_dstate);
}
break;
+ case 0x4402: /* Media Operations sanitize */
+ {
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ __do_sanitize(ct3d);
+ }
+ break;
case 0x4304: /* scan media */
{
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
@@ -2879,7 +3469,8 @@ static void bg_timercb(void *opaque)
}
} else {
/* estimate only */
- cci->bg.complete_pct = 100 * now / total_time;
+ cci->bg.complete_pct =
+ 100 * (now - cci->bg.starttime) / cci->bg.runtime;
timer_mod(cci->bg.timer, now + CXL_MBOX_BG_UPDATE_FREQ);
}
@@ -2899,6 +3490,8 @@ static void bg_timercb(void *opaque)
msi_notify(pdev, cxl_dstate->mbox_msi_n);
}
}
+
+ qemu_mutex_unlock(&cci->bg.lock);
}
static void cxl_rebuild_cel(CXLCCI *cci)
@@ -2927,12 +3520,21 @@ void cxl_init_cci(CXLCCI *cci, size_t payload_max)
cci->bg.complete_pct = 0;
cci->bg.starttime = 0;
cci->bg.runtime = 0;
+ cci->bg.aborted = false;
cci->bg.timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
bg_timercb, cci);
+ qemu_mutex_init(&cci->bg.lock);
memset(&cci->fw, 0, sizeof(cci->fw));
cci->fw.active_slot = 1;
cci->fw.slot[cci->fw.active_slot - 1] = true;
+ cci->initialized = true;
+}
+
+void cxl_destroy_cci(CXLCCI *cci)
+{
+ qemu_mutex_destroy(&cci->bg.lock);
+ cci->initialized = false;
}
static void cxl_copy_cci_commands(CXLCCI *cci, const struct cxl_cmd (*cxl_cmds)[256])
@@ -2996,6 +3598,10 @@ void cxl_initialize_t3_ld_cci(CXLCCI *cci, DeviceState *d, DeviceState *intf,
static const struct cxl_cmd cxl_cmd_set_t3_fm_owned_ld_mctp[256][256] = {
[INFOSTAT][IS_IDENTIFY] = { "IDENTIFY", cmd_infostat_identify, 0, 0},
+ [INFOSTAT][GET_RESPONSE_MSG_LIMIT] = { "GET_RESPONSE_MSG_LIMIT",
+ cmd_get_response_msg_limit, 0, 0 },
+ [INFOSTAT][SET_RESPONSE_MSG_LIMIT] = { "SET_RESPONSE_MSG_LIMIT",
+ cmd_set_response_msg_limit, 1, 0 },
[LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0,
0 },
[LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 },
diff --git a/hw/cxl/switch-mailbox-cci.c b/hw/cxl/switch-mailbox-cci.c
index ba399c6..223f220 100644
--- a/hw/cxl/switch-mailbox-cci.c
+++ b/hw/cxl/switch-mailbox-cci.c
@@ -17,10 +17,12 @@
#include "hw/qdev-properties.h"
#include "hw/cxl/cxl.h"
+#define CXL_SWCCI_MSIX_MBOX 3
+
static void cswmbcci_reset(DeviceState *dev)
{
CSWMBCCIDev *cswmb = CXL_SWITCH_MAILBOX_CCI(dev);
- cxl_device_register_init_swcci(cswmb);
+ cxl_device_register_init_swcci(cswmb, CXL_SWCCI_MSIX_MBOX);
}
static void cswbcci_realize(PCIDevice *pci_dev, Error **errp)
@@ -65,13 +67,12 @@ static void cswmbcci_exit(PCIDevice *pci_dev)
/* Nothing to do here yet */
}
-static Property cxl_switch_cci_props[] = {
+static const Property cxl_switch_cci_props[] = {
DEFINE_PROP_LINK("target", CSWMBCCIDev,
target, TYPE_CXL_USP, PCIDevice *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cswmbcci_class_init(ObjectClass *oc, void *data)
+static void cswmbcci_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
@@ -89,7 +90,7 @@ static void cswmbcci_class_init(ObjectClass *oc, void *data)
pc->device_id = 0xa123;
pc->revision = 0;
dc->desc = "CXL Switch Mailbox CCI";
- dc->reset = cswmbcci_reset;
+ device_class_set_legacy_reset(dc, cswmbcci_reset);
device_class_set_props(dc, cxl_switch_cci_props);
}
@@ -98,7 +99,7 @@ static const TypeInfo cswmbcci_info = {
.parent = TYPE_PCI_DEVICE,
.class_init = cswmbcci_class_init,
.instance_size = sizeof(CSWMBCCIDev),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index a4552c8..1e95ab2 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -66,9 +66,6 @@ config BOCHS_DISPLAY
select VGA
select EDID
-config BLIZZARD
- bool
-
config FRAMEBUFFER
bool
@@ -76,7 +73,7 @@ config SM501
bool
select I2C
select DDC
- select SERIAL
+ select SERIAL_MM
select USB_OHCI_SYSBUS
config TCX
@@ -143,3 +140,12 @@ config XLNX_DISPLAYPORT
config DM163
bool
+
+config MAC_PVG_MMIO
+ bool
+ depends on MAC_PVG && AARCH64
+
+config MAC_PVG_PCI
+ bool
+ depends on MAC_PVG && PCI
+ default y if PCI_DEVICES
diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m
new file mode 100644
index 0000000..b0b6e29
--- /dev/null
+++ b/hw/display/apple-gfx-mmio.m
@@ -0,0 +1,285 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device, MMIO (arm64) variant
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU as an MMIO-based
+ * system device for macOS on arm64 VMs.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "block/aio-wait.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "apple-gfx.h"
+#include "trace.h"
+
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXMMIOState, APPLE_GFX_MMIO)
+
+/*
+ * ParavirtualizedGraphics.Framework only ships header files for the PCI
+ * variant which does not include IOSFC descriptors and host devices. We add
+ * their definitions here so that we can also work with the ARM version.
+ */
+typedef bool(^IOSFCRaiseInterrupt)(uint32_t vector);
+typedef bool(^IOSFCUnmapMemory)(void *, void *, void *, void *, void *, void *);
+typedef bool(^IOSFCMapMemory)(uint64_t phys, uint64_t len, bool ro, void **va,
+ void *, void *);
+
+@interface PGDeviceDescriptor (IOSurfaceMapper)
+@property (readwrite, nonatomic) bool usingIOSurfaceMapper;
+@end
+
+@interface PGIOSurfaceHostDeviceDescriptor : NSObject
+-(PGIOSurfaceHostDeviceDescriptor *)init;
+@property (readwrite, nonatomic, copy, nullable) IOSFCMapMemory mapMemory;
+@property (readwrite, nonatomic, copy, nullable) IOSFCUnmapMemory unmapMemory;
+@property (readwrite, nonatomic, copy, nullable) IOSFCRaiseInterrupt raiseInterrupt;
+@end
+
+@interface PGIOSurfaceHostDevice : NSObject
+-(instancetype)initWithDescriptor:(PGIOSurfaceHostDeviceDescriptor *)desc;
+-(uint32_t)mmioReadAtOffset:(size_t)offset;
+-(void)mmioWriteAtOffset:(size_t)offset value:(uint32_t)value;
+@end
+
+struct AppleGFXMapSurfaceMemoryJob;
+struct AppleGFXMMIOState {
+ SysBusDevice parent_obj;
+
+ AppleGFXState common;
+
+ qemu_irq irq_gfx;
+ qemu_irq irq_iosfc;
+ MemoryRegion iomem_iosfc;
+ PGIOSurfaceHostDevice *pgiosfc;
+};
+
+typedef struct AppleGFXMMIOJob {
+ AppleGFXMMIOState *state;
+ uint64_t offset;
+ uint64_t value;
+ bool completed;
+} AppleGFXMMIOJob;
+
+static void iosfc_do_read(void *opaque)
+{
+ AppleGFXMMIOJob *job = opaque;
+ job->value = [job->state->pgiosfc mmioReadAtOffset:job->offset];
+ qatomic_set(&job->completed, true);
+ aio_wait_kick();
+}
+
+static uint64_t iosfc_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AppleGFXMMIOJob job = {
+ .state = opaque,
+ .offset = offset,
+ .completed = false,
+ };
+ dispatch_queue_t queue =
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_async_f(queue, &job, iosfc_do_read);
+ AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+ trace_apple_gfx_mmio_iosfc_read(offset, job.value);
+ return job.value;
+}
+
+static void iosfc_do_write(void *opaque)
+{
+ AppleGFXMMIOJob *job = opaque;
+ [job->state->pgiosfc mmioWriteAtOffset:job->offset value:job->value];
+ qatomic_set(&job->completed, true);
+ aio_wait_kick();
+}
+
+static void iosfc_write(void *opaque, hwaddr offset, uint64_t val,
+ unsigned size)
+{
+ AppleGFXMMIOJob job = {
+ .state = opaque,
+ .offset = offset,
+ .value = val,
+ .completed = false,
+ };
+ dispatch_queue_t queue =
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ dispatch_async_f(queue, &job, iosfc_do_write);
+ AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+ trace_apple_gfx_mmio_iosfc_write(offset, val);
+}
+
+static const MemoryRegionOps apple_iosfc_ops = {
+ .read = iosfc_read,
+ .write = iosfc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+static void raise_irq_bh(void *opaque)
+{
+ qemu_irq *irq = opaque;
+
+ qemu_irq_pulse(*irq);
+}
+
+static void *apple_gfx_mmio_map_surface_memory(uint64_t guest_physical_address,
+ uint64_t length, bool read_only)
+{
+ void *mem;
+ MemoryRegion *region = NULL;
+
+ RCU_READ_LOCK_GUARD();
+ mem = apple_gfx_host_ptr_for_gpa_range(guest_physical_address,
+ length, read_only, &region);
+ if (mem) {
+ memory_region_ref(region);
+ }
+ return mem;
+}
+
+static bool apple_gfx_mmio_unmap_surface_memory(void *ptr)
+{
+ MemoryRegion *region;
+ ram_addr_t offset = 0;
+
+ RCU_READ_LOCK_GUARD();
+ region = memory_region_from_host(ptr, &offset);
+ if (!region) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: memory at %p to be unmapped not found.\n",
+ __func__, ptr);
+ return false;
+ }
+
+ trace_apple_gfx_iosfc_unmap_memory_region(ptr, region);
+ memory_region_unref(region);
+ return true;
+}
+
+static PGIOSurfaceHostDevice *apple_gfx_prepare_iosurface_host_device(
+ AppleGFXMMIOState *s)
+{
+ PGIOSurfaceHostDeviceDescriptor *iosfc_desc =
+ [PGIOSurfaceHostDeviceDescriptor new];
+ PGIOSurfaceHostDevice *iosfc_host_dev;
+
+ iosfc_desc.mapMemory =
+ ^bool(uint64_t phys, uint64_t len, bool ro, void **va, void *e, void *f) {
+ *va = apple_gfx_mmio_map_surface_memory(phys, len, ro);
+
+ trace_apple_gfx_iosfc_map_memory(phys, len, ro, va, e, f, *va);
+
+ return *va != NULL;
+ };
+
+ iosfc_desc.unmapMemory =
+ ^bool(void *va, void *b, void *c, void *d, void *e, void *f) {
+ return apple_gfx_mmio_unmap_surface_memory(va);
+ };
+
+ iosfc_desc.raiseInterrupt = ^bool(uint32_t vector) {
+ trace_apple_gfx_iosfc_raise_irq(vector);
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ raise_irq_bh, &s->irq_iosfc);
+ return true;
+ };
+
+ iosfc_host_dev =
+ [[PGIOSurfaceHostDevice alloc] initWithDescriptor:iosfc_desc];
+ [iosfc_desc release];
+ return iosfc_host_dev;
+}
+
+static void apple_gfx_mmio_realize(DeviceState *dev, Error **errp)
+{
+ @autoreleasepool {
+ AppleGFXMMIOState *s = APPLE_GFX_MMIO(dev);
+ PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
+
+ desc.raiseInterrupt = ^(uint32_t vector) {
+ trace_apple_gfx_raise_irq(vector);
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ raise_irq_bh, &s->irq_gfx);
+ };
+
+ desc.usingIOSurfaceMapper = true;
+ s->pgiosfc = apple_gfx_prepare_iosurface_host_device(s);
+
+ if (!apple_gfx_common_realize(&s->common, dev, desc, errp)) {
+ [s->pgiosfc release];
+ s->pgiosfc = nil;
+ }
+
+ [desc release];
+ desc = nil;
+ }
+}
+
+static void apple_gfx_mmio_init(Object *obj)
+{
+ AppleGFXMMIOState *s = APPLE_GFX_MMIO(obj);
+
+ apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_MMIO);
+
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->common.iomem_gfx);
+ memory_region_init_io(&s->iomem_iosfc, obj, &apple_iosfc_ops, s,
+ TYPE_APPLE_GFX_MMIO, 0x10000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem_iosfc);
+ sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_gfx);
+ sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq_iosfc);
+}
+
+static void apple_gfx_mmio_reset(Object *obj, ResetType type)
+{
+ AppleGFXMMIOState *s = APPLE_GFX_MMIO(obj);
+ [s->common.pgdev reset];
+}
+
+static const Property apple_gfx_mmio_properties[] = {
+ DEFINE_PROP_ARRAY("display-modes", AppleGFXMMIOState,
+ common.num_display_modes, common.display_modes,
+ qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode),
+};
+
+static void apple_gfx_mmio_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = apple_gfx_mmio_reset;
+ dc->hotpluggable = false;
+ dc->realize = apple_gfx_mmio_realize;
+
+ device_class_set_props(dc, apple_gfx_mmio_properties);
+}
+
+static const TypeInfo apple_gfx_mmio_types[] = {
+ {
+ .name = TYPE_APPLE_GFX_MMIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AppleGFXMMIOState),
+ .class_init = apple_gfx_mmio_class_init,
+ .instance_init = apple_gfx_mmio_init,
+ }
+};
+DEFINE_TYPES(apple_gfx_mmio_types)
diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m
new file mode 100644
index 0000000..b0694f4
--- /dev/null
+++ b/hw/display/apple-gfx-pci.m
@@ -0,0 +1,157 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device, PCI variant
+ *
+ * Copyright © 2023-2024 Phil Dennis-Jordan
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU as a PCI device
+ * aimed primarily at x86-64 macOS VMs.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci_device.h"
+#include "hw/pci/msi.h"
+#include "apple-gfx.h"
+#include "trace.h"
+
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+
+OBJECT_DECLARE_SIMPLE_TYPE(AppleGFXPCIState, APPLE_GFX_PCI)
+
+struct AppleGFXPCIState {
+ PCIDevice parent_obj;
+
+ AppleGFXState common;
+};
+
+static const char *apple_gfx_pci_option_rom_path = NULL;
+
+static void apple_gfx_init_option_rom_path(void)
+{
+ NSURL *option_rom_url = PGCopyOptionROMURL();
+ const char *option_rom_path = option_rom_url.fileSystemRepresentation;
+ apple_gfx_pci_option_rom_path = g_strdup(option_rom_path);
+ [option_rom_url release];
+}
+
+static void apple_gfx_pci_init(Object *obj)
+{
+ AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
+
+ if (!apple_gfx_pci_option_rom_path) {
+ /*
+ * The following is done on device not class init to avoid running
+ * ObjC code before fork() in -daemonize mode.
+ */
+ PCIDeviceClass *pci = PCI_DEVICE_CLASS(object_get_class(obj));
+ apple_gfx_init_option_rom_path();
+ pci->romfile = apple_gfx_pci_option_rom_path;
+ }
+
+ apple_gfx_common_init(obj, &s->common, TYPE_APPLE_GFX_PCI);
+}
+
+typedef struct AppleGFXPCIInterruptJob {
+ PCIDevice *device;
+ uint32_t vector;
+} AppleGFXPCIInterruptJob;
+
+static void apple_gfx_pci_raise_interrupt(void *opaque)
+{
+ AppleGFXPCIInterruptJob *job = opaque;
+
+ if (msi_enabled(job->device)) {
+ msi_notify(job->device, job->vector);
+ }
+ g_free(job);
+}
+
+static void apple_gfx_pci_interrupt(PCIDevice *dev, uint32_t vector)
+{
+ AppleGFXPCIInterruptJob *job;
+
+ trace_apple_gfx_raise_irq(vector);
+ job = g_malloc0(sizeof(*job));
+ job->device = dev;
+ job->vector = vector;
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ apple_gfx_pci_raise_interrupt, job);
+}
+
+static void apple_gfx_pci_realize(PCIDevice *dev, Error **errp)
+{
+ AppleGFXPCIState *s = APPLE_GFX_PCI(dev);
+ int ret;
+
+ pci_register_bar(dev, PG_PCI_BAR_MMIO,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &s->common.iomem_gfx);
+
+ ret = msi_init(dev, 0x0 /* config offset; 0 = find space */,
+ PG_PCI_MAX_MSI_VECTORS, true /* msi64bit */,
+ false /* msi_per_vector_mask */, errp);
+ if (ret != 0) {
+ return;
+ }
+
+ @autoreleasepool {
+ PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
+ desc.raiseInterrupt = ^(uint32_t vector) {
+ apple_gfx_pci_interrupt(dev, vector);
+ };
+
+ apple_gfx_common_realize(&s->common, DEVICE(dev), desc, errp);
+ [desc release];
+ desc = nil;
+ }
+}
+
+static void apple_gfx_pci_reset(Object *obj, ResetType type)
+{
+ AppleGFXPCIState *s = APPLE_GFX_PCI(obj);
+ [s->common.pgdev reset];
+}
+
+static const Property apple_gfx_pci_properties[] = {
+ DEFINE_PROP_ARRAY("display-modes", AppleGFXPCIState,
+ common.num_display_modes, common.display_modes,
+ qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode),
+};
+
+static void apple_gfx_pci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pci = PCI_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = apple_gfx_pci_reset;
+ dc->desc = "macOS Paravirtualized Graphics PCI Display Controller";
+ dc->hotpluggable = false;
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+
+ pci->vendor_id = PG_PCI_VENDOR_ID;
+ pci->device_id = PG_PCI_DEVICE_ID;
+ pci->class_id = PCI_CLASS_DISPLAY_OTHER;
+ pci->realize = apple_gfx_pci_realize;
+
+ device_class_set_props(dc, apple_gfx_pci_properties);
+}
+
+static const TypeInfo apple_gfx_pci_types[] = {
+ {
+ .name = TYPE_APPLE_GFX_PCI,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(AppleGFXPCIState),
+ .class_init = apple_gfx_pci_class_init,
+ .instance_init = apple_gfx_pci_init,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { },
+ },
+ }
+};
+DEFINE_TYPES(apple_gfx_pci_types)
+
diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h
new file mode 100644
index 0000000..a8b1d1e
--- /dev/null
+++ b/hw/display/apple-gfx.h
@@ -0,0 +1,74 @@
+/*
+ * Data structures and functions shared between variants of the macOS
+ * ParavirtualizedGraphics.framework based apple-gfx display adapter.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_APPLE_GFX_H
+#define QEMU_APPLE_GFX_H
+
+#include "qemu/queue.h"
+#include "system/memory.h"
+#include "hw/qdev-properties.h"
+#include "ui/surface.h"
+
+#define TYPE_APPLE_GFX_MMIO "apple-gfx-mmio"
+#define TYPE_APPLE_GFX_PCI "apple-gfx-pci"
+
+@class PGDeviceDescriptor;
+@protocol PGDevice;
+@protocol PGDisplay;
+@protocol MTLDevice;
+@protocol MTLTexture;
+@protocol MTLCommandQueue;
+
+typedef QTAILQ_HEAD(, PGTask_s) PGTaskList;
+
+typedef struct AppleGFXDisplayMode {
+ uint16_t width_px;
+ uint16_t height_px;
+ uint16_t refresh_rate_hz;
+} AppleGFXDisplayMode;
+
+typedef struct AppleGFXState {
+ /* Initialised on init/realize() */
+ MemoryRegion iomem_gfx;
+ id<PGDevice> pgdev;
+ id<PGDisplay> pgdisp;
+ QemuConsole *con;
+ id<MTLDevice> mtl;
+ id<MTLCommandQueue> mtl_queue;
+ AppleGFXDisplayMode *display_modes;
+ uint32_t num_display_modes;
+
+ /* List `tasks` is protected by task_mutex */
+ QemuMutex task_mutex;
+ PGTaskList tasks;
+
+ /* Mutable state (BQL protected) */
+ QEMUCursor *cursor;
+ DisplaySurface *surface;
+ id<MTLTexture> texture;
+ int8_t pending_frames; /* # guest frames in the rendering pipeline */
+ bool gfx_update_requested; /* QEMU display system wants a new frame */
+ bool new_frame_ready; /* Guest has rendered a frame, ready to be used */
+ bool using_managed_texture_storage;
+ uint32_t rendering_frame_width;
+ uint32_t rendering_frame_height;
+
+ /* Mutable state (atomic) */
+ bool cursor_show;
+} AppleGFXState;
+
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_name);
+bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
+ PGDeviceDescriptor *desc, Error **errp);
+void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_physical,
+ uint64_t length, bool read_only,
+ MemoryRegion **mapping_in_region);
+
+extern const PropertyInfo qdev_prop_apple_gfx_display_mode;
+
+#endif
+
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
new file mode 100644
index 0000000..174d56a
--- /dev/null
+++ b/hw/display/apple-gfx.m
@@ -0,0 +1,880 @@
+/*
+ * QEMU Apple ParavirtualizedGraphics.framework device
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * ParavirtualizedGraphics.framework is a set of libraries that macOS provides
+ * which implements 3d graphics passthrough to the host as well as a
+ * proprietary guest communication channel to drive it. This device model
+ * implements support to drive that library from within QEMU.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/lockable.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qapi/visitor.h"
+#include "qapi/error.h"
+#include "block/aio-wait.h"
+#include "system/address-spaces.h"
+#include "system/dma.h"
+#include "migration/blocker.h"
+#include "ui/console.h"
+#include "apple-gfx.h"
+#include "trace.h"
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <dispatch/dispatch.h>
+
+#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
+
+static const AppleGFXDisplayMode apple_gfx_default_modes[] = {
+ { 1920, 1080, 60 },
+ { 1440, 1080, 60 },
+ { 1280, 1024, 60 },
+};
+
+static Error *apple_gfx_mig_blocker;
+static uint32_t next_pgdisplay_serial_num = 1;
+
+static dispatch_queue_t get_background_queue(void)
+{
+ return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+}
+
+/* ------ PGTask and task operations: new/destroy/map/unmap ------ */
+
+/*
+ * This implements the type declared in <ParavirtualizedGraphics/PGDevice.h>
+ * which is opaque from the framework's point of view. It is used in callbacks
+ * in the form of its typedef PGTask_t, which also already exists in the
+ * framework headers.
+ *
+ * A "task" in PVG terminology represents a host-virtual contiguous address
+ * range which is reserved in a large chunk on task creation. The mapMemory
+ * callback then requests ranges of guest system memory (identified by their
+ * GPA) to be mapped into subranges of this reserved address space.
+ * This type of operation isn't well-supported by QEMU's memory subsystem,
+ * but it is fortunately trivial to achieve with Darwin's mach_vm_remap() call,
+ * which allows us to refer to the same backing memory via multiple virtual
+ * address ranges. The Mach VM APIs are therefore used throughout for managing
+ * task memory.
+ */
+struct PGTask_s {
+ QTAILQ_ENTRY(PGTask_s) node;
+ AppleGFXState *s;
+ mach_vm_address_t address;
+ uint64_t len;
+ /*
+ * All unique MemoryRegions for which a mapping has been created in this
+ * task, and on which we have thus called memory_region_ref(). There are
+ * usually very few regions of system RAM in total, so we expect this array
+ * to be very short. Therefore, no need for sorting or fancy search
+ * algorithms, linear search will do.
+ * Protected by AppleGFXState's task_mutex.
+ */
+ GPtrArray *mapped_regions;
+};
+
+static PGTask_t *apple_gfx_new_task(AppleGFXState *s, uint64_t len)
+{
+ mach_vm_address_t task_mem;
+ PGTask_t *task;
+ kern_return_t r;
+
+ r = mach_vm_allocate(mach_task_self(), &task_mem, len, VM_FLAGS_ANYWHERE);
+ if (r != KERN_SUCCESS) {
+ return NULL;
+ }
+
+ task = g_new0(PGTask_t, 1);
+ task->s = s;
+ task->address = task_mem;
+ task->len = len;
+ task->mapped_regions = g_ptr_array_sized_new(2 /* Usually enough */);
+
+ QEMU_LOCK_GUARD(&s->task_mutex);
+ QTAILQ_INSERT_TAIL(&s->tasks, task, node);
+
+ return task;
+}
+
+static void apple_gfx_destroy_task(AppleGFXState *s, PGTask_t *task)
+{
+ GPtrArray *regions = task->mapped_regions;
+ MemoryRegion *region;
+ size_t i;
+
+ for (i = 0; i < regions->len; ++i) {
+ region = g_ptr_array_index(regions, i);
+ memory_region_unref(region);
+ }
+ g_ptr_array_unref(regions);
+
+ mach_vm_deallocate(mach_task_self(), task->address, task->len);
+
+ QEMU_LOCK_GUARD(&s->task_mutex);
+ QTAILQ_REMOVE(&s->tasks, task, node);
+ g_free(task);
+}
+
+void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_physical,
+ uint64_t length, bool read_only,
+ MemoryRegion **mapping_in_region)
+{
+ MemoryRegion *ram_region;
+ char *host_ptr;
+ hwaddr ram_region_offset = 0;
+ hwaddr ram_region_length = length;
+
+ ram_region = address_space_translate(&address_space_memory,
+ guest_physical,
+ &ram_region_offset,
+ &ram_region_length, !read_only,
+ MEMTXATTRS_UNSPECIFIED);
+
+ if (!ram_region || ram_region_length < length ||
+ !memory_access_is_direct(ram_region, !read_only,
+ MEMTXATTRS_UNSPECIFIED)) {
+ return NULL;
+ }
+
+ host_ptr = memory_region_get_ram_ptr(ram_region);
+ if (!host_ptr) {
+ return NULL;
+ }
+ host_ptr += ram_region_offset;
+ *mapping_in_region = ram_region;
+ return host_ptr;
+}
+
+static bool apple_gfx_task_map_memory(AppleGFXState *s, PGTask_t *task,
+ uint64_t virtual_offset,
+ PGPhysicalMemoryRange_t *ranges,
+ uint32_t range_count, bool read_only)
+{
+ kern_return_t r;
+ void *source_ptr;
+ mach_vm_address_t target;
+ vm_prot_t cur_protection, max_protection;
+ bool success = true;
+ MemoryRegion *region;
+
+ RCU_READ_LOCK_GUARD();
+ QEMU_LOCK_GUARD(&s->task_mutex);
+
+ trace_apple_gfx_map_memory(task, range_count, virtual_offset, read_only);
+ for (int i = 0; i < range_count; i++) {
+ PGPhysicalMemoryRange_t *range = &ranges[i];
+
+ target = task->address + virtual_offset;
+ virtual_offset += range->physicalLength;
+
+ trace_apple_gfx_map_memory_range(i, range->physicalAddress,
+ range->physicalLength);
+
+ region = NULL;
+ source_ptr = apple_gfx_host_ptr_for_gpa_range(range->physicalAddress,
+ range->physicalLength,
+ read_only, &region);
+ if (!source_ptr) {
+ success = false;
+ continue;
+ }
+
+ if (!g_ptr_array_find(task->mapped_regions, region, NULL)) {
+ g_ptr_array_add(task->mapped_regions, region);
+ memory_region_ref(region);
+ }
+
+ cur_protection = 0;
+ max_protection = 0;
+ /* Map guest RAM at range->physicalAddress into PG task memory range */
+ r = mach_vm_remap(mach_task_self(),
+ &target, range->physicalLength, vm_page_size - 1,
+ VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
+ mach_task_self(), (mach_vm_address_t)source_ptr,
+ false /* shared mapping, no copy */,
+ &cur_protection, &max_protection,
+ VM_INHERIT_COPY);
+ trace_apple_gfx_remap(r, source_ptr, target);
+ g_assert(r == KERN_SUCCESS);
+ }
+
+ return success;
+}
+
+static void apple_gfx_task_unmap_memory(AppleGFXState *s, PGTask_t *task,
+ uint64_t virtual_offset, uint64_t length)
+{
+ kern_return_t r;
+ mach_vm_address_t range_address;
+
+ trace_apple_gfx_unmap_memory(task, virtual_offset, length);
+
+ /*
+ * Replace task memory range with fresh 0 pages, undoing the mapping
+ * from guest RAM.
+ */
+ range_address = task->address + virtual_offset;
+ r = mach_vm_allocate(mach_task_self(), &range_address, length,
+ VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
+ g_assert(r == KERN_SUCCESS);
+}
+
+/* ------ Rendering and frame management ------ */
+
+static void apple_gfx_render_frame_completed_bh(void *opaque);
+
+static void apple_gfx_render_new_frame(AppleGFXState *s)
+{
+ bool managed_texture = s->using_managed_texture_storage;
+ uint32_t width = surface_width(s->surface);
+ uint32_t height = surface_height(s->surface);
+ MTLRegion region = MTLRegionMake2D(0, 0, width, height);
+ id<MTLCommandBuffer> command_buffer = [s->mtl_queue commandBuffer];
+ id<MTLTexture> texture = s->texture;
+
+ assert(bql_locked());
+ [texture retain];
+ [command_buffer retain];
+
+ s->rendering_frame_width = width;
+ s->rendering_frame_height = height;
+
+ dispatch_async(get_background_queue(), ^{
+ /*
+ * This is not safe to call from the BQL/BH due to PVG-internal locks
+ * causing deadlocks.
+ */
+ bool r = [s->pgdisp encodeCurrentFrameToCommandBuffer:command_buffer
+ texture:texture
+ region:region];
+ if (!r) {
+ [texture release];
+ [command_buffer release];
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: encodeCurrentFrameToCommandBuffer:texture:region: "
+ "failed\n", __func__);
+ bql_lock();
+ --s->pending_frames;
+ if (s->pending_frames > 0) {
+ apple_gfx_render_new_frame(s);
+ }
+ bql_unlock();
+ return;
+ }
+
+ if (managed_texture) {
+ /* "Managed" textures exist in both VRAM and RAM and must be synced. */
+ id<MTLBlitCommandEncoder> blit = [command_buffer blitCommandEncoder];
+ [blit synchronizeResource:texture];
+ [blit endEncoding];
+ }
+ [texture release];
+ [command_buffer addCompletedHandler:
+ ^(id<MTLCommandBuffer> cb)
+ {
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ apple_gfx_render_frame_completed_bh, s);
+ }];
+ [command_buffer commit];
+ [command_buffer release];
+ });
+}
+
+static void copy_mtl_texture_to_surface_mem(id<MTLTexture> texture, void *vram)
+{
+ /*
+ * TODO: Skip this entirely on a pure Metal or headless/guest-only
+ * rendering path, else use a blit command encoder? Needs careful
+ * (double?) buffering design.
+ */
+ size_t width = texture.width, height = texture.height;
+ MTLRegion region = MTLRegionMake2D(0, 0, width, height);
+ [texture getBytes:vram
+ bytesPerRow:(width * 4)
+ bytesPerImage:(width * height * 4)
+ fromRegion:region
+ mipmapLevel:0
+ slice:0];
+}
+
+static void apple_gfx_render_frame_completed_bh(void *opaque)
+{
+ AppleGFXState *s = opaque;
+
+ @autoreleasepool {
+ --s->pending_frames;
+ assert(s->pending_frames >= 0);
+
+ /* Only update display if mode hasn't changed since we started rendering. */
+ if (s->rendering_frame_width == surface_width(s->surface) &&
+ s->rendering_frame_height == surface_height(s->surface)) {
+ copy_mtl_texture_to_surface_mem(s->texture, surface_data(s->surface));
+ if (s->gfx_update_requested) {
+ s->gfx_update_requested = false;
+ dpy_gfx_update_full(s->con);
+ graphic_hw_update_done(s->con);
+ s->new_frame_ready = false;
+ } else {
+ s->new_frame_ready = true;
+ }
+ }
+ if (s->pending_frames > 0) {
+ apple_gfx_render_new_frame(s);
+ }
+ }
+}
+
+static void apple_gfx_fb_update_display(void *opaque)
+{
+ AppleGFXState *s = opaque;
+
+ assert(bql_locked());
+ if (s->new_frame_ready) {
+ dpy_gfx_update_full(s->con);
+ s->new_frame_ready = false;
+ graphic_hw_update_done(s->con);
+ } else if (s->pending_frames > 0) {
+ s->gfx_update_requested = true;
+ } else {
+ graphic_hw_update_done(s->con);
+ }
+}
+
+static const GraphicHwOps apple_gfx_fb_ops = {
+ .gfx_update = apple_gfx_fb_update_display,
+ .gfx_update_async = true,
+};
+
+/* ------ Mouse cursor and display mode setting ------ */
+
+static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
+{
+ MTLTextureDescriptor *textureDescriptor;
+
+ if (s->surface &&
+ width == surface_width(s->surface) &&
+ height == surface_height(s->surface)) {
+ return;
+ }
+
+ [s->texture release];
+
+ s->surface = qemu_create_displaysurface(width, height);
+
+ @autoreleasepool {
+ textureDescriptor =
+ [MTLTextureDescriptor
+ texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+ width:width
+ height:height
+ mipmapped:NO];
+ textureDescriptor.usage = s->pgdisp.minimumTextureUsage;
+ s->texture = [s->mtl newTextureWithDescriptor:textureDescriptor];
+ s->using_managed_texture_storage =
+ (s->texture.storageMode == MTLStorageModeManaged);
+ }
+
+ dpy_gfx_replace_surface(s->con, s->surface);
+}
+
+static void update_cursor(AppleGFXState *s)
+{
+ assert(bql_locked());
+ dpy_mouse_set(s->con, s->pgdisp.cursorPosition.x,
+ s->pgdisp.cursorPosition.y, qatomic_read(&s->cursor_show));
+}
+
+static void update_cursor_bh(void *opaque)
+{
+ AppleGFXState *s = opaque;
+ update_cursor(s);
+}
+
+typedef struct AppleGFXSetCursorGlyphJob {
+ AppleGFXState *s;
+ NSBitmapImageRep *glyph;
+ PGDisplayCoord_t hotspot;
+} AppleGFXSetCursorGlyphJob;
+
+static void set_cursor_glyph(void *opaque)
+{
+ AppleGFXSetCursorGlyphJob *job = opaque;
+ AppleGFXState *s = job->s;
+ NSBitmapImageRep *glyph = job->glyph;
+ uint32_t bpp = glyph.bitsPerPixel;
+ size_t width = glyph.pixelsWide;
+ size_t height = glyph.pixelsHigh;
+ size_t padding_bytes_per_row = glyph.bytesPerRow - width * 4;
+ const uint8_t* px_data = glyph.bitmapData;
+
+ trace_apple_gfx_cursor_set(bpp, width, height);
+
+ if (s->cursor) {
+ cursor_unref(s->cursor);
+ s->cursor = NULL;
+ }
+
+ if (bpp == 32) { /* Shouldn't be anything else, but just to be safe... */
+ s->cursor = cursor_alloc(width, height);
+ s->cursor->hot_x = job->hotspot.x;
+ s->cursor->hot_y = job->hotspot.y;
+
+ uint32_t *dest_px = s->cursor->data;
+
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ /*
+ * NSBitmapImageRep's red & blue channels are swapped
+ * compared to QEMUCursor's.
+ */
+ *dest_px =
+ (px_data[0] << 16u) |
+ (px_data[1] << 8u) |
+ (px_data[2] << 0u) |
+ (px_data[3] << 24u);
+ ++dest_px;
+ px_data += 4;
+ }
+ px_data += padding_bytes_per_row;
+ }
+ dpy_cursor_define(s->con, s->cursor);
+ update_cursor(s);
+ }
+ [glyph release];
+
+ g_free(job);
+}
+
+/* ------ DMA (device reading system memory) ------ */
+
+typedef struct AppleGFXReadMemoryJob {
+ QemuEvent event;
+ hwaddr physical_address;
+ uint64_t length;
+ void *dst;
+ bool success;
+} AppleGFXReadMemoryJob;
+
+static void apple_gfx_do_read_memory(void *opaque)
+{
+ AppleGFXReadMemoryJob *job = opaque;
+ MemTxResult r;
+
+ r = dma_memory_read(&address_space_memory, job->physical_address,
+ job->dst, job->length, MEMTXATTRS_UNSPECIFIED);
+ job->success = (r == MEMTX_OK);
+
+ qemu_event_set(&job->event);
+}
+
+static bool apple_gfx_read_memory(AppleGFXState *s, hwaddr physical_address,
+ uint64_t length, void *dst)
+{
+ AppleGFXReadMemoryJob job = {
+ .physical_address = physical_address, .length = length, .dst = dst
+ };
+
+ trace_apple_gfx_read_memory(physical_address, length, dst);
+
+ /* Performing DMA requires BQL, so do it in a BH. */
+ qemu_event_init(&job.event, 0);
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ apple_gfx_do_read_memory, &job);
+ qemu_event_wait(&job.event);
+ qemu_event_destroy(&job.event);
+ return job.success;
+}
+
+/* ------ Memory-mapped device I/O operations ------ */
+
+typedef struct AppleGFXIOJob {
+ AppleGFXState *state;
+ uint64_t offset;
+ uint64_t value;
+ bool completed;
+} AppleGFXIOJob;
+
+static void apple_gfx_do_read(void *opaque)
+{
+ AppleGFXIOJob *job = opaque;
+ job->value = [job->state->pgdev mmioReadAtOffset:job->offset];
+ qatomic_set(&job->completed, true);
+ aio_wait_kick();
+}
+
+static uint64_t apple_gfx_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AppleGFXIOJob job = {
+ .state = opaque,
+ .offset = offset,
+ .completed = false,
+ };
+ dispatch_queue_t queue = get_background_queue();
+
+ dispatch_async_f(queue, &job, apple_gfx_do_read);
+ AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+ trace_apple_gfx_read(offset, job.value);
+ return job.value;
+}
+
+static void apple_gfx_do_write(void *opaque)
+{
+ AppleGFXIOJob *job = opaque;
+ [job->state->pgdev mmioWriteAtOffset:job->offset value:job->value];
+ qatomic_set(&job->completed, true);
+ aio_wait_kick();
+}
+
+static void apple_gfx_write(void *opaque, hwaddr offset, uint64_t val,
+ unsigned size)
+{
+ /*
+ * The methods mmioReadAtOffset: and especially mmioWriteAtOffset: can
+ * trigger synchronous operations on other dispatch queues, which in turn
+ * may call back out on one or more of the callback blocks. For this reason,
+ * and as we are holding the BQL, we invoke the I/O methods on a pool
+ * thread and handle AIO tasks while we wait. Any work in the callbacks
+ * requiring the BQL will in turn schedule BHs which this thread will
+ * process while waiting.
+ */
+ AppleGFXIOJob job = {
+ .state = opaque,
+ .offset = offset,
+ .value = val,
+ .completed = false,
+ };
+ dispatch_queue_t queue = get_background_queue();
+
+ dispatch_async_f(queue, &job, apple_gfx_do_write);
+ AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
+
+ trace_apple_gfx_write(offset, val);
+}
+
+static const MemoryRegionOps apple_gfx_ops = {
+ .read = apple_gfx_read,
+ .write = apple_gfx_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static size_t apple_gfx_get_default_mmio_range_size(void)
+{
+ size_t mmio_range_size;
+ @autoreleasepool {
+ PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
+ mmio_range_size = desc.mmioLength;
+ [desc release];
+ }
+ return mmio_range_size;
+}
+
+/* ------ Initialisation and startup ------ */
+
+void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_name)
+{
+ size_t mmio_range_size = apple_gfx_get_default_mmio_range_size();
+
+ trace_apple_gfx_common_init(obj_name, mmio_range_size);
+ memory_region_init_io(&s->iomem_gfx, obj, &apple_gfx_ops, s, obj_name,
+ mmio_range_size);
+
+ /* TODO: PVG framework supports serialising device state: integrate it! */
+}
+
+static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
+ PGDeviceDescriptor *desc)
+{
+ desc.createTask = ^(uint64_t vmSize, void * _Nullable * _Nonnull baseAddress) {
+ PGTask_t *task = apple_gfx_new_task(s, vmSize);
+ *baseAddress = (void *)task->address;
+ trace_apple_gfx_create_task(vmSize, *baseAddress);
+ return task;
+ };
+
+ desc.destroyTask = ^(PGTask_t * _Nonnull task) {
+ trace_apple_gfx_destroy_task(task, task->mapped_regions->len);
+
+ apple_gfx_destroy_task(s, task);
+ };
+
+ desc.mapMemory = ^bool(PGTask_t * _Nonnull task, uint32_t range_count,
+ uint64_t virtual_offset, bool read_only,
+ PGPhysicalMemoryRange_t * _Nonnull ranges) {
+ return apple_gfx_task_map_memory(s, task, virtual_offset,
+ ranges, range_count, read_only);
+ };
+
+ desc.unmapMemory = ^bool(PGTask_t * _Nonnull task, uint64_t virtual_offset,
+ uint64_t length) {
+ apple_gfx_task_unmap_memory(s, task, virtual_offset, length);
+ return true;
+ };
+
+ desc.readMemory = ^bool(uint64_t physical_address, uint64_t length,
+ void * _Nonnull dst) {
+ return apple_gfx_read_memory(s, physical_address, length, dst);
+ };
+}
+
+static void new_frame_handler_bh(void *opaque)
+{
+ AppleGFXState *s = opaque;
+
+ /* Drop frames if guest gets too far ahead. */
+ if (s->pending_frames >= 2) {
+ return;
+ }
+ ++s->pending_frames;
+ if (s->pending_frames > 1) {
+ return;
+ }
+
+ @autoreleasepool {
+ apple_gfx_render_new_frame(s);
+ }
+}
+
+static PGDisplayDescriptor *apple_gfx_prepare_display_descriptor(AppleGFXState *s)
+{
+ PGDisplayDescriptor *disp_desc = [PGDisplayDescriptor new];
+
+ disp_desc.name = @"QEMU display";
+ disp_desc.sizeInMillimeters = NSMakeSize(400., 300.); /* A 20" display */
+ disp_desc.queue = dispatch_get_main_queue();
+ disp_desc.newFrameEventHandler = ^(void) {
+ trace_apple_gfx_new_frame();
+ aio_bh_schedule_oneshot(qemu_get_aio_context(), new_frame_handler_bh, s);
+ };
+ disp_desc.modeChangeHandler = ^(PGDisplayCoord_t sizeInPixels,
+ OSType pixelFormat) {
+ trace_apple_gfx_mode_change(sizeInPixels.x, sizeInPixels.y);
+
+ BQL_LOCK_GUARD();
+ set_mode(s, sizeInPixels.x, sizeInPixels.y);
+ };
+ disp_desc.cursorGlyphHandler = ^(NSBitmapImageRep *glyph,
+ PGDisplayCoord_t hotspot) {
+ AppleGFXSetCursorGlyphJob *job = g_malloc0(sizeof(*job));
+ job->s = s;
+ job->glyph = glyph;
+ job->hotspot = hotspot;
+ [glyph retain];
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ set_cursor_glyph, job);
+ };
+ disp_desc.cursorShowHandler = ^(BOOL show) {
+ trace_apple_gfx_cursor_show(show);
+ qatomic_set(&s->cursor_show, show);
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ update_cursor_bh, s);
+ };
+ disp_desc.cursorMoveHandler = ^(void) {
+ trace_apple_gfx_cursor_move();
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ update_cursor_bh, s);
+ };
+
+ return disp_desc;
+}
+
+static NSArray<PGDisplayMode *> *apple_gfx_create_display_mode_array(
+ const AppleGFXDisplayMode display_modes[], uint32_t display_mode_count)
+{
+ PGDisplayMode *mode_obj;
+ NSMutableArray<PGDisplayMode *> *mode_array =
+ [[NSMutableArray alloc] initWithCapacity:display_mode_count];
+
+ for (unsigned i = 0; i < display_mode_count; i++) {
+ const AppleGFXDisplayMode *mode = &display_modes[i];
+ trace_apple_gfx_display_mode(i, mode->width_px, mode->height_px);
+ PGDisplayCoord_t mode_size = { mode->width_px, mode->height_px };
+
+ mode_obj =
+ [[PGDisplayMode alloc] initWithSizeInPixels:mode_size
+ refreshRateInHz:mode->refresh_rate_hz];
+ [mode_array addObject:mode_obj];
+ [mode_obj release];
+ }
+
+ return mode_array;
+}
+
+static id<MTLDevice> copy_suitable_metal_device(void)
+{
+ id<MTLDevice> dev = nil;
+ NSArray<id<MTLDevice>> *devs = MTLCopyAllDevices();
+
+ /* Prefer a unified memory GPU. Failing that, pick a non-removable GPU. */
+ for (size_t i = 0; i < devs.count; ++i) {
+ if (devs[i].hasUnifiedMemory) {
+ dev = devs[i];
+ break;
+ }
+ if (!devs[i].removable) {
+ dev = devs[i];
+ }
+ }
+
+ if (dev != nil) {
+ [dev retain];
+ } else {
+ dev = MTLCreateSystemDefaultDevice();
+ }
+ [devs release];
+
+ return dev;
+}
+
+bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
+ PGDeviceDescriptor *desc, Error **errp)
+{
+ PGDisplayDescriptor *disp_desc;
+ const AppleGFXDisplayMode *display_modes = apple_gfx_default_modes;
+ uint32_t num_display_modes = ARRAY_SIZE(apple_gfx_default_modes);
+ NSArray<PGDisplayMode *> *mode_array;
+
+ if (apple_gfx_mig_blocker == NULL) {
+ error_setg(&apple_gfx_mig_blocker,
+ "Migration state blocked by apple-gfx display device");
+ if (migrate_add_blocker(&apple_gfx_mig_blocker, errp) < 0) {
+ return false;
+ }
+ }
+
+ qemu_mutex_init(&s->task_mutex);
+ QTAILQ_INIT(&s->tasks);
+ s->mtl = copy_suitable_metal_device();
+ s->mtl_queue = [s->mtl newCommandQueue];
+
+ desc.device = s->mtl;
+
+ apple_gfx_register_task_mapping_handlers(s, desc);
+
+ s->cursor_show = true;
+
+ s->pgdev = PGNewDeviceWithDescriptor(desc);
+
+ disp_desc = apple_gfx_prepare_display_descriptor(s);
+ /*
+ * Although the framework does, this integration currently does not support
+ * multiple virtual displays connected to a single PV graphics device.
+ * It is however possible to create
+ * more than one instance of the device, each with one display. The macOS
+ * guest will ignore these displays if they share the same serial number,
+ * so ensure each instance gets a unique one.
+ */
+ s->pgdisp = [s->pgdev newDisplayWithDescriptor:disp_desc
+ port:0
+ serialNum:next_pgdisplay_serial_num++];
+ [disp_desc release];
+
+ if (s->display_modes != NULL && s->num_display_modes > 0) {
+ trace_apple_gfx_common_realize_modes_property(s->num_display_modes);
+ display_modes = s->display_modes;
+ num_display_modes = s->num_display_modes;
+ }
+ s->pgdisp.modeList = mode_array =
+ apple_gfx_create_display_mode_array(display_modes, num_display_modes);
+ [mode_array release];
+
+ s->con = graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
+ return true;
+}
+
+/* ------ Display mode list device property ------ */
+
+static void apple_gfx_get_display_mode(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ Property *prop = opaque;
+ AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop);
+ /* 3 uint16s (max 5 digits) + 2 separator characters + nul. */
+ char buffer[5 * 3 + 2 + 1];
+ char *pos = buffer;
+
+ int rc = snprintf(buffer, sizeof(buffer),
+ "%"PRIu16"x%"PRIu16"@%"PRIu16,
+ mode->width_px, mode->height_px,
+ mode->refresh_rate_hz);
+ assert(rc < sizeof(buffer));
+
+ visit_type_str(v, name, &pos, errp);
+}
+
+static void apple_gfx_set_display_mode(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ Property *prop = opaque;
+ AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop);
+ const char *endptr;
+ g_autofree char *str = NULL;
+ int ret;
+ int val;
+
+ if (!visit_type_str(v, name, &str, errp)) {
+ return;
+ }
+
+ endptr = str;
+
+ ret = qemu_strtoi(endptr, &endptr, 10, &val);
+ if (ret || val > UINT16_MAX || val <= 0) {
+ error_setg(errp, "width in '%s' must be a decimal integer number"
+ " of pixels in the range 1..65535", name);
+ return;
+ }
+ mode->width_px = val;
+ if (*endptr != 'x') {
+ goto separator_error;
+ }
+
+ ret = qemu_strtoi(endptr + 1, &endptr, 10, &val);
+ if (ret || val > UINT16_MAX || val <= 0) {
+ error_setg(errp, "height in '%s' must be a decimal integer number"
+ " of pixels in the range 1..65535", name);
+ return;
+ }
+ mode->height_px = val;
+ if (*endptr != '@') {
+ goto separator_error;
+ }
+
+ ret = qemu_strtoi(endptr + 1, &endptr, 10, &val);
+ if (ret || val > UINT16_MAX || val <= 0) {
+ error_setg(errp, "refresh rate in '%s'"
+ " must be a positive decimal integer (Hertz)", name);
+ return;
+ }
+ mode->refresh_rate_hz = val;
+ return;
+
+separator_error:
+ error_setg(errp,
+ "Each display mode takes the format '<width>x<height>@<rate>'");
+}
+
+const PropertyInfo qdev_prop_apple_gfx_display_mode = {
+ .type = "display_mode",
+ .description =
+ "Display mode in pixels and Hertz, as <width>x<height>@<refresh-rate> "
+ "Example: 3840x2160@60",
+ .get = apple_gfx_get_display_mode,
+ .set = apple_gfx_set_display_mode,
+};
diff --git a/hw/display/artist.c b/hw/display/artist.c
index d913453..3fafc8a 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -48,6 +48,7 @@ struct ARTISTState {
struct vram_buffer vram_buffer[16];
+ bool disable;
uint16_t width;
uint16_t height;
uint16_t depth;
@@ -1211,8 +1212,8 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
break;
case 0x380004:
- /* 0x02000000 Buserror */
- val = 0x6dc20006;
+ /* magic number detected by SeaBIOS-hppa */
+ val = s->disable ? 0 : 0x6dc20006;
break;
default:
@@ -1432,7 +1433,7 @@ static int vmstate_artist_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_artist = {
.name = "artist",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 2,
.post_load = vmstate_artist_post_load,
.fields = (const VMStateField[]) {
@@ -1470,28 +1471,29 @@ static const VMStateDescription vmstate_artist = {
VMSTATE_UINT32(font_write1, ARTISTState),
VMSTATE_UINT32(font_write2, ARTISTState),
VMSTATE_UINT32(font_write_pos_y, ARTISTState),
+ VMSTATE_BOOL(disable, ARTISTState),
VMSTATE_END_OF_LIST()
}
};
-static Property artist_properties[] = {
+static const Property artist_properties[] = {
DEFINE_PROP_UINT16("width", ARTISTState, width, 1280),
DEFINE_PROP_UINT16("height", ARTISTState, height, 1024),
DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("disable", ARTISTState, disable, false),
};
static void artist_reset(DeviceState *qdev)
{
}
-static void artist_class_init(ObjectClass *klass, void *data)
+static void artist_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = artist_realizefn;
dc->vmsd = &vmstate_artist;
- dc->reset = artist_reset;
+ device_class_set_legacy_reset(dc, artist_reset);
device_class_set_props(dc, artist_properties);
}
diff --git a/hw/display/ati.c b/hw/display/ati.c
index b1f94f5..7de2773 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -1039,7 +1039,7 @@ static void ati_vga_exit(PCIDevice *dev)
graphic_console_close(s->vga.con);
}
-static Property ati_vga_properties[] = {
+static const Property ati_vga_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", ATIVGAState, vga.vram_size_mb, 16),
DEFINE_PROP_STRING("model", ATIVGAState, model),
DEFINE_PROP_UINT16("x-device-id", ATIVGAState, dev_id,
@@ -1047,15 +1047,14 @@ static Property ati_vga_properties[] = {
DEFINE_PROP_BOOL("guest_hwcursor", ATIVGAState, cursor_guest_mode, false),
/* this is a debug option, prefer PROP_UINT over PROP_BIT for simplicity */
DEFINE_PROP_UINT8("x-pixman", ATIVGAState, use_pixman, DEFAULT_X_PIXMAN),
- DEFINE_PROP_END_OF_LIST()
};
-static void ati_vga_class_init(ObjectClass *klass, void *data)
+static void ati_vga_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = ati_vga_reset;
+ device_class_set_legacy_reset(dc, ati_vga_reset);
device_class_set_props(dc, ati_vga_properties);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
@@ -1080,7 +1079,7 @@ static const TypeInfo ati_vga_info = {
.instance_size = sizeof(ATIVGAState),
.class_init = ati_vga_class_init,
.instance_init = ati_vga_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index 650db3d..820e67a 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -429,7 +429,7 @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
qemu_console_resize(s->con, s->config.xres, s->config.yres);
}
-static Property bcm2835_fb_props[] = {
+static const Property bcm2835_fb_props[] = {
DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
DEFAULT_VCRAM_SIZE),
@@ -440,16 +440,15 @@ static Property bcm2835_fb_props[] = {
initial_config.pixo, 1), /* 1=RGB, 0=BGR */
DEFINE_PROP_UINT32("alpha", BCM2835FBState,
initial_config.alpha, 2), /* alpha ignored */
- DEFINE_PROP_END_OF_LIST()
};
-static void bcm2835_fb_class_init(ObjectClass *klass, void *data)
+static void bcm2835_fb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, bcm2835_fb_props);
dc->realize = bcm2835_fb_realize;
- dc->reset = bcm2835_fb_reset;
+ device_class_set_legacy_reset(dc, bcm2835_fb_reset);
dc->vmsd = &vmstate_bcm2835_fb;
}
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
deleted file mode 100644
index 030abbe..0000000
--- a/hw/display/blizzard.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/bitops.h"
-#include "ui/console.h"
-#include "hw/display/blizzard.h"
-#include "ui/pixel_ops.h"
-
-typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
-
-typedef struct {
- uint8_t reg;
- uint32_t addr;
- int swallow;
-
- int pll;
- int pll_range;
- int pll_ctrl;
- uint8_t pll_mode;
- uint8_t clksel;
- int memenable;
- int memrefresh;
- uint8_t timing[3];
- int priority;
-
- uint8_t lcd_config;
- int x;
- int y;
- int skipx;
- int skipy;
- uint8_t hndp;
- uint8_t vndp;
- uint8_t hsync;
- uint8_t vsync;
- uint8_t pclk;
- uint8_t u;
- uint8_t v;
- uint8_t yrc[2];
- int ix[2];
- int iy[2];
- int ox[2];
- int oy[2];
-
- int enable;
- int blank;
- int bpp;
- int invalidate;
- int mx[2];
- int my[2];
- uint8_t mode;
- uint8_t effect;
- uint8_t iformat;
- uint8_t source;
- QemuConsole *con;
- blizzard_fn_t *line_fn_tab[2];
- void *fb;
-
- uint8_t hssi_config[3];
- uint8_t tv_config;
- uint8_t tv_timing[4];
- uint8_t vbi;
- uint8_t tv_x;
- uint8_t tv_y;
- uint8_t tv_test;
- uint8_t tv_filter_config;
- uint8_t tv_filter_idx;
- uint8_t tv_filter_coeff[0x20];
- uint8_t border_r;
- uint8_t border_g;
- uint8_t border_b;
- uint8_t gamma_config;
- uint8_t gamma_idx;
- uint8_t gamma_lut[0x100];
- uint8_t matrix_ena;
- uint8_t matrix_coeff[0x12];
- uint8_t matrix_r;
- uint8_t matrix_g;
- uint8_t matrix_b;
- uint8_t pm;
- uint8_t status;
- uint8_t rgbgpio_dir;
- uint8_t rgbgpio;
- uint8_t gpio_dir;
- uint8_t gpio;
- uint8_t gpio_edge[2];
- uint8_t gpio_irq;
- uint8_t gpio_pdown;
-
- struct {
- int x;
- int y;
- int dx;
- int dy;
- int len;
- int buflen;
- void *buf;
- void *data;
- uint16_t *ptr;
- int angle;
- int pitch;
- blizzard_fn_t line_fn;
- } data;
-} BlizzardState;
-
-/* Bytes(!) per pixel */
-static const int blizzard_iformat_bpp[0x10] = {
- 0,
- 2, /* RGB 5:6:5*/
- 3, /* RGB 6:6:6 mode 1 */
- 3, /* RGB 8:8:8 mode 1 */
- 0, 0,
- 4, /* RGB 6:6:6 mode 2 */
- 4, /* RGB 8:8:8 mode 2 */
- 0, /* YUV 4:2:2 */
- 0, /* YUV 4:2:0 */
- 0, 0, 0, 0, 0, 0,
-};
-
-static void blizzard_window(BlizzardState *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- uint8_t *src, *dst;
- int bypp[2];
- int bypl[3];
- int y;
- blizzard_fn_t fn = s->data.line_fn;
-
- if (!fn)
- return;
- if (s->mx[0] > s->data.x)
- s->mx[0] = s->data.x;
- if (s->my[0] > s->data.y)
- s->my[0] = s->data.y;
- if (s->mx[1] < s->data.x + s->data.dx)
- s->mx[1] = s->data.x + s->data.dx;
- if (s->my[1] < s->data.y + s->data.dy)
- s->my[1] = s->data.y + s->data.dy;
-
- bypp[0] = s->bpp;
- bypp[1] = surface_bytes_per_pixel(surface);
- bypl[0] = bypp[0] * s->data.pitch;
- bypl[1] = bypp[1] * s->x;
- bypl[2] = bypp[0] * s->data.dx;
-
- src = s->data.data;
- dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
- for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
- fn(dst, src, bypl[2]);
-}
-
-static int blizzard_transfer_setup(BlizzardState *s)
-{
- if (s->source > 3 || !s->bpp ||
- s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
- return 0;
-
- s->data.angle = s->effect & 3;
- s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
- s->data.x = s->ix[0];
- s->data.y = s->iy[0];
- s->data.dx = s->ix[1] - s->ix[0] + 1;
- s->data.dy = s->iy[1] - s->iy[0] + 1;
- s->data.len = s->bpp * s->data.dx * s->data.dy;
- s->data.pitch = s->data.dx;
- if (s->data.len > s->data.buflen) {
- s->data.buf = g_realloc(s->data.buf, s->data.len);
- s->data.buflen = s->data.len;
- }
- s->data.ptr = s->data.buf;
- s->data.data = s->data.buf;
- s->data.len /= 2;
- return 1;
-}
-
-static void blizzard_reset(BlizzardState *s)
-{
- s->reg = 0;
- s->swallow = 0;
-
- s->pll = 9;
- s->pll_range = 1;
- s->pll_ctrl = 0x14;
- s->pll_mode = 0x32;
- s->clksel = 0x00;
- s->memenable = 0;
- s->memrefresh = 0x25c;
- s->timing[0] = 0x3f;
- s->timing[1] = 0x13;
- s->timing[2] = 0x21;
- s->priority = 0;
-
- s->lcd_config = 0x74;
- s->x = 8;
- s->y = 1;
- s->skipx = 0;
- s->skipy = 0;
- s->hndp = 3;
- s->vndp = 2;
- s->hsync = 1;
- s->vsync = 1;
- s->pclk = 0x80;
-
- s->ix[0] = 0;
- s->ix[1] = 0;
- s->iy[0] = 0;
- s->iy[1] = 0;
- s->ox[0] = 0;
- s->ox[1] = 0;
- s->oy[0] = 0;
- s->oy[1] = 0;
-
- s->yrc[0] = 0x00;
- s->yrc[1] = 0x30;
- s->u = 0;
- s->v = 0;
-
- s->iformat = 3;
- s->source = 0;
- s->bpp = blizzard_iformat_bpp[s->iformat];
-
- s->hssi_config[0] = 0x00;
- s->hssi_config[1] = 0x00;
- s->hssi_config[2] = 0x01;
- s->tv_config = 0x00;
- s->tv_timing[0] = 0x00;
- s->tv_timing[1] = 0x00;
- s->tv_timing[2] = 0x00;
- s->tv_timing[3] = 0x00;
- s->vbi = 0x10;
- s->tv_x = 0x14;
- s->tv_y = 0x03;
- s->tv_test = 0x00;
- s->tv_filter_config = 0x80;
- s->tv_filter_idx = 0x00;
- s->border_r = 0x10;
- s->border_g = 0x80;
- s->border_b = 0x80;
- s->gamma_config = 0x00;
- s->gamma_idx = 0x00;
- s->matrix_ena = 0x00;
- memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
- s->matrix_r = 0x00;
- s->matrix_g = 0x00;
- s->matrix_b = 0x00;
- s->pm = 0x02;
- s->status = 0x00;
- s->rgbgpio_dir = 0x00;
- s->gpio_dir = 0x00;
- s->gpio_edge[0] = 0x00;
- s->gpio_edge[1] = 0x00;
- s->gpio_irq = 0x00;
- s->gpio_pdown = 0xff;
-}
-
-static inline void blizzard_invalidate_display(void *opaque) {
- BlizzardState *s = (BlizzardState *) opaque;
-
- s->invalidate = 1;
-}
-
-static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- switch (reg) {
- case 0x00: /* Revision Code */
- return 0xa5;
-
- case 0x02: /* Configuration Readback */
- return 0x83; /* Macrovision OK, CNF[2:0] = 3 */
-
- case 0x04: /* PLL M-Divider */
- return (s->pll - 1) | (1 << 7);
- case 0x06: /* PLL Lock Range Control */
- return s->pll_range;
- case 0x08: /* PLL Lock Synthesis Control 0 */
- return s->pll_ctrl & 0xff;
- case 0x0a: /* PLL Lock Synthesis Control 1 */
- return s->pll_ctrl >> 8;
- case 0x0c: /* PLL Mode Control 0 */
- return s->pll_mode;
-
- case 0x0e: /* Clock-Source Select */
- return s->clksel;
-
- case 0x10: /* Memory Controller Activate */
- case 0x14: /* Memory Controller Bank 0 Status Flag */
- return s->memenable;
-
- case 0x18: /* Auto-Refresh Interval Setting 0 */
- return s->memrefresh & 0xff;
- case 0x1a: /* Auto-Refresh Interval Setting 1 */
- return s->memrefresh >> 8;
-
- case 0x1c: /* Power-On Sequence Timing Control */
- return s->timing[0];
- case 0x1e: /* Timing Control 0 */
- return s->timing[1];
- case 0x20: /* Timing Control 1 */
- return s->timing[2];
-
- case 0x24: /* Arbitration Priority Control */
- return s->priority;
-
- case 0x28: /* LCD Panel Configuration */
- return s->lcd_config;
-
- case 0x2a: /* LCD Horizontal Display Width */
- return s->x >> 3;
- case 0x2c: /* LCD Horizontal Non-display Period */
- return s->hndp;
- case 0x2e: /* LCD Vertical Display Height 0 */
- return s->y & 0xff;
- case 0x30: /* LCD Vertical Display Height 1 */
- return s->y >> 8;
- case 0x32: /* LCD Vertical Non-display Period */
- return s->vndp;
- case 0x34: /* LCD HS Pulse-width */
- return s->hsync;
- case 0x36: /* LCd HS Pulse Start Position */
- return s->skipx >> 3;
- case 0x38: /* LCD VS Pulse-width */
- return s->vsync;
- case 0x3a: /* LCD VS Pulse Start Position */
- return s->skipy;
-
- case 0x3c: /* PCLK Polarity */
- return s->pclk;
-
- case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
- return s->hssi_config[0];
- case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
- return s->hssi_config[1];
- case 0x42: /* High-speed Serial Interface Tx Mode */
- return s->hssi_config[2];
- case 0x44: /* TV Display Configuration */
- return s->tv_config;
- case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */
- return s->tv_timing[(reg - 0x46) >> 1];
- case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
- return s->vbi;
- case 0x50: /* TV Horizontal Start Position */
- return s->tv_x;
- case 0x52: /* TV Vertical Start Position */
- return s->tv_y;
- case 0x54: /* TV Test Pattern Setting */
- return s->tv_test;
- case 0x56: /* TV Filter Setting */
- return s->tv_filter_config;
- case 0x58: /* TV Filter Coefficient Index */
- return s->tv_filter_idx;
- case 0x5a: /* TV Filter Coefficient Data */
- if (s->tv_filter_idx < 0x20)
- return s->tv_filter_coeff[s->tv_filter_idx ++];
- return 0;
-
- case 0x60: /* Input YUV/RGB Translate Mode 0 */
- return s->yrc[0];
- case 0x62: /* Input YUV/RGB Translate Mode 1 */
- return s->yrc[1];
- case 0x64: /* U Data Fix */
- return s->u;
- case 0x66: /* V Data Fix */
- return s->v;
-
- case 0x68: /* Display Mode */
- return s->mode;
-
- case 0x6a: /* Special Effects */
- return s->effect;
-
- case 0x6c: /* Input Window X Start Position 0 */
- return s->ix[0] & 0xff;
- case 0x6e: /* Input Window X Start Position 1 */
- return s->ix[0] >> 3;
- case 0x70: /* Input Window Y Start Position 0 */
- return s->ix[0] & 0xff;
- case 0x72: /* Input Window Y Start Position 1 */
- return s->ix[0] >> 3;
- case 0x74: /* Input Window X End Position 0 */
- return s->ix[1] & 0xff;
- case 0x76: /* Input Window X End Position 1 */
- return s->ix[1] >> 3;
- case 0x78: /* Input Window Y End Position 0 */
- return s->ix[1] & 0xff;
- case 0x7a: /* Input Window Y End Position 1 */
- return s->ix[1] >> 3;
- case 0x7c: /* Output Window X Start Position 0 */
- return s->ox[0] & 0xff;
- case 0x7e: /* Output Window X Start Position 1 */
- return s->ox[0] >> 3;
- case 0x80: /* Output Window Y Start Position 0 */
- return s->oy[0] & 0xff;
- case 0x82: /* Output Window Y Start Position 1 */
- return s->oy[0] >> 3;
- case 0x84: /* Output Window X End Position 0 */
- return s->ox[1] & 0xff;
- case 0x86: /* Output Window X End Position 1 */
- return s->ox[1] >> 3;
- case 0x88: /* Output Window Y End Position 0 */
- return s->oy[1] & 0xff;
- case 0x8a: /* Output Window Y End Position 1 */
- return s->oy[1] >> 3;
-
- case 0x8c: /* Input Data Format */
- return s->iformat;
- case 0x8e: /* Data Source Select */
- return s->source;
- case 0x90: /* Display Memory Data Port */
- return 0;
-
- case 0xa8: /* Border Color 0 */
- return s->border_r;
- case 0xaa: /* Border Color 1 */
- return s->border_g;
- case 0xac: /* Border Color 2 */
- return s->border_b;
-
- case 0xb4: /* Gamma Correction Enable */
- return s->gamma_config;
- case 0xb6: /* Gamma Correction Table Index */
- return s->gamma_idx;
- case 0xb8: /* Gamma Correction Table Data */
- return s->gamma_lut[s->gamma_idx ++];
-
- case 0xba: /* 3x3 Matrix Enable */
- return s->matrix_ena;
- case 0xbc ... 0xde: /* Coefficient Registers */
- return s->matrix_coeff[(reg - 0xbc) >> 1];
- case 0xe0: /* 3x3 Matrix Red Offset */
- return s->matrix_r;
- case 0xe2: /* 3x3 Matrix Green Offset */
- return s->matrix_g;
- case 0xe4: /* 3x3 Matrix Blue Offset */
- return s->matrix_b;
-
- case 0xe6: /* Power-save */
- return s->pm;
- case 0xe8: /* Non-display Period Control / Status */
- return s->status | (1 << 5);
- case 0xea: /* RGB Interface Control */
- return s->rgbgpio_dir;
- case 0xec: /* RGB Interface Status */
- return s->rgbgpio;
- case 0xee: /* General-purpose IO Pins Configuration */
- return s->gpio_dir;
- case 0xf0: /* General-purpose IO Pins Status / Control */
- return s->gpio;
- case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
- return s->gpio_edge[0];
- case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
- return s->gpio_edge[1];
- case 0xf6: /* GPIO Interrupt Status */
- return s->gpio_irq;
- case 0xf8: /* GPIO Pull-down Control */
- return s->gpio_pdown;
-
- default:
- fprintf(stderr, "%s: unknown register %02x\n", __func__, reg);
- return 0;
- }
-}
-
-static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- switch (reg) {
- case 0x04: /* PLL M-Divider */
- s->pll = (value & 0x3f) + 1;
- break;
- case 0x06: /* PLL Lock Range Control */
- s->pll_range = value & 3;
- break;
- case 0x08: /* PLL Lock Synthesis Control 0 */
- s->pll_ctrl &= 0xf00;
- s->pll_ctrl |= (value << 0) & 0x0ff;
- break;
- case 0x0a: /* PLL Lock Synthesis Control 1 */
- s->pll_ctrl &= 0x0ff;
- s->pll_ctrl |= (value << 8) & 0xf00;
- break;
- case 0x0c: /* PLL Mode Control 0 */
- s->pll_mode = value & 0x77;
- if ((value & 3) == 0 || (value & 3) == 3)
- fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
- __func__, value & 3);
- break;
-
- case 0x0e: /* Clock-Source Select */
- s->clksel = value & 0xff;
- break;
-
- case 0x10: /* Memory Controller Activate */
- s->memenable = value & 1;
- break;
- case 0x14: /* Memory Controller Bank 0 Status Flag */
- break;
-
- case 0x18: /* Auto-Refresh Interval Setting 0 */
- s->memrefresh &= 0xf00;
- s->memrefresh |= (value << 0) & 0x0ff;
- break;
- case 0x1a: /* Auto-Refresh Interval Setting 1 */
- s->memrefresh &= 0x0ff;
- s->memrefresh |= (value << 8) & 0xf00;
- break;
-
- case 0x1c: /* Power-On Sequence Timing Control */
- s->timing[0] = value & 0x7f;
- break;
- case 0x1e: /* Timing Control 0 */
- s->timing[1] = value & 0x17;
- break;
- case 0x20: /* Timing Control 1 */
- s->timing[2] = value & 0x35;
- break;
-
- case 0x24: /* Arbitration Priority Control */
- s->priority = value & 1;
- break;
-
- case 0x28: /* LCD Panel Configuration */
- s->lcd_config = value & 0xff;
- if (value & (1 << 7))
- fprintf(stderr, "%s: data swap not supported!\n", __func__);
- break;
-
- case 0x2a: /* LCD Horizontal Display Width */
- s->x = value << 3;
- break;
- case 0x2c: /* LCD Horizontal Non-display Period */
- s->hndp = value & 0xff;
- break;
- case 0x2e: /* LCD Vertical Display Height 0 */
- s->y &= 0x300;
- s->y |= (value << 0) & 0x0ff;
- break;
- case 0x30: /* LCD Vertical Display Height 1 */
- s->y &= 0x0ff;
- s->y |= (value << 8) & 0x300;
- break;
- case 0x32: /* LCD Vertical Non-display Period */
- s->vndp = value & 0xff;
- break;
- case 0x34: /* LCD HS Pulse-width */
- s->hsync = value & 0xff;
- break;
- case 0x36: /* LCD HS Pulse Start Position */
- s->skipx = value & 0xff;
- break;
- case 0x38: /* LCD VS Pulse-width */
- s->vsync = value & 0xbf;
- break;
- case 0x3a: /* LCD VS Pulse Start Position */
- s->skipy = value & 0xff;
- break;
-
- case 0x3c: /* PCLK Polarity */
- s->pclk = value & 0x82;
- /* Affects calculation of s->hndp, s->hsync and s->skipx. */
- break;
-
- case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
- s->hssi_config[0] = value;
- break;
- case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
- s->hssi_config[1] = value;
- if (((value >> 4) & 3) == 3)
- fprintf(stderr, "%s: Illegal active-data-links value\n",
- __func__);
- break;
- case 0x42: /* High-speed Serial Interface Tx Mode */
- s->hssi_config[2] = value & 0xbd;
- break;
-
- case 0x44: /* TV Display Configuration */
- s->tv_config = value & 0xfe;
- break;
- case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */
- s->tv_timing[(reg - 0x46) >> 1] = value;
- break;
- case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
- s->vbi = value;
- break;
- case 0x50: /* TV Horizontal Start Position */
- s->tv_x = value;
- break;
- case 0x52: /* TV Vertical Start Position */
- s->tv_y = value & 0x7f;
- break;
- case 0x54: /* TV Test Pattern Setting */
- s->tv_test = value;
- break;
- case 0x56: /* TV Filter Setting */
- s->tv_filter_config = value & 0xbf;
- break;
- case 0x58: /* TV Filter Coefficient Index */
- s->tv_filter_idx = value & 0x1f;
- break;
- case 0x5a: /* TV Filter Coefficient Data */
- if (s->tv_filter_idx < 0x20)
- s->tv_filter_coeff[s->tv_filter_idx ++] = value;
- break;
-
- case 0x60: /* Input YUV/RGB Translate Mode 0 */
- s->yrc[0] = value & 0xb0;
- break;
- case 0x62: /* Input YUV/RGB Translate Mode 1 */
- s->yrc[1] = value & 0x30;
- break;
- case 0x64: /* U Data Fix */
- s->u = value & 0xff;
- break;
- case 0x66: /* V Data Fix */
- s->v = value & 0xff;
- break;
-
- case 0x68: /* Display Mode */
- if ((s->mode ^ value) & 3)
- s->invalidate = 1;
- s->mode = value & 0xb7;
- s->enable = value & 1;
- s->blank = (value >> 1) & 1;
- if (value & (1 << 4))
- fprintf(stderr, "%s: Macrovision enable attempt!\n", __func__);
- break;
-
- case 0x6a: /* Special Effects */
- s->effect = value & 0xfb;
- break;
-
- case 0x6c: /* Input Window X Start Position 0 */
- s->ix[0] &= 0x300;
- s->ix[0] |= (value << 0) & 0x0ff;
- break;
- case 0x6e: /* Input Window X Start Position 1 */
- s->ix[0] &= 0x0ff;
- s->ix[0] |= (value << 8) & 0x300;
- break;
- case 0x70: /* Input Window Y Start Position 0 */
- s->iy[0] &= 0x300;
- s->iy[0] |= (value << 0) & 0x0ff;
- break;
- case 0x72: /* Input Window Y Start Position 1 */
- s->iy[0] &= 0x0ff;
- s->iy[0] |= (value << 8) & 0x300;
- break;
- case 0x74: /* Input Window X End Position 0 */
- s->ix[1] &= 0x300;
- s->ix[1] |= (value << 0) & 0x0ff;
- break;
- case 0x76: /* Input Window X End Position 1 */
- s->ix[1] &= 0x0ff;
- s->ix[1] |= (value << 8) & 0x300;
- break;
- case 0x78: /* Input Window Y End Position 0 */
- s->iy[1] &= 0x300;
- s->iy[1] |= (value << 0) & 0x0ff;
- break;
- case 0x7a: /* Input Window Y End Position 1 */
- s->iy[1] &= 0x0ff;
- s->iy[1] |= (value << 8) & 0x300;
- break;
- case 0x7c: /* Output Window X Start Position 0 */
- s->ox[0] &= 0x300;
- s->ox[0] |= (value << 0) & 0x0ff;
- break;
- case 0x7e: /* Output Window X Start Position 1 */
- s->ox[0] &= 0x0ff;
- s->ox[0] |= (value << 8) & 0x300;
- break;
- case 0x80: /* Output Window Y Start Position 0 */
- s->oy[0] &= 0x300;
- s->oy[0] |= (value << 0) & 0x0ff;
- break;
- case 0x82: /* Output Window Y Start Position 1 */
- s->oy[0] &= 0x0ff;
- s->oy[0] |= (value << 8) & 0x300;
- break;
- case 0x84: /* Output Window X End Position 0 */
- s->ox[1] &= 0x300;
- s->ox[1] |= (value << 0) & 0x0ff;
- break;
- case 0x86: /* Output Window X End Position 1 */
- s->ox[1] &= 0x0ff;
- s->ox[1] |= (value << 8) & 0x300;
- break;
- case 0x88: /* Output Window Y End Position 0 */
- s->oy[1] &= 0x300;
- s->oy[1] |= (value << 0) & 0x0ff;
- break;
- case 0x8a: /* Output Window Y End Position 1 */
- s->oy[1] &= 0x0ff;
- s->oy[1] |= (value << 8) & 0x300;
- break;
-
- case 0x8c: /* Input Data Format */
- s->iformat = value & 0xf;
- s->bpp = blizzard_iformat_bpp[s->iformat];
- if (!s->bpp)
- fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
- __func__, s->iformat);
- break;
- case 0x8e: /* Data Source Select */
- s->source = value & 7;
- /* Currently all windows will be "destructive overlays". */
- if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
- s->iy[0] != s->oy[0] ||
- s->ix[1] != s->ox[1] ||
- s->iy[1] != s->oy[1])) ||
- !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
- (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
- fprintf(stderr, "%s: Illegal input/output window positions\n",
- __func__);
-
- blizzard_transfer_setup(s);
- break;
-
- case 0x90: /* Display Memory Data Port */
- if (!s->data.len && !blizzard_transfer_setup(s))
- break;
-
- *s->data.ptr ++ = value;
- if (-- s->data.len == 0)
- blizzard_window(s);
- break;
-
- case 0xa8: /* Border Color 0 */
- s->border_r = value;
- break;
- case 0xaa: /* Border Color 1 */
- s->border_g = value;
- break;
- case 0xac: /* Border Color 2 */
- s->border_b = value;
- break;
-
- case 0xb4: /* Gamma Correction Enable */
- s->gamma_config = value & 0x87;
- break;
- case 0xb6: /* Gamma Correction Table Index */
- s->gamma_idx = value;
- break;
- case 0xb8: /* Gamma Correction Table Data */
- s->gamma_lut[s->gamma_idx ++] = value;
- break;
-
- case 0xba: /* 3x3 Matrix Enable */
- s->matrix_ena = value & 1;
- break;
- case 0xbc ... 0xde: /* Coefficient Registers */
- s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
- break;
- case 0xe0: /* 3x3 Matrix Red Offset */
- s->matrix_r = value;
- break;
- case 0xe2: /* 3x3 Matrix Green Offset */
- s->matrix_g = value;
- break;
- case 0xe4: /* 3x3 Matrix Blue Offset */
- s->matrix_b = value;
- break;
-
- case 0xe6: /* Power-save */
- s->pm = value & 0x83;
- if (value & s->mode & 1)
- fprintf(stderr, "%s: The display must be disabled before entering "
- "Standby Mode\n", __func__);
- break;
- case 0xe8: /* Non-display Period Control / Status */
- s->status = value & 0x1b;
- break;
- case 0xea: /* RGB Interface Control */
- s->rgbgpio_dir = value & 0x8f;
- break;
- case 0xec: /* RGB Interface Status */
- s->rgbgpio = value & 0xcf;
- break;
- case 0xee: /* General-purpose IO Pins Configuration */
- s->gpio_dir = value;
- break;
- case 0xf0: /* General-purpose IO Pins Status / Control */
- s->gpio = value;
- break;
- case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
- s->gpio_edge[0] = value;
- break;
- case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
- s->gpio_edge[1] = value;
- break;
- case 0xf6: /* GPIO Interrupt Status */
- s->gpio_irq &= value;
- break;
- case 0xf8: /* GPIO Pull-down Control */
- s->gpio_pdown = value;
- break;
-
- default:
- fprintf(stderr, "%s: unknown register %02x\n", __func__, reg);
- break;
- }
-}
-
-uint16_t s1d13745_read(void *opaque, int dc)
-{
- BlizzardState *s = (BlizzardState *) opaque;
- uint16_t value = blizzard_reg_read(s, s->reg);
-
- if (s->swallow -- > 0)
- return 0;
- if (dc)
- s->reg ++;
-
- return value;
-}
-
-void s1d13745_write(void *opaque, int dc, uint16_t value)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- if (s->swallow -- > 0)
- return;
- if (dc) {
- blizzard_reg_write(s, s->reg, value);
-
- if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
- s->reg += 2;
- } else
- s->reg = value & 0xff;
-}
-
-void s1d13745_write_block(void *opaque, int dc,
- void *buf, size_t len, int pitch)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- while (len > 0) {
- if (s->reg == 0x90 && dc &&
- (s->data.len || blizzard_transfer_setup(s)) &&
- len >= (s->data.len << 1)) {
- len -= s->data.len << 1;
- s->data.len = 0;
- s->data.data = buf;
- if (pitch)
- s->data.pitch = pitch;
- blizzard_window(s);
- s->data.data = s->data.buf;
- continue;
- }
-
- s1d13745_write(opaque, dc, *(uint16_t *) buf);
- len -= 2;
- buf += 2;
- }
-}
-
-static void blizzard_update_display(void *opaque)
-{
- BlizzardState *s = (BlizzardState *) opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int y, bypp, bypl, bwidth;
- uint8_t *src, *dst;
-
- if (!s->enable)
- return;
-
- if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
- s->invalidate = 1;
- qemu_console_resize(s->con, s->x, s->y);
- surface = qemu_console_surface(s->con);
- }
-
- if (s->invalidate) {
- s->invalidate = 0;
-
- if (s->blank) {
- bypp = surface_bytes_per_pixel(surface);
- memset(surface_data(surface), 0, bypp * s->x * s->y);
- return;
- }
-
- s->mx[0] = 0;
- s->mx[1] = s->x;
- s->my[0] = 0;
- s->my[1] = s->y;
- }
-
- if (s->mx[1] <= s->mx[0])
- return;
-
- bypp = surface_bytes_per_pixel(surface);
- bypl = bypp * s->x;
- bwidth = bypp * (s->mx[1] - s->mx[0]);
- y = s->my[0];
- src = s->fb + bypl * y + bypp * s->mx[0];
- dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
- for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
- memcpy(dst, src, bwidth);
-
- dpy_gfx_update(s->con, s->mx[0], s->my[0],
- s->mx[1] - s->mx[0], y - s->my[0]);
-
- s->mx[0] = s->x;
- s->mx[1] = 0;
- s->my[0] = s->y;
- s->my[1] = 0;
-}
-
-static void blizzard_draw_line16_32(uint32_t *dest,
- const uint16_t *src, unsigned int width)
-{
- uint16_t data;
- unsigned int r, g, b;
- const uint16_t *end = (const void *) src + width;
- while (src < end) {
- data = *src ++;
- b = extract16(data, 0, 5) << 3;
- g = extract16(data, 5, 6) << 2;
- r = extract16(data, 11, 5) << 3;
- *dest++ = rgb_to_pixel32(r, g, b);
- }
-}
-
-static void blizzard_draw_line24mode1_32(uint32_t *dest,
- const uint8_t *src, unsigned int width)
-{
- /* TODO: check if SDL 24-bit planes are not in the same format and
- * if so, use memcpy */
- unsigned int r[2], g[2], b[2];
- const uint8_t *end = src + width;
- while (src < end) {
- g[0] = *src ++;
- r[0] = *src ++;
- r[1] = *src ++;
- b[0] = *src ++;
- *dest++ = rgb_to_pixel32(r[0], g[0], b[0]);
- b[1] = *src ++;
- g[1] = *src ++;
- *dest++ = rgb_to_pixel32(r[1], g[1], b[1]);
- }
-}
-
-static void blizzard_draw_line24mode2_32(uint32_t *dest,
- const uint8_t *src, unsigned int width)
-{
- unsigned int r, g, b;
- const uint8_t *end = src + width;
- while (src < end) {
- r = *src ++;
- src ++;
- b = *src ++;
- g = *src ++;
- *dest++ = rgb_to_pixel32(r, g, b);
- }
-}
-
-/* No rotation */
-static blizzard_fn_t blizzard_draw_fn_32[0x10] = {
- NULL,
- /* RGB 5:6:5*/
- (blizzard_fn_t) blizzard_draw_line16_32,
- /* RGB 6:6:6 mode 1 */
- (blizzard_fn_t) blizzard_draw_line24mode1_32,
- /* RGB 8:8:8 mode 1 */
- (blizzard_fn_t) blizzard_draw_line24mode1_32,
- NULL, NULL,
- /* RGB 6:6:6 mode 2 */
- (blizzard_fn_t) blizzard_draw_line24mode2_32,
- /* RGB 8:8:8 mode 2 */
- (blizzard_fn_t) blizzard_draw_line24mode2_32,
- /* YUV 4:2:2 */
- NULL,
- /* YUV 4:2:0 */
- NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
-};
-
-/* 90deg, 180deg and 270deg rotation */
-static blizzard_fn_t blizzard_draw_fn_r_32[0x10] = {
- /* TODO */
- [0 ... 0xf] = NULL,
-};
-
-static const GraphicHwOps blizzard_ops = {
- .invalidate = blizzard_invalidate_display,
- .gfx_update = blizzard_update_display,
-};
-
-void *s1d13745_init(qemu_irq gpio_int)
-{
- BlizzardState *s = g_malloc0(sizeof(*s));
- DisplaySurface *surface;
-
- s->fb = g_malloc(0x180000);
-
- s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
- surface = qemu_console_surface(s->con);
-
- assert(surface_bits_per_pixel(surface) == 32);
-
- s->line_fn_tab[0] = blizzard_draw_fn_32;
- s->line_fn_tab[1] = blizzard_draw_fn_r_32;
-
- blizzard_reset(s);
-
- return s;
-}
diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c
index 3b1d922..ad2821c 100644
--- a/hw/display/bochs-display.c
+++ b/hw/display/bochs-display.c
@@ -345,14 +345,13 @@ static void bochs_display_exit(PCIDevice *dev)
graphic_console_close(s->con);
}
-static Property bochs_display_properties[] = {
+static const Property bochs_display_properties[] = {
DEFINE_PROP_SIZE("vgamem", BochsDisplayState, vgamem, 16 * MiB),
DEFINE_PROP_BOOL("edid", BochsDisplayState, enable_edid, true),
DEFINE_EDID_PROPERTIES(BochsDisplayState, edid_info),
- DEFINE_PROP_END_OF_LIST(),
};
-static void bochs_display_class_init(ObjectClass *klass, void *data)
+static void bochs_display_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -375,7 +374,7 @@ static const TypeInfo bochs_display_type_info = {
.instance_size = sizeof(BochsDisplayState),
.instance_init = bochs_display_init,
.class_init = bochs_display_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index b271faa..daeef15 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -361,20 +361,19 @@ static void cg3_reset(DeviceState *d)
qemu_irq_lower(s->irq);
}
-static Property cg3_properties[] = {
+static const Property cg3_properties[] = {
DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
DEFINE_PROP_UINT16("width", CG3State, width, -1),
DEFINE_PROP_UINT16("height", CG3State, height, -1),
DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cg3_class_init(ObjectClass *klass, void *data)
+static void cg3_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cg3_realizefn;
- dc->reset = cg3_reset;
+ device_class_set_legacy_reset(dc, cg3_reset);
dc->vmsd = &vmstate_cg3;
device_class_set_props(dc, cg3_properties);
}
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 150883a..ef08694 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -36,7 +36,7 @@
#include "qemu/module.h"
#include "qemu/units.h"
#include "qemu/log.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "qapi/error.h"
#include "trace.h"
#include "hw/pci/pci_device.h"
@@ -2982,17 +2982,16 @@ static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp)
}
}
-static Property pci_vga_cirrus_properties[] = {
+static const Property pci_vga_cirrus_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState,
cirrus_vga.vga.vram_size_mb, 4),
DEFINE_PROP_BOOL("blitter", struct PCICirrusVGAState,
cirrus_vga.enable_blitter, true),
DEFINE_PROP_BOOL("global-vmstate", struct PCICirrusVGAState,
cirrus_vga.vga.global_vmstate, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cirrus_vga_class_init(ObjectClass *klass, void *data)
+static void cirrus_vga_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -3014,7 +3013,7 @@ static const TypeInfo cirrus_vga_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCICirrusVGAState),
.class_init = cirrus_vga_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/display/cirrus_vga_isa.c b/hw/display/cirrus_vga_isa.c
index 84be516..4b55c48 100644
--- a/hw/display/cirrus_vga_isa.c
+++ b/hw/display/cirrus_vga_isa.c
@@ -69,15 +69,14 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
/* FIXME not qdev yet */
}
-static Property isa_cirrus_vga_properties[] = {
+static const Property isa_cirrus_vga_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
cirrus_vga.vga.vram_size_mb, 4),
DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState,
cirrus_vga.enable_blitter, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
+static void isa_cirrus_vga_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/display/dm163.c b/hw/display/dm163.c
index f92aee3..f8340d8 100644
--- a/hw/display/dm163.c
+++ b/hw/display/dm163.c
@@ -271,7 +271,7 @@ static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
unsigned row)
{
for (unsigned _ = 0; _ < LED_SQUARE_SIZE; _++) {
- for (int x = 0; x < RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE; x++) {
+ for (int x = RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE - 1; x >= 0; x--) {
/* UI layer guarantees that there's 32 bits per pixel (Mar 2024) */
*dest++ = s->buffer[s->buffer_idx_of_row[row]][x / LED_SQUARE_SIZE];
}
@@ -325,12 +325,12 @@ static void dm163_realize(DeviceState *dev, Error **errp)
RGB_MATRIX_NUM_ROWS * LED_SQUARE_SIZE);
}
-static void dm163_class_init(ObjectClass *klass, void *data)
+static void dm163_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
- dc->desc = "DM163";
+ dc->desc = "DM163 8x3-channel constant current LED driver";
dc->vmsd = &vmstate_dm163;
dc->realize = dm163_realize;
rc->phases.hold = dm163_reset_hold;
diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c
index aab1b1a..a157dc6 100644
--- a/hw/display/dpcd.c
+++ b/hw/display/dpcd.c
@@ -141,11 +141,11 @@ static const VMStateDescription vmstate_dpcd = {
}
};
-static void dpcd_class_init(ObjectClass *oc, void *data)
+static void dpcd_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = dpcd_reset;
+ device_class_set_legacy_reset(dc, dpcd_reset);
dc->vmsd = &vmstate_dpcd;
}
diff --git a/hw/display/edid-region.c b/hw/display/edid-region.c
index 675429d..f1596fb 100644
--- a/hw/display/edid-region.c
+++ b/hw/display/edid-region.c
@@ -1,5 +1,5 @@
#include "qemu/osdep.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/display/edid.h"
static uint64_t edid_region_read(void *ptr, hwaddr addr, unsigned size)
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 5712558..c61e028 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1925,10 +1925,9 @@ static const GraphicHwOps exynos4210_fimd_ops = {
.gfx_update = exynos4210_fimd_update,
};
-static Property exynos4210_fimd_properties[] = {
+static const Property exynos4210_fimd_properties[] = {
DEFINE_PROP_LINK("framebuffer-memory", Exynos4210fimdState, fbmem,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
static void exynos4210_fimd_init(Object *obj)
@@ -1959,12 +1958,12 @@ static void exynos4210_fimd_realize(DeviceState *dev, Error **errp)
s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s);
}
-static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
+static void exynos4210_fimd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &exynos4210_fimd_vmstate;
- dc->reset = exynos4210_fimd_reset;
+ device_class_set_legacy_reset(dc, exynos4210_fimd_reset);
dc->realize = exynos4210_fimd_realize;
device_class_set_props(dc, exynos4210_fimd_properties);
}
diff --git a/hw/display/framebuffer.h b/hw/display/framebuffer.h
index 38fa0dc..29a828c 100644
--- a/hw/display/framebuffer.h
+++ b/hw/display/framebuffer.h
@@ -1,7 +1,7 @@
#ifndef QEMU_FRAMEBUFFER_H
#define QEMU_FRAMEBUFFER_H
-#include "exec/memory.h"
+#include "system/memory.h"
/* Framebuffer device helper routines. */
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index e08ec3f..a6ddc21 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -512,9 +512,8 @@ static void g364fb_sysbus_reset(DeviceState *d)
g364fb_reset(&s->g364);
}
-static Property g364fb_sysbus_properties[] = {
+static const Property g364fb_sysbus_properties[] = {
DEFINE_PROP_UINT32("vram_size", G364SysBusState, g364.vram_size, 8 * MiB),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_g364fb_sysbus = {
@@ -527,14 +526,14 @@ static const VMStateDescription vmstate_g364fb_sysbus = {
}
};
-static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
+static void g364fb_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = g364fb_sysbus_realize;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "G364 framebuffer";
- dc->reset = g364fb_sysbus_reset;
+ device_class_set_legacy_reset(dc, g364fb_sysbus_reset);
dc->vmsd = &vmstate_g364fb_sysbus;
device_class_set_props(dc, g364fb_sysbus_properties);
}
diff --git a/hw/display/i2c-ddc.c b/hw/display/i2c-ddc.c
index 3f9d1e1..2adfc1a 100644
--- a/hw/display/i2c-ddc.c
+++ b/hw/display/i2c-ddc.c
@@ -95,17 +95,16 @@ static const VMStateDescription vmstate_i2c_ddc = {
}
};
-static Property i2c_ddc_properties[] = {
+static const Property i2c_ddc_properties[] = {
DEFINE_EDID_PROPERTIES(I2CDDCState, edid_info),
- DEFINE_PROP_END_OF_LIST(),
};
-static void i2c_ddc_class_init(ObjectClass *oc, void *data)
+static void i2c_ddc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
- dc->reset = i2c_ddc_reset;
+ device_class_set_legacy_reset(dc, i2c_ddc_reset);
dc->vmsd = &vmstate_i2c_ddc;
device_class_set_props(dc, i2c_ddc_properties);
isc->event = i2c_ddc_event;
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index 534f15d..90e82b5 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -294,13 +294,13 @@ static void jazz_led_reset(DeviceState *d)
qemu_console_resize(s->con, 60, 80);
}
-static void jazz_led_class_init(ObjectClass *klass, void *data)
+static void jazz_led_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "Jazz LED display",
dc->vmsd = &vmstate_jazz_led;
- dc->reset = jazz_led_reset;
+ device_class_set_legacy_reset(dc, jazz_led_reset);
dc->realize = jazz_led_realize;
}
diff --git a/hw/display/macfb.c b/hw/display/macfb.c
index 1ace341..574d667 100644
--- a/hw/display/macfb.c
+++ b/hw/display/macfb.c
@@ -383,7 +383,6 @@ static void macfb_sense_write(MacfbState *s, uint32_t val)
s->regs[DAFB_MODE_SENSE >> 2] = val;
trace_macfb_sense_write(val);
- return;
}
static void macfb_update_mode(MacfbState *s)
@@ -758,13 +757,12 @@ static void macfb_nubus_reset(DeviceState *d)
macfb_reset(&s->macfb);
}
-static Property macfb_sysbus_properties[] = {
+static const Property macfb_sysbus_properties[] = {
DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640),
DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480),
DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8),
DEFINE_PROP_UINT8("display", MacfbSysBusState, macfb.type,
MACFB_DISPLAY_VGA),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_macfb_sysbus = {
@@ -777,13 +775,12 @@ static const VMStateDescription vmstate_macfb_sysbus = {
}
};
-static Property macfb_nubus_properties[] = {
+static const Property macfb_nubus_properties[] = {
DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640),
DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480),
DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8),
DEFINE_PROP_UINT8("display", MacfbNubusState, macfb.type,
MACFB_DISPLAY_VGA),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_macfb_nubus = {
@@ -796,18 +793,18 @@ static const VMStateDescription vmstate_macfb_nubus = {
}
};
-static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
+static void macfb_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = macfb_sysbus_realize;
dc->desc = "SysBus Macintosh framebuffer";
- dc->reset = macfb_sysbus_reset;
+ device_class_set_legacy_reset(dc, macfb_sysbus_reset);
dc->vmsd = &vmstate_macfb_sysbus;
device_class_set_props(dc, macfb_sysbus_properties);
}
-static void macfb_nubus_class_init(ObjectClass *klass, void *data)
+static void macfb_nubus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
MacfbNubusDeviceClass *ndc = NUBUS_MACFB_CLASS(klass);
@@ -817,7 +814,7 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data)
device_class_set_parent_unrealize(dc, macfb_nubus_unrealize,
&ndc->parent_unrealize);
dc->desc = "Nubus Macintosh framebuffer";
- dc->reset = macfb_nubus_reset;
+ device_class_set_legacy_reset(dc, macfb_nubus_reset);
dc->vmsd = &vmstate_macfb_nubus;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
device_class_set_props(dc, macfb_nubus_properties);
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 7db05ea..90e6c04 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -22,13 +22,9 @@ system_ss.add(when: 'CONFIG_VGA_MMIO', if_true: files('vga-mmio.c'))
system_ss.add(when: 'CONFIG_VMWARE_VGA', if_true: files('vmware_vga.c'))
system_ss.add(when: 'CONFIG_BOCHS_DISPLAY', if_true: files('bochs-display.c'))
-system_ss.add(when: 'CONFIG_BLIZZARD', if_true: files('blizzard.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_fimd.c'))
system_ss.add(when: 'CONFIG_FRAMEBUFFER', if_true: files('framebuffer.c'))
-system_ss.add(when: 'CONFIG_ZAURUS', if_true: files('tc6393xb.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dss.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_lcd.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_fb.c'))
system_ss.add(when: 'CONFIG_SM501', if_true: files('sm501.c'))
system_ss.add(when: 'CONFIG_TCX', if_true: files('tcx.c'))
@@ -65,6 +61,8 @@ system_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c'))
system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c', 'ati_dbg.c'), pixman])
+system_ss.add(when: [pvg, 'CONFIG_MAC_PVG_PCI'], if_true: [files('apple-gfx.m', 'apple-gfx-pci.m')])
+system_ss.add(when: [pvg, 'CONFIG_MAC_PVG_MMIO'], if_true: [files('apple-gfx.m', 'apple-gfx-mmio.m')])
if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
virtio_gpu_ss = ss.source_set()
diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c
index 8446ff3..ec81b76 100644
--- a/hw/display/next-fb.c
+++ b/hw/display/next-fb.c
@@ -119,7 +119,7 @@ static void nextfb_realize(DeviceState *dev, Error **errp)
qemu_console_resize(s->con, s->cols, s->rows);
}
-static void nextfb_class_init(ObjectClass *oc, void *data)
+static void nextfb_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c
deleted file mode 100644
index f33fc76..0000000
--- a/hw/display/omap_dss.c
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
- * OMAP2 Display Subsystem.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-
-struct omap_dss_s {
- qemu_irq irq;
- qemu_irq drq;
- DisplayState *state;
- MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
-
- int autoidle;
- int control;
- int enable;
-
- struct omap_dss_panel_s {
- int enable;
- int nx;
- int ny;
-
- int x;
- int y;
- } dig, lcd;
-
- struct {
- uint32_t idlemode;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t control;
- uint32_t config;
- uint32_t capable;
- uint32_t timing[4];
- int line;
- uint32_t bg[2];
- uint32_t trans[2];
-
- struct omap_dss_plane_s {
- int enable;
- int bpp;
- int posx;
- int posy;
- int nx;
- int ny;
-
- hwaddr addr[3];
-
- uint32_t attr;
- uint32_t tresh;
- int rowinc;
- int colinc;
- int wininc;
- } l[3];
-
- int invalidate;
- uint16_t palette[256];
- } dispc;
-
- struct {
- int idlemode;
- uint32_t control;
- int enable;
- int pixels;
- int busy;
- int skiplines;
- uint16_t rxbuf;
- uint32_t config[2];
- uint32_t time[4];
- uint32_t data[6];
- uint16_t vsync;
- uint16_t hsync;
- struct rfbi_chip_s *chip[2];
- } rfbi;
-};
-
-static void omap_dispc_interrupt_update(struct omap_dss_s *s)
-{
- qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
-}
-
-static void omap_rfbi_reset(struct omap_dss_s *s)
-{
- s->rfbi.idlemode = 0;
- s->rfbi.control = 2;
- s->rfbi.enable = 0;
- s->rfbi.pixels = 0;
- s->rfbi.skiplines = 0;
- s->rfbi.busy = 0;
- s->rfbi.config[0] = 0x00310000;
- s->rfbi.config[1] = 0x00310000;
- s->rfbi.time[0] = 0;
- s->rfbi.time[1] = 0;
- s->rfbi.time[2] = 0;
- s->rfbi.time[3] = 0;
- s->rfbi.data[0] = 0;
- s->rfbi.data[1] = 0;
- s->rfbi.data[2] = 0;
- s->rfbi.data[3] = 0;
- s->rfbi.data[4] = 0;
- s->rfbi.data[5] = 0;
- s->rfbi.vsync = 0;
- s->rfbi.hsync = 0;
-}
-
-void omap_dss_reset(struct omap_dss_s *s)
-{
- s->autoidle = 0;
- s->control = 0;
- s->enable = 0;
-
- s->dig.enable = 0;
- s->dig.nx = 1;
- s->dig.ny = 1;
-
- s->lcd.enable = 0;
- s->lcd.nx = 1;
- s->lcd.ny = 1;
-
- s->dispc.idlemode = 0;
- s->dispc.irqst = 0;
- s->dispc.irqen = 0;
- s->dispc.control = 0;
- s->dispc.config = 0;
- s->dispc.capable = 0x161;
- s->dispc.timing[0] = 0;
- s->dispc.timing[1] = 0;
- s->dispc.timing[2] = 0;
- s->dispc.timing[3] = 0;
- s->dispc.line = 0;
- s->dispc.bg[0] = 0;
- s->dispc.bg[1] = 0;
- s->dispc.trans[0] = 0;
- s->dispc.trans[1] = 0;
-
- s->dispc.l[0].enable = 0;
- s->dispc.l[0].bpp = 0;
- s->dispc.l[0].addr[0] = 0;
- s->dispc.l[0].addr[1] = 0;
- s->dispc.l[0].addr[2] = 0;
- s->dispc.l[0].posx = 0;
- s->dispc.l[0].posy = 0;
- s->dispc.l[0].nx = 1;
- s->dispc.l[0].ny = 1;
- s->dispc.l[0].attr = 0;
- s->dispc.l[0].tresh = 0;
- s->dispc.l[0].rowinc = 1;
- s->dispc.l[0].colinc = 1;
- s->dispc.l[0].wininc = 0;
-
- omap_rfbi_reset(s);
- omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_diss_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* DSS_REVISIONNUMBER */
- return 0x20;
-
- case 0x10: /* DSS_SYSCONFIG */
- return s->autoidle;
-
- case 0x14: /* DSS_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* DSS_CONTROL */
- return s->control;
-
- case 0x50: /* DSS_PSA_LCD_REG_1 */
- case 0x54: /* DSS_PSA_LCD_REG_2 */
- case 0x58: /* DSS_PSA_VIDEO_REG */
- /* TODO: fake some values when appropriate s->control bits are set */
- return 0;
-
- case 0x5c: /* DSS_STATUS */
- return 1 + (s->control & 1);
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_diss_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* DSS_REVISIONNUMBER */
- case 0x14: /* DSS_SYSSTATUS */
- case 0x50: /* DSS_PSA_LCD_REG_1 */
- case 0x54: /* DSS_PSA_LCD_REG_2 */
- case 0x58: /* DSS_PSA_VIDEO_REG */
- case 0x5c: /* DSS_STATUS */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* DSS_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->autoidle = value & 1;
- break;
-
- case 0x40: /* DSS_CONTROL */
- s->control = value & 0x3dd;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_diss_ops = {
- .read = omap_diss_read,
- .write = omap_diss_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_disc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* DISPC_REVISION */
- return 0x20;
-
- case 0x010: /* DISPC_SYSCONFIG */
- return s->dispc.idlemode;
-
- case 0x014: /* DISPC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x018: /* DISPC_IRQSTATUS */
- return s->dispc.irqst;
-
- case 0x01c: /* DISPC_IRQENABLE */
- return s->dispc.irqen;
-
- case 0x040: /* DISPC_CONTROL */
- return s->dispc.control;
-
- case 0x044: /* DISPC_CONFIG */
- return s->dispc.config;
-
- case 0x048: /* DISPC_CAPABLE */
- return s->dispc.capable;
-
- case 0x04c: /* DISPC_DEFAULT_COLOR0 */
- return s->dispc.bg[0];
- case 0x050: /* DISPC_DEFAULT_COLOR1 */
- return s->dispc.bg[1];
- case 0x054: /* DISPC_TRANS_COLOR0 */
- return s->dispc.trans[0];
- case 0x058: /* DISPC_TRANS_COLOR1 */
- return s->dispc.trans[1];
-
- case 0x05c: /* DISPC_LINE_STATUS */
- return 0x7ff;
- case 0x060: /* DISPC_LINE_NUMBER */
- return s->dispc.line;
-
- case 0x064: /* DISPC_TIMING_H */
- return s->dispc.timing[0];
- case 0x068: /* DISPC_TIMING_V */
- return s->dispc.timing[1];
- case 0x06c: /* DISPC_POL_FREQ */
- return s->dispc.timing[2];
- case 0x070: /* DISPC_DIVISOR */
- return s->dispc.timing[3];
-
- case 0x078: /* DISPC_SIZE_DIG */
- return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
- case 0x07c: /* DISPC_SIZE_LCD */
- return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
-
- case 0x080: /* DISPC_GFX_BA0 */
- return s->dispc.l[0].addr[0];
- case 0x084: /* DISPC_GFX_BA1 */
- return s->dispc.l[0].addr[1];
- case 0x088: /* DISPC_GFX_POSITION */
- return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
- case 0x08c: /* DISPC_GFX_SIZE */
- return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
- case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- return s->dispc.l[0].attr;
- case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- return s->dispc.l[0].tresh;
- case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
- return 256;
- case 0x0ac: /* DISPC_GFX_ROW_INC */
- return s->dispc.l[0].rowinc;
- case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- return s->dispc.l[0].colinc;
- case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- return s->dispc.l[0].wininc;
- case 0x0b8: /* DISPC_GFX_TABLE_BA */
- return s->dispc.l[0].addr[2];
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
- case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
- case 0x170: /* DISPC_VID2_FIR */
- case 0x174: /* DISPC_VID2_PICTURE_SIZE */
- case 0x178: /* DISPC_VID2_ACCU0 */
- case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
- case 0x1d4: /* DISPC_DATA_CYCLE1 */
- case 0x1d8: /* DISPC_DATA_CYCLE2 */
- case 0x1dc: /* DISPC_DATA_CYCLE3 */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_disc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x010: /* DISPC_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->dispc.idlemode = value & 0x301b;
- break;
-
- case 0x018: /* DISPC_IRQSTATUS */
- s->dispc.irqst &= ~value;
- omap_dispc_interrupt_update(s);
- break;
-
- case 0x01c: /* DISPC_IRQENABLE */
- s->dispc.irqen = value & 0xffff;
- omap_dispc_interrupt_update(s);
- break;
-
- case 0x040: /* DISPC_CONTROL */
- s->dispc.control = value & 0x07ff9fff;
- s->dig.enable = (value >> 1) & 1;
- s->lcd.enable = (value >> 0) & 1;
- if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */
- if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
- fprintf(stderr, "%s: Overlay Optimization when no overlay "
- "region effectively exists leads to "
- "unpredictable behaviour!\n", __func__);
- }
- if (value & (1 << 6)) { /* GODIGITAL */
- /* XXX: Shadowed fields are:
- * s->dispc.config
- * s->dispc.capable
- * s->dispc.bg[0]
- * s->dispc.bg[1]
- * s->dispc.trans[0]
- * s->dispc.trans[1]
- * s->dispc.line
- * s->dispc.timing[0]
- * s->dispc.timing[1]
- * s->dispc.timing[2]
- * s->dispc.timing[3]
- * s->lcd.nx
- * s->lcd.ny
- * s->dig.nx
- * s->dig.ny
- * s->dispc.l[0].addr[0]
- * s->dispc.l[0].addr[1]
- * s->dispc.l[0].addr[2]
- * s->dispc.l[0].posx
- * s->dispc.l[0].posy
- * s->dispc.l[0].nx
- * s->dispc.l[0].ny
- * s->dispc.l[0].tresh
- * s->dispc.l[0].rowinc
- * s->dispc.l[0].colinc
- * s->dispc.l[0].wininc
- * All they need to be loaded here from their shadow registers.
- */
- }
- if (value & (1 << 5)) { /* GOLCD */
- /* XXX: Likewise for LCD here. */
- }
- s->dispc.invalidate = 1;
- break;
-
- case 0x044: /* DISPC_CONFIG */
- s->dispc.config = value & 0x3fff;
- /* XXX:
- * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
- * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
- */
- s->dispc.invalidate = 1;
- break;
-
- case 0x048: /* DISPC_CAPABLE */
- s->dispc.capable = value & 0x3ff;
- break;
-
- case 0x04c: /* DISPC_DEFAULT_COLOR0 */
- s->dispc.bg[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x050: /* DISPC_DEFAULT_COLOR1 */
- s->dispc.bg[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x054: /* DISPC_TRANS_COLOR0 */
- s->dispc.trans[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x058: /* DISPC_TRANS_COLOR1 */
- s->dispc.trans[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
-
- case 0x060: /* DISPC_LINE_NUMBER */
- s->dispc.line = value & 0x7ff;
- break;
-
- case 0x064: /* DISPC_TIMING_H */
- s->dispc.timing[0] = value & 0x0ff0ff3f;
- break;
- case 0x068: /* DISPC_TIMING_V */
- s->dispc.timing[1] = value & 0x0ff0ff3f;
- break;
- case 0x06c: /* DISPC_POL_FREQ */
- s->dispc.timing[2] = value & 0x0003ffff;
- break;
- case 0x070: /* DISPC_DIVISOR */
- s->dispc.timing[3] = value & 0x00ff00ff;
- break;
-
- case 0x078: /* DISPC_SIZE_DIG */
- s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
- break;
- case 0x07c: /* DISPC_SIZE_LCD */
- s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
- break;
- case 0x080: /* DISPC_GFX_BA0 */
- s->dispc.l[0].addr[0] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
- case 0x084: /* DISPC_GFX_BA1 */
- s->dispc.l[0].addr[1] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
- case 0x088: /* DISPC_GFX_POSITION */
- s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */
- s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */
- s->dispc.invalidate = 1;
- break;
- case 0x08c: /* DISPC_GFX_SIZE */
- s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */
- s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */
- s->dispc.invalidate = 1;
- break;
- case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- s->dispc.l[0].attr = value & 0x7ff;
- if (value & (3 << 9))
- fprintf(stderr, "%s: Big-endian pixel format not supported\n",
- __func__);
- s->dispc.l[0].enable = value & 1;
- s->dispc.l[0].bpp = (value >> 1) & 0xf;
- s->dispc.invalidate = 1;
- break;
- case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- s->dispc.l[0].tresh = value & 0x01ff01ff;
- break;
- case 0x0ac: /* DISPC_GFX_ROW_INC */
- s->dispc.l[0].rowinc = value;
- s->dispc.invalidate = 1;
- break;
- case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- s->dispc.l[0].colinc = value;
- s->dispc.invalidate = 1;
- break;
- case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- s->dispc.l[0].wininc = value;
- break;
- case 0x0b8: /* DISPC_GFX_TABLE_BA */
- s->dispc.l[0].addr[2] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
- case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
- case 0x170: /* DISPC_VID2_FIR */
- case 0x174: /* DISPC_VID2_PICTURE_SIZE */
- case 0x178: /* DISPC_VID2_ACCU0 */
- case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
- case 0x1d4: /* DISPC_DATA_CYCLE1 */
- case 0x1d8: /* DISPC_DATA_CYCLE2 */
- case 0x1dc: /* DISPC_DATA_CYCLE3 */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_disc_ops = {
- .read = omap_disc_read,
- .write = omap_disc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
-{
- if (!s->rfbi.busy)
- return;
-
- /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */
-
- s->rfbi.busy = 0;
-}
-
-static void omap_rfbi_transfer_start(struct omap_dss_s *s)
-{
- void *data;
- hwaddr len;
- hwaddr data_addr;
- int pitch;
- static void *bounce_buffer;
- static hwaddr bounce_len;
-
- if (!s->rfbi.enable || s->rfbi.busy)
- return;
-
- if (s->rfbi.control & (1 << 1)) { /* BYPASS */
- /* TODO: in non-Bypass mode we probably need to just assert the
- * DRQ and wait for DMA to write the pixels. */
- qemu_log_mask(LOG_UNIMP, "%s: Bypass mode unimplemented\n", __func__);
- return;
- }
-
- if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */
- return;
- /* TODO: check that LCD output is enabled in DISPC. */
-
- s->rfbi.busy = 1;
-
- len = s->rfbi.pixels * 2;
-
- data_addr = s->dispc.l[0].addr[0];
- data = cpu_physical_memory_map(data_addr, &len, false);
- if (data && len != s->rfbi.pixels * 2) {
- cpu_physical_memory_unmap(data, len, 0, 0);
- data = NULL;
- len = s->rfbi.pixels * 2;
- }
- if (!data) {
- if (len > bounce_len) {
- bounce_buffer = g_realloc(bounce_buffer, len);
- }
- data = bounce_buffer;
- cpu_physical_memory_read(data_addr, data, len);
- }
-
- /* TODO bpp */
- s->rfbi.pixels = 0;
-
- /* TODO: negative values */
- pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
-
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
-
- if (data != bounce_buffer) {
- cpu_physical_memory_unmap(data, len, 0, len);
- }
-
- omap_rfbi_transfer_stop(s);
-
- /* TODO */
- s->dispc.irqst |= 1; /* FRAMEDONE */
- omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_rfbi_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* RFBI_REVISION */
- return 0x10;
-
- case 0x10: /* RFBI_SYSCONFIG */
- return s->rfbi.idlemode;
-
- case 0x14: /* RFBI_SYSSTATUS */
- return 1 | (s->rfbi.busy << 8); /* RESETDONE */
-
- case 0x40: /* RFBI_CONTROL */
- return s->rfbi.control;
-
- case 0x44: /* RFBI_PIXELCNT */
- return s->rfbi.pixels;
-
- case 0x48: /* RFBI_LINE_NUMBER */
- return s->rfbi.skiplines;
-
- case 0x58: /* RFBI_READ */
- case 0x5c: /* RFBI_STATUS */
- return s->rfbi.rxbuf;
-
- case 0x60: /* RFBI_CONFIG0 */
- return s->rfbi.config[0];
- case 0x64: /* RFBI_ONOFF_TIME0 */
- return s->rfbi.time[0];
- case 0x68: /* RFBI_CYCLE_TIME0 */
- return s->rfbi.time[1];
- case 0x6c: /* RFBI_DATA_CYCLE1_0 */
- return s->rfbi.data[0];
- case 0x70: /* RFBI_DATA_CYCLE2_0 */
- return s->rfbi.data[1];
- case 0x74: /* RFBI_DATA_CYCLE3_0 */
- return s->rfbi.data[2];
-
- case 0x78: /* RFBI_CONFIG1 */
- return s->rfbi.config[1];
- case 0x7c: /* RFBI_ONOFF_TIME1 */
- return s->rfbi.time[2];
- case 0x80: /* RFBI_CYCLE_TIME1 */
- return s->rfbi.time[3];
- case 0x84: /* RFBI_DATA_CYCLE1_1 */
- return s->rfbi.data[3];
- case 0x88: /* RFBI_DATA_CYCLE2_1 */
- return s->rfbi.data[4];
- case 0x8c: /* RFBI_DATA_CYCLE3_1 */
- return s->rfbi.data[5];
-
- case 0x90: /* RFBI_VSYNC_WIDTH */
- return s->rfbi.vsync;
- case 0x94: /* RFBI_HSYNC_WIDTH */
- return s->rfbi.hsync;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_rfbi_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x10: /* RFBI_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_rfbi_reset(s);
- s->rfbi.idlemode = value & 0x19;
- break;
-
- case 0x40: /* RFBI_CONTROL */
- s->rfbi.control = value & 0xf;
- s->rfbi.enable = value & 1;
- if (value & (1 << 4) && /* ITE */
- !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
- omap_rfbi_transfer_start(s);
- break;
-
- case 0x44: /* RFBI_PIXELCNT */
- s->rfbi.pixels = value;
- break;
-
- case 0x48: /* RFBI_LINE_NUMBER */
- s->rfbi.skiplines = value & 0x7ff;
- break;
-
- case 0x4c: /* RFBI_CMD */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
- break;
- case 0x50: /* RFBI_PARAM */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
- break;
- case 0x54: /* RFBI_DATA */
- /* TODO: take into account the format set up in s->rfbi.config[?] and
- * s->rfbi.data[?], but special-case the most usual scenario so that
- * speed doesn't suffer. */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
- }
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
- }
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
- case 0x58: /* RFBI_READ */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
- else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
-
- case 0x5c: /* RFBI_STATUS */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
- else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
-
- case 0x60: /* RFBI_CONFIG0 */
- s->rfbi.config[0] = value & 0x003f1fff;
- break;
-
- case 0x64: /* RFBI_ONOFF_TIME0 */
- s->rfbi.time[0] = value & 0x3fffffff;
- break;
- case 0x68: /* RFBI_CYCLE_TIME0 */
- s->rfbi.time[1] = value & 0x0fffffff;
- break;
- case 0x6c: /* RFBI_DATA_CYCLE1_0 */
- s->rfbi.data[0] = value & 0x0f1f0f1f;
- break;
- case 0x70: /* RFBI_DATA_CYCLE2_0 */
- s->rfbi.data[1] = value & 0x0f1f0f1f;
- break;
- case 0x74: /* RFBI_DATA_CYCLE3_0 */
- s->rfbi.data[2] = value & 0x0f1f0f1f;
- break;
- case 0x78: /* RFBI_CONFIG1 */
- s->rfbi.config[1] = value & 0x003f1fff;
- break;
-
- case 0x7c: /* RFBI_ONOFF_TIME1 */
- s->rfbi.time[2] = value & 0x3fffffff;
- break;
- case 0x80: /* RFBI_CYCLE_TIME1 */
- s->rfbi.time[3] = value & 0x0fffffff;
- break;
- case 0x84: /* RFBI_DATA_CYCLE1_1 */
- s->rfbi.data[3] = value & 0x0f1f0f1f;
- break;
- case 0x88: /* RFBI_DATA_CYCLE2_1 */
- s->rfbi.data[4] = value & 0x0f1f0f1f;
- break;
- case 0x8c: /* RFBI_DATA_CYCLE3_1 */
- s->rfbi.data[5] = value & 0x0f1f0f1f;
- break;
-
- case 0x90: /* RFBI_VSYNC_WIDTH */
- s->rfbi.vsync = value & 0xffff;
- break;
- case 0x94: /* RFBI_HSYNC_WIDTH */
- s->rfbi.hsync = value & 0xffff;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_rfbi_ops = {
- .read = omap_rfbi_read,
- .write = omap_rfbi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_venc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* REV_ID */
- case 0x04: /* STATUS */
- case 0x08: /* F_CONTROL */
- case 0x10: /* VIDOUT_CTRL */
- case 0x14: /* SYNC_CTRL */
- case 0x1c: /* LLEN */
- case 0x20: /* FLENS */
- case 0x24: /* HFLTR_CTRL */
- case 0x28: /* CC_CARR_WSS_CARR */
- case 0x2c: /* C_PHASE */
- case 0x30: /* GAIN_U */
- case 0x34: /* GAIN_V */
- case 0x38: /* GAIN_Y */
- case 0x3c: /* BLACK_LEVEL */
- case 0x40: /* BLANK_LEVEL */
- case 0x44: /* X_COLOR */
- case 0x48: /* M_CONTROL */
- case 0x4c: /* BSTAMP_WSS_DATA */
- case 0x50: /* S_CARR */
- case 0x54: /* LINE21 */
- case 0x58: /* LN_SEL */
- case 0x5c: /* L21__WC_CTL */
- case 0x60: /* HTRIGGER_VTRIGGER */
- case 0x64: /* SAVID__EAVID */
- case 0x68: /* FLEN__FAL */
- case 0x6c: /* LAL__PHASE_RESET */
- case 0x70: /* HS_INT_START_STOP_X */
- case 0x74: /* HS_EXT_START_STOP_X */
- case 0x78: /* VS_INT_START_X */
- case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
- case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
- case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
- case 0x88: /* VS_EXT_STOP_Y */
- case 0x90: /* AVID_START_STOP_X */
- case 0x94: /* AVID_START_STOP_Y */
- case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
- case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
- case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
- case 0xb0: /* TVDETGP_INT_START_STOP_X */
- case 0xb4: /* TVDETGP_INT_START_STOP_Y */
- case 0xb8: /* GEN_CTRL */
- case 0xc4: /* DAC_TST__DAC_A */
- case 0xc8: /* DAC_B__DAC_C */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_venc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, size);
- return;
- }
-
- switch (addr) {
- case 0x08: /* F_CONTROL */
- case 0x10: /* VIDOUT_CTRL */
- case 0x14: /* SYNC_CTRL */
- case 0x1c: /* LLEN */
- case 0x20: /* FLENS */
- case 0x24: /* HFLTR_CTRL */
- case 0x28: /* CC_CARR_WSS_CARR */
- case 0x2c: /* C_PHASE */
- case 0x30: /* GAIN_U */
- case 0x34: /* GAIN_V */
- case 0x38: /* GAIN_Y */
- case 0x3c: /* BLACK_LEVEL */
- case 0x40: /* BLANK_LEVEL */
- case 0x44: /* X_COLOR */
- case 0x48: /* M_CONTROL */
- case 0x4c: /* BSTAMP_WSS_DATA */
- case 0x50: /* S_CARR */
- case 0x54: /* LINE21 */
- case 0x58: /* LN_SEL */
- case 0x5c: /* L21__WC_CTL */
- case 0x60: /* HTRIGGER_VTRIGGER */
- case 0x64: /* SAVID__EAVID */
- case 0x68: /* FLEN__FAL */
- case 0x6c: /* LAL__PHASE_RESET */
- case 0x70: /* HS_INT_START_STOP_X */
- case 0x74: /* HS_EXT_START_STOP_X */
- case 0x78: /* VS_INT_START_X */
- case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
- case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
- case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
- case 0x88: /* VS_EXT_STOP_Y */
- case 0x90: /* AVID_START_STOP_X */
- case 0x94: /* AVID_START_STOP_Y */
- case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
- case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
- case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
- case 0xb0: /* TVDETGP_INT_START_STOP_X */
- case 0xb4: /* TVDETGP_INT_START_STOP_Y */
- case 0xb8: /* GEN_CTRL */
- case 0xc4: /* DAC_TST__DAC_A */
- case 0xc8: /* DAC_B__DAC_C */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_venc_ops = {
- .read = omap_venc_read,
- .write = omap_venc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_im3_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x0a8: /* SBIMERRLOGA */
- case 0x0b0: /* SBIMERRLOG */
- case 0x190: /* SBIMSTATE */
- case 0x198: /* SBTMSTATE_L */
- case 0x19c: /* SBTMSTATE_H */
- case 0x1a8: /* SBIMCONFIG_L */
- case 0x1ac: /* SBIMCONFIG_H */
- case 0x1f8: /* SBID_L */
- case 0x1fc: /* SBID_H */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_im3_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x0b0: /* SBIMERRLOG */
- case 0x190: /* SBIMSTATE */
- case 0x198: /* SBTMSTATE_L */
- case 0x19c: /* SBTMSTATE_H */
- case 0x1a8: /* SBIMCONFIG_L */
- case 0x1ac: /* SBIMCONFIG_H */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_im3_ops = {
- .read = omap_im3_read,
- .write = omap_im3_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- hwaddr l3_base,
- qemu_irq irq, qemu_irq drq,
- omap_clk fck1, omap_clk fck2, omap_clk ck54m,
- omap_clk ick1, omap_clk ick2)
-{
- struct omap_dss_s *s = g_new0(struct omap_dss_s, 1);
-
- s->irq = irq;
- s->drq = drq;
- omap_dss_reset(s);
-
- memory_region_init_io(&s->iomem_diss1, NULL, &omap_diss_ops, s, "omap.diss1",
- omap_l4_region_size(ta, 0));
- memory_region_init_io(&s->iomem_disc1, NULL, &omap_disc_ops, s, "omap.disc1",
- omap_l4_region_size(ta, 1));
- memory_region_init_io(&s->iomem_rfbi1, NULL, &omap_rfbi_ops, s, "omap.rfbi1",
- omap_l4_region_size(ta, 2));
- memory_region_init_io(&s->iomem_venc1, NULL, &omap_venc_ops, s, "omap.venc1",
- omap_l4_region_size(ta, 3));
- memory_region_init_io(&s->iomem_im3, NULL, &omap_im3_ops, s,
- "omap.im3", 0x1000);
-
- omap_l4_attach(ta, 0, &s->iomem_diss1);
- omap_l4_attach(ta, 1, &s->iomem_disc1);
- omap_l4_attach(ta, 2, &s->iomem_rfbi1);
- omap_l4_attach(ta, 3, &s->iomem_venc1);
- memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
-
-#if 0
- s->state = graphic_console_init(omap_update_display,
- omap_invalidate_display, omap_screen_dump, s);
-#endif
-
- return s;
-}
-
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
-{
- if (cs < 0 || cs > 1)
- hw_error("%s: wrong CS %i\n", __func__, cs);
- s->rfbi.chip[cs] = chip;
-}
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index 7f145bb..09c3c59 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -535,10 +535,9 @@ static const GraphicHwOps pl110_gfx_ops = {
.gfx_update = pl110_update_display,
};
-static Property pl110_properties[] = {
+static const Property pl110_properties[] = {
DEFINE_PROP_LINK("framebuffer-memory", PL110State, fbmem,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
static void pl110_realize(DeviceState *dev, Error **errp)
@@ -581,7 +580,7 @@ static void pl111_init(Object *obj)
s->version = VERSION_PL111;
}
-static void pl110_class_init(ObjectClass *klass, void *data)
+static void pl110_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
deleted file mode 100644
index a9d0d98..0000000
--- a/hw/display/pxa2xx_lcd.c
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- * Intel XScale PXA255/270 LCDC emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "ui/console.h"
-#include "hw/arm/pxa.h"
-#include "ui/pixel_ops.h"
-#include "hw/boards.h"
-/* FIXME: For graphic_rotate. Should probably be done in common code. */
-#include "sysemu/sysemu.h"
-#include "framebuffer.h"
-
-struct DMAChannel {
- uint32_t branch;
- uint8_t up;
- uint8_t palette[1024];
- uint8_t pbuffer[1024];
- void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
- int *miny, int *maxy);
-
- uint32_t descriptor;
- uint32_t source;
- uint32_t id;
- uint32_t command;
-};
-
-struct PXA2xxLCDState {
- MemoryRegion *sysmem;
- MemoryRegion iomem;
- MemoryRegionSection fbsection;
- qemu_irq irq;
- int irqlevel;
-
- int invalidated;
- QemuConsole *con;
- int dest_width;
- int xres, yres;
- int pal_for;
- int transp;
- enum {
- pxa_lcdc_2bpp = 1,
- pxa_lcdc_4bpp = 2,
- pxa_lcdc_8bpp = 3,
- pxa_lcdc_16bpp = 4,
- pxa_lcdc_18bpp = 5,
- pxa_lcdc_18pbpp = 6,
- pxa_lcdc_19bpp = 7,
- pxa_lcdc_19pbpp = 8,
- pxa_lcdc_24bpp = 9,
- pxa_lcdc_25bpp = 10,
- } bpp;
-
- uint32_t control[6];
- uint32_t status[2];
- uint32_t ovl1c[2];
- uint32_t ovl2c[2];
- uint32_t ccr;
- uint32_t cmdcr;
- uint32_t trgbr;
- uint32_t tcr;
- uint32_t liidr;
- uint8_t bscntr;
-
- struct DMAChannel dma_ch[7];
-
- qemu_irq vsync_cb;
- int orientation;
-};
-
-typedef struct QEMU_PACKED {
- uint32_t fdaddr;
- uint32_t fsaddr;
- uint32_t fidr;
- uint32_t ldcmd;
-} PXAFrameDescriptor;
-
-#define LCCR0 0x000 /* LCD Controller Control register 0 */
-#define LCCR1 0x004 /* LCD Controller Control register 1 */
-#define LCCR2 0x008 /* LCD Controller Control register 2 */
-#define LCCR3 0x00c /* LCD Controller Control register 3 */
-#define LCCR4 0x010 /* LCD Controller Control register 4 */
-#define LCCR5 0x014 /* LCD Controller Control register 5 */
-
-#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */
-#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */
-#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */
-#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */
-#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */
-#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */
-#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */
-
-#define LCSR1 0x034 /* LCD Controller Status register 1 */
-#define LCSR0 0x038 /* LCD Controller Status register 0 */
-#define LIIDR 0x03c /* LCD Controller Interrupt ID register */
-
-#define TRGBR 0x040 /* TMED RGB Seed register */
-#define TCR 0x044 /* TMED Control register */
-
-#define OVL1C1 0x050 /* Overlay 1 Control register 1 */
-#define OVL1C2 0x060 /* Overlay 1 Control register 2 */
-#define OVL2C1 0x070 /* Overlay 2 Control register 1 */
-#define OVL2C2 0x080 /* Overlay 2 Control register 2 */
-#define CCR 0x090 /* Cursor Control register */
-
-#define CMDCR 0x100 /* Command Control register */
-#define PRSR 0x104 /* Panel Read Status register */
-
-#define PXA_LCDDMA_CHANS 7
-#define DMA_FDADR 0x00 /* Frame Descriptor Address register */
-#define DMA_FSADR 0x04 /* Frame Source Address register */
-#define DMA_FIDR 0x08 /* Frame ID register */
-#define DMA_LDCMD 0x0c /* Command register */
-
-/* LCD Buffer Strength Control register */
-#define BSCNTR 0x04000054
-
-/* Bitfield masks */
-#define LCCR0_ENB (1 << 0)
-#define LCCR0_CMS (1 << 1)
-#define LCCR0_SDS (1 << 2)
-#define LCCR0_LDM (1 << 3)
-#define LCCR0_SOFM0 (1 << 4)
-#define LCCR0_IUM (1 << 5)
-#define LCCR0_EOFM0 (1 << 6)
-#define LCCR0_PAS (1 << 7)
-#define LCCR0_DPD (1 << 9)
-#define LCCR0_DIS (1 << 10)
-#define LCCR0_QDM (1 << 11)
-#define LCCR0_PDD (0xff << 12)
-#define LCCR0_BSM0 (1 << 20)
-#define LCCR0_OUM (1 << 21)
-#define LCCR0_LCDT (1 << 22)
-#define LCCR0_RDSTM (1 << 23)
-#define LCCR0_CMDIM (1 << 24)
-#define LCCR0_OUC (1 << 25)
-#define LCCR0_LDDALT (1 << 26)
-#define LCCR1_PPL(x) ((x) & 0x3ff)
-#define LCCR2_LPP(x) ((x) & 0x3ff)
-#define LCCR3_API (15 << 16)
-#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8))
-#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
-#define LCCR4_K1(x) (((x) >> 0) & 7)
-#define LCCR4_K2(x) (((x) >> 3) & 7)
-#define LCCR4_K3(x) (((x) >> 6) & 7)
-#define LCCR4_PALFOR(x) (((x) >> 15) & 3)
-#define LCCR5_SOFM(ch) (1 << (ch - 1))
-#define LCCR5_EOFM(ch) (1 << (ch + 7))
-#define LCCR5_BSM(ch) (1 << (ch + 15))
-#define LCCR5_IUM(ch) (1 << (ch + 23))
-#define OVLC1_EN (1 << 31)
-#define CCR_CEN (1 << 31)
-#define FBR_BRA (1 << 0)
-#define FBR_BINT (1 << 1)
-#define FBR_SRCADDR (0xfffffff << 4)
-#define LCSR0_LDD (1 << 0)
-#define LCSR0_SOF0 (1 << 1)
-#define LCSR0_BER (1 << 2)
-#define LCSR0_ABC (1 << 3)
-#define LCSR0_IU0 (1 << 4)
-#define LCSR0_IU1 (1 << 5)
-#define LCSR0_OU (1 << 6)
-#define LCSR0_QD (1 << 7)
-#define LCSR0_EOF0 (1 << 8)
-#define LCSR0_BS0 (1 << 9)
-#define LCSR0_SINT (1 << 10)
-#define LCSR0_RDST (1 << 11)
-#define LCSR0_CMDINT (1 << 12)
-#define LCSR0_BERCH(x) (((x) & 7) << 28)
-#define LCSR1_SOF(ch) (1 << (ch - 1))
-#define LCSR1_EOF(ch) (1 << (ch + 7))
-#define LCSR1_BS(ch) (1 << (ch + 15))
-#define LCSR1_IU(ch) (1 << (ch + 23))
-#define LDCMD_LENGTH(x) ((x) & 0x001ffffc)
-#define LDCMD_EOFINT (1 << 21)
-#define LDCMD_SOFINT (1 << 22)
-#define LDCMD_PAL (1 << 26)
-
-/* Size of a pixel in the QEMU UI output surface, in bytes */
-#define DEST_PIXEL_WIDTH 4
-
-/* Line drawing code to handle the various possible guest pixel formats */
-
-# define SKIP_PIXEL(to) do { to += deststep; } while (0)
-# define COPY_PIXEL(to, from) \
- do { \
- *(uint32_t *) to = from; \
- SKIP_PIXEL(to); \
- } while (0)
-
-#if HOST_BIG_ENDIAN
-# define SWAP_WORDS 1
-#endif
-
-#define FN_2(x) FN(x + 1) FN(x)
-#define FN_4(x) FN_2(x + 2) FN_2(x)
-
-static void pxa2xx_draw_line2(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
-#ifdef SWAP_WORDS
- FN_4(12)
- FN_4(8)
- FN_4(4)
- FN_4(0)
-#else
- FN_4(0)
- FN_4(4)
- FN_4(8)
- FN_4(12)
-#endif
-#undef FN
- width -= 16;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line4(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
-#ifdef SWAP_WORDS
- FN_2(6)
- FN_2(4)
- FN_2(2)
- FN_2(0)
-#else
- FN_2(0)
- FN_2(2)
- FN_2(4)
- FN_2(6)
-#endif
-#undef FN
- width -= 8;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line8(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
-#ifdef SWAP_WORDS
- FN(24)
- FN(16)
- FN(8)
- FN(0)
-#else
- FN(0)
- FN(8)
- FN(16)
- FN(24)
-#endif
-#undef FN
- width -= 4;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line16(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x1f) << 3;
- data >>= 5;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x1f) << 3;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 2;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line16t(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- r = (data & 0x1f) << 3;
- data >>= 5;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data >>= 1;
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- r = (data & 0x1f) << 3;
- data >>= 5;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 2;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line18(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x3f) << 2;
- data >>= 6;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x3f) << 2;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-/* The wicked packed format */
-static void pxa2xx_draw_line18p(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data[3];
- unsigned int r, g, b;
- while (width > 0) {
- data[0] = *(uint32_t *) src;
- src += 4;
- data[1] = *(uint32_t *) src;
- src += 4;
- data[2] = *(uint32_t *) src;
- src += 4;
-#ifdef SWAP_WORDS
- data[0] = bswap32(data[0]);
- data[1] = bswap32(data[1]);
- data[2] = bswap32(data[2]);
-#endif
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- r = (data[0] & 0x3f) << 2;
- data[0] >>= 12;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = ((data[1] & 0xf) << 4) | (data[0] << 2);
- data[1] >>= 4;
- r = (data[1] & 0x3f) << 2;
- data[1] >>= 12;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- g = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- r = ((data[2] & 0x3) << 6) | (data[1] << 2);
- data[2] >>= 8;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- g = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- r = data[2] << 2;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 4;
- }
-}
-
-static void pxa2xx_draw_line19(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x3f) << 2;
- data >>= 6;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x3f) << 2;
- data >>= 6;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 1;
- src += 4;
- }
-}
-
-/* The wicked packed format */
-static void pxa2xx_draw_line19p(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data[3];
- unsigned int r, g, b;
- while (width > 0) {
- data[0] = *(uint32_t *) src;
- src += 4;
- data[1] = *(uint32_t *) src;
- src += 4;
- data[2] = *(uint32_t *) src;
- src += 4;
-# ifdef SWAP_WORDS
- data[0] = bswap32(data[0]);
- data[1] = bswap32(data[1]);
- data[2] = bswap32(data[2]);
-# endif
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- r = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- if (data[0] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data[0] >>= 6;
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = ((data[1] & 0xf) << 4) | (data[0] << 2);
- data[1] >>= 4;
- r = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- if (data[1] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data[1] >>= 6;
- b = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- g = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- r = ((data[2] & 0x3) << 6) | (data[1] << 2);
- data[2] >>= 2;
- if (data[2] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data[2] >>= 6;
- b = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- g = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- r = data[2] << 2;
- data[2] >>= 6;
- if (data[2] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 4;
- }
-}
-
-static void pxa2xx_draw_line24(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = data & 0xff;
- data >>= 8;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line24t(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x7f) << 1;
- data >>= 7;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- data >>= 8;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 1;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line25(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = data & 0xff;
- data >>= 8;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- data >>= 8;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 1;
- src += 4;
- }
-}
-
-/* Overlay planes disabled, no transparency */
-static drawfn pxa2xx_draw_fn_32[16] = {
- [0 ... 0xf] = NULL,
- [pxa_lcdc_2bpp] = pxa2xx_draw_line2,
- [pxa_lcdc_4bpp] = pxa2xx_draw_line4,
- [pxa_lcdc_8bpp] = pxa2xx_draw_line8,
- [pxa_lcdc_16bpp] = pxa2xx_draw_line16,
- [pxa_lcdc_18bpp] = pxa2xx_draw_line18,
- [pxa_lcdc_18pbpp] = pxa2xx_draw_line18p,
- [pxa_lcdc_24bpp] = pxa2xx_draw_line24,
-};
-
-/* Overlay planes enabled, transparency used */
-static drawfn pxa2xx_draw_fn_32t[16] = {
- [0 ... 0xf] = NULL,
- [pxa_lcdc_4bpp] = pxa2xx_draw_line4,
- [pxa_lcdc_8bpp] = pxa2xx_draw_line8,
- [pxa_lcdc_16bpp] = pxa2xx_draw_line16t,
- [pxa_lcdc_19bpp] = pxa2xx_draw_line19,
- [pxa_lcdc_19pbpp] = pxa2xx_draw_line19p,
- [pxa_lcdc_24bpp] = pxa2xx_draw_line24t,
- [pxa_lcdc_25bpp] = pxa2xx_draw_line25,
-};
-
-#undef COPY_PIXEL
-#undef SKIP_PIXEL
-
-#ifdef SWAP_WORDS
-# undef SWAP_WORDS
-#endif
-
-/* Route internal interrupt lines to the global IC */
-static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
-{
- int level = 0;
- level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM);
- level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0);
- level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM);
- level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1));
- level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM);
- level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM);
- level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0);
- level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0);
- level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM);
- level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
- level |= (s->status[1] & ~s->control[5]);
-
- qemu_set_irq(s->irq, !!level);
- s->irqlevel = level;
-}
-
-/* Set Branch Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (ch == 0) {
- s->status[0] |= LCSR0_BS0;
- unmasked = !(s->control[0] & LCCR0_BSM0);
- } else {
- s->status[1] |= LCSR1_BS(ch);
- unmasked = !(s->control[5] & LCCR5_BSM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set Start Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
- return;
-
- if (ch == 0) {
- s->status[0] |= LCSR0_SOF0;
- unmasked = !(s->control[0] & LCCR0_SOFM0);
- } else {
- s->status[1] |= LCSR1_SOF(ch);
- unmasked = !(s->control[5] & LCCR5_SOFM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set End Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
- return;
-
- if (ch == 0) {
- s->status[0] |= LCSR0_EOF0;
- unmasked = !(s->control[0] & LCCR0_EOFM0);
- } else {
- s->status[1] |= LCSR1_EOF(ch);
- unmasked = !(s->control[5] & LCCR5_EOFM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set Bus Error Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
-{
- s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
-}
-
-/* Load new Frame Descriptors from DMA */
-static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
-{
- PXAFrameDescriptor desc;
- hwaddr descptr;
- int i;
-
- for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
- s->dma_ch[i].source = 0;
-
- if (!s->dma_ch[i].up)
- continue;
-
- if (s->dma_ch[i].branch & FBR_BRA) {
- descptr = s->dma_ch[i].branch & FBR_SRCADDR;
- if (s->dma_ch[i].branch & FBR_BINT)
- pxa2xx_dma_bs_set(s, i);
- s->dma_ch[i].branch &= ~FBR_BRA;
- } else
- descptr = s->dma_ch[i].descriptor;
-
- if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
- sizeof(desc) <= PXA2XX_SDRAM_BASE + current_machine->ram_size) ||
- (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
- PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
- continue;
- }
-
- cpu_physical_memory_read(descptr, &desc, sizeof(desc));
- s->dma_ch[i].descriptor = le32_to_cpu(desc.fdaddr);
- s->dma_ch[i].source = le32_to_cpu(desc.fsaddr);
- s->dma_ch[i].id = le32_to_cpu(desc.fidr);
- s->dma_ch[i].command = le32_to_cpu(desc.ldcmd);
- }
-}
-
-static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- int ch;
-
- switch (offset) {
- case LCCR0:
- return s->control[0];
- case LCCR1:
- return s->control[1];
- case LCCR2:
- return s->control[2];
- case LCCR3:
- return s->control[3];
- case LCCR4:
- return s->control[4];
- case LCCR5:
- return s->control[5];
-
- case OVL1C1:
- return s->ovl1c[0];
- case OVL1C2:
- return s->ovl1c[1];
- case OVL2C1:
- return s->ovl2c[0];
- case OVL2C2:
- return s->ovl2c[1];
-
- case CCR:
- return s->ccr;
-
- case CMDCR:
- return s->cmdcr;
-
- case TRGBR:
- return s->trgbr;
- case TCR:
- return s->tcr;
-
- case 0x200 ... 0x1000: /* DMA per-channel registers */
- ch = (offset - 0x200) >> 4;
- if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
- goto fail;
-
- switch (offset & 0xf) {
- case DMA_FDADR:
- return s->dma_ch[ch].descriptor;
- case DMA_FSADR:
- return s->dma_ch[ch].source;
- case DMA_FIDR:
- return s->dma_ch[ch].id;
- case DMA_LDCMD:
- return s->dma_ch[ch].command;
- default:
- goto fail;
- }
-
- case FBR0:
- return s->dma_ch[0].branch;
- case FBR1:
- return s->dma_ch[1].branch;
- case FBR2:
- return s->dma_ch[2].branch;
- case FBR3:
- return s->dma_ch[3].branch;
- case FBR4:
- return s->dma_ch[4].branch;
- case FBR5:
- return s->dma_ch[5].branch;
- case FBR6:
- return s->dma_ch[6].branch;
-
- case BSCNTR:
- return s->bscntr;
-
- case PRSR:
- return 0;
-
- case LCSR0:
- return s->status[0];
- case LCSR1:
- return s->status[1];
- case LIIDR:
- return s->liidr;
-
- default:
- fail:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- int ch;
-
- switch (offset) {
- case LCCR0:
- /* ACK Quick Disable done */
- if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
- s->status[0] |= LCSR0_QD;
-
- if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) {
- qemu_log_mask(LOG_UNIMP,
- "%s: internal frame buffer unsupported\n", __func__);
- }
- if ((s->control[3] & LCCR3_API) &&
- (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
- s->status[0] |= LCSR0_ABC;
-
- s->control[0] = value & 0x07ffffff;
- pxa2xx_lcdc_int_update(s);
-
- s->dma_ch[0].up = !!(value & LCCR0_ENB);
- s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
- break;
-
- case LCCR1:
- s->control[1] = value;
- break;
-
- case LCCR2:
- s->control[2] = value;
- break;
-
- case LCCR3:
- s->control[3] = value & 0xefffffff;
- s->bpp = LCCR3_BPP(value);
- break;
-
- case LCCR4:
- s->control[4] = value & 0x83ff81ff;
- break;
-
- case LCCR5:
- s->control[5] = value & 0x3f3f3f3f;
- break;
-
- case OVL1C1:
- if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
- qemu_log_mask(LOG_UNIMP, "%s: Overlay 1 not supported\n", __func__);
- }
- s->ovl1c[0] = value & 0x80ffffff;
- s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
- break;
-
- case OVL1C2:
- s->ovl1c[1] = value & 0x000fffff;
- break;
-
- case OVL2C1:
- if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
- qemu_log_mask(LOG_UNIMP, "%s: Overlay 2 not supported\n", __func__);
- }
- s->ovl2c[0] = value & 0x80ffffff;
- s->dma_ch[2].up = !!(value & OVLC1_EN);
- s->dma_ch[3].up = !!(value & OVLC1_EN);
- s->dma_ch[4].up = !!(value & OVLC1_EN);
- break;
-
- case OVL2C2:
- s->ovl2c[1] = value & 0x007fffff;
- break;
-
- case CCR:
- if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) {
- qemu_log_mask(LOG_UNIMP,
- "%s: Hardware cursor unimplemented\n", __func__);
- }
- s->ccr = value & 0x81ffffe7;
- s->dma_ch[5].up = !!(value & CCR_CEN);
- break;
-
- case CMDCR:
- s->cmdcr = value & 0xff;
- break;
-
- case TRGBR:
- s->trgbr = value & 0x00ffffff;
- break;
-
- case TCR:
- s->tcr = value & 0x7fff;
- break;
-
- case 0x200 ... 0x1000: /* DMA per-channel registers */
- ch = (offset - 0x200) >> 4;
- if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
- goto fail;
-
- switch (offset & 0xf) {
- case DMA_FDADR:
- s->dma_ch[ch].descriptor = value & 0xfffffff0;
- break;
-
- default:
- goto fail;
- }
- break;
-
- case FBR0:
- s->dma_ch[0].branch = value & 0xfffffff3;
- break;
- case FBR1:
- s->dma_ch[1].branch = value & 0xfffffff3;
- break;
- case FBR2:
- s->dma_ch[2].branch = value & 0xfffffff3;
- break;
- case FBR3:
- s->dma_ch[3].branch = value & 0xfffffff3;
- break;
- case FBR4:
- s->dma_ch[4].branch = value & 0xfffffff3;
- break;
- case FBR5:
- s->dma_ch[5].branch = value & 0xfffffff3;
- break;
- case FBR6:
- s->dma_ch[6].branch = value & 0xfffffff3;
- break;
-
- case BSCNTR:
- s->bscntr = value & 0xf;
- break;
-
- case PRSR:
- break;
-
- case LCSR0:
- s->status[0] &= ~(value & 0xfff);
- if (value & LCSR0_BER)
- s->status[0] &= ~LCSR0_BERCH(7);
- break;
-
- case LCSR1:
- s->status[1] &= ~(value & 0x3e3f3f);
- break;
-
- default:
- fail:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_lcdc_ops = {
- .read = pxa2xx_lcdc_read,
- .write = pxa2xx_lcdc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Load new palette for a given DMA channel, convert to internal format */
-static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, n, format, r, g, b, alpha;
- uint32_t *dest;
- uint8_t *src;
- s->pal_for = LCCR4_PALFOR(s->control[4]);
- format = s->pal_for;
-
- switch (bpp) {
- case pxa_lcdc_2bpp:
- n = 4;
- break;
- case pxa_lcdc_4bpp:
- n = 16;
- break;
- case pxa_lcdc_8bpp:
- n = 256;
- break;
- default:
- return;
- }
-
- src = (uint8_t *) s->dma_ch[ch].pbuffer;
- dest = (uint32_t *) s->dma_ch[ch].palette;
- alpha = r = g = b = 0;
-
- for (i = 0; i < n; i ++) {
- switch (format) {
- case 0: /* 16 bpp, no transparency */
- alpha = 0;
- if (s->control[0] & LCCR0_CMS) {
- r = g = b = *(uint16_t *) src & 0xff;
- }
- else {
- r = (*(uint16_t *) src & 0xf800) >> 8;
- g = (*(uint16_t *) src & 0x07e0) >> 3;
- b = (*(uint16_t *) src & 0x001f) << 3;
- }
- src += 2;
- break;
- case 1: /* 16 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xf80000) >> 16;
- g = (*(uint32_t *) src & 0x00fc00) >> 8;
- b = (*(uint32_t *) src & 0x0000f8);
- }
- src += 4;
- break;
- case 2: /* 18 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xfc0000) >> 16;
- g = (*(uint32_t *) src & 0x00fc00) >> 8;
- b = (*(uint32_t *) src & 0x0000fc);
- }
- src += 4;
- break;
- case 3: /* 24 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xff0000) >> 16;
- g = (*(uint32_t *) src & 0x00ff00) >> 8;
- b = (*(uint32_t *) src & 0x0000ff);
- }
- src += 4;
- break;
- }
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- *dest = rgb_to_pixel8(r, g, b) | alpha;
- break;
- case 15:
- *dest = rgb_to_pixel15(r, g, b) | alpha;
- break;
- case 16:
- *dest = rgb_to_pixel16(r, g, b) | alpha;
- break;
- case 24:
- *dest = rgb_to_pixel24(r, g, b) | alpha;
- break;
- case 32:
- *dest = rgb_to_pixel32(r, g, b) | alpha;
- break;
- }
- dest ++;
- }
-}
-
-static inline drawfn pxa2xx_drawfn(PXA2xxLCDState *s)
-{
- if (s->transp) {
- return pxa2xx_draw_fn_32t[s->bpp];
- } else {
- return pxa2xx_draw_fn_32[s->bpp];
- }
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn)
- return;
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
- src_width *= 3;
- else if (s->bpp > pxa_lcdc_16bpp)
- src_width *= 4;
- else if (s->bpp > pxa_lcdc_8bpp)
- src_width *= 2;
-
- dest_width = s->xres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, dest_width, DEST_PIXEL_WIDTH,
- s->invalidated,
- fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn)
- return;
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
- src_width *= 3;
- else if (s->bpp > pxa_lcdc_16bpp)
- src_width *= 4;
- else if (s->bpp > pxa_lcdc_8bpp)
- src_width *= 2;
-
- dest_width = s->yres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, DEST_PIXEL_WIDTH, -dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette,
- miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn) {
- return;
- }
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
- src_width *= 3;
- } else if (s->bpp > pxa_lcdc_16bpp) {
- src_width *= 4;
- } else if (s->bpp > pxa_lcdc_8bpp) {
- src_width *= 2;
- }
-
- dest_width = s->xres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -dest_width, -DEST_PIXEL_WIDTH,
- s->invalidated,
- fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn) {
- return;
- }
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
- src_width *= 3;
- } else if (s->bpp > pxa_lcdc_16bpp) {
- src_width *= 4;
- } else if (s->bpp > pxa_lcdc_8bpp) {
- src_width *= 2;
- }
-
- dest_width = s->yres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -DEST_PIXEL_WIDTH, dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette,
- miny, maxy);
-}
-
-static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
-{
- int width, height;
- if (!(s->control[0] & LCCR0_ENB))
- return;
-
- width = LCCR1_PPL(s->control[1]) + 1;
- height = LCCR2_LPP(s->control[2]) + 1;
-
- if (width != s->xres || height != s->yres) {
- if (s->orientation == 90 || s->orientation == 270) {
- qemu_console_resize(s->con, height, width);
- } else {
- qemu_console_resize(s->con, width, height);
- }
- s->invalidated = 1;
- s->xres = width;
- s->yres = height;
- }
-}
-
-static void pxa2xx_update_display(void *opaque)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- hwaddr fbptr;
- int miny, maxy;
- int ch;
- if (!(s->control[0] & LCCR0_ENB))
- return;
-
- pxa2xx_descriptor_load(s);
-
- pxa2xx_lcdc_resize(s);
- miny = s->yres;
- maxy = 0;
- s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
- /* Note: With overlay planes the order depends on LCCR0 bit 25. */
- for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
- if (s->dma_ch[ch].up) {
- if (!s->dma_ch[ch].source) {
- pxa2xx_dma_ber_set(s, ch);
- continue;
- }
- fbptr = s->dma_ch[ch].source;
- if (!((fbptr >= PXA2XX_SDRAM_BASE &&
- fbptr <= PXA2XX_SDRAM_BASE + current_machine->ram_size) ||
- (fbptr >= PXA2XX_INTERNAL_BASE &&
- fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
- pxa2xx_dma_ber_set(s, ch);
- continue;
- }
-
- if (s->dma_ch[ch].command & LDCMD_PAL) {
- cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
- MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
- sizeof(s->dma_ch[ch].pbuffer)));
- pxa2xx_palette_parse(s, ch, s->bpp);
- } else {
- /* Do we need to reparse palette */
- if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
- pxa2xx_palette_parse(s, ch, s->bpp);
-
- /* ACK frame start */
- pxa2xx_dma_sof_set(s, ch);
-
- s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
- s->invalidated = 0;
-
- /* ACK frame completed */
- pxa2xx_dma_eof_set(s, ch);
- }
- }
-
- if (s->control[0] & LCCR0_DIS) {
- /* ACK last frame completed */
- s->control[0] &= ~LCCR0_ENB;
- s->status[0] |= LCSR0_LDD;
- }
-
- if (miny >= 0) {
- switch (s->orientation) {
- case 0:
- dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
- break;
- case 90:
- dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
- break;
- case 180:
- maxy = s->yres - maxy - 1;
- miny = s->yres - miny - 1;
- dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
- break;
- case 270:
- maxy = s->yres - maxy - 1;
- miny = s->yres - miny - 1;
- dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
- break;
- }
- }
- pxa2xx_lcdc_int_update(s);
-
- qemu_irq_raise(s->vsync_cb);
-}
-
-static void pxa2xx_invalidate_display(void *opaque)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- s->invalidated = 1;
-}
-
-static void pxa2xx_lcdc_orientation(void *opaque, int angle)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-
- switch (angle) {
- case 0:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
- break;
- case 90:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
- break;
- case 180:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
- break;
- case 270:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
- break;
- }
-
- s->orientation = angle;
- s->xres = s->yres = -1;
- pxa2xx_lcdc_resize(s);
-}
-
-static const VMStateDescription vmstate_dma_channel = {
- .name = "dma_channel",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(branch, struct DMAChannel),
- VMSTATE_UINT8(up, struct DMAChannel),
- VMSTATE_BUFFER(pbuffer, struct DMAChannel),
- VMSTATE_UINT32(descriptor, struct DMAChannel),
- VMSTATE_UINT32(source, struct DMAChannel),
- VMSTATE_UINT32(id, struct DMAChannel),
- VMSTATE_UINT32(command, struct DMAChannel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
-{
- PXA2xxLCDState *s = opaque;
-
- s->bpp = LCCR3_BPP(s->control[3]);
- s->xres = s->yres = s->pal_for = -1;
-
- return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_lcdc = {
- .name = "pxa2xx_lcdc",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = pxa2xx_lcdc_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(irqlevel, PXA2xxLCDState),
- VMSTATE_INT32(transp, PXA2xxLCDState),
- VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
- VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
- VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
- VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
- VMSTATE_UINT32(ccr, PXA2xxLCDState),
- VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
- VMSTATE_UINT32(trgbr, PXA2xxLCDState),
- VMSTATE_UINT32(tcr, PXA2xxLCDState),
- VMSTATE_UINT32(liidr, PXA2xxLCDState),
- VMSTATE_UINT8(bscntr, PXA2xxLCDState),
- VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
- vmstate_dma_channel, struct DMAChannel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps pxa2xx_ops = {
- .invalidate = pxa2xx_invalidate_display,
- .gfx_update = pxa2xx_update_display,
-};
-
-PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
- hwaddr base, qemu_irq irq)
-{
- PXA2xxLCDState *s;
-
- s = g_new0(PXA2xxLCDState, 1);
- s->invalidated = 1;
- s->irq = irq;
- s->sysmem = sysmem;
-
- pxa2xx_lcdc_orientation(s, graphic_rotate);
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_lcdc_ops, s,
- "pxa2xx-lcd-controller", 0x00100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
-
- vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
-
- return s;
-}
-
-void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
-{
- s->vsync_cb = handler;
-}
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index 335d01e..eda6d3d 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -21,7 +21,7 @@
#include "qemu/osdep.h"
#include "qxl.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "trace.h"
static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 7178dec..18f482c 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -29,7 +29,8 @@
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/qdev-properties.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
+#include "migration/cpr.h"
#include "migration/vmstate.h"
#include "trace.h"
@@ -50,7 +51,7 @@
#undef ALIGN
#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
-#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9"
+#define PIXEL_SIZE 0.2936875 /* 1280x1024 is 14.8" x 11.9" */
#define QXL_MODE(_x, _y, _b, _o) \
{ .x_res = _x, \
@@ -333,6 +334,10 @@ static void init_qxl_rom(PCIQXLDevice *d)
uint32_t fb;
int i, n;
+ if (cpr_is_incoming()) {
+ goto skip_init;
+ }
+
memset(rom, 0, d->rom_size);
rom->magic = cpu_to_le32(QXL_ROM_MAGIC);
@@ -390,6 +395,7 @@ static void init_qxl_rom(PCIQXLDevice *d)
sizeof(rom->client_monitors_config));
}
+skip_init:
d->shadow_rom = *rom;
d->rom = rom;
d->modes = modes;
@@ -403,6 +409,9 @@ static void init_qxl_ram(PCIQXLDevice *d)
buf = d->vga.vram_ptr;
d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
+ if (cpr_is_incoming()) {
+ return;
+ }
d->ram->magic = cpu_to_le32(QXL_RAM_MAGIC);
d->ram->int_pending = cpu_to_le32(0);
d->ram->int_mask = cpu_to_le32(0);
@@ -539,6 +548,10 @@ static void interface_set_compression_level(QXLInstance *sin, int level)
trace_qxl_interface_set_compression_level(qxl->id, level);
qxl->shadow_rom.compression_level = cpu_to_le32(level);
+ if (cpr_is_incoming()) {
+ assert(qxl->rom->compression_level == cpu_to_le32(level));
+ return;
+ }
qxl->rom->compression_level = cpu_to_le32(level);
qxl_rom_set_dirty(qxl);
}
@@ -997,7 +1010,8 @@ static void interface_set_client_capabilities(QXLInstance *sin,
}
if (runstate_check(RUN_STATE_INMIGRATE) ||
- runstate_check(RUN_STATE_POSTMIGRATE)) {
+ runstate_check(RUN_STATE_POSTMIGRATE) ||
+ cpr_is_incoming()) {
return;
}
@@ -1200,6 +1214,10 @@ static void qxl_reset_state(PCIQXLDevice *d)
{
QXLRom *rom = d->rom;
+ if (cpr_is_incoming()) {
+ return;
+ }
+
qxl_check_state(d);
d->shadow_rom.update_id = cpu_to_le32(0);
*rom = d->shadow_rom;
@@ -1301,8 +1319,8 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
};
uint64_t guest_start;
uint64_t guest_end;
- int pci_region;
- pcibus_t pci_start;
+ int pci_region = -1;
+ pcibus_t pci_start = PCI_BAR_UNMAPPED;
pcibus_t pci_end;
MemoryRegion *mr;
intptr_t virt_start;
@@ -1370,8 +1388,11 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
memslot.virt_start = virt_start + (guest_start - pci_start);
memslot.virt_end = virt_start + (guest_end - pci_start);
memslot.addr_delta = memslot.virt_start - delta;
- memslot.generation = d->rom->slot_generation = 0;
- qxl_rom_set_dirty(d);
+ if (!cpr_is_incoming()) {
+ d->rom->slot_generation = 0;
+ qxl_rom_set_dirty(d);
+ }
+ memslot.generation = d->rom->slot_generation;
qemu_spice_add_memslot(&d->ssd, &memslot, async);
d->guest_slots[slot_id].mr = mr;
@@ -2458,7 +2479,7 @@ static const VMStateDescription qxl_vmstate = {
}
};
-static Property qxl_properties[] = {
+static const Property qxl_properties[] = {
DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * MiB),
DEFINE_PROP_UINT64("vram_size", PCIQXLDevice, vram32_size, 64 * MiB),
DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
@@ -2475,10 +2496,9 @@ static Property qxl_properties[] = {
DEFINE_PROP_UINT32("xres", PCIQXLDevice, xres, 0),
DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0),
DEFINE_PROP_BOOL("global-vmstate", PCIQXLDevice, vga.global_vmstate, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void qxl_pci_class_init(ObjectClass *klass, void *data)
+static void qxl_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -2486,7 +2506,7 @@ static void qxl_pci_class_init(ObjectClass *klass, void *data)
k->vendor_id = REDHAT_PCI_VENDOR_ID;
k->device_id = QXL_DEVICE_ID_STABLE;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->reset = qxl_reset_handler;
+ device_class_set_legacy_reset(dc, qxl_reset_handler);
dc->vmsd = &qxl_vmstate;
device_class_set_props(dc, qxl_properties);
}
@@ -2497,13 +2517,13 @@ static const TypeInfo qxl_pci_type_info = {
.instance_size = sizeof(PCIQXLDevice),
.abstract = true,
.class_init = qxl_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void qxl_primary_class_init(ObjectClass *klass, void *data)
+static void qxl_primary_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -2523,7 +2543,7 @@ static const TypeInfo qxl_primary_info = {
module_obj("qxl-vga");
module_kconfig(QXL);
-static void qxl_secondary_class_init(ObjectClass *klass, void *data)
+static void qxl_secondary_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/display/ramfb-standalone.c b/hw/display/ramfb-standalone.c
index 20eab34..08f2d5d 100644
--- a/hw/display/ramfb-standalone.c
+++ b/hw/display/ramfb-standalone.c
@@ -60,12 +60,11 @@ static const VMStateDescription ramfb_dev_vmstate = {
}
};
-static Property ramfb_properties[] = {
+static const Property ramfb_properties[] = {
DEFINE_PROP_BOOL("x-migrate", RAMFBStandaloneState, migrate, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ramfb_class_initfn(ObjectClass *klass, void *data)
+static void ramfb_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -73,13 +72,12 @@ static void ramfb_class_initfn(ObjectClass *klass, void *data)
dc->vmsd = &ramfb_dev_vmstate;
dc->realize = ramfb_realizefn;
dc->desc = "ram framebuffer standalone device";
- dc->user_creatable = true;
device_class_set_props(dc, ramfb_properties);
}
static const TypeInfo ramfb_info = {
.name = TYPE_RAMFB_DEVICE,
- .parent = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
.instance_size = sizeof(RAMFBStandaloneState),
.class_init = ramfb_class_initfn,
};
diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c
index 6086baf..8c0f907 100644
--- a/hw/display/ramfb.c
+++ b/hw/display/ramfb.c
@@ -17,7 +17,7 @@
#include "hw/display/ramfb.h"
#include "hw/display/bochs-vbe.h" /* for limits */
#include "ui/console.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
struct QEMU_PACKED RAMFBCfg {
uint64_t addr;
diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c
index 60c3f78..d00d3e9 100644
--- a/hw/display/sii9022.c
+++ b/hw/display/sii9022.c
@@ -167,7 +167,7 @@ static void sii9022_realize(DeviceState *dev, Error **errp)
i2c_slave_create_simple(bus, TYPE_I2CDDC, 0x50);
}
-static void sii9022_class_init(ObjectClass *klass, void *data)
+static void sii9022_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -175,7 +175,7 @@ static void sii9022_class_init(ObjectClass *klass, void *data)
k->event = sii9022_event;
k->recv = sii9022_rx;
k->send = sii9022_tx;
- dc->reset = sii9022_reset;
+ device_class_set_legacy_reset(dc, sii9022_reset);
dc->realize = sii9022_realize;
dc->vmsd = &vmstate_sii9022;
}
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 26dc817..6d2f186 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -29,7 +29,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/usb/hcd-ohci.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "ui/console.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
@@ -2054,11 +2054,10 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp)
/* TODO : chain irq to IRL */
}
-static Property sm501_sysbus_properties[] = {
+static const Property sm501_sysbus_properties[] = {
DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0),
/* this a debug option, prefer PROP_UINT over PROP_BIT for simplicity */
DEFINE_PROP_UINT8("x-pixman", SM501SysBusState, state.use_pixman, DEFAULT_X_PIXMAN),
- DEFINE_PROP_END_OF_LIST(),
};
static void sm501_reset_sysbus(DeviceState *dev)
@@ -2078,7 +2077,7 @@ static const VMStateDescription vmstate_sm501_sysbus = {
}
};
-static void sm501_sysbus_class_init(ObjectClass *klass, void *data)
+static void sm501_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2086,7 +2085,7 @@ static void sm501_sysbus_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "SM501 Multimedia Companion";
device_class_set_props(dc, sm501_sysbus_properties);
- dc->reset = sm501_reset_sysbus;
+ device_class_set_legacy_reset(dc, sm501_reset_sysbus);
dc->vmsd = &vmstate_sm501_sysbus;
}
@@ -2143,10 +2142,9 @@ static void sm501_realize_pci(PCIDevice *dev, Error **errp)
&s->state.mmio_region);
}
-static Property sm501_pci_properties[] = {
+static const Property sm501_pci_properties[] = {
DEFINE_PROP_UINT32("vram-size", SM501PCIState, vram_size, 64 * MiB),
DEFINE_PROP_UINT8("x-pixman", SM501PCIState, state.use_pixman, DEFAULT_X_PIXMAN),
- DEFINE_PROP_END_OF_LIST(),
};
static void sm501_reset_pci(DeviceState *dev)
@@ -2169,7 +2167,7 @@ static const VMStateDescription vmstate_sm501_pci = {
}
};
-static void sm501_pci_class_init(ObjectClass *klass, void *data)
+static void sm501_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -2181,7 +2179,7 @@ static void sm501_pci_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "SM501 Display Controller";
device_class_set_props(dc, sm501_pci_properties);
- dc->reset = sm501_reset_pci;
+ device_class_set_legacy_reset(dc, sm501_reset_pci);
dc->hotpluggable = false;
dc->vmsd = &vmstate_sm501_pci;
}
@@ -2198,7 +2196,7 @@ static const TypeInfo sm501_pci_info = {
.instance_size = sizeof(SM501PCIState),
.class_init = sm501_pci_class_init,
.instance_init = sm501_pci_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index e292cff..8778143 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -311,7 +311,7 @@ static void ssd0303_realize(DeviceState *dev, Error **errp)
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
}
-static void ssd0303_class_init(ObjectClass *klass, void *data)
+static void ssd0303_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index 96cf0dc..af5ff4f 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -361,7 +361,7 @@ static void ssd0323_realize(SSIPeripheral *d, Error **errp)
qdev_init_gpio_in(dev, ssd0323_cd, 1);
}
-static void ssd0323_class_init(ObjectClass *klass, void *data)
+static void ssd0323_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
deleted file mode 100644
index c7beba4..0000000
--- a/hw/display/tc6393xb.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * Most features are currently unsupported!!!
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/host-utils.h"
-#include "hw/irq.h"
-#include "hw/display/tc6393xb.h"
-#include "exec/memory.h"
-#include "hw/block/flash.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "sysemu/blockdev.h"
-
-#define IRQ_TC6393_NAND 0
-#define IRQ_TC6393_MMC 1
-#define IRQ_TC6393_OHCI 2
-#define IRQ_TC6393_SERIAL 3
-#define IRQ_TC6393_FB 4
-
-#define TC6393XB_NR_IRQS 8
-
-#define TC6393XB_GPIOS 16
-
-#define SCR_REVID 0x08 /* b Revision ID */
-#define SCR_ISR 0x50 /* b Interrupt Status */
-#define SCR_IMR 0x52 /* b Interrupt Mask */
-#define SCR_IRR 0x54 /* b Interrupt Routing */
-#define SCR_GPER 0x60 /* w GP Enable */
-#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */
-#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */
-#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */
-#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */
-#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */
-#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */
-#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */
-#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */
-#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */
-#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */
-#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */
-#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */
-#define SCR_CCR 0x98 /* w Clock Control */
-#define SCR_PLL2CR 0x9a /* w PLL2 Control */
-#define SCR_PLL1CR 0x9c /* l PLL1 Control */
-#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */
-#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */
-#define SCR_FER 0xe0 /* b Function Enable */
-#define SCR_MCR 0xe4 /* w Mode Control */
-#define SCR_CONFIG 0xfc /* b Configuration Control */
-#define SCR_DEBUG 0xff /* b Debug */
-
-#define NAND_CFG_COMMAND 0x04 /* w Command */
-#define NAND_CFG_BASE 0x10 /* l Control Base Address */
-#define NAND_CFG_INTP 0x3d /* b Interrupt Pin */
-#define NAND_CFG_INTE 0x48 /* b Int Enable */
-#define NAND_CFG_EC 0x4a /* b Event Control */
-#define NAND_CFG_ICC 0x4c /* b Internal Clock Control */
-#define NAND_CFG_ECCC 0x5b /* b ECC Control */
-#define NAND_CFG_NFTC 0x60 /* b NAND Flash Transaction Control */
-#define NAND_CFG_NFM 0x61 /* b NAND Flash Monitor */
-#define NAND_CFG_NFPSC 0x62 /* b NAND Flash Power Supply Control */
-#define NAND_CFG_NFDC 0x63 /* b NAND Flash Detect Control */
-
-#define NAND_DATA 0x00 /* l Data */
-#define NAND_MODE 0x04 /* b Mode */
-#define NAND_STATUS 0x05 /* b Status */
-#define NAND_ISR 0x06 /* b Interrupt Status */
-#define NAND_IMR 0x07 /* b Interrupt Mask */
-
-#define NAND_MODE_WP 0x80
-#define NAND_MODE_CE 0x10
-#define NAND_MODE_ALE 0x02
-#define NAND_MODE_CLE 0x01
-#define NAND_MODE_ECC_MASK 0x60
-#define NAND_MODE_ECC_EN 0x20
-#define NAND_MODE_ECC_READ 0x40
-#define NAND_MODE_ECC_RST 0x60
-
-struct TC6393xbState {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq *sub_irqs;
- struct {
- uint8_t ISR;
- uint8_t IMR;
- uint8_t IRR;
- uint16_t GPER;
- uint8_t GPI_SR[3];
- uint8_t GPI_IMR[3];
- uint8_t GPI_EDER[3];
- uint8_t GPI_LIR[3];
- uint8_t GP_IARCR[3];
- uint8_t GP_IARLCR[3];
- uint8_t GPI_BCR[3];
- uint16_t GPA_IARCR;
- uint16_t GPA_IARLCR;
- uint16_t CCR;
- uint16_t PLL2CR;
- uint32_t PLL1CR;
- uint8_t DIARCR;
- uint8_t DBOCR;
- uint8_t FER;
- uint16_t MCR;
- uint8_t CONFIG;
- uint8_t DEBUG;
- } scr;
- uint32_t gpio_dir;
- uint32_t gpio_level;
- uint32_t prev_level;
- qemu_irq handler[TC6393XB_GPIOS];
- qemu_irq *gpio_in;
-
- struct {
- uint8_t mode;
- uint8_t isr;
- uint8_t imr;
- } nand;
- int nand_enable;
- uint32_t nand_phys;
- DeviceState *flash;
- ECCState ecc;
-
- QemuConsole *con;
- MemoryRegion vram;
- uint16_t *vram_ptr;
- uint32_t scr_width, scr_height; /* in pixels */
- qemu_irq l3v;
- unsigned blank : 1,
- blanked : 1;
-};
-
-static void tc6393xb_gpio_set(void *opaque, int line, int level)
-{
-// TC6393xbState *s = opaque;
-
- if (line > TC6393XB_GPIOS) {
- printf("%s: No GPIO pin %i\n", __func__, line);
- return;
- }
-
- // FIXME: how does the chip reflect the GPIO input level change?
-}
-
-static void tc6393xb_gpio_handler_update(TC6393xbState *s)
-{
- uint32_t level, diff;
- int bit;
-
- level = s->gpio_level & s->gpio_dir;
- level &= MAKE_64BIT_MASK(0, TC6393XB_GPIOS);
-
- for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- qemu_set_irq(s->handler[bit], (level >> bit) & 1);
- }
-
- s->prev_level = level;
-}
-
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
-{
- return s->l3v;
-}
-
-static void tc6393xb_l3v(void *opaque, int line, int level)
-{
- TC6393xbState *s = opaque;
- s->blank = !level;
- fprintf(stderr, "L3V: %d\n", level);
-}
-
-static void tc6393xb_sub_irq(void *opaque, int line, int level) {
- TC6393xbState *s = opaque;
- uint8_t isr = s->scr.ISR;
- if (level)
- isr |= 1 << line;
- else
- isr &= ~(1 << line);
- s->scr.ISR = isr;
- qemu_set_irq(s->irq, isr & s->scr.IMR);
-}
-
-#define SCR_REG_B(N) \
- case SCR_ ##N: return s->scr.N
-#define SCR_REG_W(N) \
- case SCR_ ##N: return s->scr.N; \
- case SCR_ ##N + 1: return s->scr.N >> 8;
-#define SCR_REG_L(N) \
- case SCR_ ##N: return s->scr.N; \
- case SCR_ ##N + 1: return s->scr.N >> 8; \
- case SCR_ ##N + 2: return s->scr.N >> 16; \
- case SCR_ ##N + 3: return s->scr.N >> 24;
-#define SCR_REG_A(N) \
- case SCR_ ##N(0): return s->scr.N[0]; \
- case SCR_ ##N(1): return s->scr.N[1]; \
- case SCR_ ##N(2): return s->scr.N[2]
-
-static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
-{
- switch (addr) {
- case SCR_REVID:
- return 3;
- case SCR_REVID+1:
- return 0;
- SCR_REG_B(ISR);
- SCR_REG_B(IMR);
- SCR_REG_B(IRR);
- SCR_REG_W(GPER);
- SCR_REG_A(GPI_SR);
- SCR_REG_A(GPI_IMR);
- SCR_REG_A(GPI_EDER);
- SCR_REG_A(GPI_LIR);
- case SCR_GPO_DSR(0):
- case SCR_GPO_DSR(1):
- case SCR_GPO_DSR(2):
- return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
- case SCR_GPO_DOECR(0):
- case SCR_GPO_DOECR(1):
- case SCR_GPO_DOECR(2):
- return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
- SCR_REG_A(GP_IARCR);
- SCR_REG_A(GP_IARLCR);
- SCR_REG_A(GPI_BCR);
- SCR_REG_W(GPA_IARCR);
- SCR_REG_W(GPA_IARLCR);
- SCR_REG_W(CCR);
- SCR_REG_W(PLL2CR);
- SCR_REG_L(PLL1CR);
- SCR_REG_B(DIARCR);
- SCR_REG_B(DBOCR);
- SCR_REG_B(FER);
- SCR_REG_W(MCR);
- SCR_REG_B(CONFIG);
- SCR_REG_B(DEBUG);
- }
- fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-#define SCR_REG_B(N) \
- case SCR_ ##N: s->scr.N = value; return;
-#define SCR_REG_W(N) \
- case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
- case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
-#define SCR_REG_L(N) \
- case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
- case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return; \
- case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return; \
- case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
-#define SCR_REG_A(N) \
- case SCR_ ##N(0): s->scr.N[0] = value; return; \
- case SCR_ ##N(1): s->scr.N[1] = value; return; \
- case SCR_ ##N(2): s->scr.N[2] = value; return
-
-static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
-{
- switch (addr) {
- SCR_REG_B(ISR);
- SCR_REG_B(IMR);
- SCR_REG_B(IRR);
- SCR_REG_W(GPER);
- SCR_REG_A(GPI_SR);
- SCR_REG_A(GPI_IMR);
- SCR_REG_A(GPI_EDER);
- SCR_REG_A(GPI_LIR);
- case SCR_GPO_DSR(0):
- case SCR_GPO_DSR(1):
- case SCR_GPO_DSR(2):
- s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
- tc6393xb_gpio_handler_update(s);
- return;
- case SCR_GPO_DOECR(0):
- case SCR_GPO_DOECR(1):
- case SCR_GPO_DOECR(2):
- s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
- tc6393xb_gpio_handler_update(s);
- return;
- SCR_REG_A(GP_IARCR);
- SCR_REG_A(GP_IARLCR);
- SCR_REG_A(GPI_BCR);
- SCR_REG_W(GPA_IARCR);
- SCR_REG_W(GPA_IARLCR);
- SCR_REG_W(CCR);
- SCR_REG_W(PLL2CR);
- SCR_REG_L(PLL1CR);
- SCR_REG_B(DIARCR);
- SCR_REG_B(DBOCR);
- SCR_REG_B(FER);
- SCR_REG_W(MCR);
- SCR_REG_B(CONFIG);
- SCR_REG_B(DEBUG);
- }
- fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-static void tc6393xb_nand_irq(TC6393xbState *s) {
- qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
- (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
-}
-
-static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
- switch (addr) {
- case NAND_CFG_COMMAND:
- return s->nand_enable ? 2 : 0;
- case NAND_CFG_BASE:
- case NAND_CFG_BASE + 1:
- case NAND_CFG_BASE + 2:
- case NAND_CFG_BASE + 3:
- return s->nand_phys >> (addr - NAND_CFG_BASE);
- }
- fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
- switch (addr) {
- case NAND_CFG_COMMAND:
- s->nand_enable = (value & 0x2);
- return;
- case NAND_CFG_BASE:
- case NAND_CFG_BASE + 1:
- case NAND_CFG_BASE + 2:
- case NAND_CFG_BASE + 3:
- s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
- s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
- return;
- }
- fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-
-static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
- switch (addr) {
- case NAND_DATA + 0:
- case NAND_DATA + 1:
- case NAND_DATA + 2:
- case NAND_DATA + 3:
- return nand_getio(s->flash);
- case NAND_MODE:
- return s->nand.mode;
- case NAND_STATUS:
- return 0x14;
- case NAND_ISR:
- return s->nand.isr;
- case NAND_IMR:
- return s->nand.imr;
- }
- fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
-// fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
-// (uint32_t) addr, value & 0xff);
- switch (addr) {
- case NAND_DATA + 0:
- case NAND_DATA + 1:
- case NAND_DATA + 2:
- case NAND_DATA + 3:
- nand_setio(s->flash, value);
- s->nand.isr |= 1;
- tc6393xb_nand_irq(s);
- return;
- case NAND_MODE:
- s->nand.mode = value;
- nand_setpins(s->flash,
- value & NAND_MODE_CLE,
- value & NAND_MODE_ALE,
- !(value & NAND_MODE_CE),
- value & NAND_MODE_WP,
- 0); // FIXME: gnd
- switch (value & NAND_MODE_ECC_MASK) {
- case NAND_MODE_ECC_RST:
- ecc_reset(&s->ecc);
- break;
- case NAND_MODE_ECC_READ:
- // FIXME
- break;
- case NAND_MODE_ECC_EN:
- ecc_reset(&s->ecc);
- }
- return;
- case NAND_ISR:
- s->nand.isr = value;
- tc6393xb_nand_irq(s);
- return;
- case NAND_IMR:
- s->nand.imr = value;
- tc6393xb_nand_irq(s);
- return;
- }
- fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-
-static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i;
- uint16_t *data_buffer;
- uint8_t *data_display;
-
- data_buffer = s->vram_ptr;
- data_display = surface_data(surface);
- for (i = 0; i < s->scr_height; i++) {
- int j;
- for (j = 0; j < s->scr_width; j++, data_display += 4, data_buffer++) {
- uint16_t color = *data_buffer;
- uint32_t dest_color = rgb_to_pixel32(
- ((color & 0xf800) * 0x108) >> 11,
- ((color & 0x7e0) * 0x41) >> 9,
- ((color & 0x1f) * 0x21) >> 2
- );
- *(uint32_t *)data_display = dest_color;
- }
- }
- dpy_gfx_update_full(s->con);
-}
-
-static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, w;
- uint8_t *d;
-
- if (!full_update)
- return;
-
- w = s->scr_width * surface_bytes_per_pixel(surface);
- d = surface_data(surface);
- for(i = 0; i < s->scr_height; i++) {
- memset(d, 0, w);
- d += surface_stride(surface);
- }
-
- dpy_gfx_update_full(s->con);
-}
-
-static void tc6393xb_update_display(void *opaque)
-{
- TC6393xbState *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int full_update;
-
- if (s->scr_width == 0 || s->scr_height == 0)
- return;
-
- full_update = 0;
- if (s->blanked != s->blank) {
- s->blanked = s->blank;
- full_update = 1;
- }
- if (s->scr_width != surface_width(surface) ||
- s->scr_height != surface_height(surface)) {
- qemu_console_resize(s->con, s->scr_width, s->scr_height);
- full_update = 1;
- }
- if (s->blanked)
- tc6393xb_draw_blank(s, full_update);
- else
- tc6393xb_draw_graphic(s, full_update);
-}
-
-
-static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- TC6393xbState *s = opaque;
-
- switch (addr >> 8) {
- case 0:
- return tc6393xb_scr_readb(s, addr & 0xff);
- case 1:
- return tc6393xb_nand_cfg_readb(s, addr & 0xff);
- };
-
- if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
-// return tc6393xb_nand_readb(s, addr & 0xff);
- uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
-// fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
- return d;
- }
-
-// fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-
-static void tc6393xb_writeb(void *opaque, hwaddr addr,
- uint64_t value, unsigned size) {
- TC6393xbState *s = opaque;
-
- switch (addr >> 8) {
- case 0:
- tc6393xb_scr_writeb(s, addr & 0xff, value);
- return;
- case 1:
- tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
- return;
- };
-
- if ((addr &~0xff) == s->nand_phys && s->nand_enable)
- tc6393xb_nand_writeb(s, addr & 0xff, value);
- else
- fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
- (uint32_t) addr, (int)value & 0xff);
-}
-
-static const GraphicHwOps tc6393xb_gfx_ops = {
- .gfx_update = tc6393xb_update_display,
-};
-
-TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
-{
- TC6393xbState *s;
- DriveInfo *nand;
- static const MemoryRegionOps tc6393xb_ops = {
- .read = tc6393xb_readb,
- .write = tc6393xb_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- };
-
- s = g_new0(TC6393xbState, 1);
- s->irq = irq;
- s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
-
- s->l3v = qemu_allocate_irq(tc6393xb_l3v, s, 0);
- s->blanked = 1;
-
- s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
-
- nand = drive_get(IF_MTD, 0, 0);
- s->flash = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- NAND_MFR_TOSHIBA, 0x76);
-
- memory_region_init_io(&s->iomem, NULL, &tc6393xb_ops, s, "tc6393xb", 0x10000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000,
- &error_fatal);
- s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
- memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
- s->scr_width = 480;
- s->scr_height = 640;
- s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
-
- return s;
-}
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 99507e7..4853c5e 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -729,7 +729,6 @@ static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr,
static void tcx_dummy_writel(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
- return;
}
static const MemoryRegionOps tcx_dummy_ops = {
@@ -879,20 +878,19 @@ static void tcx_realizefn(DeviceState *dev, Error **errp)
qemu_console_resize(s->con, s->width, s->height);
}
-static Property tcx_properties[] = {
+static const Property tcx_properties[] = {
DEFINE_PROP_UINT32("vram_size", TCXState, vram_size, -1),
DEFINE_PROP_UINT16("width", TCXState, width, -1),
DEFINE_PROP_UINT16("height", TCXState, height, -1),
DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void tcx_class_init(ObjectClass *klass, void *data)
+static void tcx_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = tcx_realizefn;
- dc->reset = tcx_reset;
+ device_class_set_legacy_reset(dc, tcx_reset);
dc->vmsd = &vmstate_tcx;
device_class_set_props(dc, tcx_properties);
}
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 781f8a3..52786e6 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -53,6 +53,9 @@ virtio_gpu_cmd_ctx_submit(uint32_t ctx, uint32_t size) "ctx 0x%x, size %d"
virtio_gpu_update_cursor(uint32_t scanout, uint32_t x, uint32_t y, const char *type, uint32_t res) "scanout %d, x %d, y %d, %s, res 0x%x"
virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x"
virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64
+virtio_gpu_inc_inflight_fences(uint32_t inflight) "in-flight+ %u"
+virtio_gpu_dec_inflight_fences(uint32_t inflight) "in-flight- %u"
+virtio_gpu_cmd_suspended(uint32_t cmd) "cmd 0x%x"
# qxl.c
disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u"
@@ -191,3 +194,33 @@ dm163_bits_ppi(unsigned dest_width) "dest_width : %u"
dm163_leds(int led, uint32_t value) "led %d: 0x%x"
dm163_channels(int channel, uint8_t value) "channel %d: 0x%x"
dm163_refresh_rate(uint32_t rr) "refresh rate %d"
+
+# apple-gfx.m
+apple_gfx_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
+apple_gfx_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
+apple_gfx_create_task(uint32_t vm_size, void *va) "vm_size=0x%x base_addr=%p"
+apple_gfx_destroy_task(void *task, unsigned int num_mapped_regions) "task=%p, task->mapped_regions->len=%u"
+apple_gfx_map_memory(void *task, uint32_t range_count, uint64_t virtual_offset, uint32_t read_only) "task=%p range_count=0x%x virtual_offset=0x%"PRIx64" read_only=%d"
+apple_gfx_map_memory_range(uint32_t i, uint64_t phys_addr, uint64_t phys_len) "[%d] phys_addr=0x%"PRIx64" phys_len=0x%"PRIx64
+apple_gfx_remap(uint64_t retval, void *source_ptr, uint64_t target) "retval=%"PRId64" source=%p target=0x%"PRIx64
+apple_gfx_unmap_memory(void *task, uint64_t virtual_offset, uint64_t length) "task=%p virtual_offset=0x%"PRIx64" length=0x%"PRIx64
+apple_gfx_read_memory(uint64_t phys_address, uint64_t length, void *dst) "phys_addr=0x%"PRIx64" length=0x%"PRIx64" dest=%p"
+apple_gfx_raise_irq(uint32_t vector) "vector=0x%x"
+apple_gfx_new_frame(void) ""
+apple_gfx_mode_change(uint64_t x, uint64_t y) "x=%"PRId64" y=%"PRId64
+apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=%d width=%"PRId64" height=0x%"PRId64
+apple_gfx_cursor_show(uint32_t show) "show=%d"
+apple_gfx_cursor_move(void) ""
+apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: %s; MMIO size: %zu bytes"
+apple_gfx_common_realize_modes_property(uint32_t num_modes) "using %u modes supplied by 'display-modes' device property"
+apple_gfx_display_mode(uint32_t mode_idx, uint16_t width_px, uint16_t height_px) "mode %2"PRIu32": %4"PRIu16"x%4"PRIu16
+
+# apple-gfx-mmio.m
+apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
+apple_gfx_mmio_iosfc_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
+apple_gfx_iosfc_map_memory(uint64_t phys, uint64_t len, uint32_t ro, void *va, void *e, void *f, void* va_result) "phys=0x%"PRIx64" len=0x%"PRIx64" ro=%d va=%p e=%p f=%p -> *va=%p"
+apple_gfx_iosfc_map_memory_new_region(size_t i, void *region, uint64_t start, uint64_t end) "index=%zu, region=%p, 0x%"PRIx64"-0x%"PRIx64
+apple_gfx_iosfc_unmap_memory(void *a, void *b, void *c, void *d, void *e, void *f) "a=%p b=%p c=%p d=%p e=%p f=%p"
+apple_gfx_iosfc_unmap_memory_region(void* mem, void *region) "unmapping @ %p from memory region %p"
+apple_gfx_iosfc_raise_irq(uint32_t vector) "vector=0x%x"
+
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index c096ec9..3618913 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -88,17 +88,16 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
rom_add_vga(VGABIOS_FILENAME);
}
-static Property vga_isa_properties[] = {
+static const Property vga_isa_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 8),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vga_isa_class_initfn(ObjectClass *klass, void *data)
+static void vga_isa_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = vga_isa_realizefn;
- dc->reset = vga_isa_reset;
+ device_class_set_legacy_reset(dc, vga_isa_reset);
dc->vmsd = &vmstate_vga_common;
device_class_set_props(dc, vga_isa_properties);
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
diff --git a/hw/display/vga-mmio.c b/hw/display/vga-mmio.c
index cd2c467..3326385 100644
--- a/hw/display/vga-mmio.c
+++ b/hw/display/vga-mmio.c
@@ -111,18 +111,17 @@ static void vga_mmio_realizefn(DeviceState *dev, Error **errp)
s->vga.con = graphic_console_init(dev, 0, s->vga.hw_ops, &s->vga);
}
-static Property vga_mmio_properties[] = {
+static const Property vga_mmio_properties[] = {
DEFINE_PROP_UINT8("it_shift", VGAMmioState, it_shift, 0),
DEFINE_PROP_UINT32("vgamem_mb", VGAMmioState, vga.vram_size_mb, 8),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vga_mmio_class_initfn(ObjectClass *klass, void *data)
+static void vga_mmio_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = vga_mmio_realizefn;
- dc->reset = vga_mmio_reset;
+ device_class_set_legacy_reset(dc, vga_mmio_reset);
dc->vmsd = &vmstate_vga_common;
device_class_set_props(dc, vga_mmio_properties);
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 2d8adce..b81f7fd 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -330,7 +330,7 @@ static void pci_secondary_vga_reset(DeviceState *dev)
vga_common_reset(&d->vga);
}
-static Property vga_pci_properties[] = {
+static const Property vga_pci_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
DEFINE_PROP_BIT("qemu-extended-regs",
@@ -339,20 +339,18 @@ static Property vga_pci_properties[] = {
PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_EDID, true),
DEFINE_EDID_PROPERTIES(PCIVGAState, edid_info),
DEFINE_PROP_BOOL("global-vmstate", PCIVGAState, vga.global_vmstate, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static Property secondary_pci_properties[] = {
+static const Property secondary_pci_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
DEFINE_PROP_BIT("qemu-extended-regs",
PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_QEXT, true),
DEFINE_PROP_BIT("edid",
PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_EDID, true),
DEFINE_EDID_PROPERTIES(PCIVGAState, edid_info),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vga_pci_class_init(ObjectClass *klass, void *data)
+static void vga_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -371,14 +369,14 @@ static const TypeInfo vga_pci_type_info = {
.instance_size = sizeof(PCIVGAState),
.abstract = true,
.class_init = vga_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
-static void vga_class_init(ObjectClass *klass, void *data)
+static void vga_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -394,7 +392,7 @@ static void vga_class_init(ObjectClass *klass, void *data)
vga_get_big_endian_fb, vga_set_big_endian_fb);
}
-static void secondary_class_init(ObjectClass *klass, void *data)
+static void secondary_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -403,7 +401,7 @@ static void secondary_class_init(ObjectClass *klass, void *data)
k->exit = pci_secondary_vga_exit;
k->class_id = PCI_CLASS_DISPLAY_OTHER;
device_class_set_props(dc, secondary_pci_properties);
- dc->reset = pci_secondary_vga_reset;
+ device_class_set_legacy_reset(dc, pci_secondary_vga_reset);
}
static const TypeInfo vga_info = {
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 892fedc..20475eb 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -24,7 +24,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "qapi/error.h"
#include "exec/tswap.h"
#include "hw/display/vga.h"
@@ -1873,7 +1873,6 @@ void vga_common_reset(VGACommonState *s)
s->cursor_start = 0;
s->cursor_end = 0;
s->cursor_offset = 0;
- s->big_endian_fb = s->default_endian_fb;
memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
memset(s->last_palette, '\0', sizeof(s->last_palette));
memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
@@ -2265,7 +2264,8 @@ bool vga_common_init(VGACommonState *s, Object *obj, Error **errp)
* into a device attribute set by the machine/platform to remove
* all target endian dependencies from this file.
*/
- s->default_endian_fb = target_words_bigendian();
+ s->default_endian_fb = target_big_endian();
+ s->big_endian_fb = s->default_endian_fb;
vga_dirty_log_start(s);
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index f77c1c1..747b5cc 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -26,8 +26,8 @@
#define HW_VGA_INT_H
#include "ui/console.h"
-#include "exec/ioport.h"
-#include "exec/memory.h"
+#include "system/ioport.h"
+#include "system/memory.h"
#include "hw/display/bochs-vbe.h"
#include "hw/acpi/acpi_aml_interface.h"
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index 63c64dd..9fc6bbc 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -18,6 +18,7 @@
#include "chardev/char-fe.h"
#include "qapi/error.h"
#include "migration/blocker.h"
+#include "standard-headers/drm/drm_fourcc.h"
typedef enum VhostUserGpuRequest {
VHOST_USER_GPU_NONE = 0,
@@ -249,7 +250,9 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
case VHOST_USER_GPU_DMABUF_SCANOUT: {
VhostUserGpuDMABUFScanout *m = &msg->payload.dmabuf_scanout;
int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr);
- uint64_t modifier = 0;
+ uint32_t offset = 0;
+ uint32_t stride = m->fd_stride;
+ uint64_t modifier = DRM_FORMAT_MOD_INVALID;
QemuDmaBuf *dmabuf;
if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
@@ -282,10 +285,10 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
}
dmabuf = qemu_dmabuf_new(m->width, m->height,
- m->fd_stride, 0, 0,
+ &offset, &stride, 0, 0,
m->fd_width, m->fd_height,
m->fd_drm_fourcc, modifier,
- fd, false, m->fd_flags &
+ &fd, 1, false, m->fd_flags &
VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP);
dpy_gl_scanout_dmabuf(con, dmabuf);
@@ -390,7 +393,7 @@ vhost_user_gpu_chr_read(void *opaque)
}
msg->request = request;
- msg->flags = size;
+ msg->flags = flags;
msg->size = size;
if (request == VHOST_USER_GPU_CURSOR_UPDATE ||
@@ -513,7 +516,7 @@ vhost_user_gpu_set_config(VirtIODevice *vdev,
}
}
-static void
+static int
vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val)
{
VhostUserGPU *g = VHOST_USER_GPU(vdev);
@@ -522,18 +525,24 @@ vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val)
if (val & VIRTIO_CONFIG_S_DRIVER_OK && vdev->vm_running) {
if (!vhost_user_gpu_do_set_socket(g, &err)) {
error_report_err(err);
- return;
+ return 0;
}
vhost_user_backend_start(g->vhost);
} else {
+ int ret;
+
/* unblock any wait and stop processing */
if (g->vhost_gpu_fd != -1) {
vhost_user_gpu_update_blocked(g, true);
qemu_chr_fe_deinit(&g->vhost_chr, true);
g->vhost_gpu_fd = -1;
}
- vhost_user_backend_stop(g->vhost);
+ ret = vhost_user_backend_stop(g->vhost);
+ if (ret < 0) {
+ return ret;
+ }
}
+ return 0;
}
static bool
@@ -631,6 +640,14 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
error_report("EDID requested but the backend doesn't support it.");
g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_EDID_ENABLED);
}
+ if (virtio_has_feature(g->vhost->dev.features,
+ VIRTIO_GPU_F_RESOURCE_UUID)) {
+ g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
+ }
+ if (virtio_has_feature(g->vhost->dev.features,
+ VIRTIO_GPU_F_RESOURCE_UUID)) {
+ g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
+ }
if (!virtio_gpu_base_device_realize(qdev, NULL, NULL, errp)) {
return;
@@ -642,16 +659,15 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
{
VhostUserGPU *g = VHOST_USER_GPU(vdev);
- return &g->vhost->dev;
+ return g->vhost ? &g->vhost->dev : NULL;
}
-static Property vhost_user_gpu_properties[] = {
+static const Property vhost_user_gpu_properties[] = {
VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf),
- DEFINE_PROP_END_OF_LIST(),
};
static void
-vhost_user_gpu_class_init(ObjectClass *klass, void *data)
+vhost_user_gpu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 4fc7ef8..9eb806b 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -110,7 +110,6 @@ static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
/* send event to guest */
virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
- return;
}
static void
@@ -235,6 +234,9 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features,
if (virtio_gpu_context_init_enabled(g->conf)) {
features |= (1 << VIRTIO_GPU_F_CONTEXT_INIT);
}
+ if (virtio_gpu_resource_uuid_enabled(g->conf)) {
+ features |= (1 << VIRTIO_GPU_F_RESOURCE_UUID);
+ }
return features;
}
@@ -260,7 +262,7 @@ virtio_gpu_base_device_unrealize(DeviceState *qdev)
}
static void
-virtio_gpu_base_class_init(ObjectClass *klass, void *data)
+virtio_gpu_base_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
index 29d20b0..c06a078 100644
--- a/hw/display/virtio-gpu-gl.c
+++ b/hw/display/virtio-gpu-gl.c
@@ -16,7 +16,7 @@
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-gpu.h"
#include "hw/virtio/virtio-gpu-bswap.h"
@@ -29,9 +29,14 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g,
struct virtio_gpu_scanout *s,
uint32_t resource_id)
{
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
uint32_t width, height;
uint32_t pixels, *data;
+ if (gl->renderer_state != RS_INITED) {
+ return;
+ }
+
data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
if (!data) {
return;
@@ -65,13 +70,22 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
return;
}
- if (!gl->renderer_inited) {
- virtio_gpu_virgl_init(g);
- gl->renderer_inited = true;
- }
- if (gl->renderer_reset) {
- gl->renderer_reset = false;
+ switch (gl->renderer_state) {
+ case RS_RESET:
virtio_gpu_virgl_reset(g);
+ /* fallthrough */
+ case RS_START:
+ if (virtio_gpu_virgl_init(g)) {
+ gl->renderer_state = RS_INIT_FAILED;
+ return;
+ }
+
+ gl->renderer_state = RS_INITED;
+ break;
+ case RS_INIT_FAILED:
+ return;
+ case RS_INITED:
+ break;
}
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
@@ -98,9 +112,9 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev)
* GL functions must be called with the associated GL context in main
* thread, and when the renderer is unblocked.
*/
- if (gl->renderer_inited && !gl->renderer_reset) {
+ if (gl->renderer_state == RS_INITED) {
virtio_gpu_virgl_reset_scanout(g);
- gl->renderer_reset = true;
+ gl->renderer_state = RS_RESET;
}
}
@@ -130,19 +144,45 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp)
}
g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
- VIRTIO_GPU_BASE(g)->virtio_config.num_capsets =
- virtio_gpu_virgl_get_num_capsets(g);
+ g->capset_ids = virtio_gpu_virgl_get_capsets(g);
+ VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = g->capset_ids->len;
+
+#if VIRGL_VERSION_MAJOR >= 1
+ g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED;
+#endif
virtio_gpu_device_realize(qdev, errp);
}
-static Property virtio_gpu_gl_properties[] = {
+static const Property virtio_gpu_gl_properties[] = {
DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags,
VIRTIO_GPU_FLAG_STATS_ENABLED, false),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags,
+ VIRTIO_GPU_FLAG_VENUS_ENABLED, false),
};
-static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data)
+static void virtio_gpu_gl_device_unrealize(DeviceState *qdev)
+{
+ VirtIOGPU *g = VIRTIO_GPU(qdev);
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev);
+
+ if (gl->renderer_state >= RS_INITED) {
+#if VIRGL_VERSION_MAJOR >= 1
+ qemu_bh_delete(gl->cmdq_resume_bh);
+#endif
+ if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
+ timer_free(gl->print_stats);
+ }
+ timer_free(gl->fence_poll);
+ virgl_renderer_cleanup(NULL);
+ }
+
+ gl->renderer_state = RS_START;
+
+ g_array_unref(g->capset_ids);
+}
+
+static void virtio_gpu_gl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -155,6 +195,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data)
vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data;
vdc->realize = virtio_gpu_gl_device_realize;
+ vdc->unrealize = virtio_gpu_gl_device_unrealize;
vdc->reset = virtio_gpu_gl_reset;
device_class_set_props(dc, virtio_gpu_gl_properties);
}
diff --git a/hw/display/virtio-gpu-pci-rutabaga.c b/hw/display/virtio-gpu-pci-rutabaga.c
index abbb898..5fdff37 100644
--- a/hw/display/virtio-gpu-pci-rutabaga.c
+++ b/hw/display/virtio-gpu-pci-rutabaga.c
@@ -34,7 +34,7 @@ static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
.parent = TYPE_VIRTIO_GPU_PCI_BASE,
.instance_size = sizeof(VirtIOGPURutabagaPCI),
.instance_init = virtio_gpu_rutabaga_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
}
diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
index da6a99f..c0d71b6 100644
--- a/hw/display/virtio-gpu-pci.c
+++ b/hw/display/virtio-gpu-pci.c
@@ -21,9 +21,8 @@
#include "hw/virtio/virtio-gpu-pci.h"
#include "qom/object.h"
-static Property virtio_gpu_pci_base_properties[] = {
+static const Property virtio_gpu_pci_base_properties[] = {
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -58,7 +57,7 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
}
}
-static void virtio_gpu_pci_base_class_init(ObjectClass *klass, void *data)
+static void virtio_gpu_pci_base_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c
index 17bf701..ed5ae52 100644
--- a/hw/display/virtio-gpu-rutabaga.c
+++ b/hw/display/virtio-gpu-rutabaga.c
@@ -1096,7 +1096,7 @@ static void virtio_gpu_rutabaga_realize(DeviceState *qdev, Error **errp)
virtio_gpu_device_realize(qdev, errp);
}
-static Property virtio_gpu_rutabaga_properties[] = {
+static const Property virtio_gpu_rutabaga_properties[] = {
DEFINE_PROP_BIT64("gfxstream-vulkan", VirtIOGPURutabaga, capset_mask,
RUTABAGA_CAPSET_GFXSTREAM_VULKAN, false),
DEFINE_PROP_BIT64("cross-domain", VirtIOGPURutabaga, capset_mask,
@@ -1108,10 +1108,9 @@ static Property virtio_gpu_rutabaga_properties[] = {
DEFINE_PROP_STRING("wayland-socket-path", VirtIOGPURutabaga,
wayland_socket_path),
DEFINE_PROP_STRING("wsi", VirtIOGPURutabaga, wsi),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, void *data)
+static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
index c02ec6d..d804f32 100644
--- a/hw/display/virtio-gpu-udmabuf.c
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -19,12 +19,13 @@
#include "hw/virtio/virtio-gpu.h"
#include "hw/virtio/virtio-gpu-pixman.h"
#include "trace.h"
-#include "exec/ramblock.h"
-#include "sysemu/hostmem.h"
+#include "system/ramblock.h"
+#include "system/hostmem.h"
#include <sys/ioctl.h>
#include <linux/memfd.h>
#include "qemu/memfd.h"
#include "standard-headers/linux/udmabuf.h"
+#include "standard-headers/drm/drm_fourcc.h"
static void virtio_gpu_create_udmabuf(struct virtio_gpu_simple_resource *res)
{
@@ -176,16 +177,19 @@ static VGPUDMABuf
struct virtio_gpu_rect *r)
{
VGPUDMABuf *dmabuf;
+ uint32_t offset = 0;
if (res->dmabuf_fd < 0) {
return NULL;
}
dmabuf = g_new0(VGPUDMABuf, 1);
- dmabuf->buf = qemu_dmabuf_new(r->width, r->height, fb->stride,
+ dmabuf->buf = qemu_dmabuf_new(r->width, r->height,
+ &offset, &fb->stride,
r->x, r->y, fb->width, fb->height,
qemu_pixman_to_drm_format(fb->format),
- 0, res->dmabuf_fd, true, false);
+ DRM_FORMAT_MOD_INVALID, &res->dmabuf_fd,
+ 1, true, false);
dmabuf->scanout_id = scanout_id;
QTAILQ_INSERT_HEAD(&g->dmabuf.bufs, dmabuf, next);
diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 9f34d0e..145a0b3 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -17,11 +17,31 @@
#include "trace.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-gpu.h"
+#include "hw/virtio/virtio-gpu-bswap.h"
+#include "hw/virtio/virtio-gpu-pixman.h"
#include "ui/egl-helpers.h"
#include <virglrenderer.h>
+struct virtio_gpu_virgl_resource {
+ struct virtio_gpu_simple_resource base;
+ MemoryRegion *mr;
+};
+
+static struct virtio_gpu_virgl_resource *
+virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id)
+{
+ struct virtio_gpu_simple_resource *res;
+
+ res = virtio_gpu_find_resource(g, resource_id);
+ if (!res) {
+ return NULL;
+ }
+
+ return container_of(res, struct virtio_gpu_virgl_resource, base);
+}
+
#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
static void *
virgl_get_egl_display(G_GNUC_UNUSED void *cookie)
@@ -30,16 +50,179 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie)
}
#endif
+#if VIRGL_VERSION_MAJOR >= 1
+struct virtio_gpu_virgl_hostmem_region {
+ MemoryRegion mr;
+ struct VirtIOGPU *g;
+ bool finish_unmapping;
+};
+
+static struct virtio_gpu_virgl_hostmem_region *
+to_hostmem_region(MemoryRegion *mr)
+{
+ return container_of(mr, struct virtio_gpu_virgl_hostmem_region, mr);
+}
+
+static void virtio_gpu_virgl_resume_cmdq_bh(void *opaque)
+{
+ VirtIOGPU *g = opaque;
+
+ virtio_gpu_process_cmdq(g);
+}
+
+static void virtio_gpu_virgl_hostmem_region_free(void *obj)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+ struct virtio_gpu_virgl_hostmem_region *vmr;
+ VirtIOGPUBase *b;
+ VirtIOGPUGL *gl;
+
+ vmr = to_hostmem_region(mr);
+ vmr->finish_unmapping = true;
+
+ b = VIRTIO_GPU_BASE(vmr->g);
+ b->renderer_blocked--;
+
+ /*
+ * memory_region_unref() is executed from RCU thread context, while
+ * virglrenderer works only on the main-loop thread that's holding GL
+ * context.
+ */
+ gl = VIRTIO_GPU_GL(vmr->g);
+ qemu_bh_schedule(gl->cmdq_resume_bh);
+}
+
+static int
+virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g,
+ struct virtio_gpu_virgl_resource *res,
+ uint64_t offset)
+{
+ struct virtio_gpu_virgl_hostmem_region *vmr;
+ VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
+ MemoryRegion *mr;
+ uint64_t size;
+ void *data;
+ int ret;
+
+ if (!virtio_gpu_hostmem_enabled(b->conf)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: hostmem disabled\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ ret = virgl_renderer_resource_map(res->base.resource_id, &data, &size);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map virgl resource: %s\n",
+ __func__, strerror(-ret));
+ return ret;
+ }
+
+ vmr = g_new0(struct virtio_gpu_virgl_hostmem_region, 1);
+ vmr->g = g;
+
+ mr = &vmr->mr;
+ memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data);
+ memory_region_add_subregion(&b->hostmem, offset, mr);
+ memory_region_set_enabled(mr, true);
+
+ /*
+ * MR could outlive the resource if MR's reference is held outside of
+ * virtio-gpu. In order to prevent unmapping resource while MR is alive,
+ * and thus, making the data pointer invalid, we will block virtio-gpu
+ * command processing until MR is fully unreferenced and freed.
+ */
+ OBJECT(mr)->free = virtio_gpu_virgl_hostmem_region_free;
+
+ res->mr = mr;
+
+ return 0;
+}
+
+static int
+virtio_gpu_virgl_unmap_resource_blob(VirtIOGPU *g,
+ struct virtio_gpu_virgl_resource *res,
+ bool *cmd_suspended)
+{
+ struct virtio_gpu_virgl_hostmem_region *vmr;
+ VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
+ MemoryRegion *mr = res->mr;
+ int ret;
+
+ if (!mr) {
+ return 0;
+ }
+
+ vmr = to_hostmem_region(res->mr);
+
+ /*
+ * Perform async unmapping in 3 steps:
+ *
+ * 1. Begin async unmapping with memory_region_del_subregion()
+ * and suspend/block cmd processing.
+ * 2. Wait for res->mr to be freed and cmd processing resumed
+ * asynchronously by virtio_gpu_virgl_hostmem_region_free().
+ * 3. Finish the unmapping with final virgl_renderer_resource_unmap().
+ */
+ if (vmr->finish_unmapping) {
+ res->mr = NULL;
+ g_free(vmr);
+
+ ret = virgl_renderer_resource_unmap(res->base.resource_id);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: failed to unmap virgl resource: %s\n",
+ __func__, strerror(-ret));
+ return ret;
+ }
+ } else {
+ *cmd_suspended = true;
+
+ /* render will be unblocked once MR is freed */
+ b->renderer_blocked++;
+
+ /* memory region owns self res->mr object and frees it by itself */
+ memory_region_set_enabled(mr, false);
+ memory_region_del_subregion(&b->hostmem, mr);
+ object_unparent(OBJECT(mr));
+ }
+
+ return 0;
+}
+#endif
+
static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
struct virtio_gpu_resource_create_2d c2d;
struct virgl_renderer_resource_create_args args;
+ struct virtio_gpu_virgl_resource *res;
VIRTIO_GPU_FILL_CMD(c2d);
trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
c2d.width, c2d.height);
+ if (c2d.resource_id == 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, c2d.resource_id);
+ if (res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
+ __func__, c2d.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = g_new0(struct virtio_gpu_virgl_resource, 1);
+ res->base.width = c2d.width;
+ res->base.height = c2d.height;
+ res->base.format = c2d.format;
+ res->base.resource_id = c2d.resource_id;
+ res->base.dmabuf_fd = -1;
+ QTAILQ_INSERT_HEAD(&g->reslist, &res->base, next);
+
args.handle = c2d.resource_id;
args.target = 2;
args.format = c2d.format;
@@ -59,11 +242,35 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
{
struct virtio_gpu_resource_create_3d c3d;
struct virgl_renderer_resource_create_args args;
+ struct virtio_gpu_virgl_resource *res;
VIRTIO_GPU_FILL_CMD(c3d);
trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
c3d.width, c3d.height, c3d.depth);
+ if (c3d.resource_id == 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, c3d.resource_id);
+ if (res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
+ __func__, c3d.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = g_new0(struct virtio_gpu_virgl_resource, 1);
+ res->base.width = c3d.width;
+ res->base.height = c3d.height;
+ res->base.format = c3d.format;
+ res->base.resource_id = c3d.resource_id;
+ res->base.dmabuf_fd = -1;
+ QTAILQ_INSERT_HEAD(&g->reslist, &res->base, next);
+
args.handle = c3d.resource_id;
args.target = c3d.target;
args.format = c3d.format;
@@ -79,15 +286,35 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
}
static void virgl_cmd_resource_unref(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
+ struct virtio_gpu_ctrl_command *cmd,
+ bool *cmd_suspended)
{
struct virtio_gpu_resource_unref unref;
+ struct virtio_gpu_virgl_resource *res;
struct iovec *res_iovs = NULL;
int num_iovs = 0;
VIRTIO_GPU_FILL_CMD(unref);
trace_virtio_gpu_cmd_res_unref(unref.resource_id);
+ res = virtio_gpu_virgl_find_resource(g, unref.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, unref.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+#if VIRGL_VERSION_MAJOR >= 1
+ if (virtio_gpu_virgl_unmap_resource_blob(g, res, cmd_suspended)) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+ if (*cmd_suspended) {
+ return;
+ }
+#endif
+
virgl_renderer_resource_detach_iov(unref.resource_id,
&res_iovs,
&num_iovs);
@@ -95,6 +322,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g,
virtio_gpu_cleanup_mapping_iov(g, res_iovs, num_iovs);
}
virgl_renderer_resource_unref(unref.resource_id);
+
+ QTAILQ_REMOVE(&g->reslist, &res->base, next);
+
+ g_free(res);
}
static void virgl_cmd_context_create(VirtIOGPU *g,
@@ -106,8 +337,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g,
trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
cc.debug_name);
- virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen,
- cc.debug_name);
+ if (cc.context_init) {
+ if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+
+#if VIRGL_VERSION_MAJOR >= 1
+ virgl_renderer_context_create_with_flags(cc.hdr.ctx_id,
+ cc.context_init,
+ cc.nlen,
+ cc.debug_name);
+ return;
+#endif
+ }
+
+ virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name);
}
static void virgl_cmd_context_destroy(VirtIOGPU *g,
@@ -171,7 +418,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
struct virgl_renderer_resource_info info;
void *d3d_tex2d = NULL;
-#ifdef HAVE_VIRGL_D3D_INFO_EXT
+#if VIRGL_VERSION_MAJOR >= 1
struct virgl_renderer_resource_info_ext ext;
memset(&ext, 0, sizeof(ext));
ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext);
@@ -375,19 +622,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g,
VIRTIO_GPU_FILL_CMD(info);
memset(&resp, 0, sizeof(resp));
- if (info.capset_index == 0) {
- resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL;
- virgl_renderer_get_cap_set(resp.capset_id,
- &resp.capset_max_version,
- &resp.capset_max_size);
- } else if (info.capset_index == 1) {
- resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2;
+
+ if (info.capset_index < g->capset_ids->len) {
+ resp.capset_id = g_array_index(g->capset_ids, uint32_t,
+ info.capset_index);
virgl_renderer_get_cap_set(resp.capset_id,
&resp.capset_max_version,
&resp.capset_max_size);
- } else {
- resp.capset_max_version = 0;
- resp.capset_max_size = 0;
}
resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
@@ -417,9 +658,221 @@ static void virgl_cmd_get_capset(VirtIOGPU *g,
g_free(resp);
}
+#if VIRGL_VERSION_MAJOR >= 1
+static void virgl_cmd_resource_create_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
+{
+ struct virgl_renderer_resource_create_blob_args virgl_args = { 0 };
+ g_autofree struct virtio_gpu_virgl_resource *res = NULL;
+ struct virtio_gpu_resource_create_blob cblob;
+ struct virgl_renderer_resource_info info;
+ int ret;
+
+ if (!virtio_gpu_blob_enabled(g->parent_obj.conf)) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ VIRTIO_GPU_FILL_CMD(cblob);
+ virtio_gpu_create_blob_bswap(&cblob);
+ trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
+
+ if (cblob.resource_id == 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, cblob.resource_id);
+ if (res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
+ __func__, cblob.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = g_new0(struct virtio_gpu_virgl_resource, 1);
+ res->base.resource_id = cblob.resource_id;
+ res->base.blob_size = cblob.size;
+ res->base.dmabuf_fd = -1;
+
+ if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
+ ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob),
+ cmd, &res->base.addrs,
+ &res->base.iov, &res->base.iov_cnt);
+ if (!ret) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+ }
+
+ virgl_args.res_handle = cblob.resource_id;
+ virgl_args.ctx_id = cblob.hdr.ctx_id;
+ virgl_args.blob_mem = cblob.blob_mem;
+ virgl_args.blob_id = cblob.blob_id;
+ virgl_args.blob_flags = cblob.blob_flags;
+ virgl_args.size = cblob.size;
+ virgl_args.iovecs = res->base.iov;
+ virgl_args.num_iovs = res->base.iov_cnt;
+
+ ret = virgl_renderer_resource_create_blob(&virgl_args);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: virgl blob create error: %s\n",
+ __func__, strerror(-ret));
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ virtio_gpu_cleanup_mapping(g, &res->base);
+ return;
+ }
+
+ ret = virgl_renderer_resource_get_info(cblob.resource_id, &info);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: resource does not have info %d: %s\n",
+ __func__, cblob.resource_id, strerror(-ret));
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ virtio_gpu_cleanup_mapping(g, &res->base);
+ virgl_renderer_resource_unref(cblob.resource_id);
+ return;
+ }
+
+ res->base.dmabuf_fd = info.fd;
+
+ QTAILQ_INSERT_HEAD(&g->reslist, &res->base, next);
+ res = NULL;
+}
+
+static void virgl_cmd_resource_map_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
+{
+ struct virtio_gpu_resource_map_blob mblob;
+ struct virtio_gpu_virgl_resource *res;
+ struct virtio_gpu_resp_map_info resp;
+ int ret;
+
+ VIRTIO_GPU_FILL_CMD(mblob);
+ virtio_gpu_map_blob_bswap(&mblob);
+
+ res = virtio_gpu_virgl_find_resource(g, mblob.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, mblob.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ ret = virtio_gpu_virgl_map_resource_blob(g, res, mblob.offset);
+ if (ret) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+
+ memset(&resp, 0, sizeof(resp));
+ resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
+ virgl_renderer_resource_get_map_info(mblob.resource_id, &resp.map_info);
+ virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
+}
+
+static void virgl_cmd_resource_unmap_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd,
+ bool *cmd_suspended)
+{
+ struct virtio_gpu_resource_unmap_blob ublob;
+ struct virtio_gpu_virgl_resource *res;
+ int ret;
+
+ VIRTIO_GPU_FILL_CMD(ublob);
+ virtio_gpu_unmap_blob_bswap(&ublob);
+
+ res = virtio_gpu_virgl_find_resource(g, ublob.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, ublob.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ ret = virtio_gpu_virgl_unmap_resource_blob(g, res, cmd_suspended);
+ if (ret) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+}
+
+static void virgl_cmd_set_scanout_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
+{
+ struct virtio_gpu_framebuffer fb = { 0 };
+ struct virtio_gpu_virgl_resource *res;
+ struct virtio_gpu_set_scanout_blob ss;
+
+ VIRTIO_GPU_FILL_CMD(ss);
+ virtio_gpu_scanout_blob_bswap(&ss);
+ trace_virtio_gpu_cmd_set_scanout_blob(ss.scanout_id, ss.resource_id,
+ ss.r.width, ss.r.height, ss.r.x,
+ ss.r.y);
+
+ if (ss.scanout_id >= g->parent_obj.conf.max_outputs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
+ __func__, ss.scanout_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
+ return;
+ }
+
+ if (ss.resource_id == 0) {
+ virtio_gpu_disable_scanout(g, ss.scanout_id);
+ return;
+ }
+
+ if (ss.width < 16 ||
+ ss.height < 16 ||
+ ss.r.x + ss.r.width > ss.width ||
+ ss.r.y + ss.r.height > ss.height) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
+ " resource %d, rect (%d,%d)+%d,%d, fb %d %d\n",
+ __func__, ss.scanout_id, ss.resource_id,
+ ss.r.x, ss.r.y, ss.r.width, ss.r.height,
+ ss.width, ss.height);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, ss.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, ss.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+ if (res->base.dmabuf_fd < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource not backed by dmabuf %d\n",
+ __func__, ss.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+
+ if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->base.blob_size)) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ g->parent_obj.enable = 1;
+ if (virtio_gpu_update_dmabuf(g, ss.scanout_id, &res->base, &fb, &ss.r)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to update dmabuf\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ virtio_gpu_update_scanout(g, ss.scanout_id, &res->base, &fb, &ss.r);
+}
+#endif
+
void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
+ bool cmd_suspended = false;
+
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
virgl_renderer_force_ctx_0();
@@ -461,7 +914,7 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
virgl_cmd_resource_flush(g, cmd);
break;
case VIRTIO_GPU_CMD_RESOURCE_UNREF:
- virgl_cmd_resource_unref(g, cmd);
+ virgl_cmd_resource_unref(g, cmd, &cmd_suspended);
break;
case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
/* TODO add security */
@@ -483,12 +936,26 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
case VIRTIO_GPU_CMD_GET_EDID:
virtio_gpu_get_edid(g, cmd);
break;
+#if VIRGL_VERSION_MAJOR >= 1
+ case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
+ virgl_cmd_resource_create_blob(g, cmd);
+ break;
+ case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB:
+ virgl_cmd_resource_map_blob(g, cmd);
+ break;
+ case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB:
+ virgl_cmd_resource_unmap_blob(g, cmd, &cmd_suspended);
+ break;
+ case VIRTIO_GPU_CMD_SET_SCANOUT_BLOB:
+ virgl_cmd_set_scanout_blob(g, cmd);
+ break;
+#endif
default:
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
break;
}
- if (cmd->finished) {
+ if (cmd_suspended || cmd->finished) {
return;
}
if (cmd->error) {
@@ -525,7 +992,7 @@ static void virgl_write_fence(void *opaque, uint32_t fence)
g_free(cmd);
g->inflight--;
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
- fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
+ trace_virtio_gpu_dec_inflight_fences(g->inflight);
}
}
}
@@ -574,6 +1041,7 @@ static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
static void virtio_gpu_print_stats(void *opaque)
{
VirtIOGPU *g = opaque;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
if (g->stats.requests) {
fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n",
@@ -588,17 +1056,18 @@ static void virtio_gpu_print_stats(void *opaque)
} else {
fprintf(stderr, "stats: idle\r");
}
- timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
+ timer_mod(gl->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
}
static void virtio_gpu_fence_poll(void *opaque)
{
VirtIOGPU *g = opaque;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
virgl_renderer_poll();
virtio_gpu_process_cmdq(g);
if (!QTAILQ_EMPTY(&g->cmdq) || !QTAILQ_EMPTY(&g->fenceq)) {
- timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10);
+ timer_mod(gl->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10);
}
}
@@ -626,6 +1095,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
{
int ret;
uint32_t flags = 0;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
if (qemu_egl_display) {
@@ -638,6 +1108,11 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE;
}
#endif
+#if VIRGL_VERSION_MAJOR >= 1
+ if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
+ flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER;
+ }
+#endif
ret = virgl_renderer_init(g, flags, &virtio_gpu_3d_cbs);
if (ret != 0) {
@@ -645,23 +1120,55 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
return ret;
}
- g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- virtio_gpu_fence_poll, g);
+ gl->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ virtio_gpu_fence_poll, g);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
- g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- virtio_gpu_print_stats, g);
- timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
+ gl->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ virtio_gpu_print_stats, g);
+ timer_mod(gl->print_stats,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
}
+
+#if VIRGL_VERSION_MAJOR >= 1
+ gl->cmdq_resume_bh = aio_bh_new(qemu_get_aio_context(),
+ virtio_gpu_virgl_resume_cmdq_bh,
+ g);
+#endif
+
return 0;
}
-int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g)
+static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id)
+{
+ g_array_append_val(capset_ids, capset_id);
+}
+
+GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g)
{
- uint32_t capset2_max_ver, capset2_max_size;
+ uint32_t capset_max_ver, capset_max_size;
+ GArray *capset_ids;
+
+ capset_ids = g_array_new(false, false, sizeof(uint32_t));
+
+ /* VIRGL is always supported. */
+ virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL);
+
virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2,
- &capset2_max_ver,
- &capset2_max_size);
+ &capset_max_ver,
+ &capset_max_size);
+ if (capset_max_ver) {
+ virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2);
+ }
+
+ if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
+ virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS,
+ &capset_max_ver,
+ &capset_max_size);
+ if (capset_max_size) {
+ virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS);
+ }
+ }
- return capset2_max_ver ? 2 : 1;
+ return capset_ids;
}
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 3281842..0a1a625 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -14,12 +14,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/iov.h"
-#include "sysemu/cpus.h"
+#include "system/cpus.h"
#include "ui/console.h"
#include "ui/rect.h"
#include "trace.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
+#include "system/dma.h"
+#include "system/system.h"
#include "hw/virtio/virtio.h"
#include "migration/qemu-file-types.h"
#include "hw/virtio/virtio-gpu.h"
@@ -28,6 +28,7 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
+#include "qemu/memfd.h"
#include "qemu/module.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -238,16 +239,6 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
return height * stride;
}
-#ifdef WIN32
-static void
-win32_pixman_image_destroy(pixman_image_t *image, void *data)
-{
- HANDLE handle = data;
-
- qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn);
-}
-#endif
-
static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
@@ -294,28 +285,20 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
- void *bits = NULL;
-#ifdef WIN32
- bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
- if (!bits) {
+ if (!qemu_pixman_image_new_shareable(
+ &res->image,
+ &res->share_handle,
+ "virtio-gpu res",
+ pformat,
+ c2d.width,
+ c2d.height,
+ c2d.height ? res->hostmem / c2d.height : 0,
+ &error_warn)) {
goto end;
}
-#endif
- res->image = pixman_image_create_bits(
- pformat,
- c2d.width,
- c2d.height,
- bits, c2d.height ? res->hostmem / c2d.height : 0);
-#ifdef WIN32
- if (res->image) {
- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
- }
-#endif
}
-#ifdef WIN32
end:
-#endif
if (!res->image) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: resource creation failed %d %d %d\n",
@@ -379,7 +362,7 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
}
-static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
+void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
{
struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id];
struct virtio_gpu_simple_resource *res;
@@ -596,11 +579,11 @@ static void virtio_unref_resource(pixman_image_t *image, void *data)
pixman_image_unref(data);
}
-static void virtio_gpu_update_scanout(VirtIOGPU *g,
- uint32_t scanout_id,
- struct virtio_gpu_simple_resource *res,
- struct virtio_gpu_framebuffer *fb,
- struct virtio_gpu_rect *r)
+void virtio_gpu_update_scanout(VirtIOGPU *g,
+ uint32_t scanout_id,
+ struct virtio_gpu_simple_resource *res,
+ struct virtio_gpu_framebuffer *fb,
+ struct virtio_gpu_rect *r)
{
struct virtio_gpu_simple_resource *ores;
struct virtio_gpu_scanout *scanout;
@@ -686,9 +669,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
/* realloc the surface ptr */
scanout->ds = qemu_create_displaysurface_pixman(rect);
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset);
-#endif
+ qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, fb->offset);
pixman_image_unref(rect);
dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con,
@@ -740,13 +721,47 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
&fb, res, &ss.r, &cmd->error);
}
+bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
+ struct virtio_gpu_set_scanout_blob *ss,
+ uint64_t blob_size)
+{
+ uint64_t fbend;
+
+ fb->format = virtio_gpu_get_pixman_format(ss->format);
+ if (!fb->format) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: host couldn't handle guest format %d\n",
+ __func__, ss->format);
+ return false;
+ }
+
+ fb->bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb->format), 8);
+ fb->width = ss->width;
+ fb->height = ss->height;
+ fb->stride = ss->strides[0];
+ fb->offset = ss->offsets[0] + ss->r.x * fb->bytes_pp + ss->r.y * fb->stride;
+
+ fbend = fb->offset;
+ fbend += (uint64_t) fb->stride * ss->r.height;
+
+ if (fbend > blob_size) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: fb end out of range\n",
+ __func__);
+ return false;
+ }
+
+ return true;
+}
+
+
+
static void virtio_gpu_set_scanout_blob(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
struct virtio_gpu_simple_resource *res;
struct virtio_gpu_framebuffer fb = { 0 };
struct virtio_gpu_set_scanout_blob ss;
- uint64_t fbend;
VIRTIO_GPU_FILL_CMD(ss);
virtio_gpu_scanout_blob_bswap(&ss);
@@ -772,28 +787,7 @@ static void virtio_gpu_set_scanout_blob(VirtIOGPU *g,
return;
}
- fb.format = virtio_gpu_get_pixman_format(ss.format);
- if (!fb.format) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: host couldn't handle guest format %d\n",
- __func__, ss.format);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
- return;
- }
-
- fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8);
- fb.width = ss.width;
- fb.height = ss.height;
- fb.stride = ss.strides[0];
- fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride;
-
- fbend = fb.offset;
- fbend += fb.stride * (ss.r.height - 1);
- fbend += fb.bytes_pp * ss.r.width;
- if (fbend > res->blob_size) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: fb end out of range\n",
- __func__);
+ if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->blob_size)) {
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
return;
}
@@ -1053,6 +1047,12 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
/* process command */
vgc->process_cmd(g, cmd);
+ /* command suspended */
+ if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
+ trace_virtio_gpu_cmd_suspended(cmd->cmd_hdr.type);
+ break;
+ }
+
QTAILQ_REMOVE(&g->cmdq, cmd, next);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
g->stats.requests++;
@@ -1065,7 +1065,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
if (g->stats.max_inflight < g->inflight) {
g->stats.max_inflight = g->inflight;
}
- fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
+ trace_virtio_gpu_inc_inflight_fences(g->inflight);
}
} else {
g_free(cmd);
@@ -1085,7 +1085,7 @@ static void virtio_gpu_process_fenceq(VirtIOGPU *g)
g_free(cmd);
g->inflight--;
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
- fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
+ trace_virtio_gpu_dec_inflight_fences(g->inflight);
}
}
}
@@ -1284,7 +1284,6 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
VirtIOGPU *g = opaque;
struct virtio_gpu_simple_resource *res;
uint32_t resource_id, pformat;
- void *bits = NULL;
int i;
g->hostmem = 0;
@@ -1311,24 +1310,17 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
}
res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
-#ifdef WIN32
- bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
- if (!bits) {
- g_free(res);
- return -EINVAL;
- }
-#endif
- res->image = pixman_image_create_bits(
- pformat,
- res->width, res->height,
- bits, res->height ? res->hostmem / res->height : 0);
- if (!res->image) {
+ if (!qemu_pixman_image_new_shareable(&res->image,
+ &res->share_handle,
+ "virtio-gpu res",
+ pformat,
+ res->width,
+ res->height,
+ res->height ? res->hostmem / res->height : 0,
+ &error_warn)) {
g_free(res);
return -EINVAL;
}
-#ifdef WIN32
- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
-#endif
res->addrs = g_new(uint64_t, res->iov_cnt);
res->iov = g_new(struct iovec, res->iov_cnt);
@@ -1461,9 +1453,7 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
return -EINVAL;
}
scanout->ds = qemu_create_displaysurface_pixman(res->image);
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
-#endif
+ qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, 0);
dpy_gfx_replace_surface(scanout->con, scanout->ds);
}
@@ -1484,15 +1474,35 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
if (virtio_gpu_blob_enabled(g->parent_obj.conf)) {
if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) &&
+ !virtio_gpu_virgl_enabled(g->parent_obj.conf) &&
!virtio_gpu_have_udmabuf()) {
error_setg(errp, "need rutabaga or udmabuf for blob resources");
return;
}
+#ifdef VIRGL_VERSION_MAJOR
+ #if VIRGL_VERSION_MAJOR < 1
if (virtio_gpu_virgl_enabled(g->parent_obj.conf)) {
- error_setg(errp, "blobs and virgl are not compatible (yet)");
+ error_setg(errp, "old virglrenderer, blob resources unsupported");
return;
}
+ #endif
+#endif
+ }
+
+ if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
+#ifdef VIRGL_VERSION_MAJOR
+ #if VIRGL_VERSION_MAJOR >= 1
+ if (!virtio_gpu_blob_enabled(g->parent_obj.conf) ||
+ !virtio_gpu_hostmem_enabled(g->parent_obj.conf)) {
+ error_setg(errp, "venus requires enabled blob and hostmem options");
+ return;
+ }
+ #else
+ error_setg(errp, "old virglrenderer, venus unsupported");
+ return;
+ #endif
+#endif
}
if (!virtio_gpu_base_device_realize(qdev,
@@ -1664,7 +1674,7 @@ static const VMStateDescription vmstate_virtio_gpu = {
.post_load = virtio_gpu_post_load,
};
-static Property virtio_gpu_properties[] = {
+static const Property virtio_gpu_properties[] = {
VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf),
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem,
256 * MiB),
@@ -1672,10 +1682,9 @@ static Property virtio_gpu_properties[] = {
VIRTIO_GPU_FLAG_BLOB_ENABLED, false),
DEFINE_PROP_SIZE("hostmem", VirtIOGPU, parent_obj.conf.hostmem, 0),
DEFINE_PROP_UINT8("x-scanout-vmstate-version", VirtIOGPU, scanout_vmstate_version, 2),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_gpu_class_init(ObjectClass *klass, void *data)
+static void virtio_gpu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 276f315..40e60f7 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -209,12 +209,11 @@ static void virtio_vga_set_big_endian_fb(Object *obj, bool value, Error **errp)
d->vga.big_endian_fb = value;
}
-static Property virtio_vga_base_properties[] = {
+static const Property virtio_vga_base_properties[] = {
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_vga_base_class_init(ObjectClass *klass, void *data)
+static void virtio_vga_base_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 3db3ff9..bc1a8ed 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -618,7 +618,7 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
uint32_t cmd, colour;
int args, len, maxloop = 1024;
int x, y, dx, dy, width, height;
- struct vmsvga_cursor_definition_s cursor;
+ QEMU_UNINITIALIZED struct vmsvga_cursor_definition_s cursor;
uint32_t cmd_start;
len = vmsvga_fifo_length(s);
@@ -1332,15 +1332,14 @@ static void pci_vmsvga_realize(PCIDevice *dev, Error **errp)
&s->chip.fifo_ram);
}
-static Property vga_vmware_properties[] = {
+static const Property vga_vmware_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", struct pci_vmsvga_state_s,
chip.vga.vram_size_mb, 16),
DEFINE_PROP_BOOL("global-vmstate", struct pci_vmsvga_state_s,
chip.vga.global_vmstate, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vmsvga_class_init(ObjectClass *klass, void *data)
+static void vmsvga_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1352,7 +1351,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_DISPLAY_VGA;
k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
k->subsystem_id = SVGA_PCI_DEVICE_ID;
- dc->reset = vmsvga_reset;
+ device_class_set_legacy_reset(dc, vmsvga_reset);
dc->vmsd = &vmstate_vmware_vga;
device_class_set_props(dc, vga_vmware_properties);
dc->hotpluggable = false;
@@ -1364,7 +1363,7 @@ static const TypeInfo vmsvga_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(struct pci_vmsvga_state_s),
.class_init = vmsvga_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 314d378..22822fe 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -29,7 +29,7 @@
#include "ui/input.h"
#include "ui/console.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/interface/io/fbif.h"
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index c42fc38..7c980ee 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -1387,18 +1387,17 @@ static void xlnx_dp_reset(DeviceState *dev)
xlnx_dp_update_irq(s);
}
-static Property xlnx_dp_device_properties[] = {
+static const Property xlnx_dp_device_properties[] = {
DEFINE_AUDIO_PROPERTIES(XlnxDPState, aud_card),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xlnx_dp_class_init(ObjectClass *oc, void *data)
+static void xlnx_dp_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = xlnx_dp_realize;
dc->vmsd = &vmstate_dp;
- dc->reset = xlnx_dp_reset;
+ device_class_set_legacy_reset(dc, xlnx_dp_reset);
device_class_set_props(dc, xlnx_dp_device_properties);
}
diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c
index 9bda450..a2771dd 100644
--- a/hw/dma/bcm2835_dma.c
+++ b/hw/dma/bcm2835_dma.c
@@ -385,12 +385,12 @@ static void bcm2835_dma_realize(DeviceState *dev, Error **errp)
bcm2835_dma_reset(dev);
}
-static void bcm2835_dma_class_init(ObjectClass *klass, void *data)
+static void bcm2835_dma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_dma_realize;
- dc->reset = bcm2835_dma_reset;
+ device_class_set_legacy_reset(dc, bcm2835_dma_reset);
dc->vmsd = &vmstate_bcm2835_dma;
}
diff --git a/hw/dma/etraxfs_dma.c b/hw/dma/etraxfs_dma.c
deleted file mode 100644
index 9c0003d..0000000
--- a/hw/dma/etraxfs_dma.c
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * QEMU ETRAX DMA Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "qemu/main-loop.h"
-#include "sysemu/runstate.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-
-#include "hw/cris/etraxfs_dma.h"
-
-#define D(x)
-
-#define RW_DATA (0x0 / 4)
-#define RW_SAVED_DATA (0x58 / 4)
-#define RW_SAVED_DATA_BUF (0x5c / 4)
-#define RW_GROUP (0x60 / 4)
-#define RW_GROUP_DOWN (0x7c / 4)
-#define RW_CMD (0x80 / 4)
-#define RW_CFG (0x84 / 4)
-#define RW_STAT (0x88 / 4)
-#define RW_INTR_MASK (0x8c / 4)
-#define RW_ACK_INTR (0x90 / 4)
-#define R_INTR (0x94 / 4)
-#define R_MASKED_INTR (0x98 / 4)
-#define RW_STREAM_CMD (0x9c / 4)
-
-#define DMA_REG_MAX (0x100 / 4)
-
-/* descriptors */
-
-// ------------------------------------------------------------ dma_descr_group
-typedef struct dma_descr_group {
- uint32_t next;
- unsigned eol : 1;
- unsigned tol : 1;
- unsigned bol : 1;
- unsigned : 1;
- unsigned intr : 1;
- unsigned : 2;
- unsigned en : 1;
- unsigned : 7;
- unsigned dis : 1;
- unsigned md : 16;
- struct dma_descr_group *up;
- union {
- struct dma_descr_context *context;
- struct dma_descr_group *group;
- } down;
-} dma_descr_group;
-
-// ---------------------------------------------------------- dma_descr_context
-typedef struct dma_descr_context {
- uint32_t next;
- unsigned eol : 1;
- unsigned : 3;
- unsigned intr : 1;
- unsigned : 1;
- unsigned store_mode : 1;
- unsigned en : 1;
- unsigned : 7;
- unsigned dis : 1;
- unsigned md0 : 16;
- unsigned md1;
- unsigned md2;
- unsigned md3;
- unsigned md4;
- uint32_t saved_data;
- uint32_t saved_data_buf;
-} dma_descr_context;
-
-// ------------------------------------------------------------- dma_descr_data
-typedef struct dma_descr_data {
- uint32_t next;
- uint32_t buf;
- unsigned eol : 1;
- unsigned : 2;
- unsigned out_eop : 1;
- unsigned intr : 1;
- unsigned wait : 1;
- unsigned : 2;
- unsigned : 3;
- unsigned in_eop : 1;
- unsigned : 4;
- unsigned md : 16;
- uint32_t after;
-} dma_descr_data;
-
-/* Constants */
-enum {
- regk_dma_ack_pkt = 0x00000100,
- regk_dma_anytime = 0x00000001,
- regk_dma_array = 0x00000008,
- regk_dma_burst = 0x00000020,
- regk_dma_client = 0x00000002,
- regk_dma_copy_next = 0x00000010,
- regk_dma_copy_up = 0x00000020,
- regk_dma_data_at_eol = 0x00000001,
- regk_dma_dis_c = 0x00000010,
- regk_dma_dis_g = 0x00000020,
- regk_dma_idle = 0x00000001,
- regk_dma_intern = 0x00000004,
- regk_dma_load_c = 0x00000200,
- regk_dma_load_c_n = 0x00000280,
- regk_dma_load_c_next = 0x00000240,
- regk_dma_load_d = 0x00000140,
- regk_dma_load_g = 0x00000300,
- regk_dma_load_g_down = 0x000003c0,
- regk_dma_load_g_next = 0x00000340,
- regk_dma_load_g_up = 0x00000380,
- regk_dma_next_en = 0x00000010,
- regk_dma_next_pkt = 0x00000010,
- regk_dma_no = 0x00000000,
- regk_dma_only_at_wait = 0x00000000,
- regk_dma_restore = 0x00000020,
- regk_dma_rst = 0x00000001,
- regk_dma_running = 0x00000004,
- regk_dma_rw_cfg_default = 0x00000000,
- regk_dma_rw_cmd_default = 0x00000000,
- regk_dma_rw_intr_mask_default = 0x00000000,
- regk_dma_rw_stat_default = 0x00000101,
- regk_dma_rw_stream_cmd_default = 0x00000000,
- regk_dma_save_down = 0x00000020,
- regk_dma_save_up = 0x00000020,
- regk_dma_set_reg = 0x00000050,
- regk_dma_set_w_size1 = 0x00000190,
- regk_dma_set_w_size2 = 0x000001a0,
- regk_dma_set_w_size4 = 0x000001c0,
- regk_dma_stopped = 0x00000002,
- regk_dma_store_c = 0x00000002,
- regk_dma_store_descr = 0x00000000,
- regk_dma_store_g = 0x00000004,
- regk_dma_store_md = 0x00000001,
- regk_dma_sw = 0x00000008,
- regk_dma_update_down = 0x00000020,
- regk_dma_yes = 0x00000001
-};
-
-enum dma_ch_state
-{
- RST = 1,
- STOPPED = 2,
- RUNNING = 4
-};
-
-struct fs_dma_channel
-{
- qemu_irq irq;
- struct etraxfs_dma_client *client;
-
- /* Internal status. */
- int stream_cmd_src;
- enum dma_ch_state state;
-
- unsigned int input : 1;
- unsigned int eol : 1;
-
- struct dma_descr_group current_g;
- struct dma_descr_context current_c;
- struct dma_descr_data current_d;
-
- /* Control registers. */
- uint32_t regs[DMA_REG_MAX];
-};
-
-struct fs_dma_ctrl
-{
- MemoryRegion mmio;
- int nr_channels;
- struct fs_dma_channel *channels;
-
- QEMUBH *bh;
-};
-
-static void DMA_run(void *opaque);
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c);
-
-static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
-{
- return ctrl->channels[c].regs[reg];
-}
-
-static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c)
-{
- return channel_reg(ctrl, c, RW_CFG) & 2;
-}
-
-static inline int channel_en(struct fs_dma_ctrl *ctrl, int c)
-{
- return (channel_reg(ctrl, c, RW_CFG) & 1)
- && ctrl->channels[c].client;
-}
-
-static inline int fs_channel(hwaddr addr)
-{
- /* Every channel has a 0x2000 ctrl register map. */
- return addr >> 13;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP);
-
- /* Load and decode. FIXME: handle endianness. */
- cpu_physical_memory_read(addr, &ctrl->channels[c].current_g,
- sizeof(ctrl->channels[c].current_g));
-}
-
-static void dump_c(int ch, struct dma_descr_context *c)
-{
- printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", c->next);
- printf("saved_data=%x\n", c->saved_data);
- printf("saved_data_buf=%x\n", c->saved_data_buf);
- printf("eol=%x\n", (uint32_t) c->eol);
-}
-
-static void dump_d(int ch, struct dma_descr_data *d)
-{
- printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", d->next);
- printf("buf=%x\n", d->buf);
- printf("after=%x\n", d->after);
- printf("intr=%x\n", (uint32_t) d->intr);
- printf("out_eop=%x\n", (uint32_t) d->out_eop);
- printf("in_eop=%x\n", (uint32_t) d->in_eop);
- printf("eol=%x\n", (uint32_t) d->eol);
-}
-#endif
-
-static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
- /* Load and decode. FIXME: handle endianness. */
- cpu_physical_memory_read(addr, &ctrl->channels[c].current_c,
- sizeof(ctrl->channels[c].current_c));
-
- D(dump_c(c, &ctrl->channels[c].current_c));
- /* I guess this should update the current pos. */
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data;
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf;
-}
-
-static void channel_load_d(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
- /* Load and decode. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr));
- cpu_physical_memory_read(addr, &ctrl->channels[c].current_d,
- sizeof(ctrl->channels[c].current_d));
-
- D(dump_d(c, &ctrl->channels[c].current_d));
- ctrl->channels[c].regs[RW_DATA] = addr;
-}
-
-static void channel_store_c(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
- /* Encode and store. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr));
- D(dump_d(c, &ctrl->channels[c].current_d));
- cpu_physical_memory_write(addr, &ctrl->channels[c].current_c,
- sizeof(ctrl->channels[c].current_c));
-}
-
-static void channel_store_d(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
- /* Encode and store. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr));
- cpu_physical_memory_write(addr, &ctrl->channels[c].current_d,
- sizeof(ctrl->channels[c].current_d));
-}
-
-static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c)
-{
- /* FIXME: */
-}
-
-static inline void channel_start(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].client)
- {
- ctrl->channels[c].eol = 0;
- ctrl->channels[c].state = RUNNING;
- if (!ctrl->channels[c].input)
- channel_out_run(ctrl, c);
- } else
- printf("WARNING: starting DMA ch %d with no client\n", c);
-
- qemu_bh_schedule_idle(ctrl->bh);
-}
-
-static void channel_continue(struct fs_dma_ctrl *ctrl, int c)
-{
- if (!channel_en(ctrl, c)
- || channel_stopped(ctrl, c)
- || ctrl->channels[c].state != RUNNING
- /* Only reload the current data descriptor if it has eol set. */
- || !ctrl->channels[c].current_d.eol) {
- D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n",
- c, ctrl->channels[c].state,
- channel_stopped(ctrl, c),
- channel_en(ctrl,c),
- ctrl->channels[c].eol));
- D(dump_d(c, &ctrl->channels[c].current_d));
- return;
- }
-
- /* Reload the current descriptor. */
- channel_load_d(ctrl, c);
-
- /* If the current descriptor cleared the eol flag and we had already
- reached eol state, do the continue. */
- if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) {
- D(printf("continue %d ok %x\n", c,
- ctrl->channels[c].current_d.next));
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.next;
- channel_load_d(ctrl, c);
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-
- channel_start(ctrl, c);
- }
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-}
-
-static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v)
-{
- unsigned int cmd = v & ((1 << 10) - 1);
-
- D(printf("%s ch=%d cmd=%x\n",
- __func__, c, cmd));
- if (cmd & regk_dma_load_d) {
- channel_load_d(ctrl, c);
- if (cmd & regk_dma_burst)
- channel_start(ctrl, c);
- }
-
- if (cmd & regk_dma_load_c) {
- channel_load_c(ctrl, c);
- }
-}
-
-static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c)
-{
- D(printf("%s %d\n", __func__, c));
- ctrl->channels[c].regs[R_INTR] &=
- ~(ctrl->channels[c].regs[RW_ACK_INTR]);
-
- ctrl->channels[c].regs[R_MASKED_INTR] =
- ctrl->channels[c].regs[R_INTR]
- & ctrl->channels[c].regs[RW_INTR_MASK];
-
- D(printf("%s: chan=%d masked_intr=%x\n", __func__,
- c,
- ctrl->channels[c].regs[R_MASKED_INTR]));
-
- qemu_set_irq(ctrl->channels[c].irq,
- !!ctrl->channels[c].regs[R_MASKED_INTR]);
-}
-
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
-{
- uint32_t len;
- uint32_t saved_data_buf;
- unsigned char buf[2 * 1024];
-
- struct dma_context_metadata meta;
- bool send_context = true;
-
- if (ctrl->channels[c].eol)
- return 0;
-
- do {
- bool out_eop;
- D(printf("ch=%d buf=%x after=%x\n",
- c,
- (uint32_t)ctrl->channels[c].current_d.buf,
- (uint32_t)ctrl->channels[c].current_d.after));
-
- if (send_context) {
- if (ctrl->channels[c].client->client.metadata_push) {
- meta.metadata = ctrl->channels[c].current_d.md;
- ctrl->channels[c].client->client.metadata_push(
- ctrl->channels[c].client->client.opaque,
- &meta);
- }
- send_context = false;
- }
-
- channel_load_d(ctrl, c);
- saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
- len = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.after;
- len -= saved_data_buf;
-
- if (len > sizeof buf)
- len = sizeof buf;
- cpu_physical_memory_read (saved_data_buf, buf, len);
-
- out_eop = ((saved_data_buf + len) ==
- ctrl->channels[c].current_d.after) &&
- ctrl->channels[c].current_d.out_eop;
-
- D(printf("channel %d pushes %x %u bytes eop=%u\n", c,
- saved_data_buf, len, out_eop));
-
- if (ctrl->channels[c].client->client.push) {
- if (len > 0) {
- ctrl->channels[c].client->client.push(
- ctrl->channels[c].client->client.opaque,
- buf, len, out_eop);
- }
- } else {
- printf("WARNING: DMA ch%d dataloss,"
- " no attached client.\n", c);
- }
-
- saved_data_buf += len;
-
- if (saved_data_buf == (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.after) {
- /* Done. Step to next. */
- if (ctrl->channels[c].current_d.out_eop) {
- send_context = true;
- }
- if (ctrl->channels[c].current_d.intr) {
- /* data intr. */
- D(printf("signal intr %d eol=%d\n",
- len, ctrl->channels[c].current_d.eol));
- ctrl->channels[c].regs[R_INTR] |= (1 << 2);
- channel_update_irq(ctrl, c);
- }
- channel_store_d(ctrl, c);
- if (ctrl->channels[c].current_d.eol) {
- D(printf("channel %d EOL\n", c));
- ctrl->channels[c].eol = 1;
-
- /* Mark the context as disabled. */
- ctrl->channels[c].current_c.dis = 1;
- channel_store_c(ctrl, c);
-
- channel_stop(ctrl, c);
- } else {
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->
- channels[c].current_d.next;
- /* Load new descriptor. */
- channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.buf;
- }
-
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- saved_data_buf;
- D(dump_d(c, &ctrl->channels[c].current_d));
- }
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
- } while (!ctrl->channels[c].eol);
- return 1;
-}
-
-static int channel_in_process(struct fs_dma_ctrl *ctrl, int c,
- unsigned char *buf, int buflen, int eop)
-{
- uint32_t len;
- uint32_t saved_data_buf;
-
- if (ctrl->channels[c].eol == 1)
- return 0;
-
- channel_load_d(ctrl, c);
- saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
- len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after;
- len -= saved_data_buf;
-
- if (len > buflen)
- len = buflen;
-
- cpu_physical_memory_write (saved_data_buf, buf, len);
- saved_data_buf += len;
-
- if (saved_data_buf ==
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.after
- || eop) {
- uint32_t r_intr = ctrl->channels[c].regs[R_INTR];
-
- D(printf("in dscr end len=%d\n",
- ctrl->channels[c].current_d.after
- - ctrl->channels[c].current_d.buf));
- ctrl->channels[c].current_d.after = saved_data_buf;
-
- /* Done. Step to next. */
- if (ctrl->channels[c].current_d.intr) {
- /* TODO: signal eop to the client. */
- /* data intr. */
- ctrl->channels[c].regs[R_INTR] |= 3;
- }
- if (eop) {
- ctrl->channels[c].current_d.in_eop = 1;
- ctrl->channels[c].regs[R_INTR] |= 8;
- }
- if (r_intr != ctrl->channels[c].regs[R_INTR])
- channel_update_irq(ctrl, c);
-
- channel_store_d(ctrl, c);
- D(dump_d(c, &ctrl->channels[c].current_d));
-
- if (ctrl->channels[c].current_d.eol) {
- D(printf("channel %d EOL\n", c));
- ctrl->channels[c].eol = 1;
-
- /* Mark the context as disabled. */
- ctrl->channels[c].current_c.dis = 1;
- channel_store_c(ctrl, c);
-
- channel_stop(ctrl, c);
- } else {
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->
- channels[c].current_d.next;
- /* Load new descriptor. */
- channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.buf;
- }
- }
-
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
- return len;
-}
-
-static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].client->client.pull) {
- ctrl->channels[c].client->client.pull(
- ctrl->channels[c].client->client.opaque);
- return 1;
- } else
- return 0;
-}
-
-static uint32_t dma_rinvalid (void *opaque, hwaddr addr)
-{
- hw_error("Unsupported short raccess. reg=" HWADDR_FMT_plx "\n", addr);
- return 0;
-}
-
-static uint64_t
-dma_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- int c;
- uint32_t r = 0;
-
- if (size != 4) {
- dma_rinvalid(opaque, addr);
- }
-
- /* Make addr relative to this channel and bounded to nr regs. */
- c = fs_channel(addr);
- addr &= 0xff;
- addr >>= 2;
- switch (addr)
- {
- case RW_STAT:
- r = ctrl->channels[c].state & 7;
- r |= ctrl->channels[c].eol << 5;
- r |= ctrl->channels[c].stream_cmd_src << 8;
- break;
-
- default:
- r = ctrl->channels[c].regs[addr];
- D(printf("%s c=%d addr=" HWADDR_FMT_plx "\n",
- __func__, c, addr));
- break;
- }
- return r;
-}
-
-static void
-dma_winvalid (void *opaque, hwaddr addr, uint32_t value)
-{
- hw_error("Unsupported short waccess. reg=" HWADDR_FMT_plx "\n", addr);
-}
-
-static void
-dma_update_state(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].regs[RW_CFG] & 2)
- ctrl->channels[c].state = STOPPED;
- if (!(ctrl->channels[c].regs[RW_CFG] & 1))
- ctrl->channels[c].state = RST;
-}
-
-static void
-dma_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- uint32_t value = val64;
- int c;
-
- if (size != 4) {
- dma_winvalid(opaque, addr, value);
- }
-
- /* Make addr relative to this channel and bounded to nr regs. */
- c = fs_channel(addr);
- addr &= 0xff;
- addr >>= 2;
- switch (addr)
- {
- case RW_DATA:
- ctrl->channels[c].regs[addr] = value;
- break;
-
- case RW_CFG:
- ctrl->channels[c].regs[addr] = value;
- dma_update_state(ctrl, c);
- break;
- case RW_CMD:
- /* continue. */
- if (value & ~1)
- printf("Invalid store to ch=%d RW_CMD %x\n",
- c, value);
- ctrl->channels[c].regs[addr] = value;
- channel_continue(ctrl, c);
- break;
-
- case RW_SAVED_DATA:
- case RW_SAVED_DATA_BUF:
- case RW_GROUP:
- case RW_GROUP_DOWN:
- ctrl->channels[c].regs[addr] = value;
- break;
-
- case RW_ACK_INTR:
- case RW_INTR_MASK:
- ctrl->channels[c].regs[addr] = value;
- channel_update_irq(ctrl, c);
- if (addr == RW_ACK_INTR)
- ctrl->channels[c].regs[RW_ACK_INTR] = 0;
- break;
-
- case RW_STREAM_CMD:
- if (value & ~1023)
- printf("Invalid store to ch=%d "
- "RW_STREAMCMD %x\n",
- c, value);
- ctrl->channels[c].regs[addr] = value;
- D(printf("stream_cmd ch=%d\n", c));
- channel_stream_cmd(ctrl, c, value);
- break;
-
- default:
- D(printf("%s c=%d " HWADDR_FMT_plx "\n",
- __func__, c, addr));
- break;
- }
-}
-
-static const MemoryRegionOps dma_ops = {
- .read = dma_read,
- .write = dma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4
- }
-};
-
-static int etraxfs_dmac_run(void *opaque)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- int i;
- int p = 0;
-
- for (i = 0;
- i < ctrl->nr_channels;
- i++)
- {
- if (ctrl->channels[i].state == RUNNING)
- {
- if (ctrl->channels[i].input) {
- p += channel_in_run(ctrl, i);
- } else {
- p += channel_out_run(ctrl, i);
- }
- }
- }
- return p;
-}
-
-int etraxfs_dmac_input(struct etraxfs_dma_client *client,
- void *buf, int len, int eop)
-{
- return channel_in_process(client->ctrl, client->channel,
- buf, len, eop);
-}
-
-/* Connect an IRQ line with a channel. */
-void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- ctrl->channels[c].irq = *line;
- ctrl->channels[c].input = input;
-}
-
-void etraxfs_dmac_connect_client(void *opaque, int c,
- struct etraxfs_dma_client *cl)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- cl->ctrl = ctrl;
- cl->channel = c;
- ctrl->channels[c].client = cl;
-}
-
-
-static void DMA_run(void *opaque)
-{
- struct fs_dma_ctrl *etraxfs_dmac = opaque;
- int p = 1;
-
- if (runstate_is_running())
- p = etraxfs_dmac_run(etraxfs_dmac);
-
- if (p)
- qemu_bh_schedule_idle(etraxfs_dmac->bh);
-}
-
-void *etraxfs_dmac_init(hwaddr base, int nr_channels)
-{
- struct fs_dma_ctrl *ctrl = NULL;
-
- ctrl = g_malloc0(sizeof *ctrl);
-
- ctrl->bh = qemu_bh_new(DMA_run, ctrl);
-
- ctrl->nr_channels = nr_channels;
- ctrl->channels = g_malloc0(sizeof ctrl->channels[0] * nr_channels);
-
- memory_region_init_io(&ctrl->mmio, NULL, &dma_ops, ctrl, "etraxfs-dma",
- nr_channels * 0x2000);
- memory_region_add_subregion(get_system_memory(), base, &ctrl->mmio);
-
- return ctrl;
-}
diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c
index e72aa2e..e226eda 100644
--- a/hw/dma/i82374.c
+++ b/hw/dma/i82374.c
@@ -139,18 +139,19 @@ static void i82374_realize(DeviceState *dev, Error **errp)
memset(s->commands, 0, sizeof(s->commands));
}
-static Property i82374_properties[] = {
+static const Property i82374_properties[] = {
DEFINE_PROP_UINT32("iobase", I82374State, iobase, 0x400),
- DEFINE_PROP_END_OF_LIST()
};
-static void i82374_class_init(ObjectClass *klass, void *data)
+static void i82374_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = i82374_realize;
dc->vmsd = &vmstate_i82374;
device_class_set_props(dc, i82374_properties);
+ dc->desc = "Intel 82374 DMA controller";
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo i82374_info = {
diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c
index 24a54ca..2463952 100644
--- a/hw/dma/i8257.c
+++ b/hw/dma/i8257.c
@@ -585,21 +585,20 @@ static void i8257_realize(DeviceState *dev, Error **errp)
d->dma_bh = qemu_bh_new(i8257_dma_run, d);
}
-static Property i8257_properties[] = {
+static const Property i8257_properties[] = {
DEFINE_PROP_INT32("base", I8257State, base, 0x00),
DEFINE_PROP_INT32("page-base", I8257State, page_base, 0x80),
DEFINE_PROP_INT32("pageh-base", I8257State, pageh_base, 0x480),
DEFINE_PROP_INT32("dshift", I8257State, dshift, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void i8257_class_init(ObjectClass *klass, void *data)
+static void i8257_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IsaDmaClass *idc = ISADMA_CLASS(klass);
dc->realize = i8257_realize;
- dc->reset = i8257_reset;
+ device_class_set_legacy_reset(dc, i8257_reset);
dc->vmsd = &vmstate_i8257;
device_class_set_props(dc, i8257_properties);
@@ -619,7 +618,7 @@ static const TypeInfo i8257_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(I8257State),
.class_init = i8257_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ISADMA },
{ }
}
diff --git a/hw/dma/meson.build b/hw/dma/meson.build
index a96c1be..cc7810b 100644
--- a/hw/dma/meson.build
+++ b/hw/dma/meson.build
@@ -5,12 +5,10 @@ system_ss.add(when: 'CONFIG_I82374', if_true: files('i82374.c'))
system_ss.add(when: 'CONFIG_I8257', if_true: files('i8257.c'))
system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('xilinx_axidma.c'))
system_ss.add(when: 'CONFIG_ZYNQ_DEVCFG', if_true: files('xlnx-zynq-devcfg.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_dma.c'))
system_ss.add(when: 'CONFIG_STP2000', if_true: files('sparc32_dma.c'))
system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dpdma.c'))
system_ss.add(when: 'CONFIG_XLNX_ZDMA', if_true: files('xlnx-zdma.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
system_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
system_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c
index 77797a6..101f91f 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -131,9 +131,9 @@ struct omap_dma_s {
#define LAST_FRAME_INTR (1 << 4)
#define END_BLOCK_INTR (1 << 5)
#define SYNC (1 << 6)
-#define END_PKT_INTR (1 << 7)
-#define TRANS_ERR_INTR (1 << 8)
-#define MISALIGN_INTR (1 << 11)
+#define END_PKT_INTR (1 << 7)
+#define TRANS_ERR_INTR (1 << 8)
+#define MISALIGN_INTR (1 << 11)
static inline void omap_dma_interrupts_update(struct omap_dma_s *s)
{
@@ -526,12 +526,12 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
/* Check all the conditions that terminate the transfer starting
* with those that can occur the soonest. */
-#define INTR_CHECK(cond, id, nelements) \
- if (cond) { \
- elements[id] = nelements; \
- if (elements[id] < min_elems) \
- min_elems = elements[id]; \
- } else \
+#define INTR_CHECK(cond, id, nelements) \
+ if (cond) { \
+ elements[id] = nelements; \
+ if (elements[id] < min_elems) \
+ min_elems = elements[id]; \
+ } else \
elements[id] = INT_MAX;
/* Elements */
@@ -686,10 +686,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
struct omap_dma_s *s = dma->opaque;
soc_dma_reset(s->dma);
- if (s->model < omap_dma_4)
- s->gcr = 0x0004;
- else
- s->gcr = 0x00010010;
+ s->gcr = 0x0004;
s->ocp = 0x00000000;
memset(&s->irqstat, 0, sizeof(s->irqstat));
memset(&s->irqen, 0, sizeof(s->irqen));
@@ -697,8 +694,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
s->lcd_ch.condition = 0;
s->lcd_ch.interrupts = 0;
s->lcd_ch.dual = 0;
- if (s->model < omap_dma_4)
- omap_dma_enable_3_1_mapping(s);
+ omap_dma_enable_3_1_mapping(s);
for (i = 0; i < s->chans; i ++) {
s->ch[i].suspend = 0;
s->ch[i].prefetch = 0;
@@ -721,10 +717,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
s->ch[i].repeat = 0;
s->ch[i].auto_init = 0;
s->ch[i].link_enabled = 0;
- if (s->model < omap_dma_4)
- s->ch[i].interrupts = 0x0003;
- else
- s->ch[i].interrupts = 0x0000;
+ s->ch[i].interrupts = 0x0003;
s->ch[i].status = 0;
s->ch[i].cstatus = 0;
s->ch[i].active = 0;
@@ -747,7 +740,7 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s,
struct omap_dma_channel_s *ch, int reg, uint16_t *value)
{
switch (reg) {
- case 0x00: /* SYS_DMA_CSDP_CH0 */
+ case 0x00: /* SYS_DMA_CSDP_CH0 */
*value = (ch->burst[1] << 14) |
(ch->pack[1] << 13) |
(ch->port[1] << 9) |
@@ -757,9 +750,9 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s,
(ch->data_type >> 1);
break;
- case 0x02: /* SYS_DMA_CCR_CH0 */
+ case 0x02: /* SYS_DMA_CCR_CH0 */
if (s->model <= omap_dma_3_1)
- *value = 0 << 10; /* FIFO_FLUSH reads as 0 */
+ *value = 0 << 10; /* FIFO_FLUSH reads as 0 */
else
*value = ch->omap_3_1_compatible_disable << 10;
*value |= (ch->mode[1] << 14) |
@@ -772,11 +765,11 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s,
(ch->fs << 5) | ch->sync;
break;
- case 0x04: /* SYS_DMA_CICR_CH0 */
+ case 0x04: /* SYS_DMA_CICR_CH0 */
*value = ch->interrupts;
break;
- case 0x06: /* SYS_DMA_CSR_CH0 */
+ case 0x06: /* SYS_DMA_CSR_CH0 */
*value = ch->status;
ch->status &= SYNC;
if (!ch->omap_3_1_compatible_disable && ch->sibling) {
@@ -786,77 +779,77 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s,
qemu_irq_lower(ch->irq);
break;
- case 0x08: /* SYS_DMA_CSSA_L_CH0 */
+ case 0x08: /* SYS_DMA_CSSA_L_CH0 */
*value = ch->addr[0] & 0x0000ffff;
break;
- case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
+ case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
*value = ch->addr[0] >> 16;
break;
- case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
+ case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
*value = ch->addr[1] & 0x0000ffff;
break;
- case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
+ case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
*value = ch->addr[1] >> 16;
break;
- case 0x10: /* SYS_DMA_CEN_CH0 */
+ case 0x10: /* SYS_DMA_CEN_CH0 */
*value = ch->elements;
break;
- case 0x12: /* SYS_DMA_CFN_CH0 */
+ case 0x12: /* SYS_DMA_CFN_CH0 */
*value = ch->frames;
break;
- case 0x14: /* SYS_DMA_CFI_CH0 */
+ case 0x14: /* SYS_DMA_CFI_CH0 */
*value = ch->frame_index[0];
break;
- case 0x16: /* SYS_DMA_CEI_CH0 */
+ case 0x16: /* SYS_DMA_CEI_CH0 */
*value = ch->element_index[0];
break;
- case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
+ case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
if (ch->omap_3_1_compatible_disable)
- *value = ch->active_set.src & 0xffff; /* CSAC */
+ *value = ch->active_set.src & 0xffff; /* CSAC */
else
*value = ch->cpc;
break;
- case 0x1a: /* DMA_CDAC */
- *value = ch->active_set.dest & 0xffff; /* CDAC */
+ case 0x1a: /* DMA_CDAC */
+ *value = ch->active_set.dest & 0xffff; /* CDAC */
break;
- case 0x1c: /* DMA_CDEI */
+ case 0x1c: /* DMA_CDEI */
*value = ch->element_index[1];
break;
- case 0x1e: /* DMA_CDFI */
+ case 0x1e: /* DMA_CDFI */
*value = ch->frame_index[1];
break;
- case 0x20: /* DMA_COLOR_L */
+ case 0x20: /* DMA_COLOR_L */
*value = ch->color & 0xffff;
break;
- case 0x22: /* DMA_COLOR_U */
+ case 0x22: /* DMA_COLOR_U */
*value = ch->color >> 16;
break;
- case 0x24: /* DMA_CCR2 */
+ case 0x24: /* DMA_CCR2 */
*value = (ch->bs << 2) |
(ch->transparent_copy << 1) |
ch->constant_fill;
break;
- case 0x28: /* DMA_CLNK_CTRL */
+ case 0x28: /* DMA_CLNK_CTRL */
*value = (ch->link_enabled << 15) |
(ch->link_next_ch & 0xf);
break;
- case 0x2a: /* DMA_LCH_CTRL */
+ case 0x2a: /* DMA_LCH_CTRL */
*value = (ch->interleave_disabled << 15) |
ch->type;
break;
@@ -871,7 +864,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
struct omap_dma_channel_s *ch, int reg, uint16_t value)
{
switch (reg) {
- case 0x00: /* SYS_DMA_CSDP_CH0 */
+ case 0x00: /* SYS_DMA_CSDP_CH0 */
ch->burst[1] = (value & 0xc000) >> 14;
ch->pack[1] = (value & 0x2000) >> 13;
ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
@@ -894,7 +887,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
}
break;
- case 0x02: /* SYS_DMA_CCR_CH0 */
+ case 0x02: /* SYS_DMA_CCR_CH0 */
ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
ch->end_prog = (value & 0x0800) >> 11;
@@ -916,88 +909,88 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
break;
- case 0x04: /* SYS_DMA_CICR_CH0 */
+ case 0x04: /* SYS_DMA_CICR_CH0 */
ch->interrupts = value & 0x3f;
break;
- case 0x06: /* SYS_DMA_CSR_CH0 */
+ case 0x06: /* SYS_DMA_CSR_CH0 */
OMAP_RO_REG((hwaddr) reg);
break;
- case 0x08: /* SYS_DMA_CSSA_L_CH0 */
+ case 0x08: /* SYS_DMA_CSSA_L_CH0 */
ch->addr[0] &= 0xffff0000;
ch->addr[0] |= value;
break;
- case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
+ case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
ch->addr[0] &= 0x0000ffff;
ch->addr[0] |= (uint32_t) value << 16;
break;
- case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
+ case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
ch->addr[1] &= 0xffff0000;
ch->addr[1] |= value;
break;
- case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
+ case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
ch->addr[1] &= 0x0000ffff;
ch->addr[1] |= (uint32_t) value << 16;
break;
- case 0x10: /* SYS_DMA_CEN_CH0 */
+ case 0x10: /* SYS_DMA_CEN_CH0 */
ch->elements = value;
break;
- case 0x12: /* SYS_DMA_CFN_CH0 */
+ case 0x12: /* SYS_DMA_CFN_CH0 */
ch->frames = value;
break;
- case 0x14: /* SYS_DMA_CFI_CH0 */
+ case 0x14: /* SYS_DMA_CFI_CH0 */
ch->frame_index[0] = (int16_t) value;
break;
- case 0x16: /* SYS_DMA_CEI_CH0 */
+ case 0x16: /* SYS_DMA_CEI_CH0 */
ch->element_index[0] = (int16_t) value;
break;
- case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
+ case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
OMAP_RO_REG((hwaddr) reg);
break;
- case 0x1c: /* DMA_CDEI */
+ case 0x1c: /* DMA_CDEI */
ch->element_index[1] = (int16_t) value;
break;
- case 0x1e: /* DMA_CDFI */
+ case 0x1e: /* DMA_CDFI */
ch->frame_index[1] = (int16_t) value;
break;
- case 0x20: /* DMA_COLOR_L */
+ case 0x20: /* DMA_COLOR_L */
ch->color &= 0xffff0000;
ch->color |= value;
break;
- case 0x22: /* DMA_COLOR_U */
+ case 0x22: /* DMA_COLOR_U */
ch->color &= 0xffff;
ch->color |= (uint32_t)value << 16;
break;
- case 0x24: /* DMA_CCR2 */
+ case 0x24: /* DMA_CCR2 */
ch->bs = (value >> 2) & 0x1;
ch->transparent_copy = (value >> 1) & 0x1;
ch->constant_fill = value & 0x1;
break;
- case 0x28: /* DMA_CLNK_CTRL */
+ case 0x28: /* DMA_CLNK_CTRL */
ch->link_enabled = (value >> 15) & 0x1;
- if (value & (1 << 14)) { /* Stop_Lnk */
+ if (value & (1 << 14)) { /* Stop_Lnk */
ch->link_enabled = 0;
omap_dma_disable_channel(s, ch);
}
ch->link_next_ch = value & 0x1f;
break;
- case 0x2a: /* DMA_LCH_CTRL */
+ case 0x2a: /* DMA_LCH_CTRL */
ch->interleave_disabled = (value >> 15) & 0x1;
ch->type = value & 0xf;
break;
@@ -1012,7 +1005,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
uint16_t value)
{
switch (offset) {
- case 0xbc0: /* DMA_LCD_CSDP */
+ case 0xbc0: /* DMA_LCD_CSDP */
s->brust_f2 = (value >> 14) & 0x3;
s->pack_f2 = (value >> 13) & 0x1;
s->data_type_f2 = (1 << ((value >> 11) & 0x3));
@@ -1021,7 +1014,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
s->data_type_f1 = (1 << ((value >> 0) & 0x3));
break;
- case 0xbc2: /* DMA_LCD_CCR */
+ case 0xbc2: /* DMA_LCD_CCR */
s->mode_f2 = (value >> 14) & 0x3;
s->mode_f1 = (value >> 12) & 0x3;
s->end_prog = (value >> 11) & 0x1;
@@ -1033,7 +1026,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
s->bs = (value >> 4) & 0x1;
break;
- case 0xbc4: /* DMA_LCD_CTRL */
+ case 0xbc4: /* DMA_LCD_CTRL */
s->dst = (value >> 8) & 0x1;
s->src = ((value >> 6) & 0x3) << 1;
s->condition = 0;
@@ -1042,91 +1035,91 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
s->dual = value & 1;
break;
- case 0xbc8: /* TOP_B1_L */
+ case 0xbc8: /* TOP_B1_L */
s->src_f1_top &= 0xffff0000;
s->src_f1_top |= 0x0000ffff & value;
break;
- case 0xbca: /* TOP_B1_U */
+ case 0xbca: /* TOP_B1_U */
s->src_f1_top &= 0x0000ffff;
s->src_f1_top |= (uint32_t)value << 16;
break;
- case 0xbcc: /* BOT_B1_L */
+ case 0xbcc: /* BOT_B1_L */
s->src_f1_bottom &= 0xffff0000;
s->src_f1_bottom |= 0x0000ffff & value;
break;
- case 0xbce: /* BOT_B1_U */
+ case 0xbce: /* BOT_B1_U */
s->src_f1_bottom &= 0x0000ffff;
s->src_f1_bottom |= (uint32_t) value << 16;
break;
- case 0xbd0: /* TOP_B2_L */
+ case 0xbd0: /* TOP_B2_L */
s->src_f2_top &= 0xffff0000;
s->src_f2_top |= 0x0000ffff & value;
break;
- case 0xbd2: /* TOP_B2_U */
+ case 0xbd2: /* TOP_B2_U */
s->src_f2_top &= 0x0000ffff;
s->src_f2_top |= (uint32_t) value << 16;
break;
- case 0xbd4: /* BOT_B2_L */
+ case 0xbd4: /* BOT_B2_L */
s->src_f2_bottom &= 0xffff0000;
s->src_f2_bottom |= 0x0000ffff & value;
break;
- case 0xbd6: /* BOT_B2_U */
+ case 0xbd6: /* BOT_B2_U */
s->src_f2_bottom &= 0x0000ffff;
s->src_f2_bottom |= (uint32_t) value << 16;
break;
- case 0xbd8: /* DMA_LCD_SRC_EI_B1 */
+ case 0xbd8: /* DMA_LCD_SRC_EI_B1 */
s->element_index_f1 = value;
break;
- case 0xbda: /* DMA_LCD_SRC_FI_B1_L */
+ case 0xbda: /* DMA_LCD_SRC_FI_B1_L */
s->frame_index_f1 &= 0xffff0000;
s->frame_index_f1 |= 0x0000ffff & value;
break;
- case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */
+ case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */
s->frame_index_f1 &= 0x0000ffff;
s->frame_index_f1 |= (uint32_t) value << 16;
break;
- case 0xbdc: /* DMA_LCD_SRC_EI_B2 */
+ case 0xbdc: /* DMA_LCD_SRC_EI_B2 */
s->element_index_f2 = value;
break;
- case 0xbde: /* DMA_LCD_SRC_FI_B2_L */
+ case 0xbde: /* DMA_LCD_SRC_FI_B2_L */
s->frame_index_f2 &= 0xffff0000;
s->frame_index_f2 |= 0x0000ffff & value;
break;
- case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */
+ case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */
s->frame_index_f2 &= 0x0000ffff;
s->frame_index_f2 |= (uint32_t) value << 16;
break;
- case 0xbe0: /* DMA_LCD_SRC_EN_B1 */
+ case 0xbe0: /* DMA_LCD_SRC_EN_B1 */
s->elements_f1 = value;
break;
- case 0xbe4: /* DMA_LCD_SRC_FN_B1 */
+ case 0xbe4: /* DMA_LCD_SRC_FN_B1 */
s->frames_f1 = value;
break;
- case 0xbe2: /* DMA_LCD_SRC_EN_B2 */
+ case 0xbe2: /* DMA_LCD_SRC_EN_B2 */
s->elements_f2 = value;
break;
- case 0xbe6: /* DMA_LCD_SRC_FN_B2 */
+ case 0xbe6: /* DMA_LCD_SRC_FN_B2 */
s->frames_f2 = value;
break;
- case 0xbea: /* DMA_LCD_LCH_CTRL */
+ case 0xbea: /* DMA_LCD_LCH_CTRL */
s->lch_type = value & 0xf;
break;
@@ -1140,7 +1133,7 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
uint16_t *ret)
{
switch (offset) {
- case 0xbc0: /* DMA_LCD_CSDP */
+ case 0xbc0: /* DMA_LCD_CSDP */
*ret = (s->brust_f2 << 14) |
(s->pack_f2 << 13) |
((s->data_type_f2 >> 1) << 11) |
@@ -1149,7 +1142,7 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
((s->data_type_f1 >> 1) << 0);
break;
- case 0xbc2: /* DMA_LCD_CCR */
+ case 0xbc2: /* DMA_LCD_CCR */
*ret = (s->mode_f2 << 14) |
(s->mode_f1 << 12) |
(s->end_prog << 11) |
@@ -1161,7 +1154,7 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
(s->bs << 4);
break;
- case 0xbc4: /* DMA_LCD_CTRL */
+ case 0xbc4: /* DMA_LCD_CTRL */
qemu_irq_lower(s->irq);
*ret = (s->dst << 8) |
((s->src & 0x6) << 5) |
@@ -1170,79 +1163,79 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
s->dual;
break;
- case 0xbc8: /* TOP_B1_L */
+ case 0xbc8: /* TOP_B1_L */
*ret = s->src_f1_top & 0xffff;
break;
- case 0xbca: /* TOP_B1_U */
+ case 0xbca: /* TOP_B1_U */
*ret = s->src_f1_top >> 16;
break;
- case 0xbcc: /* BOT_B1_L */
+ case 0xbcc: /* BOT_B1_L */
*ret = s->src_f1_bottom & 0xffff;
break;
- case 0xbce: /* BOT_B1_U */
+ case 0xbce: /* BOT_B1_U */
*ret = s->src_f1_bottom >> 16;
break;
- case 0xbd0: /* TOP_B2_L */
+ case 0xbd0: /* TOP_B2_L */
*ret = s->src_f2_top & 0xffff;
break;
- case 0xbd2: /* TOP_B2_U */
+ case 0xbd2: /* TOP_B2_U */
*ret = s->src_f2_top >> 16;
break;
- case 0xbd4: /* BOT_B2_L */
+ case 0xbd4: /* BOT_B2_L */
*ret = s->src_f2_bottom & 0xffff;
break;
- case 0xbd6: /* BOT_B2_U */
+ case 0xbd6: /* BOT_B2_U */
*ret = s->src_f2_bottom >> 16;
break;
- case 0xbd8: /* DMA_LCD_SRC_EI_B1 */
+ case 0xbd8: /* DMA_LCD_SRC_EI_B1 */
*ret = s->element_index_f1;
break;
- case 0xbda: /* DMA_LCD_SRC_FI_B1_L */
+ case 0xbda: /* DMA_LCD_SRC_FI_B1_L */
*ret = s->frame_index_f1 & 0xffff;
break;
- case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */
+ case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */
*ret = s->frame_index_f1 >> 16;
break;
- case 0xbdc: /* DMA_LCD_SRC_EI_B2 */
+ case 0xbdc: /* DMA_LCD_SRC_EI_B2 */
*ret = s->element_index_f2;
break;
- case 0xbde: /* DMA_LCD_SRC_FI_B2_L */
+ case 0xbde: /* DMA_LCD_SRC_FI_B2_L */
*ret = s->frame_index_f2 & 0xffff;
break;
- case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */
+ case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */
*ret = s->frame_index_f2 >> 16;
break;
- case 0xbe0: /* DMA_LCD_SRC_EN_B1 */
+ case 0xbe0: /* DMA_LCD_SRC_EN_B1 */
*ret = s->elements_f1;
break;
- case 0xbe4: /* DMA_LCD_SRC_FN_B1 */
+ case 0xbe4: /* DMA_LCD_SRC_FN_B1 */
*ret = s->frames_f1;
break;
- case 0xbe2: /* DMA_LCD_SRC_EN_B2 */
+ case 0xbe2: /* DMA_LCD_SRC_EN_B2 */
*ret = s->elements_f2;
break;
- case 0xbe6: /* DMA_LCD_SRC_FN_B2 */
+ case 0xbe6: /* DMA_LCD_SRC_FN_B2 */
*ret = s->frames_f2;
break;
- case 0xbea: /* DMA_LCD_LCH_CTRL */
+ case 0xbea: /* DMA_LCD_LCH_CTRL */
*ret = s->lch_type;
break;
@@ -1256,7 +1249,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
uint16_t value)
{
switch (offset) {
- case 0x300: /* SYS_DMA_LCD_CTRL */
+ case 0x300: /* SYS_DMA_LCD_CTRL */
s->src = (value & 0x40) ? imif : emiff;
s->condition = 0;
/* Assume no bus errors and thus no BUS_ERROR irq bits. */
@@ -1264,42 +1257,42 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
s->dual = value & 1;
break;
- case 0x302: /* SYS_DMA_LCD_TOP_F1_L */
+ case 0x302: /* SYS_DMA_LCD_TOP_F1_L */
s->src_f1_top &= 0xffff0000;
s->src_f1_top |= 0x0000ffff & value;
break;
- case 0x304: /* SYS_DMA_LCD_TOP_F1_U */
+ case 0x304: /* SYS_DMA_LCD_TOP_F1_U */
s->src_f1_top &= 0x0000ffff;
s->src_f1_top |= (uint32_t)value << 16;
break;
- case 0x306: /* SYS_DMA_LCD_BOT_F1_L */
+ case 0x306: /* SYS_DMA_LCD_BOT_F1_L */
s->src_f1_bottom &= 0xffff0000;
s->src_f1_bottom |= 0x0000ffff & value;
break;
- case 0x308: /* SYS_DMA_LCD_BOT_F1_U */
+ case 0x308: /* SYS_DMA_LCD_BOT_F1_U */
s->src_f1_bottom &= 0x0000ffff;
s->src_f1_bottom |= (uint32_t)value << 16;
break;
- case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */
+ case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */
s->src_f2_top &= 0xffff0000;
s->src_f2_top |= 0x0000ffff & value;
break;
- case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */
+ case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */
s->src_f2_top &= 0x0000ffff;
s->src_f2_top |= (uint32_t)value << 16;
break;
- case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */
+ case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */
s->src_f2_bottom &= 0xffff0000;
s->src_f2_bottom |= 0x0000ffff & value;
break;
- case 0x310: /* SYS_DMA_LCD_BOT_F2_U */
+ case 0x310: /* SYS_DMA_LCD_BOT_F2_U */
s->src_f2_bottom &= 0x0000ffff;
s->src_f2_bottom |= (uint32_t)value << 16;
break;
@@ -1316,7 +1309,7 @@ static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
int i;
switch (offset) {
- case 0x300: /* SYS_DMA_LCD_CTRL */
+ case 0x300: /* SYS_DMA_LCD_CTRL */
i = s->condition;
s->condition = 0;
qemu_irq_lower(s->irq);
@@ -1324,35 +1317,35 @@ static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
(s->interrupts << 1) | s->dual;
break;
- case 0x302: /* SYS_DMA_LCD_TOP_F1_L */
+ case 0x302: /* SYS_DMA_LCD_TOP_F1_L */
*ret = s->src_f1_top & 0xffff;
break;
- case 0x304: /* SYS_DMA_LCD_TOP_F1_U */
+ case 0x304: /* SYS_DMA_LCD_TOP_F1_U */
*ret = s->src_f1_top >> 16;
break;
- case 0x306: /* SYS_DMA_LCD_BOT_F1_L */
+ case 0x306: /* SYS_DMA_LCD_BOT_F1_L */
*ret = s->src_f1_bottom & 0xffff;
break;
- case 0x308: /* SYS_DMA_LCD_BOT_F1_U */
+ case 0x308: /* SYS_DMA_LCD_BOT_F1_U */
*ret = s->src_f1_bottom >> 16;
break;
- case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */
+ case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */
*ret = s->src_f2_top & 0xffff;
break;
- case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */
+ case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */
*ret = s->src_f2_top >> 16;
break;
- case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */
+ case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */
*ret = s->src_f2_bottom & 0xffff;
break;
- case 0x310: /* SYS_DMA_LCD_BOT_F2_U */
+ case 0x310: /* SYS_DMA_LCD_BOT_F2_U */
*ret = s->src_f2_bottom >> 16;
break;
@@ -1365,18 +1358,18 @@ static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value)
{
switch (offset) {
- case 0x400: /* SYS_DMA_GCR */
+ case 0x400: /* SYS_DMA_GCR */
s->gcr = value;
break;
- case 0x404: /* DMA_GSCR */
+ case 0x404: /* DMA_GSCR */
if (value & 0x8)
omap_dma_disable_3_1_mapping(s);
else
omap_dma_enable_3_1_mapping(s);
break;
- case 0x408: /* DMA_GRST */
+ case 0x408: /* DMA_GRST */
if (value & 0x1)
omap_dma_reset(s->dma);
break;
@@ -1391,57 +1384,57 @@ static int omap_dma_sys_read(struct omap_dma_s *s, int offset,
uint16_t *ret)
{
switch (offset) {
- case 0x400: /* SYS_DMA_GCR */
+ case 0x400: /* SYS_DMA_GCR */
*ret = s->gcr;
break;
- case 0x404: /* DMA_GSCR */
+ case 0x404: /* DMA_GSCR */
*ret = s->omap_3_1_mapping_disabled << 3;
break;
- case 0x408: /* DMA_GRST */
+ case 0x408: /* DMA_GRST */
*ret = 0;
break;
- case 0x442: /* DMA_HW_ID */
- case 0x444: /* DMA_PCh2_ID */
- case 0x446: /* DMA_PCh0_ID */
- case 0x448: /* DMA_PCh1_ID */
- case 0x44a: /* DMA_PChG_ID */
- case 0x44c: /* DMA_PChD_ID */
+ case 0x442: /* DMA_HW_ID */
+ case 0x444: /* DMA_PCh2_ID */
+ case 0x446: /* DMA_PCh0_ID */
+ case 0x448: /* DMA_PCh1_ID */
+ case 0x44a: /* DMA_PChG_ID */
+ case 0x44c: /* DMA_PChD_ID */
*ret = 1;
break;
- case 0x44e: /* DMA_CAPS_0_U */
+ case 0x44e: /* DMA_CAPS_0_U */
*ret = (s->caps[0] >> 16) & 0xffff;
break;
- case 0x450: /* DMA_CAPS_0_L */
+ case 0x450: /* DMA_CAPS_0_L */
*ret = (s->caps[0] >> 0) & 0xffff;
break;
- case 0x452: /* DMA_CAPS_1_U */
+ case 0x452: /* DMA_CAPS_1_U */
*ret = (s->caps[1] >> 16) & 0xffff;
break;
- case 0x454: /* DMA_CAPS_1_L */
+ case 0x454: /* DMA_CAPS_1_L */
*ret = (s->caps[1] >> 0) & 0xffff;
break;
- case 0x456: /* DMA_CAPS_2 */
+ case 0x456: /* DMA_CAPS_2 */
*ret = s->caps[2];
break;
- case 0x458: /* DMA_CAPS_3 */
+ case 0x458: /* DMA_CAPS_3 */
*ret = s->caps[3];
break;
- case 0x45a: /* DMA_CAPS_4 */
+ case 0x45a: /* DMA_CAPS_4 */
*ret = s->caps[4];
break;
- case 0x460: /* DMA_PCh2_SR */
- case 0x480: /* DMA_PCh0_SR */
- case 0x482: /* DMA_PCh1_SR */
- case 0x4c0: /* DMA_PChD_SR_0 */
+ case 0x460: /* DMA_PCh2_SR */
+ case 0x480: /* DMA_PCh0_SR */
+ case 0x482: /* DMA_PCh1_SR */
+ case 0x4c0: /* DMA_PChD_SR_0 */
qemu_log_mask(LOG_UNIMP,
"%s: Physical Channel Status Registers not implemented\n",
__func__);
@@ -1587,41 +1580,40 @@ static void omap_dma_setcaps(struct omap_dma_s *s)
case omap_dma_3_1:
break;
case omap_dma_3_2:
- case omap_dma_4:
/* XXX Only available for sDMA */
s->caps[0] =
- (1 << 19) | /* Constant Fill Capability */
- (1 << 18); /* Transparent BLT Capability */
+ (1 << 19) | /* Constant Fill Capability */
+ (1 << 18); /* Transparent BLT Capability */
s->caps[1] =
- (1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */
+ (1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */
s->caps[2] =
- (1 << 8) | /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */
- (1 << 7) | /* DST_DOUBLE_INDEX_ADRS_CPBLTY */
- (1 << 6) | /* DST_SINGLE_INDEX_ADRS_CPBLTY */
- (1 << 5) | /* DST_POST_INCRMNT_ADRS_CPBLTY */
- (1 << 4) | /* DST_CONST_ADRS_CPBLTY */
- (1 << 3) | /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */
- (1 << 2) | /* SRC_SINGLE_INDEX_ADRS_CPBLTY */
- (1 << 1) | /* SRC_POST_INCRMNT_ADRS_CPBLTY */
- (1 << 0); /* SRC_CONST_ADRS_CPBLTY */
+ (1 << 8) | /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */
+ (1 << 7) | /* DST_DOUBLE_INDEX_ADRS_CPBLTY */
+ (1 << 6) | /* DST_SINGLE_INDEX_ADRS_CPBLTY */
+ (1 << 5) | /* DST_POST_INCRMNT_ADRS_CPBLTY */
+ (1 << 4) | /* DST_CONST_ADRS_CPBLTY */
+ (1 << 3) | /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */
+ (1 << 2) | /* SRC_SINGLE_INDEX_ADRS_CPBLTY */
+ (1 << 1) | /* SRC_POST_INCRMNT_ADRS_CPBLTY */
+ (1 << 0); /* SRC_CONST_ADRS_CPBLTY */
s->caps[3] =
- (1 << 6) | /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */
- (1 << 7) | /* PKT_SYNCHR_CPBLTY (DMA 4 only) */
- (1 << 5) | /* CHANNEL_CHAINING_CPBLTY */
- (1 << 4) | /* LCh_INTERLEAVE_CPBLTY */
- (1 << 3) | /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */
- (1 << 2) | /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */
- (1 << 1) | /* FRAME_SYNCHR_CPBLTY */
- (1 << 0); /* ELMNT_SYNCHR_CPBLTY */
+ (1 << 6) | /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */
+ (1 << 7) | /* PKT_SYNCHR_CPBLTY (DMA 4 only) */
+ (1 << 5) | /* CHANNEL_CHAINING_CPBLTY */
+ (1 << 4) | /* LCh_INTERLEAVE_CPBLTY */
+ (1 << 3) | /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */
+ (1 << 2) | /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */
+ (1 << 1) | /* FRAME_SYNCHR_CPBLTY */
+ (1 << 0); /* ELMNT_SYNCHR_CPBLTY */
s->caps[4] =
- (1 << 7) | /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */
- (1 << 6) | /* SYNC_STATUS_CPBLTY */
- (1 << 5) | /* BLOCK_INTERRUPT_CPBLTY */
- (1 << 4) | /* LAST_FRAME_INTERRUPT_CPBLTY */
- (1 << 3) | /* FRAME_INTERRUPT_CPBLTY */
- (1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */
- (1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */
- (1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
+ (1 << 7) | /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */
+ (1 << 6) | /* SYNC_STATUS_CPBLTY */
+ (1 << 5) | /* BLOCK_INTERRUPT_CPBLTY */
+ (1 << 4) | /* LAST_FRAME_INTERRUPT_CPBLTY */
+ (1 << 3) | /* FRAME_INTERRUPT_CPBLTY */
+ (1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */
+ (1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */
+ (1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
break;
}
}
@@ -1678,443 +1670,6 @@ struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
return s->dma;
}
-static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
-{
- struct omap_dma_channel_s *ch = s->ch;
- uint32_t bmp, bit;
-
- for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
- if (ch->status) {
- bmp |= bit;
- ch->cstatus |= ch->status;
- ch->status = 0;
- }
- if ((s->irqstat[0] |= s->irqen[0] & bmp))
- qemu_irq_raise(s->irq[0]);
- if ((s->irqstat[1] |= s->irqen[1] & bmp))
- qemu_irq_raise(s->irq[1]);
- if ((s->irqstat[2] |= s->irqen[2] & bmp))
- qemu_irq_raise(s->irq[2]);
- if ((s->irqstat[3] |= s->irqen[3] & bmp))
- qemu_irq_raise(s->irq[3]);
-}
-
-static uint64_t omap_dma4_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dma_s *s = opaque;
- int irqn = 0, chnum;
- struct omap_dma_channel_s *ch;
-
- if (size == 1) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* DMA4_REVISION */
- return 0x40;
-
- case 0x14: /* DMA4_IRQSTATUS_L3 */
- irqn ++;
- /* fall through */
- case 0x10: /* DMA4_IRQSTATUS_L2 */
- irqn ++;
- /* fall through */
- case 0x0c: /* DMA4_IRQSTATUS_L1 */
- irqn ++;
- /* fall through */
- case 0x08: /* DMA4_IRQSTATUS_L0 */
- return s->irqstat[irqn];
-
- case 0x24: /* DMA4_IRQENABLE_L3 */
- irqn ++;
- /* fall through */
- case 0x20: /* DMA4_IRQENABLE_L2 */
- irqn ++;
- /* fall through */
- case 0x1c: /* DMA4_IRQENABLE_L1 */
- irqn ++;
- /* fall through */
- case 0x18: /* DMA4_IRQENABLE_L0 */
- return s->irqen[irqn];
-
- case 0x28: /* DMA4_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x2c: /* DMA4_OCP_SYSCONFIG */
- return s->ocp;
-
- case 0x64: /* DMA4_CAPS_0 */
- return s->caps[0];
- case 0x6c: /* DMA4_CAPS_2 */
- return s->caps[2];
- case 0x70: /* DMA4_CAPS_3 */
- return s->caps[3];
- case 0x74: /* DMA4_CAPS_4 */
- return s->caps[4];
-
- case 0x78: /* DMA4_GCR */
- return s->gcr;
-
- case 0x80 ... 0xfff:
- addr -= 0x80;
- chnum = addr / 0x60;
- ch = s->ch + chnum;
- addr -= chnum * 0x60;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return 0;
- }
-
- /* Per-channel registers */
- switch (addr) {
- case 0x00: /* DMA4_CCR */
- return (ch->buf_disable << 25) |
- (ch->src_sync << 24) |
- (ch->prefetch << 23) |
- ((ch->sync & 0x60) << 14) |
- (ch->bs << 18) |
- (ch->transparent_copy << 17) |
- (ch->constant_fill << 16) |
- (ch->mode[1] << 14) |
- (ch->mode[0] << 12) |
- (0 << 10) | (0 << 9) |
- (ch->suspend << 8) |
- (ch->enable << 7) |
- (ch->priority << 6) |
- (ch->fs << 5) | (ch->sync & 0x1f);
-
- case 0x04: /* DMA4_CLNK_CTRL */
- return (ch->link_enabled << 15) | ch->link_next_ch;
-
- case 0x08: /* DMA4_CICR */
- return ch->interrupts;
-
- case 0x0c: /* DMA4_CSR */
- return ch->cstatus;
-
- case 0x10: /* DMA4_CSDP */
- return (ch->endian[0] << 21) |
- (ch->endian_lock[0] << 20) |
- (ch->endian[1] << 19) |
- (ch->endian_lock[1] << 18) |
- (ch->write_mode << 16) |
- (ch->burst[1] << 14) |
- (ch->pack[1] << 13) |
- (ch->translate[1] << 9) |
- (ch->burst[0] << 7) |
- (ch->pack[0] << 6) |
- (ch->translate[0] << 2) |
- (ch->data_type >> 1);
-
- case 0x14: /* DMA4_CEN */
- return ch->elements;
-
- case 0x18: /* DMA4_CFN */
- return ch->frames;
-
- case 0x1c: /* DMA4_CSSA */
- return ch->addr[0];
-
- case 0x20: /* DMA4_CDSA */
- return ch->addr[1];
-
- case 0x24: /* DMA4_CSEI */
- return ch->element_index[0];
-
- case 0x28: /* DMA4_CSFI */
- return ch->frame_index[0];
-
- case 0x2c: /* DMA4_CDEI */
- return ch->element_index[1];
-
- case 0x30: /* DMA4_CDFI */
- return ch->frame_index[1];
-
- case 0x34: /* DMA4_CSAC */
- return ch->active_set.src & 0xffff;
-
- case 0x38: /* DMA4_CDAC */
- return ch->active_set.dest & 0xffff;
-
- case 0x3c: /* DMA4_CCEN */
- return ch->active_set.element;
-
- case 0x40: /* DMA4_CCFN */
- return ch->active_set.frame;
-
- case 0x44: /* DMA4_COLOR */
- /* XXX only in sDMA */
- return ch->color;
-
- default:
- OMAP_BAD_REG(addr);
- return 0;
- }
-}
-
-static void omap_dma4_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dma_s *s = opaque;
- int chnum, irqn = 0;
- struct omap_dma_channel_s *ch;
-
- if (size == 1) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x14: /* DMA4_IRQSTATUS_L3 */
- irqn ++;
- /* fall through */
- case 0x10: /* DMA4_IRQSTATUS_L2 */
- irqn ++;
- /* fall through */
- case 0x0c: /* DMA4_IRQSTATUS_L1 */
- irqn ++;
- /* fall through */
- case 0x08: /* DMA4_IRQSTATUS_L0 */
- s->irqstat[irqn] &= ~value;
- if (!s->irqstat[irqn])
- qemu_irq_lower(s->irq[irqn]);
- return;
-
- case 0x24: /* DMA4_IRQENABLE_L3 */
- irqn ++;
- /* fall through */
- case 0x20: /* DMA4_IRQENABLE_L2 */
- irqn ++;
- /* fall through */
- case 0x1c: /* DMA4_IRQENABLE_L1 */
- irqn ++;
- /* fall through */
- case 0x18: /* DMA4_IRQENABLE_L0 */
- s->irqen[irqn] = value;
- return;
-
- case 0x2c: /* DMA4_OCP_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dma_reset(s->dma);
- s->ocp = value & 0x3321;
- if (((s->ocp >> 12) & 3) == 3) { /* MIDLEMODE */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid DMA power mode\n",
- __func__);
- }
- return;
-
- case 0x78: /* DMA4_GCR */
- s->gcr = value & 0x00ff00ff;
- if ((value & 0xff) == 0x00) { /* MAX_CHANNEL_FIFO_DEPTH */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: wrong FIFO depth in GCR\n",
- __func__);
- }
- return;
-
- case 0x80 ... 0xfff:
- addr -= 0x80;
- chnum = addr / 0x60;
- ch = s->ch + chnum;
- addr -= chnum * 0x60;
- break;
-
- case 0x00: /* DMA4_REVISION */
- case 0x28: /* DMA4_SYSSTATUS */
- case 0x64: /* DMA4_CAPS_0 */
- case 0x6c: /* DMA4_CAPS_2 */
- case 0x70: /* DMA4_CAPS_3 */
- case 0x74: /* DMA4_CAPS_4 */
- OMAP_RO_REG(addr);
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-
- /* Per-channel registers */
- switch (addr) {
- case 0x00: /* DMA4_CCR */
- ch->buf_disable = (value >> 25) & 1;
- ch->src_sync = (value >> 24) & 1; /* XXX For CamDMA must be 1 */
- if (ch->buf_disable && !ch->src_sync) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Buffering disable is not allowed in "
- "destination synchronised mode\n", __func__);
- }
- ch->prefetch = (value >> 23) & 1;
- ch->bs = (value >> 18) & 1;
- ch->transparent_copy = (value >> 17) & 1;
- ch->constant_fill = (value >> 16) & 1;
- ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
- ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
- ch->suspend = (value & 0x0100) >> 8;
- ch->priority = (value & 0x0040) >> 6;
- ch->fs = (value & 0x0020) >> 5;
- if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1]) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: For a packet transfer at least one port "
- "must be constant-addressed\n", __func__);
- }
- ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
- /* XXX must be 0x01 for CamDMA */
-
- if (value & 0x0080)
- omap_dma_enable_channel(s, ch);
- else
- omap_dma_disable_channel(s, ch);
-
- break;
-
- case 0x04: /* DMA4_CLNK_CTRL */
- ch->link_enabled = (value >> 15) & 0x1;
- ch->link_next_ch = value & 0x1f;
- break;
-
- case 0x08: /* DMA4_CICR */
- ch->interrupts = value & 0x09be;
- break;
-
- case 0x0c: /* DMA4_CSR */
- ch->cstatus &= ~value;
- break;
-
- case 0x10: /* DMA4_CSDP */
- ch->endian[0] =(value >> 21) & 1;
- ch->endian_lock[0] =(value >> 20) & 1;
- ch->endian[1] =(value >> 19) & 1;
- ch->endian_lock[1] =(value >> 18) & 1;
- if (ch->endian[0] != ch->endian[1]) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: DMA endianness conversion enable attempt\n",
- __func__);
- }
- ch->write_mode = (value >> 16) & 3;
- ch->burst[1] = (value & 0xc000) >> 14;
- ch->pack[1] = (value & 0x2000) >> 13;
- ch->translate[1] = (value & 0x1e00) >> 9;
- ch->burst[0] = (value & 0x0180) >> 7;
- ch->pack[0] = (value & 0x0040) >> 6;
- ch->translate[0] = (value & 0x003c) >> 2;
- if (ch->translate[0] | ch->translate[1]) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: bad MReqAddressTranslate sideband signal\n",
- __func__);
- }
- ch->data_type = 1 << (value & 3);
- if ((value & 3) == 3) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: bad data_type for DMA channel\n", __func__);
- ch->data_type >>= 1;
- }
- break;
-
- case 0x14: /* DMA4_CEN */
- ch->set_update = 1;
- ch->elements = value & 0xffffff;
- break;
-
- case 0x18: /* DMA4_CFN */
- ch->frames = value & 0xffff;
- ch->set_update = 1;
- break;
-
- case 0x1c: /* DMA4_CSSA */
- ch->addr[0] = (hwaddr) (uint32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x20: /* DMA4_CDSA */
- ch->addr[1] = (hwaddr) (uint32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x24: /* DMA4_CSEI */
- ch->element_index[0] = (int16_t) value;
- ch->set_update = 1;
- break;
-
- case 0x28: /* DMA4_CSFI */
- ch->frame_index[0] = (int32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x2c: /* DMA4_CDEI */
- ch->element_index[1] = (int16_t) value;
- ch->set_update = 1;
- break;
-
- case 0x30: /* DMA4_CDFI */
- ch->frame_index[1] = (int32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x44: /* DMA4_COLOR */
- /* XXX only in sDMA */
- ch->color = value;
- break;
-
- case 0x34: /* DMA4_CSAC */
- case 0x38: /* DMA4_CDAC */
- case 0x3c: /* DMA4_CCEN */
- case 0x40: /* DMA4_CCFN */
- OMAP_RO_REG(addr);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_dma4_ops = {
- .read = omap_dma4_read,
- .write = omap_dma4_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
- MemoryRegion *sysmem,
- struct omap_mpu_state_s *mpu, int fifo,
- int chans, omap_clk iclk, omap_clk fclk)
-{
- int i;
- struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
-
- s->model = omap_dma_4;
- s->chans = chans;
- s->mpu = mpu;
- s->clk = fclk;
-
- s->dma = soc_dma_init(s->chans);
- s->dma->freq = omap_clk_getrate(fclk);
- s->dma->transfer_fn = omap_dma_transfer_generic;
- s->dma->setup_fn = omap_dma_transfer_setup;
- s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
- s->dma->opaque = s;
- for (i = 0; i < s->chans; i ++) {
- s->ch[i].dma = &s->dma->ch[i];
- s->dma->ch[i].opaque = &s->ch[i];
- }
-
- memcpy(&s->irq, irqs, sizeof(s->irq));
- s->intr_update = omap_dma_interrupts_4_update;
-
- omap_dma_setcaps(s);
- omap_clk_adduser(s->clk, qemu_allocate_irq(omap_dma_clk_update, s, 0));
- omap_dma_reset(s->dma);
- omap_dma_clk_update(s, 0, !!s->dma->freq);
-
- memory_region_init_io(&s->iomem, NULL, &omap_dma4_ops, s, "omap.dma4", 0x1000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- mpu->drq = s->dma->drq;
-
- return s->dma;
-}
-
struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma)
{
struct omap_dma_s *s = dma->opaque;
diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index 1e49c22..277d934 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -408,20 +408,19 @@ static void pl081_init(Object *obj)
s->nchannels = 2;
}
-static Property pl080_properties[] = {
+static const Property pl080_properties[] = {
DEFINE_PROP_LINK("downstream", PL080State, downstream,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pl080_class_init(ObjectClass *oc, void *data)
+static void pl080_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->vmsd = &vmstate_pl080;
dc->realize = pl080_realize;
device_class_set_props(dc, pl080_properties);
- dc->reset = pl080_reset;
+ device_class_set_legacy_reset(dc, pl080_reset);
}
static const TypeInfo pl080_info = {
diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c
index 5f89295..a570bb0 100644
--- a/hw/dma/pl330.c
+++ b/hw/dma/pl330.c
@@ -22,7 +22,7 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/timer.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
@@ -1646,7 +1646,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
pl330_fifo_init(&s->fifo, s->data_width / 4 * s->data_buffer_dep);
}
-static Property pl330_properties[] = {
+static const Property pl330_properties[] = {
/* CR0 */
DEFINE_PROP_UINT32("num_chnls", PL330State, num_chnls, 8),
DEFINE_PROP_UINT8("num_periph_req", PL330State, num_periph_req, 4),
@@ -1669,16 +1669,14 @@ static Property pl330_properties[] = {
DEFINE_PROP_LINK("memory", PL330State, mem_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void pl330_class_init(ObjectClass *klass, void *data)
+static void pl330_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pl330_realize;
- dc->reset = pl330_reset;
+ device_class_set_legacy_reset(dc, pl330_reset);
device_class_set_props(dc, pl330_properties);
dc->vmsd = &vmstate_pl330;
}
diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c
deleted file mode 100644
index 9f62f0b..0000000
--- a/hw/dma/pxa2xx_dma.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Intel XScale PXA255/270 DMA controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define PXA255_DMA_NUM_CHANNELS 16
-#define PXA27X_DMA_NUM_CHANNELS 32
-
-#define PXA2XX_DMA_NUM_REQUESTS 75
-
-typedef struct {
- uint32_t descr;
- uint32_t src;
- uint32_t dest;
- uint32_t cmd;
- uint32_t state;
- int request;
-} PXA2xxDMAChannel;
-
-#define TYPE_PXA2XX_DMA "pxa2xx-dma"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxDMAState, PXA2XX_DMA)
-
-struct PXA2xxDMAState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
-
- uint32_t stopintr;
- uint32_t eorintr;
- uint32_t rasintr;
- uint32_t startintr;
- uint32_t endintr;
-
- uint32_t align;
- uint32_t pio;
-
- int channels;
- PXA2xxDMAChannel *chan;
-
- uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
-
- /* Flag to avoid recursive DMA invocations. */
- int running;
-};
-
-#define DCSR0 0x0000 /* DMA Control / Status register for Channel 0 */
-#define DCSR31 0x007c /* DMA Control / Status register for Channel 31 */
-#define DALGN 0x00a0 /* DMA Alignment register */
-#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status register */
-#define DRQSR0 0x00e0 /* DMA DREQ<0> Status register */
-#define DRQSR1 0x00e4 /* DMA DREQ<1> Status register */
-#define DRQSR2 0x00e8 /* DMA DREQ<2> Status register */
-#define DINT 0x00f0 /* DMA Interrupt register */
-#define DRCMR0 0x0100 /* Request to Channel Map register 0 */
-#define DRCMR63 0x01fc /* Request to Channel Map register 63 */
-#define D_CH0 0x0200 /* Channel 0 Descriptor start */
-#define DRCMR64 0x1100 /* Request to Channel Map register 64 */
-#define DRCMR74 0x1128 /* Request to Channel Map register 74 */
-
-/* Per-channel register */
-#define DDADR 0x00
-#define DSADR 0x01
-#define DTADR 0x02
-#define DCMD 0x03
-
-/* Bit-field masks */
-#define DRCMR_CHLNUM 0x1f
-#define DRCMR_MAPVLD (1 << 7)
-#define DDADR_STOP (1 << 0)
-#define DDADR_BREN (1 << 1)
-#define DCMD_LEN 0x1fff
-#define DCMD_WIDTH(x) (1 << ((((x) >> 14) & 3) - 1))
-#define DCMD_SIZE(x) (4 << (((x) >> 16) & 3))
-#define DCMD_FLYBYT (1 << 19)
-#define DCMD_FLYBYS (1 << 20)
-#define DCMD_ENDIRQEN (1 << 21)
-#define DCMD_STARTIRQEN (1 << 22)
-#define DCMD_CMPEN (1 << 25)
-#define DCMD_FLOWTRG (1 << 28)
-#define DCMD_FLOWSRC (1 << 29)
-#define DCMD_INCTRGADDR (1 << 30)
-#define DCMD_INCSRCADDR (1 << 31)
-#define DCSR_BUSERRINTR (1 << 0)
-#define DCSR_STARTINTR (1 << 1)
-#define DCSR_ENDINTR (1 << 2)
-#define DCSR_STOPINTR (1 << 3)
-#define DCSR_RASINTR (1 << 4)
-#define DCSR_REQPEND (1 << 8)
-#define DCSR_EORINT (1 << 9)
-#define DCSR_CMPST (1 << 10)
-#define DCSR_MASKRUN (1 << 22)
-#define DCSR_RASIRQEN (1 << 23)
-#define DCSR_CLRCMPST (1 << 24)
-#define DCSR_SETCMPST (1 << 25)
-#define DCSR_EORSTOPEN (1 << 26)
-#define DCSR_EORJMPEN (1 << 27)
-#define DCSR_EORIRQEN (1 << 28)
-#define DCSR_STOPIRQEN (1 << 29)
-#define DCSR_NODESCFETCH (1 << 30)
-#define DCSR_RUN (1 << 31)
-
-static inline void pxa2xx_dma_update(PXA2xxDMAState *s, int ch)
-{
- if (ch >= 0) {
- if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
- (s->chan[ch].state & DCSR_STOPINTR))
- s->stopintr |= 1 << ch;
- else
- s->stopintr &= ~(1 << ch);
-
- if ((s->chan[ch].state & DCSR_EORIRQEN) &&
- (s->chan[ch].state & DCSR_EORINT))
- s->eorintr |= 1 << ch;
- else
- s->eorintr &= ~(1 << ch);
-
- if ((s->chan[ch].state & DCSR_RASIRQEN) &&
- (s->chan[ch].state & DCSR_RASINTR))
- s->rasintr |= 1 << ch;
- else
- s->rasintr &= ~(1 << ch);
-
- if (s->chan[ch].state & DCSR_STARTINTR)
- s->startintr |= 1 << ch;
- else
- s->startintr &= ~(1 << ch);
-
- if (s->chan[ch].state & DCSR_ENDINTR)
- s->endintr |= 1 << ch;
- else
- s->endintr &= ~(1 << ch);
- }
-
- if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
- qemu_irq_raise(s->irq);
- else
- qemu_irq_lower(s->irq);
-}
-
-static inline void pxa2xx_dma_descriptor_fetch(
- PXA2xxDMAState *s, int ch)
-{
- uint32_t desc[4];
- hwaddr daddr = s->chan[ch].descr & ~0xf;
- if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
- daddr += 32;
-
- cpu_physical_memory_read(daddr, desc, 16);
- s->chan[ch].descr = desc[DDADR];
- s->chan[ch].src = desc[DSADR];
- s->chan[ch].dest = desc[DTADR];
- s->chan[ch].cmd = desc[DCMD];
-
- if (s->chan[ch].cmd & DCMD_FLOWSRC)
- s->chan[ch].src &= ~3;
- if (s->chan[ch].cmd & DCMD_FLOWTRG)
- s->chan[ch].dest &= ~3;
-
- if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
- printf("%s: unsupported mode in channel %i\n", __func__, ch);
-
- if (s->chan[ch].cmd & DCMD_STARTIRQEN)
- s->chan[ch].state |= DCSR_STARTINTR;
-}
-
-static void pxa2xx_dma_run(PXA2xxDMAState *s)
-{
- int c, srcinc, destinc;
- uint32_t n, size;
- uint32_t width;
- uint32_t length;
- uint8_t buffer[32];
- PXA2xxDMAChannel *ch;
-
- if (s->running ++)
- return;
-
- while (s->running) {
- s->running = 1;
- for (c = 0; c < s->channels; c ++) {
- ch = &s->chan[c];
-
- while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
- /* Test for pending requests */
- if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
- break;
-
- length = ch->cmd & DCMD_LEN;
- size = DCMD_SIZE(ch->cmd);
- width = DCMD_WIDTH(ch->cmd);
-
- srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
- destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
-
- while (length) {
- size = MIN(length, size);
-
- for (n = 0; n < size; n += width) {
- cpu_physical_memory_read(ch->src, buffer + n, width);
- ch->src += srcinc;
- }
-
- for (n = 0; n < size; n += width) {
- cpu_physical_memory_write(ch->dest, buffer + n, width);
- ch->dest += destinc;
- }
-
- length -= size;
-
- if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
- !ch->request) {
- ch->state |= DCSR_EORINT;
- if (ch->state & DCSR_EORSTOPEN)
- ch->state |= DCSR_STOPINTR;
- if ((ch->state & DCSR_EORJMPEN) &&
- !(ch->state & DCSR_NODESCFETCH))
- pxa2xx_dma_descriptor_fetch(s, c);
- break;
- }
- }
-
- ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
-
- /* Is the transfer complete now? */
- if (!length) {
- if (ch->cmd & DCMD_ENDIRQEN)
- ch->state |= DCSR_ENDINTR;
-
- if ((ch->state & DCSR_NODESCFETCH) ||
- (ch->descr & DDADR_STOP) ||
- (ch->state & DCSR_EORSTOPEN)) {
- ch->state |= DCSR_STOPINTR;
- ch->state &= ~DCSR_RUN;
-
- break;
- }
-
- ch->state |= DCSR_STOPINTR;
- break;
- }
- }
- }
-
- s->running --;
- }
-}
-
-static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
- unsigned int channel;
-
- if (size != 4) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
- __func__, size);
- return 5;
- }
-
- switch (offset) {
- case DRCMR64 ... DRCMR74:
- offset -= DRCMR64 - DRCMR0 - (64 << 2);
- /* Fall through */
- case DRCMR0 ... DRCMR63:
- channel = (offset - DRCMR0) >> 2;
- return s->req[channel];
-
- case DRQSR0:
- case DRQSR1:
- case DRQSR2:
- return 0;
-
- case DCSR0 ... DCSR31:
- channel = offset >> 2;
- if (s->chan[channel].request)
- return s->chan[channel].state | DCSR_REQPEND;
- return s->chan[channel].state;
-
- case DINT:
- return s->stopintr | s->eorintr | s->rasintr |
- s->startintr | s->endintr;
-
- case DALGN:
- return s->align;
-
- case DPCSR:
- return s->pio;
- }
-
- if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
- channel = (offset - D_CH0) >> 4;
- switch ((offset & 0x0f) >> 2) {
- case DDADR:
- return s->chan[channel].descr;
- case DSADR:
- return s->chan[channel].src;
- case DTADR:
- return s->chan[channel].dest;
- case DCMD:
- return s->chan[channel].cmd;
- }
- }
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- return 7;
-}
-
-static void pxa2xx_dma_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
- unsigned int channel;
-
- if (size != 4) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
- __func__, size);
- return;
- }
-
- switch (offset) {
- case DRCMR64 ... DRCMR74:
- offset -= DRCMR64 - DRCMR0 - (64 << 2);
- /* Fall through */
- case DRCMR0 ... DRCMR63:
- channel = (offset - DRCMR0) >> 2;
-
- if (value & DRCMR_MAPVLD)
- if ((value & DRCMR_CHLNUM) > s->channels)
- hw_error("%s: Bad DMA channel %i\n",
- __func__, (unsigned)value & DRCMR_CHLNUM);
-
- s->req[channel] = value;
- break;
-
- case DRQSR0:
- case DRQSR1:
- case DRQSR2:
- /* Nothing to do */
- break;
-
- case DCSR0 ... DCSR31:
- channel = offset >> 2;
- s->chan[channel].state &= 0x0000071f & ~(value &
- (DCSR_EORINT | DCSR_ENDINTR |
- DCSR_STARTINTR | DCSR_BUSERRINTR));
- s->chan[channel].state |= value & 0xfc800000;
-
- if (s->chan[channel].state & DCSR_STOPIRQEN)
- s->chan[channel].state &= ~DCSR_STOPINTR;
-
- if (value & DCSR_NODESCFETCH) {
- /* No-descriptor-fetch mode */
- if (value & DCSR_RUN) {
- s->chan[channel].state &= ~DCSR_STOPINTR;
- pxa2xx_dma_run(s);
- }
- } else {
- /* Descriptor-fetch mode */
- if (value & DCSR_RUN) {
- s->chan[channel].state &= ~DCSR_STOPINTR;
- pxa2xx_dma_descriptor_fetch(s, channel);
- pxa2xx_dma_run(s);
- }
- }
-
- /* Shouldn't matter as our DMA is synchronous. */
- if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
- s->chan[channel].state |= DCSR_STOPINTR;
-
- if (value & DCSR_CLRCMPST)
- s->chan[channel].state &= ~DCSR_CMPST;
- if (value & DCSR_SETCMPST)
- s->chan[channel].state |= DCSR_CMPST;
-
- pxa2xx_dma_update(s, channel);
- break;
-
- case DALGN:
- s->align = value;
- break;
-
- case DPCSR:
- s->pio = value & 0x80000001;
- break;
-
- default:
- if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
- channel = (offset - D_CH0) >> 4;
- switch ((offset & 0x0f) >> 2) {
- case DDADR:
- s->chan[channel].descr = value;
- break;
- case DSADR:
- s->chan[channel].src = value;
- break;
- case DTADR:
- s->chan[channel].dest = value;
- break;
- case DCMD:
- s->chan[channel].cmd = value;
- break;
- default:
- goto fail;
- }
-
- break;
- }
- fail:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_dma_ops = {
- .read = pxa2xx_dma_read,
- .write = pxa2xx_dma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_dma_request(void *opaque, int req_num, int on)
-{
- PXA2xxDMAState *s = opaque;
- int ch;
- if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
- hw_error("%s: Bad DMA request %i\n", __func__, req_num);
-
- if (!(s->req[req_num] & DRCMR_MAPVLD))
- return;
- ch = s->req[req_num] & DRCMR_CHLNUM;
-
- if (!s->chan[ch].request && on)
- s->chan[ch].state |= DCSR_RASINTR;
- else
- s->chan[ch].state &= ~DCSR_RASINTR;
- if (s->chan[ch].request && !on)
- s->chan[ch].state |= DCSR_EORINT;
-
- s->chan[ch].request = on;
- if (on) {
- pxa2xx_dma_run(s);
- pxa2xx_dma_update(s, ch);
- }
-}
-
-static void pxa2xx_dma_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- PXA2xxDMAState *s = PXA2XX_DMA(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
-
- qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_dma_ops, s,
- "pxa2xx.dma", 0x00010000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-static void pxa2xx_dma_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxDMAState *s = PXA2XX_DMA(dev);
- int i;
-
- if (s->channels <= 0) {
- error_setg(errp, "channels value invalid");
- return;
- }
-
- s->chan = g_new0(PXA2xxDMAChannel, s->channels);
-
- for (i = 0; i < s->channels; i ++)
- s->chan[i].state = DCSR_STOPINTR;
-}
-
-DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_new("pxa2xx-dma");
- qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_new("pxa2xx-dma");
- qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-static bool is_version_0(void *opaque, int version_id)
-{
- return version_id == 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_dma_chan = {
- .name = "pxa2xx_dma_chan",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(descr, PXA2xxDMAChannel),
- VMSTATE_UINT32(src, PXA2xxDMAChannel),
- VMSTATE_UINT32(dest, PXA2xxDMAChannel),
- VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
- VMSTATE_UINT32(state, PXA2xxDMAChannel),
- VMSTATE_INT32(request, PXA2xxDMAChannel),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static const VMStateDescription vmstate_pxa2xx_dma = {
- .name = "pxa2xx_dma",
- .version_id = 1,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UNUSED_TEST(is_version_0, 4),
- VMSTATE_UINT32(stopintr, PXA2xxDMAState),
- VMSTATE_UINT32(eorintr, PXA2xxDMAState),
- VMSTATE_UINT32(rasintr, PXA2xxDMAState),
- VMSTATE_UINT32(startintr, PXA2xxDMAState),
- VMSTATE_UINT32(endintr, PXA2xxDMAState),
- VMSTATE_UINT32(align, PXA2xxDMAState),
- VMSTATE_UINT32(pio, PXA2xxDMAState),
- VMSTATE_BUFFER(req, PXA2xxDMAState),
- VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
- vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_dma_properties[] = {
- DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx DMA controller";
- dc->vmsd = &vmstate_pxa2xx_dma;
- device_class_set_props(dc, pxa2xx_dma_properties);
- dc->realize = pxa2xx_dma_realize;
-}
-
-static const TypeInfo pxa2xx_dma_info = {
- .name = TYPE_PXA2XX_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxDMAState),
- .instance_init = pxa2xx_dma_init,
- .class_init = pxa2xx_dma_class_init,
-};
-
-static void pxa2xx_dma_register_types(void)
-{
- type_register_static(&pxa2xx_dma_info);
-}
-
-type_init(pxa2xx_dma_register_types)
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
index 9152841..b6ed1d4 100644
--- a/hw/dma/rc4030.c
+++ b/hw/dma/rc4030.c
@@ -32,7 +32,7 @@
#include "qemu/timer.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "trace.h"
#include "qom/object.h"
@@ -701,13 +701,13 @@ static void rc4030_unrealize(DeviceState *dev)
object_unparent(OBJECT(&s->dma_mr));
}
-static void rc4030_class_init(ObjectClass *klass, void *class_data)
+static void rc4030_class_init(ObjectClass *klass, const void *class_data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = rc4030_realize;
dc->unrealize = rc4030_unrealize;
- dc->reset = rc4030_reset;
+ device_class_set_legacy_reset(dc, rc4030_reset);
dc->vmsd = &vmstate_rc4030;
}
@@ -720,7 +720,7 @@ static const TypeInfo rc4030_info = {
};
static void rc4030_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/dma/sifive_pdma.c b/hw/dma/sifive_pdma.c
index 1dd88f3..48de3a2 100644
--- a/hw/dma/sifive_pdma.c
+++ b/hw/dma/sifive_pdma.c
@@ -28,7 +28,7 @@
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/dma/sifive_pdma.h"
#define DMA_CONTROL 0x000
@@ -152,7 +152,6 @@ done:
error:
s->chan[ch].state = DMA_CHAN_STATE_ERROR;
s->chan[ch].control |= CONTROL_ERR;
- return;
}
static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch)
@@ -465,7 +464,7 @@ static void sifive_pdma_realize(DeviceState *dev, Error **errp)
}
}
-static void sifive_pdma_class_init(ObjectClass *klass, void *data)
+static void sifive_pdma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
index 8019641..60c23b6 100644
--- a/hw/dma/sparc32_dma.c
+++ b/hw/dma/sparc32_dma.c
@@ -32,7 +32,7 @@
#include "hw/sparc/sun4m_iommu.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "trace.h"
@@ -274,11 +274,11 @@ static void sparc32_dma_device_init(Object *obj)
qdev_init_gpio_out(dev, s->gpio, 2);
}
-static void sparc32_dma_device_class_init(ObjectClass *klass, void *data)
+static void sparc32_dma_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = sparc32_dma_device_reset;
+ device_class_set_legacy_reset(dc, sparc32_dma_device_reset);
dc->vmsd = &vmstate_sparc32_dma_device;
}
@@ -316,7 +316,8 @@ static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(sysbus), &error_fatal);
}
-static void sparc32_espdma_device_class_init(ObjectClass *klass, void *data)
+static void sparc32_espdma_device_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -351,7 +352,8 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(lance), &error_fatal);
}
-static void sparc32_ledma_device_class_init(ObjectClass *klass, void *data)
+static void sparc32_ledma_device_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -426,7 +428,7 @@ static void sparc32_dma_init(Object *obj)
TYPE_SPARC32_LEDMA_DEVICE);
}
-static void sparc32_dma_class_init(ObjectClass *klass, void *data)
+static void sparc32_dma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index 7707634..2020399 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -33,7 +33,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/stream.h"
#include "qom/object.h"
#include "trace.h"
@@ -611,7 +611,7 @@ static void xilinx_axidma_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property axidma_properties[] = {
+static const Property axidma_properties[] = {
DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
DEFINE_PROP_LINK("axistream-connected", XilinxAXIDMA,
tx_data_dev, TYPE_STREAM_SINK, StreamSink *),
@@ -619,15 +619,14 @@ static Property axidma_properties[] = {
tx_control_dev, TYPE_STREAM_SINK, StreamSink *),
DEFINE_PROP_LINK("dma", XilinxAXIDMA, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void axidma_class_init(ObjectClass *klass, void *data)
+static void axidma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = xilinx_axidma_realize;
- dc->reset = xilinx_axidma_reset;
+ device_class_set_legacy_reset(dc, xilinx_axidma_reset);
device_class_set_props(dc, axidma_properties);
}
@@ -640,7 +639,8 @@ static StreamSinkClass xilinx_axidma_control_stream_class = {
.push = xilinx_axidma_control_stream_push,
};
-static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data)
+static void xilinx_axidma_stream_class_init(ObjectClass *klass,
+ const void *data)
{
StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
@@ -662,7 +662,7 @@ static const TypeInfo xilinx_axidma_data_stream_info = {
.instance_size = sizeof(XilinxAXIDMAStreamSink),
.class_init = xilinx_axidma_stream_class_init,
.class_data = &xilinx_axidma_data_stream_class,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_STREAM_SINK },
{ }
}
@@ -674,7 +674,7 @@ static const TypeInfo xilinx_axidma_control_stream_info = {
.instance_size = sizeof(XilinxAXIDMAStreamSink),
.class_init = xilinx_axidma_stream_class_init,
.class_data = &xilinx_axidma_control_stream_class,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_STREAM_SINK },
{ }
}
diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c
index 670c956..0c075e7 100644
--- a/hw/dma/xlnx-zdma.c
+++ b/hw/dma/xlnx-zdma.c
@@ -810,18 +810,17 @@ static const VMStateDescription vmstate_zdma = {
}
};
-static Property zdma_props[] = {
+static const Property zdma_props[] = {
DEFINE_PROP_UINT32("bus-width", XlnxZDMA, cfg.bus_width, 64),
DEFINE_PROP_LINK("dma", XlnxZDMA, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void zdma_class_init(ObjectClass *klass, void *data)
+static void zdma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = zdma_reset;
+ device_class_set_legacy_reset(dc, zdma_reset);
dc->realize = zdma_realize;
device_class_set_props(dc, zdma_props);
dc->vmsd = &vmstate_zdma;
diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index e901f68..2684571 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -29,7 +29,7 @@
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "qemu/bitops.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -380,11 +380,11 @@ static void xlnx_zynq_devcfg_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, void *data)
+static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_zynq_devcfg_reset;
+ device_class_set_legacy_reset(dc, xlnx_zynq_devcfg_reset);
dc->vmsd = &vmstate_xlnx_zynq_devcfg;
}
diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c
index ae30748..d8c7da1 100644
--- a/hw/dma/xlnx_csu_dma.c
+++ b/hw/dma/xlnx_csu_dma.c
@@ -25,7 +25,7 @@
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/ptimer.h"
#include "hw/stream.h"
#include "hw/register.h"
@@ -287,7 +287,7 @@ static uint32_t xlnx_csu_dma_advance(XlnxCSUDMA *s, uint32_t len)
static void xlnx_csu_dma_src_notify(void *opaque)
{
XlnxCSUDMA *s = XLNX_CSU_DMA(opaque);
- unsigned char buf[4 * 1024];
+ QEMU_UNINITIALIZED unsigned char buf[4 * 1024];
size_t rlen = 0;
ptimer_transaction_begin(s->src_timer);
@@ -691,7 +691,7 @@ static const VMStateDescription vmstate_xlnx_csu_dma = {
}
};
-static Property xlnx_csu_dma_properties[] = {
+static const Property xlnx_csu_dma_properties[] = {
/*
* Ref PG021, Stream Data Width:
* Data width in bits of the AXI S2MM AXI4-Stream Data bus.
@@ -710,16 +710,15 @@ static Property xlnx_csu_dma_properties[] = {
TYPE_STREAM_SINK, StreamSink *),
DEFINE_PROP_LINK("dma", XlnxCSUDMA, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
+static void xlnx_csu_dma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_CLASS(klass);
- dc->reset = xlnx_csu_dma_reset;
+ device_class_set_legacy_reset(dc, xlnx_csu_dma_reset);
dc->realize = xlnx_csu_dma_realize;
dc->vmsd = &vmstate_xlnx_csu_dma;
device_class_set_props(dc, xlnx_csu_dma_properties);
@@ -745,7 +744,7 @@ static const TypeInfo xlnx_csu_dma_info = {
.class_init = xlnx_csu_dma_class_init,
.class_size = sizeof(XlnxCSUDMAClass),
.instance_init = xlnx_csu_dma_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_STREAM_SINK },
{ }
}
diff --git a/hw/dma/xlnx_dpdma.c b/hw/dma/xlnx_dpdma.c
index a685bd2..3d88ccc 100644
--- a/hw/dma/xlnx_dpdma.c
+++ b/hw/dma/xlnx_dpdma.c
@@ -593,12 +593,12 @@ static void xlnx_dpdma_reset(DeviceState *dev)
}
}
-static void xlnx_dpdma_class_init(ObjectClass *oc, void *data)
+static void xlnx_dpdma_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->vmsd = &vmstate_xlnx_dpdma;
- dc->reset = xlnx_dpdma_reset;
+ device_class_set_legacy_reset(dc, xlnx_dpdma_reset);
}
static const TypeInfo xlnx_dpdma_info = {
diff --git a/hw/fsi/aspeed_apb2opb.c b/hw/fsi/aspeed_apb2opb.c
index ea50718..172ba16 100644
--- a/hw/fsi/aspeed_apb2opb.c
+++ b/hw/fsi/aspeed_apb2opb.c
@@ -320,13 +320,13 @@ static void fsi_aspeed_apb2opb_reset(DeviceState *dev)
memcpy(s->regs, aspeed_apb2opb_reset, ASPEED_APB2OPB_NR_REGS);
}
-static void fsi_aspeed_apb2opb_class_init(ObjectClass *klass, void *data)
+static void fsi_aspeed_apb2opb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "ASPEED APB2OPB Bridge";
dc->realize = fsi_aspeed_apb2opb_realize;
- dc->reset = fsi_aspeed_apb2opb_reset;
+ device_class_set_legacy_reset(dc, fsi_aspeed_apb2opb_reset);
}
static const TypeInfo aspeed_apb2opb_info = {
diff --git a/hw/fsi/cfam.c b/hw/fsi/cfam.c
index c62f0f7..e2145c5 100644
--- a/hw/fsi/cfam.c
+++ b/hw/fsi/cfam.c
@@ -145,7 +145,7 @@ static void fsi_cfam_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&cfam->lbus.mr, 0, &fsi_dev->iomem);
}
-static void fsi_cfam_class_init(ObjectClass *klass, void *data)
+static void fsi_cfam_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->bus_type = TYPE_FSI_BUS;
diff --git a/hw/fsi/fsi-master.c b/hw/fsi/fsi-master.c
index a5f0598..083a550 100644
--- a/hw/fsi/fsi-master.c
+++ b/hw/fsi/fsi-master.c
@@ -144,14 +144,14 @@ static void fsi_master_reset(DeviceState *dev)
s->regs[FSI_MVER] = 0xe0050101;
}
-static void fsi_master_class_init(ObjectClass *klass, void *data)
+static void fsi_master_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->bus_type = TYPE_OP_BUS;
dc->desc = "FSI Master";
dc->realize = fsi_master_realize;
- dc->reset = fsi_master_reset;
+ device_class_set_legacy_reset(dc, fsi_master_reset);
}
static const TypeInfo fsi_master_info = {
diff --git a/hw/fsi/fsi.c b/hw/fsi/fsi.c
index 9a5f4e6..6c52d5e 100644
--- a/hw/fsi/fsi.c
+++ b/hw/fsi/fsi.c
@@ -76,13 +76,13 @@ static void fsi_slave_init(Object *o)
s, TYPE_FSI_SLAVE, 0x400);
}
-static void fsi_slave_class_init(ObjectClass *klass, void *data)
+static void fsi_slave_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->bus_type = TYPE_FSI_BUS;
dc->desc = "FSI Slave";
- dc->reset = fsi_slave_reset;
+ device_class_set_legacy_reset(dc, fsi_slave_reset);
}
static const TypeInfo fsi_slave_info = {
diff --git a/hw/fsi/lbus.c b/hw/fsi/lbus.c
index 20495f4..8ec7f5f 100644
--- a/hw/fsi/lbus.c
+++ b/hw/fsi/lbus.c
@@ -91,13 +91,13 @@ static void fsi_scratchpad_reset(DeviceState *dev)
memset(s->regs, 0, sizeof(s->regs));
}
-static void fsi_scratchpad_class_init(ObjectClass *klass, void *data)
+static void fsi_scratchpad_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->bus_type = TYPE_FSI_LBUS;
dc->realize = fsi_scratchpad_realize;
- dc->reset = fsi_scratchpad_reset;
+ device_class_set_legacy_reset(dc, fsi_scratchpad_reset);
}
static const TypeInfo fsi_scratchpad_info = {
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
index 19c97cc..a209294 100644
--- a/hw/gpio/Kconfig
+++ b/hw/gpio/Kconfig
@@ -1,7 +1,3 @@
-config MAX7310
- bool
- depends on I2C
-
config PL061
bool
@@ -20,6 +16,17 @@ config SIFIVE_GPIO
config STM32L4X5_GPIO
bool
+config PCA9552
+ bool
+ depends on I2C
+
+config PCA9554
+ bool
+ depends on I2C
+
config PCF8574
bool
depends on I2C
+
+config ZAURUS_SCOOP
+ bool
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 6474bb8..609a556 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+ SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+ SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+ SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+ SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+ SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+ SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+ SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+ SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+ SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+ SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
{
uint32_t falling_edge = 0, rising_edge = 0;
@@ -281,7 +313,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
diff &= mode_mask;
if (diff) {
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
- uint32_t mask = 1 << gpio;
+ uint32_t mask = 1U << gpio;
/* If the gpio needs to be updated... */
if (!(diff & mask)) {
@@ -340,7 +372,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, uint32_t set_idx,
value &= ~pin_mask;
}
- aspeed_gpio_update(s, &s->sets[set_idx], value, ~s->sets[set_idx].direction);
+ aspeed_gpio_update(s, &s->sets[set_idx], value,
+ ~s->sets[set_idx].direction);
}
/*
@@ -629,7 +662,6 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
uint64_t data, uint32_t size)
{
-
AspeedGPIOState *s = ASPEED_GPIO(opaque);
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
const GPIOSetProperties *props;
@@ -641,7 +673,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
uint32_t reg_value = 0;
- uint32_t cleared;
+ uint32_t pending = 0;
set = &s->sets[set_idx];
props = &agc->props[set_idx];
@@ -703,16 +735,23 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
reg_value);
- /* set interrupt status */
- reg_value = set->int_status;
- reg_value = deposit32(reg_value, pin_idx, 1,
- FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
- cleared = ctpop32(reg_value & set->int_status);
- if (s->pending && cleared) {
- assert(s->pending >= cleared);
- s->pending -= cleared;
+ /* interrupt status */
+ if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+ /* pending is either 1 or 0 for a 1-bit field */
+ pending = extract32(set->int_status, pin_idx, 1);
+
+ assert(s->pending >= pending);
+
+ /* No change to s->pending if pending is 0 */
+ s->pending -= pending;
+
+ /*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+ set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
}
- set->int_status &= ~reg_value;
break;
case gpio_reg_idx_debounce:
reg_value = set->debounce_1;
@@ -761,7 +800,6 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
return;
}
aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
- return;
}
static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
@@ -889,7 +927,6 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
return;
}
aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
- return;
}
static int get_set_idx(AspeedGPIOState *s, const char *group, int *group_idx)
@@ -963,7 +1000,314 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
aspeed_gpio_set_pin_level(s, set_idx, pin, level);
}
-/****************** Setup functions ******************/
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+ uint32_t pin)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ GPIOSets *set;
+ uint64_t value = 0;
+ uint32_t set_idx;
+ uint32_t pin_idx;
+
+ set_idx = pin / ASPEED_GPIOS_PER_SET;
+ pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+ if (set_idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+ __func__, set_idx);
+ return 0;
+ }
+
+ set = &s->sets[set_idx];
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+ extract32(set->data_read, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+ extract32(set->direction, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+ extract32(set->int_enable, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+ extract32(set->int_sens_0, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+ extract32(set->int_sens_1, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+ extract32(set->int_sens_2, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+ extract32(set->reset_tol, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+ extract32(set->debounce_1, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+ extract32(set->debounce_2, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+ extract32(set->input_mask, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_STATUS,
+ extract32(set->int_status, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_IN_DATA,
+ extract32(set->data_value, pin_idx, 1));
+ return value;
+}
+
+static void aspeed_gpio_2700_write_control_reg(AspeedGPIOState *s,
+ uint32_t pin, uint64_t data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ const GPIOSetProperties *props;
+ GPIOSets *set;
+ uint32_t set_idx;
+ uint32_t pin_idx;
+ uint32_t group_value = 0;
+ uint32_t pending = 0;
+
+ set_idx = pin / ASPEED_GPIOS_PER_SET;
+ pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+ if (set_idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+ __func__, set_idx);
+ return;
+ }
+
+ set = &s->sets[set_idx];
+ props = &agc->props[set_idx];
+
+ /* direction */
+ group_value = set->direction;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DIRECTION));
+ /*
+ * where data is the value attempted to be written to the pin:
+ * pin type | input mask | output mask | expected value
+ * ------------------------------------------------------------
+ * bidirectional | 1 | 1 | data
+ * input only | 1 | 0 | 0
+ * output only | 0 | 1 | 1
+ * no pin | 0 | 0 | 0
+ *
+ * which is captured by:
+ * data = ( data | ~input) & output;
+ */
+ group_value = (group_value | ~props->input) & props->output;
+ set->direction = update_value_control_source(set, set->direction,
+ group_value);
+
+ /* out data */
+ group_value = set->data_read;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_OUT_DATA));
+ group_value &= props->output;
+ group_value = update_value_control_source(set, set->data_read,
+ group_value);
+ set->data_read = group_value;
+
+ /* interrupt enable */
+ group_value = set->int_enable;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_ENABLE));
+ set->int_enable = update_value_control_source(set, set->int_enable,
+ group_value);
+
+ /* interrupt sensitivity type 0 */
+ group_value = set->int_sens_0;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_0));
+ set->int_sens_0 = update_value_control_source(set, set->int_sens_0,
+ group_value);
+
+ /* interrupt sensitivity type 1 */
+ group_value = set->int_sens_1;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_1));
+ set->int_sens_1 = update_value_control_source(set, set->int_sens_1,
+ group_value);
+
+ /* interrupt sensitivity type 2 */
+ group_value = set->int_sens_2;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_2));
+ set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
+ group_value);
+
+ /* reset tolerance enable */
+ group_value = set->reset_tol;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_RESET_TOLERANCE));
+ set->reset_tol = update_value_control_source(set, set->reset_tol,
+ group_value);
+
+ /* debounce 1 */
+ group_value = set->debounce_1;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DEBOUNCE_1));
+ set->debounce_1 = update_value_control_source(set, set->debounce_1,
+ group_value);
+
+ /* debounce 2 */
+ group_value = set->debounce_2;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DEBOUNCE_2));
+ set->debounce_2 = update_value_control_source(set, set->debounce_2,
+ group_value);
+
+ /* input mask */
+ group_value = set->input_mask;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INPUT_MASK));
+ /*
+ * feeds into interrupt generation
+ * 0: read from data value reg will be updated
+ * 1: read from data value reg will not be updated
+ */
+ set->input_mask = group_value & props->input;
+
+ /* blink counter 1 */
+ /* blink counter 2 */
+ /* unimplement */
+
+ /* interrupt status */
+ if (SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_STATUS)) {
+ /* pending is either 1 or 0 for a 1-bit field */
+ pending = extract32(set->int_status, pin_idx, 1);
+
+ assert(s->pending >= pending);
+
+ /* No change to s->pending if pending is 0 */
+ s->pending -= pending;
+
+ /*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+ set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
+ }
+
+ aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
+}
+
+static uint64_t aspeed_gpio_2700_read(void *opaque, hwaddr offset,
+ uint32_t size)
+{
+ AspeedGPIOState *s = ASPEED_GPIO(opaque);
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ GPIOSets *set;
+ uint64_t value;
+ uint64_t reg;
+ uint32_t pin;
+ uint32_t idx;
+
+ reg = offset >> 2;
+
+ if (reg >= agc->reg_table_count) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ case R_GPIO_2700_DEBOUNCE_TIME_1 ... R_GPIO_2700_DEBOUNCE_TIME_3:
+ idx = reg - R_GPIO_2700_DEBOUNCE_TIME_1;
+
+ if (idx >= ASPEED_GPIO_NR_DEBOUNCE_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: debounce index: %d, out of bounds\n",
+ __func__, idx);
+ return 0;
+ }
+
+ value = (uint64_t) s->debounce_regs[idx];
+ break;
+ case R_GPIO_2700_INT_STATUS_1 ... R_GPIO_2700_INT_STATUS_7:
+ idx = reg - R_GPIO_2700_INT_STATUS_1;
+
+ if (idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: interrupt status index: %d, out of bounds\n",
+ __func__, idx);
+ return 0;
+ }
+
+ set = &s->sets[idx];
+ value = (uint64_t) set->int_status;
+ break;
+ case R_GPIO_A0_CONTROL ... R_GPIO_AA7_CONTROL:
+ pin = reg - R_GPIO_A0_CONTROL;
+
+ if (pin >= agc->nr_gpio_pins) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid pin number: %d\n",
+ __func__, pin);
+ return 0;
+ }
+
+ value = aspeed_gpio_2700_read_control_reg(s, pin);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ return 0;
+ }
+
+ trace_aspeed_gpio_read(offset, value);
+ return value;
+}
+
+static void aspeed_gpio_2700_write(void *opaque, hwaddr offset,
+ uint64_t data, uint32_t size)
+{
+ AspeedGPIOState *s = ASPEED_GPIO(opaque);
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ uint64_t reg;
+ uint32_t pin;
+ uint32_t idx;
+
+ trace_aspeed_gpio_write(offset, data);
+
+ reg = offset >> 2;
+
+ if (reg >= agc->reg_table_count) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ return;
+ }
+
+ switch (reg) {
+ case R_GPIO_2700_DEBOUNCE_TIME_1 ... R_GPIO_2700_DEBOUNCE_TIME_3:
+ idx = reg - R_GPIO_2700_DEBOUNCE_TIME_1;
+
+ if (idx >= ASPEED_GPIO_NR_DEBOUNCE_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: debounce index: %d out of bounds\n",
+ __func__, idx);
+ return;
+ }
+
+ s->debounce_regs[idx] = (uint32_t) data;
+ break;
+ case R_GPIO_A0_CONTROL ... R_GPIO_AA7_CONTROL:
+ pin = reg - R_GPIO_A0_CONTROL;
+
+ if (pin >= agc->nr_gpio_pins) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid pin number: %d\n",
+ __func__, pin);
+ return;
+ }
+
+ if (SHARED_FIELD_EX32(data, GPIO_CONTROL_RESERVED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid reserved data: 0x%"
+ PRIx64"\n", __func__, data);
+ return;
+ }
+
+ aspeed_gpio_2700_write_control_reg(s, pin, data);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ break;
+ }
+}
+
+/* Setup functions */
static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
@@ -1009,6 +1353,16 @@ static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
[5] = {0x000000ff, 0x00000000, {"U"} },
};
+static GPIOSetProperties ast2700_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
+ [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
+ [1] = {0x0fffffff, 0x0fffffff, {"E", "F", "G", "H"} },
+ [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
+ [3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} },
+ [4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} },
+ [5] = {0xffffffff, 0xffffffff, {"U", "V", "W", "X"} },
+ [6] = {0x00ffffff, 0x00ffffff, {"Y", "Z", "AA"} },
+};
+
static const MemoryRegionOps aspeed_gpio_ops = {
.read = aspeed_gpio_read,
.write = aspeed_gpio_write,
@@ -1017,6 +1371,14 @@ static const MemoryRegionOps aspeed_gpio_ops = {
.valid.max_access_size = 4,
};
+static const MemoryRegionOps aspeed_gpio_2700_ops = {
+ .read = aspeed_gpio_2700_read,
+ .write = aspeed_gpio_2700_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
static void aspeed_gpio_reset(DeviceState *dev)
{
AspeedGPIOState *s = ASPEED_GPIO(dev);
@@ -1046,8 +1408,8 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp)
}
}
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
- TYPE_ASPEED_GPIO, 0x800);
+ memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
+ TYPE_ASPEED_GPIO, agc->mem_size);
sysbus_init_mmio(sbd, &s->iomem);
}
@@ -1111,17 +1473,17 @@ static const VMStateDescription vmstate_aspeed_gpio = {
}
};
-static void aspeed_gpio_class_init(ObjectClass *klass, void *data)
+static void aspeed_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_gpio_realize;
- dc->reset = aspeed_gpio_reset;
+ device_class_set_legacy_reset(dc, aspeed_gpio_reset);
dc->desc = "Aspeed GPIO Controller";
dc->vmsd = &vmstate_aspeed_gpio;
}
-static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data)
+static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, const void *data)
{
AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
@@ -1130,9 +1492,11 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 7;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
}
-static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
+static void aspeed_gpio_2500_class_init(ObjectClass *klass, const void *data)
{
AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
@@ -1141,9 +1505,12 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 8;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
}
-static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
+static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass,
+ const void *data)
{
AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
@@ -1152,9 +1519,12 @@ static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 7;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x800;
+ agc->reg_ops = &aspeed_gpio_ops;
}
-static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
+static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass,
+ const void *data)
{
AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
@@ -1163,9 +1533,11 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 2;
agc->reg_table = aspeed_1_8v_gpios;
agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x800;
+ agc->reg_ops = &aspeed_gpio_ops;
}
-static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
+static void aspeed_gpio_1030_class_init(ObjectClass *klass, const void *data)
{
AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
@@ -1174,6 +1546,20 @@ static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 6;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
+}
+
+static void aspeed_gpio_2700_class_init(ObjectClass *klass, const void *data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
+
+ agc->props = ast2700_set_props;
+ agc->nr_gpio_pins = 216;
+ agc->nr_gpio_sets = 7;
+ agc->reg_table_count = GPIO_2700_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_2700_ops;
}
static const TypeInfo aspeed_gpio_info = {
@@ -1220,6 +1606,13 @@ static const TypeInfo aspeed_gpio_ast1030_info = {
.instance_init = aspeed_gpio_init,
};
+static const TypeInfo aspeed_gpio_ast2700_info = {
+ .name = TYPE_ASPEED_GPIO "-ast2700",
+ .parent = TYPE_ASPEED_GPIO,
+ .class_init = aspeed_gpio_2700_class_init,
+ .instance_init = aspeed_gpio_init,
+};
+
static void aspeed_gpio_register_types(void)
{
type_register_static(&aspeed_gpio_info);
@@ -1228,6 +1621,7 @@ static void aspeed_gpio_register_types(void)
type_register_static(&aspeed_gpio_ast2600_3_3v_info);
type_register_static(&aspeed_gpio_ast2600_1_8v_info);
type_register_static(&aspeed_gpio_ast1030_info);
+ type_register_static(&aspeed_gpio_ast2700_info);
}
type_init(aspeed_gpio_register_types);
diff --git a/hw/gpio/bcm2835_gpio.c b/hw/gpio/bcm2835_gpio.c
index 6bd50bb..dfb5d5c 100644
--- a/hw/gpio/bcm2835_gpio.c
+++ b/hw/gpio/bcm2835_gpio.c
@@ -319,13 +319,13 @@ static void bcm2835_gpio_realize(DeviceState *dev, Error **errp)
s->sdbus_sdhost = SD_BUS(obj);
}
-static void bcm2835_gpio_class_init(ObjectClass *klass, void *data)
+static void bcm2835_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_bcm2835_gpio;
dc->realize = &bcm2835_gpio_realize;
- dc->reset = &bcm2835_gpio_reset;
+ device_class_set_legacy_reset(dc, bcm2835_gpio_reset);
}
static const TypeInfo bcm2835_gpio_info = {
diff --git a/hw/gpio/bcm2838_gpio.c b/hw/gpio/bcm2838_gpio.c
index 2ddf62f..1069e78 100644
--- a/hw/gpio/bcm2838_gpio.c
+++ b/hw/gpio/bcm2838_gpio.c
@@ -293,7 +293,6 @@ static void bcm2838_gpio_write(void *opaque, hwaddr offset, uint64_t value,
qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n",
TYPE_BCM2838_GPIO, __func__, offset);
}
- return;
}
static void bcm2838_gpio_reset(DeviceState *dev)
@@ -365,13 +364,13 @@ static void bcm2838_gpio_realize(DeviceState *dev, Error **errp)
s->sdbus_sdhost = SD_BUS(obj);
}
-static void bcm2838_gpio_class_init(ObjectClass *klass, void *data)
+static void bcm2838_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_bcm2838_gpio;
dc->realize = &bcm2838_gpio_realize;
- dc->reset = &bcm2838_gpio_reset;
+ device_class_set_legacy_reset(dc, bcm2838_gpio_reset);
}
static const TypeInfo bcm2838_gpio_info = {
diff --git a/hw/gpio/gpio_key.c b/hw/gpio/gpio_key.c
index 61bb587..40c028b 100644
--- a/hw/gpio/gpio_key.c
+++ b/hw/gpio/gpio_key.c
@@ -85,13 +85,13 @@ static void gpio_key_realize(DeviceState *dev, Error **errp)
s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, gpio_key_timer_expired, s);
}
-static void gpio_key_class_init(ObjectClass *klass, void *data)
+static void gpio_key_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = gpio_key_realize;
dc->vmsd = &vmstate_gpio_key;
- dc->reset = &gpio_key_reset;
+ device_class_set_legacy_reset(dc, gpio_key_reset);
}
static const TypeInfo gpio_key_info = {
diff --git a/hw/gpio/gpio_pwr.c b/hw/gpio/gpio_pwr.c
index dbaf1c7..2d14f8b 100644
--- a/hw/gpio/gpio_pwr.c
+++ b/hw/gpio/gpio_pwr.c
@@ -24,7 +24,7 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#define TYPE_GPIOPWR "gpio-pwr"
OBJECT_DECLARE_SIMPLE_TYPE(GPIO_PWR_State, GPIOPWR)
diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
index e53b00d..450ece4 100644
--- a/hw/gpio/imx_gpio.c
+++ b/hw/gpio/imx_gpio.c
@@ -24,6 +24,7 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "trace.h"
#ifndef DEBUG_IMX_GPIO
#define DEBUG_IMX_GPIO 0
@@ -34,14 +35,6 @@ typedef enum IMXGPIOLevel {
IMX_GPIO_LEVEL_HIGH = 1,
} IMXGPIOLevel;
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_GPIO) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPIO, \
- __func__, ##args); \
- } \
- } while (0)
-
static const char *imx_gpio_reg_name(uint32_t reg)
{
switch (reg) {
@@ -79,7 +72,7 @@ static void imx_gpio_update_int(IMXGPIOState *s)
static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
{
/* if this signal isn't configured as an input signal, nothing to do */
- if (!extract32(s->gdir, line, 1)) {
+ if (extract32(s->gdir, line, 1)) {
return;
}
@@ -111,6 +104,8 @@ static void imx_gpio_set(void *opaque, int line, int level)
IMXGPIOState *s = IMX_GPIO(opaque);
IMXGPIOLevel imx_level = level ? IMX_GPIO_LEVEL_HIGH : IMX_GPIO_LEVEL_LOW;
+ trace_imx_gpio_set(DEVICE(s)->canonical_path, line, imx_level);
+
imx_gpio_set_int_line(s, line, imx_level);
/* this is an input signal, so set PSR */
@@ -200,7 +195,8 @@ static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size)
break;
}
- DPRINTF("(%s) = 0x%" PRIx32 "\n", imx_gpio_reg_name(offset), reg_value);
+ trace_imx_gpio_read(DEVICE(s)->canonical_path, imx_gpio_reg_name(offset),
+ reg_value);
return reg_value;
}
@@ -210,8 +206,8 @@ static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value,
{
IMXGPIOState *s = IMX_GPIO(opaque);
- DPRINTF("(%s, value = 0x%" PRIx32 ")\n", imx_gpio_reg_name(offset),
- (uint32_t)value);
+ trace_imx_gpio_write(DEVICE(s)->canonical_path, imx_gpio_reg_name(offset),
+ value);
switch (offset) {
case DR_ADDR:
@@ -261,8 +257,6 @@ static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value,
HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset);
break;
}
-
- return;
}
static const MemoryRegionOps imx_gpio_ops = {
@@ -290,11 +284,10 @@ static const VMStateDescription vmstate_imx_gpio = {
}
};
-static Property imx_gpio_properties[] = {
+static const Property imx_gpio_properties[] = {
DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq,
false),
- DEFINE_PROP_END_OF_LIST(),
};
static void imx_gpio_reset(DeviceState *dev)
@@ -328,12 +321,12 @@ static void imx_gpio_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
-static void imx_gpio_class_init(ObjectClass *klass, void *data)
+static void imx_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_gpio_realize;
- dc->reset = imx_gpio_reset;
+ device_class_set_legacy_reset(dc, imx_gpio_reset);
device_class_set_props(dc, imx_gpio_properties);
dc->vmsd = &vmstate_imx_gpio;
dc->desc = "i.MX GPIO controller";
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
deleted file mode 100644
index 8631571..0000000
--- a/hw/gpio/max7310.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * MAX7310 8-port GPIO expansion chip.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This file is licensed under GNU GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define TYPE_MAX7310 "max7310"
-OBJECT_DECLARE_SIMPLE_TYPE(MAX7310State, MAX7310)
-
-struct MAX7310State {
- I2CSlave parent_obj;
-
- int i2c_command_byte;
- int len;
-
- uint8_t level;
- uint8_t direction;
- uint8_t polarity;
- uint8_t status;
- uint8_t command;
- qemu_irq handler[8];
- qemu_irq *gpio_in;
-};
-
-static void max7310_reset(DeviceState *dev)
-{
- MAX7310State *s = MAX7310(dev);
-
- s->level &= s->direction;
- s->direction = 0xff;
- s->polarity = 0xf0;
- s->status = 0x01;
- s->command = 0x00;
-}
-
-static uint8_t max7310_rx(I2CSlave *i2c)
-{
- MAX7310State *s = MAX7310(i2c);
-
- switch (s->command) {
- case 0x00: /* Input port */
- return s->level ^ s->polarity;
-
- case 0x01: /* Output port */
- return s->level & ~s->direction;
-
- case 0x02: /* Polarity inversion */
- return s->polarity;
-
- case 0x03: /* Configuration */
- return s->direction;
-
- case 0x04: /* Timeout */
- return s->status;
-
- case 0xff: /* Reserved */
- return 0xff;
-
- default:
- qemu_log_mask(LOG_UNIMP, "%s: Unsupported register 0x02%" PRIx8 "\n",
- __func__, s->command);
- break;
- }
- return 0xff;
-}
-
-static int max7310_tx(I2CSlave *i2c, uint8_t data)
-{
- MAX7310State *s = MAX7310(i2c);
- uint8_t diff;
- int line;
-
- if (s->len ++ > 1) {
-#ifdef VERBOSE
- printf("%s: message too long (%i bytes)\n", __func__, s->len);
-#endif
- return 1;
- }
-
- if (s->i2c_command_byte) {
- s->command = data;
- s->i2c_command_byte = 0;
- return 0;
- }
-
- switch (s->command) {
- case 0x01: /* Output port */
- for (diff = (data ^ s->level) & ~s->direction; diff;
- diff &= ~(1 << line)) {
- line = ctz32(diff);
- if (s->handler[line])
- qemu_set_irq(s->handler[line], (data >> line) & 1);
- }
- s->level = (s->level & s->direction) | (data & ~s->direction);
- break;
-
- case 0x02: /* Polarity inversion */
- s->polarity = data;
- break;
-
- case 0x03: /* Configuration */
- s->level &= ~(s->direction ^ data);
- s->direction = data;
- break;
-
- case 0x04: /* Timeout */
- s->status = data;
- break;
-
- case 0x00: /* Input port - ignore writes */
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "%s: Unsupported register 0x02%" PRIx8 "\n",
- __func__, s->command);
- return 1;
- }
-
- return 0;
-}
-
-static int max7310_event(I2CSlave *i2c, enum i2c_event event)
-{
- MAX7310State *s = MAX7310(i2c);
- s->len = 0;
-
- switch (event) {
- case I2C_START_SEND:
- s->i2c_command_byte = 1;
- break;
- case I2C_FINISH:
-#ifdef VERBOSE
- if (s->len == 1)
- printf("%s: message too short (%i bytes)\n", __func__, s->len);
-#endif
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_max7310 = {
- .name = "max7310",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(i2c_command_byte, MAX7310State),
- VMSTATE_INT32(len, MAX7310State),
- VMSTATE_UINT8(level, MAX7310State),
- VMSTATE_UINT8(direction, MAX7310State),
- VMSTATE_UINT8(polarity, MAX7310State),
- VMSTATE_UINT8(status, MAX7310State),
- VMSTATE_UINT8(command, MAX7310State),
- VMSTATE_I2C_SLAVE(parent_obj, MAX7310State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void max7310_gpio_set(void *opaque, int line, int level)
-{
- MAX7310State *s = (MAX7310State *) opaque;
- assert(line >= 0 && line < ARRAY_SIZE(s->handler));
-
- if (level)
- s->level |= s->direction & (1 << line);
- else
- s->level &= ~(s->direction & (1 << line));
-}
-
-/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
- * but also accepts sequences that are not SMBus so return an I2C device. */
-static void max7310_realize(DeviceState *dev, Error **errp)
-{
- MAX7310State *s = MAX7310(dev);
-
- qdev_init_gpio_in(dev, max7310_gpio_set, ARRAY_SIZE(s->handler));
- qdev_init_gpio_out(dev, s->handler, ARRAY_SIZE(s->handler));
-}
-
-static void max7310_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- dc->realize = max7310_realize;
- k->event = max7310_event;
- k->recv = max7310_rx;
- k->send = max7310_tx;
- dc->reset = max7310_reset;
- dc->vmsd = &vmstate_max7310;
-}
-
-static const TypeInfo max7310_info = {
- .name = TYPE_MAX7310,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(MAX7310State),
- .class_init = max7310_class_init,
-};
-
-static void max7310_register_types(void)
-{
- type_register_static(&max7310_info);
-}
-
-type_init(max7310_register_types)
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
index a7495d1..7484061 100644
--- a/hw/gpio/meson.build
+++ b/hw/gpio/meson.build
@@ -1,11 +1,10 @@
system_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c'))
system_ss.add(when: 'CONFIG_GPIO_MPC8XXX', if_true: files('mpc8xxx.c'))
system_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c'))
-system_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
system_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c'))
system_ss.add(when: 'CONFIG_PCA9554', if_true: files('pca9554.c'))
system_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))
-system_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
+system_ss.add(when: 'CONFIG_ZAURUS_SCOOP', if_true: files('zaurus.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c'))
diff --git a/hw/gpio/mpc8xxx.c b/hw/gpio/mpc8xxx.c
index 0b3f9e5..257497a 100644
--- a/hw/gpio/mpc8xxx.c
+++ b/hw/gpio/mpc8xxx.c
@@ -23,7 +23,6 @@
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
-#include "qemu/module.h"
#include "qom/object.h"
#define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio"
@@ -200,25 +199,22 @@ static void mpc8xxx_gpio_initfn(Object *obj)
qdev_init_gpio_out(dev, s->out, 32);
}
-static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
+static void mpc8xxx_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_mpc8xxx_gpio;
- dc->reset = mpc8xxx_gpio_reset;
+ device_class_set_legacy_reset(dc, mpc8xxx_gpio_reset);
}
-static const TypeInfo mpc8xxx_gpio_info = {
- .name = TYPE_MPC8XXX_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MPC8XXXGPIOState),
- .instance_init = mpc8xxx_gpio_initfn,
- .class_init = mpc8xxx_gpio_class_init,
+static const TypeInfo mpc8xxx_gpio_types[] = {
+ {
+ .name = TYPE_MPC8XXX_GPIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MPC8XXXGPIOState),
+ .instance_init = mpc8xxx_gpio_initfn,
+ .class_init = mpc8xxx_gpio_class_init,
+ },
};
-static void mpc8xxx_gpio_register_types(void)
-{
- type_register_static(&mpc8xxx_gpio_info);
-}
-
-type_init(mpc8xxx_gpio_register_types)
+DEFINE_TYPES(mpc8xxx_gpio_types)
diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c
index ba19b9e..66f8256 100644
--- a/hw/gpio/npcm7xx_gpio.c
+++ b/hw/gpio/npcm7xx_gpio.c
@@ -220,8 +220,6 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
return;
}
- diff = s->regs[reg] ^ value;
-
switch (reg) {
case NPCM7XX_GPIO_TLOCK1:
case NPCM7XX_GPIO_TLOCK2:
@@ -242,6 +240,7 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
case NPCM7XX_GPIO_PU:
case NPCM7XX_GPIO_PD:
case NPCM7XX_GPIO_IEM:
+ diff = s->regs[reg] ^ value;
s->regs[reg] = value;
npcm7xx_gpio_update_pins(s, diff);
break;
@@ -386,7 +385,7 @@ static const VMStateDescription vmstate_npcm7xx_gpio = {
},
};
-static Property npcm7xx_gpio_properties[] = {
+static const Property npcm7xx_gpio_properties[] = {
/* Bit n set => pin n has pullup enabled by default. */
DEFINE_PROP_UINT32("reset-pullup", NPCM7xxGPIOState, reset_pu, 0),
/* Bit n set => pin n has pulldown enabled by default. */
@@ -395,10 +394,9 @@ static Property npcm7xx_gpio_properties[] = {
DEFINE_PROP_UINT32("reset-osrc", NPCM7xxGPIOState, reset_osrc, 0),
/* Bit n set => pin n has high drive strength by default. */
DEFINE_PROP_UINT32("reset-odsc", NPCM7xxGPIOState, reset_odsc, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void npcm7xx_gpio_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_gpio_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *reset = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c
index ffc7dff..d94c0c4 100644
--- a/hw/gpio/nrf51_gpio.c
+++ b/hw/gpio/nrf51_gpio.c
@@ -40,7 +40,6 @@ static bool is_connected(uint32_t config, uint32_t level)
break;
default:
g_assert_not_reached();
- break;
}
return state;
@@ -305,12 +304,12 @@ static void nrf51_gpio_init(Object *obj)
qdev_init_gpio_out_named(DEVICE(s), &s->detect, "detect", 1);
}
-static void nrf51_gpio_class_init(ObjectClass *klass, void *data)
+static void nrf51_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_nrf51_gpio;
- dc->reset = nrf51_gpio_reset;
+ device_class_set_legacy_reset(dc, nrf51_gpio_reset);
dc->desc = "nRF51 GPIO";
}
diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c
index a3341d7..f27806b 100644
--- a/hw/gpio/omap_gpio.c
+++ b/hw/gpio/omap_gpio.c
@@ -80,25 +80,25 @@ static uint64_t omap_gpio_read(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* DATA_INPUT */
+ case 0x00: /* DATA_INPUT */
return s->inputs & s->pins;
- case 0x04: /* DATA_OUTPUT */
+ case 0x04: /* DATA_OUTPUT */
return s->outputs;
- case 0x08: /* DIRECTION_CONTROL */
+ case 0x08: /* DIRECTION_CONTROL */
return s->dir;
- case 0x0c: /* INTERRUPT_CONTROL */
+ case 0x0c: /* INTERRUPT_CONTROL */
return s->edge;
- case 0x10: /* INTERRUPT_MASK */
+ case 0x10: /* INTERRUPT_MASK */
return s->mask;
- case 0x14: /* INTERRUPT_STATUS */
+ case 0x14: /* INTERRUPT_STATUS */
return s->ints;
- case 0x18: /* PIN_CONTROL (not in OMAP310) */
+ case 0x18: /* PIN_CONTROL (not in OMAP310) */
OMAP_BAD_REG(addr);
return s->pins;
}
@@ -121,11 +121,11 @@ static void omap_gpio_write(void *opaque, hwaddr addr,
}
switch (offset) {
- case 0x00: /* DATA_INPUT */
+ case 0x00: /* DATA_INPUT */
OMAP_RO_REG(addr);
return;
- case 0x04: /* DATA_OUTPUT */
+ case 0x04: /* DATA_OUTPUT */
diff = (s->outputs ^ value) & ~s->dir;
s->outputs = value;
while ((ln = ctz32(diff)) != 32) {
@@ -135,7 +135,7 @@ static void omap_gpio_write(void *opaque, hwaddr addr,
}
break;
- case 0x08: /* DIRECTION_CONTROL */
+ case 0x08: /* DIRECTION_CONTROL */
diff = s->outputs & (s->dir ^ value);
s->dir = value;
@@ -147,21 +147,21 @@ static void omap_gpio_write(void *opaque, hwaddr addr,
}
break;
- case 0x0c: /* INTERRUPT_CONTROL */
+ case 0x0c: /* INTERRUPT_CONTROL */
s->edge = value;
break;
- case 0x10: /* INTERRUPT_MASK */
+ case 0x10: /* INTERRUPT_MASK */
s->mask = value;
break;
- case 0x14: /* INTERRUPT_STATUS */
+ case 0x14: /* INTERRUPT_STATUS */
s->ints &= ~value;
if (!s->ints)
qemu_irq_lower(s->irq);
break;
- case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */
+ case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */
OMAP_BAD_REG(addr);
s->pins = value;
break;
@@ -190,408 +190,6 @@ static void omap_gpio_reset(struct omap_gpio_s *s)
s->pins = ~0;
}
-struct omap2_gpio_s {
- qemu_irq irq[2];
- qemu_irq wkup;
- qemu_irq *handler;
- MemoryRegion iomem;
-
- uint8_t revision;
- uint8_t config[2];
- uint32_t inputs;
- uint32_t outputs;
- uint32_t dir;
- uint32_t level[2];
- uint32_t edge[2];
- uint32_t mask[2];
- uint32_t wumask;
- uint32_t ints[2];
- uint32_t debounce;
- uint8_t delay;
-};
-
-struct Omap2GpioState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- int mpu_model;
- void *iclk;
- void *fclk[6];
- int modulecount;
- struct omap2_gpio_s *modules;
- qemu_irq *handler;
- int autoidle;
- int gpo;
-};
-
-/* General-Purpose Interface of OMAP2/3 */
-static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
- int line)
-{
- qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
-}
-
-static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)
-{
- if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */
- return;
- if (!(s->config[0] & (3 << 3))) /* Force Idle */
- return;
- if (!(s->wumask & (1 << line)))
- return;
-
- qemu_irq_raise(s->wkup);
-}
-
-static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
- uint32_t diff)
-{
- int ln;
-
- s->outputs ^= diff;
- diff &= ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
- diff &= ~(1 << ln);
- }
-}
-
-static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)
-{
- s->ints[line] |= s->dir &
- ((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
- omap2_gpio_module_int_update(s, line);
-}
-
-static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
-{
- s->ints[0] |= 1 << line;
- omap2_gpio_module_int_update(s, 0);
- s->ints[1] |= 1 << line;
- omap2_gpio_module_int_update(s, 1);
- omap2_gpio_module_wake(s, line);
-}
-
-static void omap2_gpio_set(void *opaque, int line, int level)
-{
- Omap2GpioState *p = opaque;
- struct omap2_gpio_s *s = &p->modules[line >> 5];
-
- line &= 31;
- if (level) {
- if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
- omap2_gpio_module_int(s, line);
- s->inputs |= 1 << line;
- } else {
- if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
- omap2_gpio_module_int(s, line);
- s->inputs &= ~(1 << line);
- }
-}
-
-static void omap2_gpio_module_reset(struct omap2_gpio_s *s)
-{
- s->config[0] = 0;
- s->config[1] = 2;
- s->ints[0] = 0;
- s->ints[1] = 0;
- s->mask[0] = 0;
- s->mask[1] = 0;
- s->wumask = 0;
- s->dir = ~0;
- s->level[0] = 0;
- s->level[1] = 0;
- s->edge[0] = 0;
- s->edge[1] = 0;
- s->debounce = 0;
- s->delay = 0;
-}
-
-static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr)
-{
- struct omap2_gpio_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* GPIO_REVISION */
- return s->revision;
-
- case 0x10: /* GPIO_SYSCONFIG */
- return s->config[0];
-
- case 0x14: /* GPIO_SYSSTATUS */
- return 0x01;
-
- case 0x18: /* GPIO_IRQSTATUS1 */
- return s->ints[0];
-
- case 0x1c: /* GPIO_IRQENABLE1 */
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- case 0x64: /* GPIO_SETIRQENABLE1 */
- return s->mask[0];
-
- case 0x20: /* GPIO_WAKEUPENABLE */
- case 0x80: /* GPIO_CLEARWKUENA */
- case 0x84: /* GPIO_SETWKUENA */
- return s->wumask;
-
- case 0x28: /* GPIO_IRQSTATUS2 */
- return s->ints[1];
-
- case 0x2c: /* GPIO_IRQENABLE2 */
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- return s->mask[1];
-
- case 0x30: /* GPIO_CTRL */
- return s->config[1];
-
- case 0x34: /* GPIO_OE */
- return s->dir;
-
- case 0x38: /* GPIO_DATAIN */
- return s->inputs;
-
- case 0x3c: /* GPIO_DATAOUT */
- case 0x90: /* GPIO_CLEARDATAOUT */
- case 0x94: /* GPIO_SETDATAOUT */
- return s->outputs;
-
- case 0x40: /* GPIO_LEVELDETECT0 */
- return s->level[0];
-
- case 0x44: /* GPIO_LEVELDETECT1 */
- return s->level[1];
-
- case 0x48: /* GPIO_RISINGDETECT */
- return s->edge[0];
-
- case 0x4c: /* GPIO_FALLINGDETECT */
- return s->edge[1];
-
- case 0x50: /* GPIO_DEBOUNCENABLE */
- return s->debounce;
-
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- return s->delay;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_gpio_module_write(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap2_gpio_s *s = opaque;
- uint32_t diff;
- int ln;
-
- switch (addr) {
- case 0x00: /* GPIO_REVISION */
- case 0x14: /* GPIO_SYSSTATUS */
- case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* GPIO_SYSCONFIG */
- if (((value >> 3) & 3) == 3) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Illegal IDLEMODE value: 3\n", __func__);
- }
- if (value & 2)
- omap2_gpio_module_reset(s);
- s->config[0] = value & 0x1d;
- break;
-
- case 0x18: /* GPIO_IRQSTATUS1 */
- if (s->ints[0] & value) {
- s->ints[0] &= ~value;
- omap2_gpio_module_level_update(s, 0);
- }
- break;
-
- case 0x1c: /* GPIO_IRQENABLE1 */
- s->mask[0] = value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x20: /* GPIO_WAKEUPENABLE */
- s->wumask = value;
- break;
-
- case 0x28: /* GPIO_IRQSTATUS2 */
- if (s->ints[1] & value) {
- s->ints[1] &= ~value;
- omap2_gpio_module_level_update(s, 1);
- }
- break;
-
- case 0x2c: /* GPIO_IRQENABLE2 */
- s->mask[1] = value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x30: /* GPIO_CTRL */
- s->config[1] = value & 7;
- break;
-
- case 0x34: /* GPIO_OE */
- diff = s->outputs & (s->dir ^ value);
- s->dir = value;
-
- value = s->outputs & ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- diff &= ~(1 << ln);
- qemu_set_irq(s->handler[ln], (value >> ln) & 1);
- }
-
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x3c: /* GPIO_DATAOUT */
- omap2_gpio_module_out_update(s, s->outputs ^ value);
- break;
-
- case 0x40: /* GPIO_LEVELDETECT0 */
- s->level[0] = value;
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x44: /* GPIO_LEVELDETECT1 */
- s->level[1] = value;
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x48: /* GPIO_RISINGDETECT */
- s->edge[0] = value;
- break;
-
- case 0x4c: /* GPIO_FALLINGDETECT */
- s->edge[1] = value;
- break;
-
- case 0x50: /* GPIO_DEBOUNCENABLE */
- s->debounce = value;
- break;
-
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- s->delay = value;
- break;
-
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- s->mask[0] &= ~value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x64: /* GPIO_SETIRQENABLE1 */
- s->mask[0] |= value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- s->mask[1] &= ~value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- s->mask[1] |= value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x80: /* GPIO_CLEARWKUENA */
- s->wumask &= ~value;
- break;
-
- case 0x84: /* GPIO_SETWKUENA */
- s->wumask |= value;
- break;
-
- case 0x90: /* GPIO_CLEARDATAOUT */
- omap2_gpio_module_out_update(s, s->outputs & value);
- break;
-
- case 0x94: /* GPIO_SETDATAOUT */
- omap2_gpio_module_out_update(s, ~s->outputs & value);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static uint64_t omap2_gpio_module_readp(void *opaque, hwaddr addr,
- unsigned size)
-{
- return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
-}
-
-static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- uint32_t cur = 0;
- uint32_t mask = 0xffff;
-
- if (size == 4) {
- omap2_gpio_module_write(opaque, addr, value);
- return;
- }
-
- switch (addr & ~3) {
- case 0x00: /* GPIO_REVISION */
- case 0x14: /* GPIO_SYSSTATUS */
- case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* GPIO_SYSCONFIG */
- case 0x1c: /* GPIO_IRQENABLE1 */
- case 0x20: /* GPIO_WAKEUPENABLE */
- case 0x2c: /* GPIO_IRQENABLE2 */
- case 0x30: /* GPIO_CTRL */
- case 0x34: /* GPIO_OE */
- case 0x3c: /* GPIO_DATAOUT */
- case 0x40: /* GPIO_LEVELDETECT0 */
- case 0x44: /* GPIO_LEVELDETECT1 */
- case 0x48: /* GPIO_RISINGDETECT */
- case 0x4c: /* GPIO_FALLINGDETECT */
- case 0x50: /* GPIO_DEBOUNCENABLE */
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- cur = omap2_gpio_module_read(opaque, addr & ~3) &
- ~(mask << ((addr & 3) << 3));
-
- /* Fall through. */
- case 0x18: /* GPIO_IRQSTATUS1 */
- case 0x28: /* GPIO_IRQSTATUS2 */
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- case 0x64: /* GPIO_SETIRQENABLE1 */
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- case 0x80: /* GPIO_CLEARWKUENA */
- case 0x84: /* GPIO_SETWKUENA */
- case 0x90: /* GPIO_CLEARDATAOUT */
- case 0x94: /* GPIO_SETDATAOUT */
- value <<= (addr & 3) << 3;
- omap2_gpio_module_write(opaque, addr, cur | value);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap2_gpio_module_ops = {
- .read = omap2_gpio_module_readp,
- .write = omap2_gpio_module_writep,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
static void omap_gpif_reset(DeviceState *dev)
{
Omap1GpioState *s = OMAP1_GPIO(dev);
@@ -599,81 +197,6 @@ static void omap_gpif_reset(DeviceState *dev)
omap_gpio_reset(&s->omap1);
}
-static void omap2_gpif_reset(DeviceState *dev)
-{
- Omap2GpioState *s = OMAP2_GPIO(dev);
- int i;
-
- for (i = 0; i < s->modulecount; i++) {
- omap2_gpio_module_reset(&s->modules[i]);
- }
- s->autoidle = 0;
- s->gpo = 0;
-}
-
-static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, unsigned size)
-{
- Omap2GpioState *s = opaque;
-
- switch (addr) {
- case 0x00: /* IPGENERICOCPSPL_REVISION */
- return 0x18;
-
- case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
- return s->autoidle;
-
- case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
- return 0x01;
-
- case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
- return 0x00;
-
- case 0x40: /* IPGENERICOCPSPL_GPO */
- return s->gpo;
-
- case 0x50: /* IPGENERICOCPSPL_GPI */
- return 0x00;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_gpif_top_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- Omap2GpioState *s = opaque;
-
- switch (addr) {
- case 0x00: /* IPGENERICOCPSPL_REVISION */
- case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
- case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
- case 0x50: /* IPGENERICOCPSPL_GPI */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap2_gpif_reset(DEVICE(s));
- s->autoidle = value & 1;
- break;
-
- case 0x40: /* IPGENERICOCPSPL_GPO */
- s->gpo = value & 1;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap2_gpif_top_ops = {
- .read = omap2_gpif_top_read,
- .write = omap2_gpif_top_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
static void omap_gpio_init(Object *obj)
{
DeviceState *dev = DEVICE(obj);
@@ -697,67 +220,21 @@ static void omap_gpio_realize(DeviceState *dev, Error **errp)
}
}
-static void omap2_gpio_realize(DeviceState *dev, Error **errp)
-{
- Omap2GpioState *s = OMAP2_GPIO(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i;
-
- if (!s->iclk) {
- error_setg(errp, "omap2-gpio: iclk not connected");
- return;
- }
-
- s->modulecount = s->mpu_model < omap2430 ? 4
- : s->mpu_model < omap3430 ? 5
- : 6;
-
- if (s->mpu_model < omap3430) {
- memory_region_init_io(&s->iomem, OBJECT(dev), &omap2_gpif_top_ops, s,
- "omap2.gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- }
-
- s->modules = g_new0(struct omap2_gpio_s, s->modulecount);
- s->handler = g_new0(qemu_irq, s->modulecount * 32);
- qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32);
- qdev_init_gpio_out(dev, s->handler, s->modulecount * 32);
-
- for (i = 0; i < s->modulecount; i++) {
- struct omap2_gpio_s *m = &s->modules[i];
-
- if (!s->fclk[i]) {
- error_setg(errp, "omap2-gpio: fclk%d not connected", i);
- return;
- }
-
- m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
- m->handler = &s->handler[i * 32];
- sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */
- sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */
- sysbus_init_irq(sbd, &m->wkup);
- memory_region_init_io(&m->iomem, OBJECT(dev), &omap2_gpio_module_ops, m,
- "omap.gpio-module", 0x1000);
- sysbus_init_mmio(sbd, &m->iomem);
- }
-}
-
void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk)
{
gpio->clk = clk;
}
-static Property omap_gpio_properties[] = {
+static const Property omap_gpio_properties[] = {
DEFINE_PROP_INT32("mpu_model", Omap1GpioState, mpu_model, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void omap_gpio_class_init(ObjectClass *klass, void *data)
+static void omap_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = omap_gpio_realize;
- dc->reset = omap_gpif_reset;
+ device_class_set_legacy_reset(dc, omap_gpif_reset);
device_class_set_props(dc, omap_gpio_properties);
/* Reason: pointer property "clk" */
dc->user_creatable = false;
@@ -771,44 +248,9 @@ static const TypeInfo omap_gpio_info = {
.class_init = omap_gpio_class_init,
};
-void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk)
-{
- gpio->iclk = clk;
-}
-
-void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk)
-{
- assert(i <= 5);
- gpio->fclk[i] = clk;
-}
-
-static Property omap2_gpio_properties[] = {
- DEFINE_PROP_INT32("mpu_model", Omap2GpioState, mpu_model, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = omap2_gpio_realize;
- dc->reset = omap2_gpif_reset;
- device_class_set_props(dc, omap2_gpio_properties);
- /* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */
- dc->user_creatable = false;
-}
-
-static const TypeInfo omap2_gpio_info = {
- .name = TYPE_OMAP2_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Omap2GpioState),
- .class_init = omap2_gpio_class_init,
-};
-
static void omap_gpio_register_types(void)
{
type_register_static(&omap_gpio_info);
- type_register_static(&omap2_gpio_info);
}
type_init(omap_gpio_register_types)
diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c
index 27d4db0..1e10238 100644
--- a/hw/gpio/pca9552.c
+++ b/hw/gpio/pca9552.c
@@ -76,7 +76,7 @@ static void pca955x_display_pins_status(PCA955xState *s,
return;
}
if (trace_event_get_state_backends(TRACE_PCA955X_GPIO_STATUS)) {
- char *buf = g_newa(char, k->pin_count + 1);
+ char buf[PCA955X_PIN_COUNT_MAX + 1];
for (i = 0; i < k->pin_count; i++) {
if (extract32(pins_status, i, 1)) {
@@ -428,12 +428,11 @@ static void pca955x_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(dev, pca955x_gpio_in_handler, k->pin_count);
}
-static Property pca955x_properties[] = {
+static const Property pca955x_properties[] = {
DEFINE_PROP_STRING("description", PCA955xState, description),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pca955x_class_init(ObjectClass *klass, void *data)
+static void pca955x_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -455,12 +454,12 @@ static const TypeInfo pca955x_info = {
.abstract = true,
};
-static void pca9552_class_init(ObjectClass *oc, void *data)
+static void pca9552_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCA955xClass *pc = PCA955X_CLASS(oc);
- dc->reset = pca9552_reset;
+ device_class_set_legacy_reset(dc, pca9552_reset);
dc->vmsd = &pca9552_vmstate;
pc->max_reg = PCA9552_LS3;
pc->pin_count = 16;
diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c
index 7d10a64..de3f883 100644
--- a/hw/gpio/pca9554.c
+++ b/hw/gpio/pca9554.c
@@ -118,11 +118,8 @@ static void pca9554_write(PCA9554State *s, uint8_t reg, uint8_t data)
static uint8_t pca9554_recv(I2CSlave *i2c)
{
PCA9554State *s = PCA9554(i2c);
- uint8_t ret;
- ret = pca9554_read(s, s->pointer & 0x3);
-
- return ret;
+ return pca9554_read(s, s->pointer & 0x3);
}
static int pca9554_send(I2CSlave *i2c, uint8_t data)
@@ -291,12 +288,11 @@ static void pca9554_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(dev, pca9554_gpio_in_handler, PCA9554_PIN_COUNT);
}
-static Property pca9554_properties[] = {
+static const Property pca9554_properties[] = {
DEFINE_PROP_STRING("description", PCA9554State, description),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pca9554_class_init(ObjectClass *klass, void *data)
+static void pca9554_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -305,7 +301,7 @@ static void pca9554_class_init(ObjectClass *klass, void *data)
k->recv = pca9554_recv;
k->send = pca9554_send;
dc->realize = pca9554_realize;
- dc->reset = pca9554_reset;
+ device_class_set_legacy_reset(dc, pca9554_reset);
dc->vmsd = &pca9554_vmstate;
device_class_set_props(dc, pca9554_properties);
}
diff --git a/hw/gpio/pcf8574.c b/hw/gpio/pcf8574.c
index d37909e..274b44b 100644
--- a/hw/gpio/pcf8574.c
+++ b/hw/gpio/pcf8574.c
@@ -138,7 +138,7 @@ static void pcf8574_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out_named(dev, &s->intrq, "nINT", 1);
}
-static void pcf8574_class_init(ObjectClass *klass, void *data)
+static void pcf8574_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -146,7 +146,7 @@ static void pcf8574_class_init(ObjectClass *klass, void *data)
k->recv = pcf8574_rx;
k->send = pcf8574_tx;
dc->realize = pcf8574_realize;
- dc->reset = pcf8574_reset;
+ device_class_set_legacy_reset(dc, pcf8574_reset);
dc->vmsd = &vmstate_pcf8574;
}
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index d5838b8..1acca3f 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -443,7 +443,6 @@ static void pl061_write(void *opaque, hwaddr offset,
return;
}
pl061_update(s);
- return;
}
static void pl061_enter_reset(Object *obj, ResetType type)
@@ -562,13 +561,12 @@ static void pl061_realize(DeviceState *dev, Error **errp)
}
}
-static Property pl061_props[] = {
+static const Property pl061_props[] = {
DEFINE_PROP_UINT32("pullups", PL061State, pullups, 0xff),
DEFINE_PROP_UINT32("pulldowns", PL061State, pulldowns, 0x0),
- DEFINE_PROP_END_OF_LIST()
};
-static void pl061_class_init(ObjectClass *klass, void *data)
+static void pl061_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/gpio/sifive_gpio.c b/hw/gpio/sifive_gpio.c
index 995a43c..5831647 100644
--- a/hw/gpio/sifive_gpio.c
+++ b/hw/gpio/sifive_gpio.c
@@ -349,9 +349,8 @@ static const VMStateDescription vmstate_sifive_gpio = {
}
};
-static Property sifive_gpio_properties[] = {
+static const Property sifive_gpio_properties[] = {
DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS),
- DEFINE_PROP_END_OF_LIST(),
};
static void sifive_gpio_realize(DeviceState *dev, Error **errp)
@@ -371,14 +370,14 @@ static void sifive_gpio_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio);
}
-static void sifive_gpio_class_init(ObjectClass *klass, void *data)
+static void sifive_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, sifive_gpio_properties);
dc->vmsd = &vmstate_sifive_gpio;
dc->realize = sifive_gpio_realize;
- dc->reset = sifive_gpio_reset;
+ device_class_set_legacy_reset(dc, sifive_gpio_reset);
dc->desc = "SiFive GPIO";
}
diff --git a/hw/gpio/stm32l4x5_gpio.c b/hw/gpio/stm32l4x5_gpio.c
index 30d8d6c..414ce83 100644
--- a/hw/gpio/stm32l4x5_gpio.c
+++ b/hw/gpio/stm32l4x5_gpio.c
@@ -447,15 +447,14 @@ static const VMStateDescription vmstate_stm32l4x5_gpio = {
}
};
-static Property stm32l4x5_gpio_properties[] = {
+static const Property stm32l4x5_gpio_properties[] = {
DEFINE_PROP_STRING("name", Stm32l4x5GpioState, name),
DEFINE_PROP_UINT32("mode-reset", Stm32l4x5GpioState, moder_reset, 0),
DEFINE_PROP_UINT32("ospeed-reset", Stm32l4x5GpioState, ospeedr_reset, 0),
DEFINE_PROP_UINT32("pupd-reset", Stm32l4x5GpioState, pupdr_reset, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void stm32l4x5_gpio_class_init(ObjectClass *klass, void *data)
+static void stm32l4x5_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
index b91cc7e..cea896b 100644
--- a/hw/gpio/trace-events
+++ b/hw/gpio/trace-events
@@ -1,5 +1,10 @@
# See docs/devel/tracing.rst for syntax documentation.
+# imx_gpio.c
+imx_gpio_read(const char *id, const char *reg, uint32_t value) "%s:[%s] -> 0x%" PRIx32
+imx_gpio_write(const char *id, const char *reg, uint32_t value) "%s:[%s] <- 0x%" PRIx32
+imx_gpio_set(const char *id, int line, int level) "%s:[%d] <- %d"
+
# npcm7xx_gpio.c
npcm7xx_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
npcm7xx_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c
index 7342440..b8d27f5 100644
--- a/hw/gpio/zaurus.c
+++ b/hw/gpio/zaurus.c
@@ -243,7 +243,7 @@ static const VMStateDescription vmstate_scoop_regs = {
},
};
-static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
+static void scoop_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig
index d4d457f..cab2104 100644
--- a/hw/hppa/Kconfig
+++ b/hw/hppa/Kconfig
@@ -9,8 +9,9 @@ config HPPA_B160L
select ASTRO
select DINO
select LASI
- select SERIAL
+ select SERIAL_MM
select SERIAL_PCI
+ select DIVA_GSP
select ISA_BUS
select I8259
select IDE_CMD646
diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h
index a9be7bb..21c777c 100644
--- a/hw/hppa/hppa_hardware.h
+++ b/hw/hppa/hppa_hardware.h
@@ -6,6 +6,11 @@
#define FIRMWARE_START 0xf0000000
#define FIRMWARE_END 0xf0800000
+#define FIRMWARE_HIGH 0xfffffff0 /* upper 32-bits of 64-bit firmware address */
+
+#define RAM_MAP_HIGH 0x0100000000 /* memory above 3.75 GB is mapped here */
+
+#define MEM_PDC_ENTRY 0x4800 /* PDC entry address */
#define DEVICE_HPA_LEN 0x00100000
@@ -18,6 +23,7 @@
#define LASI_UART_HPA 0xffd05000
#define LASI_SCSI_HPA 0xffd06000
#define LASI_LAN_HPA 0xffd07000
+#define LASI_RTC_HPA 0xffd09000
#define LASI_LPT_HPA 0xffd02000
#define LASI_AUDIO_HPA 0xffd04000
#define LASI_PS2KBD_HPA 0xffd08000
@@ -27,16 +33,23 @@
#define CPU_HPA 0xfffb0000
#define MEMORY_HPA 0xfffff000
-#define PCI_HPA DINO_HPA /* PCI bus */
#define IDE_HPA 0xf9000000 /* Boot disc controller */
+#define ASTRO_HPA 0xfed00000
+#define ELROY0_HPA 0xfed30000
+#define ELROY2_HPA 0xfed32000
+#define ELROY8_HPA 0xfed38000
+#define ELROYc_HPA 0xfed3c000
+#define ASTRO_MEMORY_HPA 0xfed10200
+
+#define SCSI_HPA 0xf1040000 /* emulated SCSI, needs to be in f region */
/* offsets to DINO HPA: */
#define DINO_PCI_ADDR 0x064
#define DINO_CONFIG_DATA 0x068
#define DINO_IO_DATA 0x06c
-#define PORT_PCI_CMD (PCI_HPA + DINO_PCI_ADDR)
-#define PORT_PCI_DATA (PCI_HPA + DINO_CONFIG_DATA)
+#define PORT_PCI_CMD hppa_port_pci_cmd
+#define PORT_PCI_DATA hppa_port_pci_data
#define FW_CFG_IO_BASE 0xfffa0000
@@ -46,7 +59,24 @@
#define HPPA_MAX_CPUS 16 /* max. number of SMP CPUs */
#define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */
+#define CR_PSW_DEFAULT 6 /* used by SeaBIOS & QEMU for default PSW */
#define CPU_HPA_CR_REG 7 /* store CPU HPA in cr7 (SeaBIOS internal) */
#define PIM_STORAGE_SIZE 600 /* storage size of pdc_pim_toc_struct (64bit) */
+#define ASTRO_BUS_MODULE 0x0a /* C3700: 0x0a, others maybe 0 ? */
+
+/* ASTRO Memory and I/O regions */
+#define ASTRO_BASE_HPA 0xfffed00000
+#define ELROY0_BASE_HPA 0xfffed30000 /* ELROY0_HPA */
+
+#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
+
+#define LMMIO_DIRECT0_BASE 0x300
+#define LMMIO_DIRECT0_MASK 0x308
+#define LMMIO_DIRECT0_ROUTE 0x310
+
+/* space register hashing */
+#define HPPA64_DIAG_SPHASH_ENABLE 0x200 /* DIAG_SPHASH_ENAB (bit 54) */
+#define HPPA64_PDC_CACHE_RET_SPID_VAL 0xfe0 /* PDC return value on 64-bit CPU */
+
#endif
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 5d0a873..dacedc5 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -11,13 +11,14 @@
#include "elf.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/runstate.h"
+#include "exec/target_page.h"
+#include "system/reset.h"
+#include "system/system.h"
+#include "system/qtest.h"
+#include "system/runstate.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/timer/i8254.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/char/parallel.h"
#include "hw/intc/i8259.h"
#include "hw/input/lasips2.h"
@@ -240,7 +241,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus,
g_memdup2(qemu_version, sizeof(qemu_version)),
sizeof(qemu_version));
- fw_cfg_add_extra_pci_roots(pci_bus, fw_cfg);
+ pci_bus_add_fw_cfg_extra_pci_roots(fw_cfg, pci_bus, &error_abort);
return fw_cfg;
}
@@ -283,16 +284,13 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type));
}
- /*
- * For now, treat address layout as if PSW_W is clear.
- * TODO: create a proper hppa64 board model and load elf64 firmware.
- */
+ /* Initialize memory */
if (hppa_is_pa20(&cpu[0]->env)) {
translate = translate_pa20;
- ram_max = 0xf0000000; /* 3.75 GB (limited by 32-bit firmware) */
+ ram_max = 256 * GiB; /* like HP rp8440 */
} else {
translate = translate_pa10;
- ram_max = 0xf0000000; /* 3.75 GB (32-bit CPU) */
+ ram_max = FIRMWARE_START; /* 3.75 GB (32-bit CPU) */
}
soft_power_reg = translate(NULL, HPA_POWER_BUTTON);
@@ -320,7 +318,22 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
info_report("Max RAM size limited to %" PRIu64 " MB", ram_max / MiB);
machine->ram_size = ram_max;
}
- memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
+ if (machine->ram_size <= FIRMWARE_START) {
+ /* contiguous memory up to 3.75 GB RAM */
+ memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
+ } else {
+ /* non-contiguous: Memory above 3.75 GB is mapped at RAM_MAP_HIGH */
+ MemoryRegion *mem_region;
+ mem_region = g_new(MemoryRegion, 2);
+ memory_region_init_alias(&mem_region[0], &addr_space->parent_obj,
+ "LowMem", machine->ram, 0, FIRMWARE_START);
+ memory_region_init_alias(&mem_region[1], &addr_space->parent_obj,
+ "HighMem", machine->ram, FIRMWARE_START,
+ machine->ram_size - FIRMWARE_START);
+ memory_region_add_subregion_overlap(addr_space, 0, &mem_region[0], -1);
+ memory_region_add_subregion_overlap(addr_space, RAM_MAP_HIGH,
+ &mem_region[1], -1);
+ }
return translate;
}
@@ -344,7 +357,6 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
uint64_t kernel_entry = 0, kernel_low, kernel_high;
MemoryRegion *addr_space = get_system_memory();
MemoryRegion *rom_region;
- unsigned int smp_cpus = machine->smp.cpus;
SysBusDevice *s;
/* SCSI disk setup. */
@@ -355,12 +367,15 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
/* Graphics setup. */
if (machine->enable_graphics && vga_interface_type != VGA_NONE) {
- vga_interface_created = true;
dev = qdev_new("artist");
s = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA));
- sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR));
+ bool disabled = object_property_get_bool(OBJECT(dev), "disable", NULL);
+ if (!disabled) {
+ sysbus_realize_and_unref(s, &error_fatal);
+ vga_interface_created = true;
+ sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA));
+ sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR));
+ }
}
/* Network setup. */
@@ -372,26 +387,17 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
pci_init_nic_devices(pci_bus, mc->default_nic);
- /* BMC board: HP Powerbar SP2 Diva (with console only) */
- pci_dev = pci_new(-1, "pci-serial");
- if (!lasi_dev) {
- /* bind default keyboard/serial to Diva card */
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev", serial_hd(0));
- }
- qdev_prop_set_uint8(DEVICE(pci_dev), "prog_if", 0);
- pci_realize_and_unref(pci_dev, pci_bus, &error_fatal);
- pci_config_set_vendor_id(pci_dev->config, PCI_VENDOR_ID_HP);
- pci_config_set_device_id(pci_dev->config, 0x1048);
- pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_VENDOR_ID], PCI_VENDOR_ID_HP);
- pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_ID], 0x1227); /* Powerbar */
-
- /* create a second serial PCI card when running Astro */
- if (serial_hd(1) && !lasi_dev) {
- pci_dev = pci_new(-1, "pci-serial-4x");
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(1));
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(2));
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev3", serial_hd(3));
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev4", serial_hd(4));
+ /* BMC board: HP Diva GSP */
+ dev = qdev_new("diva-gsp");
+ if (!object_property_get_bool(OBJECT(dev), "disable", NULL)) {
+ pci_dev = pci_new_multifunction(PCI_DEVFN(2, 0), "diva-gsp");
+ if (!lasi_dev) {
+ /* bind default keyboard/serial to Diva card */
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(0));
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(1));
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev3", serial_hd(2));
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev4", serial_hd(3));
+ }
pci_realize_and_unref(pci_dev, pci_bus, &error_fatal);
}
@@ -429,7 +435,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
size = load_elf(firmware_filename, NULL, translate, NULL,
&firmware_entry, &firmware_low, &firmware_high, NULL,
- true, EM_PARISC, 0, 0);
+ ELFDATA2MSB, EM_PARISC, 0, 0);
if (size < 0) {
error_report("could not load firmware '%s'", firmware_filename);
@@ -456,7 +462,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
if (kernel_filename) {
size = load_elf(kernel_filename, NULL, linux_kernel_virt_to_phys,
NULL, &kernel_entry, &kernel_low, &kernel_high, NULL,
- true, EM_PARISC, 0, 0);
+ ELFDATA2MSB, EM_PARISC, 0, 0);
kernel_entry = linux_kernel_virt_to_phys(NULL, kernel_entry);
@@ -470,8 +476,8 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
kernel_low, kernel_high, kernel_entry, size / KiB);
if (kernel_cmdline) {
- cpu[0]->env.gr[24] = 0x4000;
- pstrcpy_targphys("cmdline", cpu[0]->env.gr[24],
+ cpu[0]->env.cmdline_or_bootorder = 0x4000;
+ pstrcpy_targphys("cmdline", cpu[0]->env.cmdline_or_bootorder,
TARGET_PAGE_SIZE, kernel_cmdline);
}
@@ -501,32 +507,22 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
}
load_image_targphys(initrd_filename, initrd_base, initrd_size);
- cpu[0]->env.gr[23] = initrd_base;
- cpu[0]->env.gr[22] = initrd_base + initrd_size;
+ cpu[0]->env.initrd_base = initrd_base;
+ cpu[0]->env.initrd_end = initrd_base + initrd_size;
}
}
if (!kernel_entry) {
/* When booting via firmware, tell firmware if we want interactive
- * mode (kernel_entry=1), and to boot from CD (gr[24]='d')
- * or hard disc * (gr[24]='c').
+ * mode (kernel_entry=1), and to boot from CD (cmdline_or_bootorder='d')
+ * or hard disc (cmdline_or_bootorder='c').
*/
kernel_entry = machine->boot_config.has_menu ? machine->boot_config.menu : 0;
- cpu[0]->env.gr[24] = machine->boot_config.order[0];
+ cpu[0]->env.cmdline_or_bootorder = machine->boot_config.order[0];
}
- /* We jump to the firmware entry routine and pass the
- * various parameters in registers. After firmware initialization,
- * firmware will start the Linux kernel with ramdisk and cmdline.
- */
- cpu[0]->env.gr[26] = machine->ram_size;
- cpu[0]->env.gr[25] = kernel_entry;
-
- /* tell firmware how many SMP CPUs to present in inventory table */
- cpu[0]->env.gr[21] = smp_cpus;
-
- /* tell firmware fw_cfg port */
- cpu[0]->env.gr[19] = FW_CFG_IO_BASE;
+ /* Keep initial kernel_entry for first boot */
+ cpu[0]->env.kernel_entry = kernel_entry;
}
/*
@@ -642,12 +638,12 @@ static void machine_HP_C3700_init(MachineState *machine)
machine_HP_common_init_tail(machine, pci_bus, translate);
}
-static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
+static void hppa_machine_reset(MachineState *ms, ResetType type)
{
unsigned int smp_cpus = ms->smp.cpus;
int i;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/* Start all CPUs at the firmware entry point.
* Monarch CPU will initialize firmware, secondary CPUs
@@ -655,26 +651,27 @@ static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
for (i = 0; i < smp_cpus; i++) {
CPUState *cs = CPU(cpu[i]);
+ /* reset CPU */
+ resettable_reset(OBJECT(cs), RESET_TYPE_COLD);
+
cpu_set_pc(cs, firmware_entry);
cpu[i]->env.psw = PSW_Q;
cpu[i]->env.gr[5] = CPU_HPA + i * 0x1000;
-
- cs->exception_index = -1;
- cs->halted = 0;
- }
-
- /* already initialized by machine_hppa_init()? */
- if (cpu[0]->env.gr[26] == ms->ram_size) {
- return;
}
cpu[0]->env.gr[26] = ms->ram_size;
- cpu[0]->env.gr[25] = 0; /* no firmware boot menu */
- cpu[0]->env.gr[24] = 'c';
- /* gr22/gr23 unused, no initrd while reboot. */
+ cpu[0]->env.gr[25] = cpu[0]->env.kernel_entry;
+ cpu[0]->env.gr[24] = cpu[0]->env.cmdline_or_bootorder;
+ cpu[0]->env.gr[23] = cpu[0]->env.initrd_base;
+ cpu[0]->env.gr[22] = cpu[0]->env.initrd_end;
cpu[0]->env.gr[21] = smp_cpus;
- /* tell firmware fw_cfg port */
cpu[0]->env.gr[19] = FW_CFG_IO_BASE;
+
+ /* reset static fields to avoid starting Linux kernel & initrd on reboot */
+ cpu[0]->env.kernel_entry = 0;
+ cpu[0]->env.initrd_base = 0;
+ cpu[0]->env.initrd_end = 0;
+ cpu[0]->env.cmdline_or_bootorder = 'c';
}
static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
@@ -686,7 +683,7 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
}
}
-static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
+static void HP_B160L_machine_init_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
TYPE_HPPA_CPU,
@@ -716,13 +713,13 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = {
.name = MACHINE_TYPE_NAME("B160L"),
.parent = TYPE_MACHINE,
.class_init = HP_B160L_machine_init_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NMI },
{ }
},
};
-static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data)
+static void HP_C3700_machine_init_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
TYPE_HPPA64_CPU,
@@ -752,7 +749,7 @@ static const TypeInfo HP_C3700_machine_init_typeinfo = {
.name = MACHINE_TYPE_NAME("C3700"),
.parent = TYPE_MACHINE,
.class_init = HP_C3700_machine_init_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NMI },
{ }
},
diff --git a/hw/hyperv/hv-balloon-our_range_memslots.h b/hw/hyperv/hv-balloon-our_range_memslots.h
index df3b686..b1f19d7 100644
--- a/hw/hyperv/hv-balloon-our_range_memslots.h
+++ b/hw/hyperv/hv-balloon-our_range_memslots.h
@@ -11,7 +11,7 @@
#define HW_HYPERV_HV_BALLOON_OUR_RANGE_MEMSLOTS_H
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qom/object.h"
#include "hv-balloon-page_range_tree.h"
diff --git a/hw/hyperv/hv-balloon.c b/hw/hyperv/hv-balloon.c
index 3a9ef07..6dbcb2d 100644
--- a/hw/hyperv/hv-balloon.c
+++ b/hw/hyperv/hv-balloon.c
@@ -10,9 +10,9 @@
#include "qemu/osdep.h"
#include "hv-balloon-internal.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "exec/cpu-common.h"
-#include "exec/ramblock.h"
+#include "system/ramblock.h"
#include "hw/boards.h"
#include "hw/hyperv/dynmem-proto.h"
#include "hw/hyperv/hv-balloon.h"
@@ -26,15 +26,15 @@
#include "qapi/qapi-commands-machine.h"
#include "qapi/qapi-events-machine.h"
#include "qapi/qapi-types-machine.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/units.h"
#include "qemu/timer.h"
-#include "sysemu/balloon.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/reset.h"
+#include "system/balloon.h"
+#include "system/hostmem.h"
+#include "system/reset.h"
#include "hv-balloon-our_range_memslots.h"
#include "hv-balloon-page_range_tree.h"
#include "trace.h"
@@ -67,10 +67,6 @@
* these requests
*/
-struct HvBalloonClass {
- VMBusDeviceClass parent_class;
-} HvBalloonClass;
-
typedef enum State {
/* not a real state */
S_NO_CHANGE = 0,
@@ -162,8 +158,9 @@ typedef struct HvBalloon {
MemoryRegion *mr;
} HvBalloon;
-OBJECT_DEFINE_TYPE_WITH_INTERFACES(HvBalloon, hv_balloon, HV_BALLOON, VMBUS_DEVICE, \
- { TYPE_MEMORY_DEVICE }, { })
+OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(HvBalloon, hv_balloon, \
+ HV_BALLOON, VMBUS_DEVICE, \
+ { TYPE_MEMORY_DEVICE }, { })
#define HV_BALLOON_SET_STATE(hvb, news) \
do { \
@@ -1733,7 +1730,7 @@ static void hv_balloon_finalize(Object *obj)
hv_balloon_unrealize_finalize_common(balloon);
}
-static Property hv_balloon_properties[] = {
+static const Property hv_balloon_properties[] = {
DEFINE_PROP_BOOL("status-report", HvBalloon,
status_report.enabled, false),
@@ -1741,11 +1738,9 @@ static Property hv_balloon_properties[] = {
DEFINE_PROP_LINK(HV_BALLOON_MEMDEV_PROP, HvBalloon, hostmem,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
DEFINE_PROP_UINT64(HV_BALLOON_ADDR_PROP, HvBalloon, addr, 0),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void hv_balloon_class_init(ObjectClass *klass, void *data)
+static void hv_balloon_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VMBusDeviceClass *vdc = VMBUS_DEVICE_CLASS(klass);
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 483dcca..e4d0688 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -11,9 +11,11 @@
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-#include "sysemu/kvm.h"
+#include "system/address-spaces.h"
+#include "system/memory.h"
+#include "exec/target_page.h"
+#include "linux/kvm.h"
+#include "system/kvm.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "qemu/lockable.h"
@@ -23,8 +25,7 @@
#include "hw/hyperv/hyperv.h"
#include "qom/object.h"
#include "target/i386/kvm/hyperv-proto.h"
-#include "target/i386/cpu.h"
-#include "exec/cpu-all.h"
+#include "exec/target_page.h"
struct SynICState {
DeviceState parent_obj;
@@ -133,12 +134,12 @@ static void synic_reset(DeviceState *dev)
assert(QLIST_EMPTY(&synic->sint_routes));
}
-static void synic_class_init(ObjectClass *klass, void *data)
+static void synic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = synic_realize;
- dc->reset = synic_reset;
+ device_class_set_legacy_reset(dc, synic_reset);
dc->user_creatable = false;
}
diff --git a/hw/hyperv/hyperv_testdev.c b/hw/hyperv/hyperv_testdev.c
index 9a56ddf..2d4a636 100644
--- a/hw/hyperv/hyperv_testdev.c
+++ b/hw/hyperv/hyperv_testdev.c
@@ -88,8 +88,7 @@ static TestSintRoute *sint_route_find(HypervTestDev *dev,
return sint_route;
}
}
- assert(false);
- return NULL;
+ g_assert_not_reached();
}
static void sint_route_destroy(HypervTestDev *dev,
@@ -187,7 +186,7 @@ static void msg_conn_destroy(HypervTestDev *dev, uint8_t conn_id)
return;
}
}
- assert(false);
+ g_assert_not_reached();
}
static void evt_conn_handler(EventNotifier *notifier)
@@ -237,7 +236,7 @@ static void evt_conn_destroy(HypervTestDev *dev, uint8_t conn_id)
return;
}
}
- assert(false);
+ g_assert_not_reached();
}
static uint64_t hv_test_dev_read(void *opaque, hwaddr addr, unsigned size)
@@ -304,7 +303,7 @@ static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
memory_region_add_subregion(io, 0x3000, &dev->sint_control);
}
-static void hv_test_dev_class_init(ObjectClass *klass, void *data)
+static void hv_test_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/hyperv/meson.build b/hw/hyperv/meson.build
index d3d2668..d1cf781 100644
--- a/hw/hyperv/meson.build
+++ b/hw/hyperv/meson.build
@@ -1,5 +1,6 @@
-specific_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'))
-specific_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true: files('hyperv_testdev.c'))
-specific_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c'))
-specific_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c'))
-specific_ss.add(when: 'CONFIG_HV_BALLOON', if_true: files('hv-balloon.c', 'hv-balloon-page_range_tree.c', 'hv-balloon-our_range_memslots.c'), if_false: files('hv-balloon-stub.c'))
+system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'))
+system_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true: files('hyperv_testdev.c'))
+system_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c'))
+system_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c'))
+system_ss.add(when: 'CONFIG_HV_BALLOON', if_true: files('hv-balloon.c', 'hv-balloon-page_range_tree.c', 'hv-balloon-our_range_memslots.c'))
+system_ss.add(when: 'CONFIG_HV_BALLOON', if_false: files('hv-balloon-stub.c'))
diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c
index 065e12f..ac7e15f 100644
--- a/hw/hyperv/syndbg.c
+++ b/hw/hyperv/syndbg.c
@@ -10,11 +10,12 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/sockets.h"
+#include "qemu/units.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/loader.h"
-#include "cpu.h"
+#include "exec/target_page.h"
#include "hw/hyperv/hyperv.h"
#include "hw/hyperv/vmbus-bridge.h"
#include "hw/hyperv/hyperv-proto.h"
@@ -183,12 +184,15 @@ static bool create_udp_pkt(HvSynDbg *syndbg, void *pkt, uint32_t pkt_len,
return true;
}
+#define MSG_BUFSZ (4 * KiB)
+
static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa,
uint32_t count, bool is_raw, uint32_t options,
uint64_t timeout, uint32_t *retrieved_count)
{
uint16_t ret;
- uint8_t data_buf[TARGET_PAGE_SIZE - UDP_PKT_HEADER_SIZE];
+ g_assert(MSG_BUFSZ >= qemu_target_page_size());
+ QEMU_UNINITIALIZED uint8_t data_buf[MSG_BUFSZ];
hwaddr out_len;
void *out_data;
ssize_t recv_byte_count;
@@ -201,7 +205,7 @@ static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa,
recv_byte_count = 0;
} else {
recv_byte_count = recv(syndbg->socket, data_buf,
- MIN(sizeof(data_buf), count), MSG_WAITALL);
+ MIN(MSG_BUFSZ, count), MSG_WAITALL);
if (recv_byte_count == -1) {
return HV_STATUS_INVALID_PARAMETER;
}
@@ -366,14 +370,13 @@ static const VMStateDescription vmstate_hv_syndbg = {
.unmigratable = 1,
};
-static Property hv_syndbg_properties[] = {
+static const Property hv_syndbg_properties[] = {
DEFINE_PROP_STRING("host_ip", HvSynDbg, host_ip),
DEFINE_PROP_UINT16("host_port", HvSynDbg, host_port, 50000),
DEFINE_PROP_BOOL("use_hcalls", HvSynDbg, use_hcalls, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void hv_syndbg_class_init(ObjectClass *klass, void *data)
+static void hv_syndbg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
index 490d805..961406c 100644
--- a/hw/hyperv/vmbus.c
+++ b/hw/hyperv/vmbus.c
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
+#include "exec/target_page.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
@@ -18,7 +19,7 @@
#include "hw/hyperv/vmbus.h"
#include "hw/hyperv/vmbus-bridge.h"
#include "hw/sysbus.h"
-#include "cpu.h"
+#include "exec/target_page.h"
#include "trace.h"
enum {
@@ -1874,7 +1875,7 @@ static void send_create_gpadl(VMBus *vmbus)
}
}
- assert(false);
+ g_assert_not_reached();
}
static bool complete_create_gpadl(VMBus *vmbus)
@@ -1889,8 +1890,7 @@ static bool complete_create_gpadl(VMBus *vmbus)
}
}
- assert(false);
- return false;
+ g_assert_not_reached();
}
static void handle_gpadl_teardown(VMBus *vmbus,
@@ -1931,7 +1931,7 @@ static void send_teardown_gpadl(VMBus *vmbus)
}
}
- assert(false);
+ g_assert_not_reached();
}
static bool complete_teardown_gpadl(VMBus *vmbus)
@@ -1946,8 +1946,7 @@ static bool complete_teardown_gpadl(VMBus *vmbus)
}
}
- assert(false);
- return false;
+ g_assert_not_reached();
}
static void handle_open_channel(VMBus *vmbus, vmbus_message_open_channel *msg,
@@ -1996,7 +1995,7 @@ static void send_open_channel(VMBus *vmbus)
}
}
- assert(false);
+ g_assert_not_reached();
}
static bool complete_open_channel(VMBus *vmbus)
@@ -2020,8 +2019,7 @@ static bool complete_open_channel(VMBus *vmbus)
}
}
- assert(false);
- return false;
+ g_assert_not_reached();
}
static void vdev_reset_on_close(VMBusDevice *vdev)
@@ -2076,7 +2074,6 @@ static void send_unload(VMBus *vmbus)
qemu_mutex_unlock(&vmbus->rx_queue_lock);
post_msg(vmbus, &msg, sizeof(msg));
- return;
}
static bool complete_unload(VMBus *vmbus)
@@ -2349,20 +2346,19 @@ static void vmbus_dev_unrealize(DeviceState *dev)
free_channels(vdev);
}
-static Property vmbus_dev_props[] = {
+static const Property vmbus_dev_props[] = {
DEFINE_PROP_UUID("instanceid", VMBusDevice, instanceid),
- DEFINE_PROP_END_OF_LIST()
};
-static void vmbus_dev_class_init(ObjectClass *klass, void *data)
+static void vmbus_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *kdev = DEVICE_CLASS(klass);
device_class_set_props(kdev, vmbus_dev_props);
kdev->bus_type = TYPE_VMBUS;
kdev->realize = vmbus_dev_realize;
kdev->unrealize = vmbus_dev_unrealize;
- kdev->reset = vmbus_dev_reset;
+ device_class_set_legacy_reset(kdev, vmbus_dev_reset);
}
static void vmbus_dev_instance_init(Object *obj)
@@ -2473,7 +2469,7 @@ static char *vmbus_get_fw_dev_path(DeviceState *dev)
return g_strdup_printf("%s@%s", qdev_fw_name(dev), uuid);
}
-static void vmbus_class_init(ObjectClass *klass, void *data)
+static void vmbus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -2656,12 +2652,11 @@ static const VMStateDescription vmstate_vmbus_bridge = {
},
};
-static Property vmbus_bridge_props[] = {
+static const Property vmbus_bridge_props[] = {
DEFINE_PROP_UINT8("irq", VMBusBridge, irq, 7),
- DEFINE_PROP_END_OF_LIST()
};
-static void vmbus_bridge_class_init(ObjectClass *klass, void *data)
+static void vmbus_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
SysBusDeviceClass *sk = SYS_BUS_DEVICE_CLASS(klass);
diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c
index 16f1d6d..fe887e1 100644
--- a/hw/i2c/allwinner-i2c.c
+++ b/hw/i2c/allwinner-i2c.c
@@ -407,7 +407,7 @@ static const MemoryRegionOps allwinner_i2c_ops = {
.write = allwinner_i2c_write,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static const VMStateDescription allwinner_i2c_vmstate = {
@@ -438,7 +438,7 @@ static void allwinner_i2c_realize(DeviceState *dev, Error **errp)
s->bus = i2c_init_bus(dev, "i2c");
}
-static void allwinner_i2c_class_init(ObjectClass *klass, void *data)
+static void allwinner_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index b52a998..83fb906 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -114,7 +114,10 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
if (!aic->has_dma) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
value = -1;
+ break;
}
+
+ value = extract64(bus->dma_dram_offset, 0, 32);
break;
case A_I2CD_DMA_LEN:
if (!aic->has_dma) {
@@ -137,6 +140,7 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
unsigned size)
{
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
switch (offset) {
@@ -150,9 +154,7 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
case A_I2CM_DMA_TX_ADDR:
case A_I2CM_DMA_RX_ADDR:
case A_I2CM_DMA_LEN_STS:
- case A_I2CC_DMA_ADDR:
case A_I2CC_DMA_LEN:
-
case A_I2CS_DEV_ADDR:
case A_I2CS_DMA_RX_ADDR:
case A_I2CS_DMA_LEN:
@@ -161,11 +163,24 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
case A_I2CS_DMA_LEN_STS:
/* Value is already set, don't do anything. */
break;
+ case A_I2CC_DMA_ADDR:
+ value = extract64(bus->dma_dram_offset, 0, 32);
+ break;
case A_I2CS_INTR_STS:
break;
case A_I2CM_CMD:
value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
break;
+ case A_I2CM_DMA_TX_ADDR_HI:
+ case A_I2CM_DMA_RX_ADDR_HI:
+ case A_I2CS_DMA_TX_ADDR_HI:
+ case A_I2CS_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ value = -1;
+ }
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
@@ -210,18 +225,18 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
{
MemTxResult result;
AspeedI2CState *s = bus->controller;
- uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
- result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr],
+ result = address_space_read(&s->dram_as, bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, data, 1);
if (result != MEMTX_OK) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
- __func__, bus->regs[reg_dma_addr]);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: DRAM read failed @%" PRIx64 "\n",
+ __func__, bus->dma_dram_offset);
return -1;
}
- bus->regs[reg_dma_addr]++;
+ bus->dma_dram_offset++;
bus->regs[reg_dma_len]--;
return 0;
}
@@ -291,7 +306,6 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
- uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl,
RX_SIZE) + 1;
@@ -323,14 +337,17 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
data = i2c_recv(bus->bus);
trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len],
bus->regs[reg_dma_len], data);
- result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr],
+
+ result = address_space_write(&s->dram_as, bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, &data, 1);
if (result != MEMTX_OK) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
- __func__, bus->regs[reg_dma_addr]);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: DRAM write failed @%" PRIx64 "\n",
+ __func__, bus->dma_dram_offset);
return;
}
- bus->regs[reg_dma_addr]++;
+
+ bus->dma_dram_offset++;
bus->regs[reg_dma_len]--;
/* In new mode, keep track of how many bytes we RXed */
if (aspeed_i2c_is_new_mode(bus->controller)) {
@@ -636,14 +653,18 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
case A_I2CM_DMA_TX_ADDR:
bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR,
ADDR);
- bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR);
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR));
bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN,
TX_BUF_LEN) + 1;
break;
case A_I2CM_DMA_RX_ADDR:
bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR,
ADDR);
- bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR);
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR));
bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN,
RX_BUF_LEN) + 1;
break;
@@ -721,6 +742,56 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
__func__);
break;
+
+ /*
+ * The AST2700 support the maximum DRAM size is 8 GB.
+ * The DRAM offset range is from 0x0_0000_0000 to
+ * 0x1_FFFF_FFFF and it is enough to use bits [33:0]
+ * saving the dram offset.
+ * Therefore, save the high part physical address bit[1:0]
+ * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
+ */
+ case A_I2CM_DMA_TX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
+ I2CM_DMA_TX_ADDR_HI,
+ ADDR_HI);
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ break;
+ case A_I2CM_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+ I2CM_DMA_RX_ADDR_HI,
+ ADDR_HI);
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ break;
+ case A_I2CS_DMA_TX_ADDR_HI:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Slave mode DMA TX Addr high is not implemented\n",
+ __func__);
+ break;
+ case A_I2CS_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+ I2CS_DMA_RX_ADDR_HI,
+ ADDR_HI);
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
@@ -811,7 +882,8 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
break;
}
- bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc;
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
+ value & 0x3ffffffc);
break;
case A_I2CD_DMA_LEN:
@@ -941,12 +1013,49 @@ static const MemoryRegionOps aspeed_i2c_share_pool_ops = {
},
};
+static uint64_t aspeed_i2c_bus_pool_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ AspeedI2CBus *s = opaque;
+ uint64_t ret = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+ }
+
+ return ret;
+}
+
+static void aspeed_i2c_bus_pool_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ AspeedI2CBus *s = opaque;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
+ }
+}
+
+static const MemoryRegionOps aspeed_i2c_bus_pool_ops = {
+ .read = aspeed_i2c_bus_pool_read,
+ .write = aspeed_i2c_bus_pool_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
static const VMStateDescription aspeed_i2c_bus_vmstate = {
.name = TYPE_ASPEED_I2C,
- .version_id = 5,
- .minimum_version_id = 5,
+ .version_id = 6,
+ .minimum_version_id = 6,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG),
+ VMSTATE_UINT8_ARRAY(pool, AspeedI2CBus, ASPEED_I2C_BUS_POOL_SIZE),
+ VMSTATE_UINT64(dma_dram_offset, AspeedI2CBus),
VMSTATE_END_OF_LIST()
}
};
@@ -996,7 +1105,21 @@ static void aspeed_i2c_instance_init(Object *obj)
* 0x140 ... 0x17F: Device 5
* 0x180 ... 0x1BF: Device 6
* 0x1C0 ... 0x1FF: Device 7
- * 0x200 ... 0x2FF: Buffer Pool (AST2500 unused in linux driver)
+ * 0x200 ... 0x20F: Device 1 buffer (AST2500 unused in linux driver)
+ * 0x210 ... 0x21F: Device 2 buffer
+ * 0x220 ... 0x22F: Device 3 buffer
+ * 0x230 ... 0x23F: Device 4 buffer
+ * 0x240 ... 0x24F: Device 5 buffer
+ * 0x250 ... 0x25F: Device 6 buffer
+ * 0x260 ... 0x26F: Device 7 buffer
+ * 0x270 ... 0x27F: Device 8 buffer
+ * 0x280 ... 0x28F: Device 9 buffer
+ * 0x290 ... 0x29F: Device 10 buffer
+ * 0x2A0 ... 0x2AF: Device 11 buffer
+ * 0x2B0 ... 0x2BF: Device 12 buffer
+ * 0x2C0 ... 0x2CF: Device 13 buffer
+ * 0x2D0 ... 0x2DF: Device 14 buffer
+ * 0x2E0 ... 0x2FF: Reserved
* 0x300 ... 0x33F: Device 8
* 0x340 ... 0x37F: Device 9
* 0x380 ... 0x3BF: Device 10
@@ -1005,6 +1128,76 @@ static void aspeed_i2c_instance_init(Object *obj)
* 0x440 ... 0x47F: Device 13
* 0x480 ... 0x4BF: Device 14
* 0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver)
+ *
+ * Address Definitions (AST2600 and AST1030)
+ * 0x000 ... 0x07F: Global Register
+ * 0x080 ... 0x0FF: Device 1
+ * 0x100 ... 0x17F: Device 2
+ * 0x180 ... 0x1FF: Device 3
+ * 0x200 ... 0x27F: Device 4
+ * 0x280 ... 0x2FF: Device 5
+ * 0x300 ... 0x37F: Device 6
+ * 0x380 ... 0x3FF: Device 7
+ * 0x400 ... 0x47F: Device 8
+ * 0x480 ... 0x4FF: Device 9
+ * 0x500 ... 0x57F: Device 10
+ * 0x580 ... 0x5FF: Device 11
+ * 0x600 ... 0x67F: Device 12
+ * 0x680 ... 0x6FF: Device 13
+ * 0x700 ... 0x77F: Device 14
+ * 0x780 ... 0x7FF: Device 15 (15 and 16 unused in AST1030)
+ * 0x800 ... 0x87F: Device 16
+ * 0xC00 ... 0xC1F: Device 1 buffer
+ * 0xC20 ... 0xC3F: Device 2 buffer
+ * 0xC40 ... 0xC5F: Device 3 buffer
+ * 0xC60 ... 0xC7F: Device 4 buffer
+ * 0xC80 ... 0xC9F: Device 5 buffer
+ * 0xCA0 ... 0xCBF: Device 6 buffer
+ * 0xCC0 ... 0xCDF: Device 7 buffer
+ * 0xCE0 ... 0xCFF: Device 8 buffer
+ * 0xD00 ... 0xD1F: Device 9 buffer
+ * 0xD20 ... 0xD3F: Device 10 buffer
+ * 0xD40 ... 0xD5F: Device 11 buffer
+ * 0xD60 ... 0xD7F: Device 12 buffer
+ * 0xD80 ... 0xD9F: Device 13 buffer
+ * 0xDA0 ... 0xDBF: Device 14 buffer
+ * 0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)
+ * 0xDE0 ... 0xDFF: Device 16 buffer
+ *
+ * Address Definitions (AST2700)
+ * 0x000 ... 0x0FF: Global Register
+ * 0x100 ... 0x17F: Device 0
+ * 0x1A0 ... 0x1BF: Device 0 buffer
+ * 0x200 ... 0x27F: Device 1
+ * 0x2A0 ... 0x2BF: Device 1 buffer
+ * 0x300 ... 0x37F: Device 2
+ * 0x3A0 ... 0x3BF: Device 2 buffer
+ * 0x400 ... 0x47F: Device 3
+ * 0x4A0 ... 0x4BF: Device 3 buffer
+ * 0x500 ... 0x57F: Device 4
+ * 0x5A0 ... 0x5BF: Device 4 buffer
+ * 0x600 ... 0x67F: Device 5
+ * 0x6A0 ... 0x6BF: Device 5 buffer
+ * 0x700 ... 0x77F: Device 6
+ * 0x7A0 ... 0x7BF: Device 6 buffer
+ * 0x800 ... 0x87F: Device 7
+ * 0x8A0 ... 0x8BF: Device 7 buffer
+ * 0x900 ... 0x97F: Device 8
+ * 0x9A0 ... 0x9BF: Device 8 buffer
+ * 0xA00 ... 0xA7F: Device 9
+ * 0xAA0 ... 0xABF: Device 9 buffer
+ * 0xB00 ... 0xB7F: Device 10
+ * 0xBA0 ... 0xBBF: Device 10 buffer
+ * 0xC00 ... 0xC7F: Device 11
+ * 0xCA0 ... 0xCBF: Device 11 buffer
+ * 0xD00 ... 0xD7F: Device 12
+ * 0xDA0 ... 0xDBF: Device 12 buffer
+ * 0xE00 ... 0xE7F: Device 13
+ * 0xEA0 ... 0xEBF: Device 13 buffer
+ * 0xF00 ... 0xF7F: Device 14
+ * 0xFA0 ... 0xFBF: Device 14 buffer
+ * 0x1000 ... 0x107F: Device 15
+ * 0x10A0 ... 0x10BF: Device 15 buffer
*/
static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
{
@@ -1012,6 +1205,8 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedI2CState *s = ASPEED_I2C(dev);
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
+ uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
+ uint32_t pool_offset = aic->pool_size + aic->pool_gap_size;
sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
@@ -1034,14 +1229,23 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
return;
}
- memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
+ memory_region_add_subregion(&s->iomem, reg_offset * (i + offset),
&s->busses[i].mr);
}
- memory_region_init_io(&s->pool_iomem, OBJECT(s),
- &aspeed_i2c_share_pool_ops, s,
- "aspeed.i2c-share-pool", aic->pool_size);
- memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem);
+ if (aic->has_share_pool) {
+ memory_region_init_io(&s->pool_iomem, OBJECT(s),
+ &aspeed_i2c_share_pool_ops, s,
+ "aspeed.i2c-share-pool", aic->pool_size);
+ memory_region_add_subregion(&s->iomem, aic->pool_base,
+ &s->pool_iomem);
+ } else {
+ for (i = 0; i < aic->num_busses; i++) {
+ memory_region_add_subregion(&s->iomem,
+ aic->pool_base + (pool_offset * i),
+ &s->busses[i].mr_pool);
+ }
+ }
if (aic->has_dma) {
if (!s->dram_mr) {
@@ -1054,18 +1258,17 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
}
}
-static Property aspeed_i2c_properties[] = {
+static const Property aspeed_i2c_properties[] = {
DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_i2c_class_init(ObjectClass *klass, void *data)
+static void aspeed_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &aspeed_i2c_vmstate;
- dc->reset = aspeed_i2c_reset;
+ device_class_set_legacy_reset(dc, aspeed_i2c_reset);
device_class_set_props(dc, aspeed_i2c_properties);
dc->realize = aspeed_i2c_realize;
dc->desc = "Aspeed I2C Controller";
@@ -1092,8 +1295,9 @@ static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
return -1;
}
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
- bus->regs[R_I2CC_DMA_ADDR] =
- ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR);
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR));
bus->regs[R_I2CC_DMA_LEN] =
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
i2c_ack(bus->bus);
@@ -1159,10 +1363,10 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data)
{
assert(address_space_write(&bus->controller->dram_as,
- bus->regs[R_I2CC_DMA_ADDR],
+ bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK);
- bus->regs[R_I2CC_DMA_ADDR]++;
+ bus->dma_dram_offset++;
bus->regs[R_I2CC_DMA_LEN]--;
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN,
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1);
@@ -1186,7 +1390,8 @@ static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data)
aspeed_i2c_bus_raise_interrupt(bus);
}
-static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data)
+static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
@@ -1217,6 +1422,7 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
AspeedI2CClass *aic;
g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id);
+ g_autofree char *pool_name = g_strdup_printf("%s.pool", name);
if (!s->controller) {
error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set");
@@ -1234,22 +1440,25 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops,
s, name, aic->reg_size);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
+
+ memory_region_init_io(&s->mr_pool, OBJECT(s), &aspeed_i2c_bus_pool_ops,
+ s, pool_name, aic->pool_size);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr_pool);
}
-static Property aspeed_i2c_bus_properties[] = {
+static const Property aspeed_i2c_bus_properties[] = {
DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0),
DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C,
AspeedI2CState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data)
+static void aspeed_i2c_bus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "Aspeed I2C Bus";
dc->realize = aspeed_i2c_bus_realize;
- dc->reset = aspeed_i2c_bus_reset;
+ device_class_set_legacy_reset(dc, aspeed_i2c_bus_reset);
device_class_set_props(dc, aspeed_i2c_bus_properties);
}
@@ -1275,7 +1484,7 @@ static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)];
}
-static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
@@ -1286,6 +1495,7 @@ static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq;
+ aic->has_share_pool = true;
aic->pool_size = 0x800;
aic->pool_base = 0x800;
aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base;
@@ -1305,10 +1515,10 @@ static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus)
static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus)
{
- return &bus->controller->share_pool[bus->id * 0x10];
+ return bus->pool;
}
-static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
@@ -1319,7 +1529,7 @@ static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq;
- aic->pool_size = 0x100;
+ aic->pool_size = 0x10;
aic->pool_base = 0x200;
aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->check_sram = true;
@@ -1338,12 +1548,7 @@ static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus)
return bus->irq;
}
-static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus)
-{
- return &bus->controller->share_pool[bus->id * 0x20];
-}
-
-static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
@@ -1354,9 +1559,9 @@ static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x80;
aic->gap = -1; /* no gap */
aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
- aic->pool_size = 0x200;
+ aic->pool_size = 0x20;
aic->pool_base = 0xC00;
- aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->has_dma = true;
aic->mem_size = 0x1000;
}
@@ -1367,7 +1572,7 @@ static const TypeInfo aspeed_2600_i2c_info = {
.class_init = aspeed_2600_i2c_class_init,
};
-static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
@@ -1378,9 +1583,9 @@ static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x80;
aic->gap = -1; /* no gap */
aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
- aic->pool_size = 0x200;
+ aic->pool_size = 0x20;
aic->pool_base = 0xC00;
- aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->has_dma = true;
aic->mem_size = 0x10000;
}
@@ -1391,6 +1596,33 @@ static const TypeInfo aspeed_1030_i2c_info = {
.class_init = aspeed_1030_i2c_class_init,
};
+static void aspeed_2700_i2c_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 I2C Controller";
+
+ aic->num_busses = 16;
+ aic->reg_size = 0x80;
+ aic->reg_gap_size = 0x80;
+ aic->gap = -1; /* no gap */
+ aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
+ aic->pool_size = 0x20;
+ aic->pool_gap_size = 0xe0;
+ aic->pool_base = 0x1a0;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
+ aic->has_dma = true;
+ aic->mem_size = 0x2000;
+ aic->has_dma64 = true;
+}
+
+static const TypeInfo aspeed_2700_i2c_info = {
+ .name = TYPE_ASPEED_2700_I2C,
+ .parent = TYPE_ASPEED_I2C,
+ .class_init = aspeed_2700_i2c_class_init,
+};
+
static void aspeed_i2c_register_types(void)
{
type_register_static(&aspeed_i2c_bus_info);
@@ -1400,6 +1632,7 @@ static void aspeed_i2c_register_types(void)
type_register_static(&aspeed_2500_i2c_info);
type_register_static(&aspeed_2600_i2c_info);
type_register_static(&aspeed_1030_i2c_info);
+ type_register_static(&aspeed_2700_i2c_info);
}
type_init(aspeed_i2c_register_types)
diff --git a/hw/i2c/bcm2835_i2c.c b/hw/i2c/bcm2835_i2c.c
index 20ec46e..be11cca 100644
--- a/hw/i2c/bcm2835_i2c.c
+++ b/hw/i2c/bcm2835_i2c.c
@@ -258,11 +258,11 @@ static const VMStateDescription vmstate_bcm2835_i2c = {
}
};
-static void bcm2835_i2c_class_init(ObjectClass *klass, void *data)
+static void bcm2835_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_i2c_reset;
+ device_class_set_legacy_reset(dc, bcm2835_i2c_reset);
dc->realize = bcm2835_i2c_realize;
dc->vmsd = &vmstate_bcm2835_i2c;
}
diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c
index de5f5aa..e020f31 100644
--- a/hw/i2c/bitbang_i2c.c
+++ b/hw/i2c/bitbang_i2c.c
@@ -222,7 +222,7 @@ static void gpio_i2c_init(Object *obj)
qdev_init_gpio_out(dev, &s->out, 1);
}
-static void gpio_i2c_class_init(ObjectClass *klass, void *data)
+static void gpio_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 4cf30b2..4b6345b 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -18,9 +18,8 @@
#define I2C_BROADCAST 0x00
-static Property i2c_props[] = {
+static const Property i2c_props[] = {
DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const TypeInfo i2c_bus_info = {
@@ -402,7 +401,7 @@ static bool i2c_slave_match(I2CSlave *candidate, uint8_t address,
return false;
}
-static void i2c_slave_class_init(ObjectClass *klass, void *data)
+static void i2c_slave_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c
index 9445424..9d0c1cd 100644
--- a/hw/i2c/exynos4210_i2c.c
+++ b/hw/i2c/exynos4210_i2c.c
@@ -309,12 +309,12 @@ static void exynos4210_i2c_init(Object *obj)
s->bus = i2c_init_bus(dev, "i2c");
}
-static void exynos4210_i2c_class_init(ObjectClass *klass, void *data)
+static void exynos4210_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &exynos4210_i2c_vmstate;
- dc->reset = exynos4210_i2c_reset;
+ device_class_set_legacy_reset(dc, exynos4210_i2c_reset);
}
static const TypeInfo exynos4210_i2c_type_info = {
diff --git a/hw/i2c/i2c_mux_pca954x.c b/hw/i2c/i2c_mux_pca954x.c
index db5db95..a8ef640 100644
--- a/hw/i2c/i2c_mux_pca954x.c
+++ b/hw/i2c/i2c_mux_pca954x.c
@@ -172,13 +172,13 @@ I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel)
return pca954x->bus[channel];
}
-static void pca9546_class_init(ObjectClass *klass, void *data)
+static void pca9546_class_init(ObjectClass *klass, const void *data)
{
Pca954xClass *s = PCA954X_CLASS(klass);
s->nchans = PCA9546_CHANNEL_COUNT;
}
-static void pca9548_class_init(ObjectClass *klass, void *data)
+static void pca9548_class_init(ObjectClass *klass, const void *data)
{
Pca954xClass *s = PCA954X_CLASS(klass);
s->nchans = PCA9548_CHANNEL_COUNT;
@@ -211,12 +211,11 @@ static void pca954x_init(Object *obj)
}
}
-static Property pca954x_props[] = {
+static const Property pca954x_props[] = {
DEFINE_PROP_STRING("name", Pca954xState, name),
- DEFINE_PROP_END_OF_LIST()
};
-static void pca954x_class_init(ObjectClass *klass, void *data)
+static void pca954x_class_init(ObjectClass *klass, const void *data)
{
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c
index a25676f..d26177c 100644
--- a/hw/i2c/imx_i2c.c
+++ b/hw/i2c/imx_i2c.c
@@ -25,18 +25,7 @@
#include "hw/i2c/i2c.h"
#include "qemu/log.h"
#include "qemu/module.h"
-
-#ifndef DEBUG_IMX_I2C
-#define DEBUG_IMX_I2C 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_I2C) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_I2C, \
- __func__, ##args); \
- } \
- } while (0)
+#include "trace.h"
static const char *imx_i2c_get_regname(unsigned offset)
{
@@ -90,13 +79,12 @@ static void imx_i2c_reset(DeviceState *dev)
static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
{
- /*
- * raise an interrupt if the device is enabled and it is configured
- * to generate some interrupts.
- */
- if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
+ if (imx_i2c_is_enabled(s)) {
s->i2sr |= I2SR_IIF;
- qemu_irq_raise(s->irq);
+
+ if (imx_i2c_interrupt_is_enabled(s)) {
+ qemu_irq_raise(s->irq);
+ }
}
}
@@ -152,8 +140,8 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
break;
}
- DPRINTF("read %s [0x%" HWADDR_PRIx "] -> 0x%02x\n",
- imx_i2c_get_regname(offset), offset, value);
+ trace_imx_i2c_read(DEVICE(s)->canonical_path, imx_i2c_get_regname(offset),
+ offset, value);
return (uint64_t)value;
}
@@ -163,8 +151,8 @@ static void imx_i2c_write(void *opaque, hwaddr offset,
{
IMXI2CState *s = IMX_I2C(opaque);
- DPRINTF("write %s [0x%" HWADDR_PRIx "] <- 0x%02x\n",
- imx_i2c_get_regname(offset), offset, (int)value);
+ trace_imx_i2c_read(DEVICE(s)->canonical_path, imx_i2c_get_regname(offset),
+ offset, value);
value &= 0xff;
@@ -308,12 +296,12 @@ static void imx_i2c_realize(DeviceState *dev, Error **errp)
s->bus = i2c_init_bus(dev, NULL);
}
-static void imx_i2c_class_init(ObjectClass *klass, void *data)
+static void imx_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &imx_i2c_vmstate;
- dc->reset = imx_i2c_reset;
+ device_class_set_legacy_reset(dc, imx_i2c_reset);
dc->realize = imx_i2c_realize;
dc->desc = "i.MX I2C Controller";
}
diff --git a/hw/i2c/microbit_i2c.c b/hw/i2c/microbit_i2c.c
index 24d36d1..2291d63 100644
--- a/hw/i2c/microbit_i2c.c
+++ b/hw/i2c/microbit_i2c.c
@@ -105,12 +105,12 @@ static void microbit_i2c_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void microbit_i2c_class_init(ObjectClass *klass, void *data)
+static void microbit_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &microbit_i2c_vmstate;
- dc->reset = microbit_i2c_reset;
+ device_class_set_legacy_reset(dc, microbit_i2c_reset);
dc->realize = microbit_i2c_realize;
dc->desc = "Microbit I2C controller";
}
diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c
index 06d4ce7..25f91b7 100644
--- a/hw/i2c/mpc_i2c.c
+++ b/hw/i2c/mpc_i2c.c
@@ -20,10 +20,10 @@
#include "qemu/osdep.h"
#include "hw/i2c/i2c.h"
#include "hw/irq.h"
-#include "qemu/module.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qom/object.h"
+#include "trace.h"
/* #define DEBUG_I2C */
@@ -224,8 +224,8 @@ static uint64_t mpc_i2c_read(void *opaque, hwaddr addr, unsigned size)
break;
}
- DPRINTF("%s: addr " HWADDR_FMT_plx " %02" PRIx32 "\n", __func__,
- addr, value);
+ trace_mpc_i2c_read(addr, value);
+
return (uint64_t)value;
}
@@ -234,8 +234,8 @@ static void mpc_i2c_write(void *opaque, hwaddr addr,
{
MPCI2CState *s = opaque;
- DPRINTF("%s: addr " HWADDR_FMT_plx " val %08" PRIx64 "\n", __func__,
- addr, value);
+ trace_mpc_i2c_write(addr, value);
+
switch (addr) {
case MPC_I2C_ADR:
s->adr = value & CADR_MASK;
@@ -334,26 +334,23 @@ static void mpc_i2c_realize(DeviceState *dev, Error **errp)
i2c->bus = i2c_init_bus(dev, "i2c");
}
-static void mpc_i2c_class_init(ObjectClass *klass, void *data)
+static void mpc_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &mpc_i2c_vmstate ;
- dc->reset = mpc_i2c_reset;
+ device_class_set_legacy_reset(dc, mpc_i2c_reset);
dc->realize = mpc_i2c_realize;
dc->desc = "MPC I2C Controller";
}
-static const TypeInfo mpc_i2c_type_info = {
- .name = TYPE_MPC_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MPCI2CState),
- .class_init = mpc_i2c_class_init,
+static const TypeInfo mpc_i2c_types[] = {
+ {
+ .name = TYPE_MPC_I2C,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MPCI2CState),
+ .class_init = mpc_i2c_class_init,
+ },
};
-static void mpc_i2c_register_types(void)
-{
- type_register_static(&mpc_i2c_type_info);
-}
-
-type_init(mpc_i2c_register_types)
+DEFINE_TYPES(mpc_i2c_types)
diff --git a/hw/i2c/npcm7xx_smbus.c b/hw/i2c/npcm7xx_smbus.c
index 22d68fc..179852a 100644
--- a/hw/i2c/npcm7xx_smbus.c
+++ b/hw/i2c/npcm7xx_smbus.c
@@ -1075,7 +1075,7 @@ static const VMStateDescription vmstate_npcm7xx_smbus = {
},
};
-static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_smbus_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c
index e5d205d..751bf74 100644
--- a/hw/i2c/omap_i2c.c
+++ b/hw/i2c/omap_i2c.c
@@ -55,16 +55,16 @@ struct OMAPI2CState {
uint16_t test;
};
-#define OMAP2_INTR_REV 0x34
-#define OMAP2_GC_REV 0x34
+#define OMAP2_INTR_REV 0x34
+#define OMAP2_GC_REV 0x34
static void omap_i2c_interrupts_update(OMAPI2CState *s)
{
qemu_set_irq(s->irq, s->stat & s->mask);
- if ((s->dma >> 15) & 1) /* RDMA_EN */
- qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
- if ((s->dma >> 7) & 1) /* XDMA_EN */
- qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
+ if ((s->dma >> 15) & 1) /* RDMA_EN */
+ qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
+ if ((s->dma >> 7) & 1) /* XDMA_EN */
+ qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
}
static void omap_i2c_fifo_run(OMAPI2CState *s)
@@ -74,25 +74,25 @@ static void omap_i2c_fifo_run(OMAPI2CState *s)
if (!i2c_bus_busy(s->bus))
return;
- if ((s->control >> 2) & 1) { /* RM */
- if ((s->control >> 1) & 1) { /* STP */
+ if ((s->control >> 2) & 1) { /* RM */
+ if ((s->control >> 1) & 1) { /* STP */
i2c_end_transfer(s->bus);
- s->control &= ~(1 << 1); /* STP */
+ s->control &= ~(1 << 1); /* STP */
s->count_cur = s->count;
s->txlen = 0;
- } else if ((s->control >> 9) & 1) { /* TRX */
+ } else if ((s->control >> 9) & 1) { /* TRX */
while (ack && s->txlen)
ack = (i2c_send(s->bus,
(s->fifo >> ((-- s->txlen) << 3)) &
0xff) >= 0);
- s->stat |= 1 << 4; /* XRDY */
+ s->stat |= 1 << 4; /* XRDY */
} else {
while (s->rxlen < 4)
s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
- s->stat |= 1 << 3; /* RRDY */
+ s->stat |= 1 << 3; /* RRDY */
}
} else {
- if ((s->control >> 9) & 1) { /* TRX */
+ if ((s->control >> 9) & 1) { /* TRX */
while (ack && s->count_cur && s->txlen) {
ack = (i2c_send(s->bus,
(s->fifo >> ((-- s->txlen) << 3)) &
@@ -100,12 +100,12 @@ static void omap_i2c_fifo_run(OMAPI2CState *s)
s->count_cur --;
}
if (ack && s->count_cur)
- s->stat |= 1 << 4; /* XRDY */
+ s->stat |= 1 << 4; /* XRDY */
else
- s->stat &= ~(1 << 4); /* XRDY */
+ s->stat &= ~(1 << 4); /* XRDY */
if (!s->count_cur) {
- s->stat |= 1 << 2; /* ARDY */
- s->control &= ~(1 << 10); /* MST */
+ s->stat |= 1 << 2; /* ARDY */
+ s->control &= ~(1 << 10); /* MST */
}
} else {
while (s->count_cur && s->rxlen < 4) {
@@ -113,26 +113,26 @@ static void omap_i2c_fifo_run(OMAPI2CState *s)
s->count_cur --;
}
if (s->rxlen)
- s->stat |= 1 << 3; /* RRDY */
+ s->stat |= 1 << 3; /* RRDY */
else
- s->stat &= ~(1 << 3); /* RRDY */
+ s->stat &= ~(1 << 3); /* RRDY */
}
if (!s->count_cur) {
- if ((s->control >> 1) & 1) { /* STP */
+ if ((s->control >> 1) & 1) { /* STP */
i2c_end_transfer(s->bus);
- s->control &= ~(1 << 1); /* STP */
+ s->control &= ~(1 << 1); /* STP */
s->count_cur = s->count;
s->txlen = 0;
} else {
- s->stat |= 1 << 2; /* ARDY */
- s->control &= ~(1 << 10); /* MST */
+ s->stat |= 1 << 2; /* ARDY */
+ s->control &= ~(1 << 10); /* MST */
}
}
}
- s->stat |= (!ack) << 1; /* NACK */
+ s->stat |= (!ack) << 1; /* NACK */
if (!ack)
- s->control &= ~(1 << 1); /* STP */
+ s->control &= ~(1 << 1); /* STP */
}
static void omap_i2c_reset(DeviceState *dev)
@@ -163,16 +163,16 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
uint16_t ret;
switch (offset) {
- case 0x00: /* I2C_REV */
- return s->revision; /* REV */
+ case 0x00: /* I2C_REV */
+ return s->revision; /* REV */
- case 0x04: /* I2C_IE */
+ case 0x04: /* I2C_IE */
return s->mask;
- case 0x08: /* I2C_STAT */
+ case 0x08: /* I2C_STAT */
return s->stat | (i2c_bus_busy(s->bus) << 12);
- case 0x0c: /* I2C_IV */
+ case 0x0c: /* I2C_IV */
if (s->revision >= OMAP2_INTR_REV)
break;
ret = ctz32(s->stat & s->mask);
@@ -185,18 +185,18 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
omap_i2c_interrupts_update(s);
return ret;
- case 0x10: /* I2C_SYSS */
- return (s->control >> 15) & 1; /* I2C_EN */
+ case 0x10: /* I2C_SYSS */
+ return (s->control >> 15) & 1; /* I2C_EN */
- case 0x14: /* I2C_BUF */
+ case 0x14: /* I2C_BUF */
return s->dma;
- case 0x18: /* I2C_CNT */
- return s->count_cur; /* DCOUNT */
+ case 0x18: /* I2C_CNT */
+ return s->count_cur; /* DCOUNT */
- case 0x1c: /* I2C_DATA */
+ case 0x1c: /* I2C_DATA */
ret = 0;
- if (s->control & (1 << 14)) { /* BE */
+ if (s->control & (1 << 14)) { /* BE */
ret |= ((s->fifo >> 0) & 0xff) << 8;
ret |= ((s->fifo >> 8) & 0xff) << 0;
} else {
@@ -204,7 +204,7 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
ret |= ((s->fifo >> 0) & 0xff) << 0;
}
if (s->rxlen == 1) {
- s->stat |= 1 << 15; /* SBD */
+ s->stat |= 1 << 15; /* SBD */
s->rxlen = 0;
} else if (s->rxlen > 1) {
if (s->rxlen > 2)
@@ -214,41 +214,41 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
/* XXX: remote access (qualifier) error - what's that? */
}
if (!s->rxlen) {
- s->stat &= ~(1 << 3); /* RRDY */
- if (((s->control >> 10) & 1) && /* MST */
- ((~s->control >> 9) & 1)) { /* TRX */
- s->stat |= 1 << 2; /* ARDY */
- s->control &= ~(1 << 10); /* MST */
+ s->stat &= ~(1 << 3); /* RRDY */
+ if (((s->control >> 10) & 1) && /* MST */
+ ((~s->control >> 9) & 1)) { /* TRX */
+ s->stat |= 1 << 2; /* ARDY */
+ s->control &= ~(1 << 10); /* MST */
}
}
- s->stat &= ~(1 << 11); /* ROVR */
+ s->stat &= ~(1 << 11); /* ROVR */
omap_i2c_fifo_run(s);
omap_i2c_interrupts_update(s);
return ret;
- case 0x20: /* I2C_SYSC */
+ case 0x20: /* I2C_SYSC */
return 0;
- case 0x24: /* I2C_CON */
+ case 0x24: /* I2C_CON */
return s->control;
- case 0x28: /* I2C_OA */
+ case 0x28: /* I2C_OA */
return s->addr[0];
- case 0x2c: /* I2C_SA */
+ case 0x2c: /* I2C_SA */
return s->addr[1];
- case 0x30: /* I2C_PSC */
+ case 0x30: /* I2C_PSC */
return s->divider;
- case 0x34: /* I2C_SCLL */
+ case 0x34: /* I2C_SCLL */
return s->times[0];
- case 0x38: /* I2C_SCLH */
+ case 0x38: /* I2C_SCLH */
return s->times[1];
- case 0x3c: /* I2C_SYSTEST */
- if (s->test & (1 << 15)) { /* ST_EN */
+ case 0x3c: /* I2C_SYSTEST */
+ if (s->test & (1 << 15)) { /* ST_EN */
s->test ^= 0xa;
return s->test;
} else
@@ -267,17 +267,17 @@ static void omap_i2c_write(void *opaque, hwaddr addr,
int nack;
switch (offset) {
- case 0x00: /* I2C_REV */
- case 0x0c: /* I2C_IV */
- case 0x10: /* I2C_SYSS */
+ case 0x00: /* I2C_REV */
+ case 0x0c: /* I2C_IV */
+ case 0x10: /* I2C_SYSS */
OMAP_RO_REG(addr);
return;
- case 0x04: /* I2C_IE */
+ case 0x04: /* I2C_IE */
s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
break;
- case 0x08: /* I2C_STAT */
+ case 0x08: /* I2C_STAT */
if (s->revision < OMAP2_INTR_REV) {
OMAP_RO_REG(addr);
return;
@@ -288,40 +288,40 @@ static void omap_i2c_write(void *opaque, hwaddr addr,
omap_i2c_interrupts_update(s);
break;
- case 0x14: /* I2C_BUF */
+ case 0x14: /* I2C_BUF */
s->dma = value & 0x8080;
- if (value & (1 << 15)) /* RDMA_EN */
- s->mask &= ~(1 << 3); /* RRDY_IE */
- if (value & (1 << 7)) /* XDMA_EN */
- s->mask &= ~(1 << 4); /* XRDY_IE */
+ if (value & (1 << 15)) /* RDMA_EN */
+ s->mask &= ~(1 << 3); /* RRDY_IE */
+ if (value & (1 << 7)) /* XDMA_EN */
+ s->mask &= ~(1 << 4); /* XRDY_IE */
break;
- case 0x18: /* I2C_CNT */
- s->count = value; /* DCOUNT */
+ case 0x18: /* I2C_CNT */
+ s->count = value; /* DCOUNT */
break;
- case 0x1c: /* I2C_DATA */
+ case 0x1c: /* I2C_DATA */
if (s->txlen > 2) {
/* XXX: remote access (qualifier) error - what's that? */
break;
}
s->fifo <<= 16;
s->txlen += 2;
- if (s->control & (1 << 14)) { /* BE */
+ if (s->control & (1 << 14)) { /* BE */
s->fifo |= ((value >> 8) & 0xff) << 8;
s->fifo |= ((value >> 0) & 0xff) << 0;
} else {
s->fifo |= ((value >> 0) & 0xff) << 8;
s->fifo |= ((value >> 8) & 0xff) << 0;
}
- s->stat &= ~(1 << 10); /* XUDF */
+ s->stat &= ~(1 << 10); /* XUDF */
if (s->txlen > 2)
- s->stat &= ~(1 << 4); /* XRDY */
+ s->stat &= ~(1 << 4); /* XRDY */
omap_i2c_fifo_run(s);
omap_i2c_interrupts_update(s);
break;
- case 0x20: /* I2C_SYSC */
+ case 0x20: /* I2C_SYSC */
if (s->revision < OMAP2_INTR_REV) {
OMAP_BAD_REG(addr);
return;
@@ -332,9 +332,9 @@ static void omap_i2c_write(void *opaque, hwaddr addr,
}
break;
- case 0x24: /* I2C_CON */
+ case 0x24: /* I2C_CON */
s->control = value & 0xcf87;
- if (~value & (1 << 15)) { /* I2C_EN */
+ if (~value & (1 << 15)) { /* I2C_EN */
if (s->revision < OMAP2_INTR_REV) {
omap_i2c_reset(DEVICE(s));
}
@@ -351,14 +351,14 @@ static void omap_i2c_write(void *opaque, hwaddr addr,
__func__);
break;
}
- if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */
- nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */
- (~value >> 9) & 1); /* TRX */
- s->stat |= nack << 1; /* NACK */
- s->control &= ~(1 << 0); /* STT */
+ if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */
+ nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */
+ (~value >> 9) & 1); /* TRX */
+ s->stat |= nack << 1; /* NACK */
+ s->control &= ~(1 << 0); /* STT */
s->fifo = 0;
if (nack)
- s->control &= ~(1 << 1); /* STP */
+ s->control &= ~(1 << 1); /* STP */
else {
s->count_cur = s->count;
omap_i2c_fifo_run(s);
@@ -367,34 +367,34 @@ static void omap_i2c_write(void *opaque, hwaddr addr,
}
break;
- case 0x28: /* I2C_OA */
+ case 0x28: /* I2C_OA */
s->addr[0] = value & 0x3ff;
break;
- case 0x2c: /* I2C_SA */
+ case 0x2c: /* I2C_SA */
s->addr[1] = value & 0x3ff;
break;
- case 0x30: /* I2C_PSC */
+ case 0x30: /* I2C_PSC */
s->divider = value;
break;
- case 0x34: /* I2C_SCLL */
+ case 0x34: /* I2C_SCLL */
s->times[0] = value;
break;
- case 0x38: /* I2C_SCLH */
+ case 0x38: /* I2C_SCLH */
s->times[1] = value;
break;
- case 0x3c: /* I2C_SYSTEST */
+ case 0x3c: /* I2C_SYSTEST */
s->test = value & 0xf80f;
- if (value & (1 << 11)) /* SBB */
+ if (value & (1 << 11)) /* SBB */
if (s->revision >= OMAP2_INTR_REV) {
s->stat |= 0x3f;
omap_i2c_interrupts_update(s);
}
- if (value & (1 << 15)) { /* ST_EN */
+ if (value & (1 << 15)) { /* ST_EN */
qemu_log_mask(LOG_UNIMP,
"%s: System Test not supported\n", __func__);
}
@@ -413,7 +413,7 @@ static void omap_i2c_writeb(void *opaque, hwaddr addr,
int offset = addr & OMAP_MPUI_REG_MASK;
switch (offset) {
- case 0x1c: /* I2C_DATA */
+ case 0x1c: /* I2C_DATA */
if (s->txlen > 2) {
/* XXX: remote access (qualifier) error - what's that? */
break;
@@ -421,9 +421,9 @@ static void omap_i2c_writeb(void *opaque, hwaddr addr,
s->fifo <<= 8;
s->txlen += 1;
s->fifo |= value & 0xff;
- s->stat &= ~(1 << 10); /* XUDF */
+ s->stat &= ~(1 << 10); /* XUDF */
if (s->txlen > 2)
- s->stat &= ~(1 << 4); /* XRDY */
+ s->stat &= ~(1 << 4); /* XRDY */
omap_i2c_fifo_run(s);
omap_i2c_interrupts_update(s);
break;
@@ -511,17 +511,16 @@ void omap_i2c_set_fclk(OMAPI2CState *i2c, omap_clk clk)
i2c->fclk = clk;
}
-static Property omap_i2c_properties[] = {
+static const Property omap_i2c_properties[] = {
DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void omap_i2c_class_init(ObjectClass *klass, void *data)
+static void omap_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, omap_i2c_properties);
- dc->reset = omap_i2c_reset;
+ device_class_set_legacy_reset(dc, omap_i2c_reset);
/* Reason: pointer properties "iclk", "fclk" */
dc->user_creatable = false;
dc->realize = omap_i2c_realize;
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 3eed811..4e685fd 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -205,7 +205,6 @@ out:
error:
s->smb_stat |= STS_DEV_ERR;
- return;
}
static void smb_transaction_start(PMSMBus *s)
diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c
index ba1d2fd..853dc4b 100644
--- a/hw/i2c/pmbus_device.c
+++ b/hw/i2c/pmbus_device.c
@@ -1902,7 +1902,7 @@ static void pmbus_device_finalize(Object *obj)
g_free(pmdev->pages);
}
-static void pmbus_device_class_init(ObjectClass *klass, void *data)
+static void pmbus_device_class_init(ObjectClass *klass, const void *data)
{
SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass);
diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c
index 75d50f1..09d4c49 100644
--- a/hw/i2c/ppc4xx_i2c.c
+++ b/hw/i2c/ppc4xx_i2c.c
@@ -354,11 +354,11 @@ static void ppc4xx_i2c_init(Object *o)
bitbang_i2c_init(&s->bitbang, s->bus);
}
-static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data)
+static void ppc4xx_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ppc4xx_i2c_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_i2c_reset);
}
static const TypeInfo ppc4xx_i2c_type_info = {
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index c42236b..0a1088f 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -137,13 +137,13 @@ static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
}
}
-static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
+static void smbus_eeprom_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
dc->realize = smbus_eeprom_realize;
- dc->reset = smbus_eeprom_reset;
+ device_class_set_legacy_reset(dc, smbus_eeprom_reset);
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
dc->vmsd = &vmstate_smbus_eeprom;
@@ -151,19 +151,16 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
dc->user_creatable = false;
}
-static const TypeInfo smbus_eeprom_info = {
- .name = TYPE_SMBUS_EEPROM,
- .parent = TYPE_SMBUS_DEVICE,
- .instance_size = sizeof(SMBusEEPROMDevice),
- .class_init = smbus_eeprom_class_initfn,
+static const TypeInfo smbus_eeprom_types[] = {
+ {
+ .name = TYPE_SMBUS_EEPROM,
+ .parent = TYPE_SMBUS_DEVICE,
+ .instance_size = sizeof(SMBusEEPROMDevice),
+ .class_init = smbus_eeprom_class_initfn,
+ },
};
-static void smbus_eeprom_register_types(void)
-{
- type_register_static(&smbus_eeprom_info);
-}
-
-type_init(smbus_eeprom_register_types)
+DEFINE_TYPES(smbus_eeprom_types)
void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf)
{
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 208f263..956c9b5 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -118,7 +118,7 @@ static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope)
qbus_build_aml(bus, scope);
}
-static void ich9_smb_class_init(ObjectClass *klass, void *data)
+static void ich9_smb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -145,7 +145,7 @@ static const TypeInfo ich9_smb_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(ICH9SMBState),
.class_init = ich9_smb_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ TYPE_ACPI_DEV_AML_IF },
{ },
diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c
index 9f9afc2..cfb61c8 100644
--- a/hw/i2c/smbus_slave.c
+++ b/hw/i2c/smbus_slave.c
@@ -201,7 +201,7 @@ static int smbus_i2c_send(I2CSlave *s, uint8_t data)
return 0;
}
-static void smbus_device_class_init(ObjectClass *klass, void *data)
+static void smbus_device_class_init(ObjectClass *klass, const void *data)
{
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index 6900e06..1ad0e95 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -35,6 +35,11 @@ aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t va
aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x"
aspeed_i2c_bus_recv(const char *mode, int i, int count, uint8_t byte) "%s recv %d/%d 0x%02x"
+# mpc_i2c.c
+
+mpc_i2c_read(uint64_t addr, uint32_t value) "[0x%" PRIx64 "] -> 0x%02" PRIx32
+mpc_i2c_write(uint64_t addr, uint32_t value) "[0x%" PRIx64 "] <- 0x%02" PRIx32
+
# npcm7xx_smbus.c
npcm7xx_smbus_read(const char *id, uint64_t offset, uint64_t value, unsigned size) "%s offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
@@ -51,3 +56,8 @@ npcm7xx_smbus_recv_fifo(const char *id, uint8_t received, uint8_t expected) "%s
pca954x_write_bytes(uint8_t value) "PCA954X write data: 0x%02x"
pca954x_read_data(uint8_t value) "PCA954X read data: 0x%02x"
+
+# imx_i2c.c
+
+imx_i2c_read(const char *id, const char *reg, uint64_t ofs, uint64_t value) "%s:[%s (0x%" PRIx64 ")] -> 0x%02" PRIx64
+imx_i2c_write(const char *id, const char *reg, uint64_t ofs, uint64_t value) "%s:[%s (0x%" PRIx64 ")] <- 0x%02" PRIx64
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index f4a33b6..eb65bda 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -10,6 +10,11 @@ config SGX
bool
depends on KVM
+config TDX
+ bool
+ select X86_FW_OVMF
+ depends on KVM
+
config PC
bool
imply APPLESMC
@@ -26,6 +31,7 @@ config PC
imply QXL
imply SEV
imply SGX
+ imply TDX
imply TEST_DEVICES
imply TPM_CRB
imply TPM_TIS_ISA
@@ -43,6 +49,7 @@ config PC
select SERIAL_ISA
select ACPI_PCI
select ACPI_VMGENID
+ select ACPI_VMCLOCK
select VIRTIO_PMEM_SUPPORTED
select VIRTIO_MEM_SUPPORTED
select HV_BALLOON_SUPPORTED
@@ -129,6 +136,16 @@ config MICROVM
select USB_XHCI_SYSBUS
select I8254
+config NITRO_ENCLAVE
+ default y
+ depends on I386 && FDT # for MICROVM
+ depends on LIBCBOR && GNUTLS # for EIF and VIRTIO_NSM
+ depends on VHOST_USER # for VHOST_USER_VSOCK
+ select EIF
+ select MICROVM
+ select VHOST_USER_VSOCK
+ select VIRTIO_NSM
+
config X86_IOMMU
bool
depends on PC
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 5d4bd2b..61851cc 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -22,7 +22,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qnum.h"
+#include "qobject/qnum.h"
#include "acpi-build.h"
#include "acpi-common.h"
#include "qemu/bitmap.h"
@@ -40,18 +40,19 @@
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/input/i8042.h"
#include "hw/acpi/memory_hotplug.h"
-#include "sysemu/tpm.h"
+#include "system/tpm.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/vmgenid.h"
+#include "hw/acpi/vmclock.h"
#include "hw/acpi/erst.h"
#include "hw/acpi/piix4.h"
-#include "sysemu/tpm_backend.h"
+#include "system/tpm_backend.h"
#include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h"
#include "hw/mem/memory-device.h"
#include "hw/mem/nvdimm.h"
-#include "sysemu/numa.h"
-#include "sysemu/reset.h"
+#include "system/numa.h"
+#include "system/reset.h"
#include "hw/hyperv/vmbus-bridge.h"
/* Supported chipsets: */
@@ -68,7 +69,6 @@
#include "hw/acpi/utils.h"
#include "hw/acpi/pci.h"
#include "hw/acpi/cxl.h"
-#include "hw/acpi/acpi_generic_initiator.h"
#include "qom/qom-qobject.h"
#include "hw/i386/amd_iommu.h"
@@ -139,7 +139,7 @@ static void init_common_fadt_data(MachineState *ms, Object *o,
/*
* "ICH9-LPC" or "PIIX4_PM" has "smm-compat" property to keep the old
* behavior for compatibility irrelevant to smm_enabled, which doesn't
- * comforms to ACPI spec.
+ * conform to the ACPI spec.
*/
bool smm_enabled = object_property_get_bool(o, "smm-compat", NULL) ?
true : x86_machine_is_smm_enabled(x86ms);
@@ -589,8 +589,8 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
}
}
-static bool build_append_notfication_callback(Aml *parent_scope,
- const PCIBus *bus)
+static bool build_append_notification_callback(Aml *parent_scope,
+ const PCIBus *bus)
{
Aml *method;
PCIBus *sec;
@@ -604,7 +604,7 @@ static bool build_append_notfication_callback(Aml *parent_scope,
continue;
}
nr_notifiers = nr_notifiers +
- build_append_notfication_callback(br_scope, sec);
+ build_append_notification_callback(br_scope, sec);
/*
* add new child scope to parent
* and keep track of bus that have PCNT,
@@ -655,6 +655,7 @@ static Aml *aml_pci_pdsm(void)
Aml *acpi_index = aml_local(2);
Aml *zero = aml_int(0);
Aml *one = aml_int(1);
+ Aml *not_supp = aml_int(0xFFFFFFFF);
Aml *func = aml_arg(2);
Aml *params = aml_arg(4);
Aml *bnum = aml_derefof(aml_index(params, aml_int(0)));
@@ -679,7 +680,7 @@ static Aml *aml_pci_pdsm(void)
*/
ifctx1 = aml_if(aml_lnot(
aml_or(aml_equal(acpi_index, zero),
- aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL)
+ aml_equal(acpi_index, not_supp), NULL)
));
{
/* have supported functions */
@@ -705,18 +706,30 @@ static Aml *aml_pci_pdsm(void)
{
Aml *pkg = aml_package(2);
- aml_append(pkg, zero);
- /*
- * optional, if not impl. should return null string
- */
- aml_append(pkg, aml_string("%s", ""));
- aml_append(ifctx, aml_store(pkg, ret));
-
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
+ aml_append(ifctx, aml_store(pkg, ret));
/*
- * update acpi-index to actual value
+ * Windows calls func=7 without checking if it's available,
+ * as workaround Microsoft has suggested to return invalid for func7
+ * Package, so return 2 elements package but only initialize elements
+ * when acpi_index is supported and leave them uninitialized, which
+ * leads elements to being Uninitialized ObjectType and should trip
+ * Windows into discarding result as an unexpected and prevent setting
+ * bogus 'PCI Label' on the device.
*/
- aml_append(ifctx, aml_store(acpi_index, aml_index(ret, zero)));
+ ifctx1 = aml_if(aml_lnot(aml_lor(
+ aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp)
+ )));
+ {
+ aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
+ /*
+ * optional, if not impl. should return null string
+ */
+ aml_append(ifctx1, aml_store(aml_string("%s", ""),
+ aml_index(ret, one)));
+ }
+ aml_append(ifctx, ifctx1);
+
aml_append(ifctx, aml_return(ret));
}
@@ -724,120 +737,45 @@ static Aml *aml_pci_pdsm(void)
return method;
}
-/**
- * build_prt_entry:
- * @link_name: link name for PCI route entry
- *
- * build AML package containing a PCI route entry for @link_name
- */
-static Aml *build_prt_entry(const char *link_name)
-{
- Aml *a_zero = aml_int(0);
- Aml *pkg = aml_package(4);
- aml_append(pkg, a_zero);
- aml_append(pkg, a_zero);
- aml_append(pkg, aml_name("%s", link_name));
- aml_append(pkg, a_zero);
- return pkg;
-}
-
/*
- * initialize_route - Initialize the interrupt routing rule
- * through a specific LINK:
- * if (lnk_idx == idx)
- * route using link 'link_name'
- */
-static Aml *initialize_route(Aml *route, const char *link_name,
- Aml *lnk_idx, int idx)
-{
- Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx)));
- Aml *pkg = build_prt_entry(link_name);
-
- aml_append(if_ctx, aml_store(pkg, route));
-
- return if_ctx;
-}
-
-/*
- * build_prt - Define interrupt rounting rules
+ * build_prt - Define interrupt routing rules
*
* Returns an array of 128 routes, one for each device,
* based on device location.
* The main goal is to equally distribute the interrupts
* over the 4 existing ACPI links (works only for i440fx).
- * The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]".
+ * The hash function is: (slot + pin) & 3 -> "LNK[D|A|B|C]".
*
*/
static Aml *build_prt(bool is_pci0_prt)
{
- Aml *method, *while_ctx, *pin, *res;
+ const int nroutes = 128;
+ Aml *rt_pkg, *method;
+ int pin;
method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
- res = aml_local(0);
- pin = aml_local(1);
- aml_append(method, aml_store(aml_package(128), res));
- aml_append(method, aml_store(aml_int(0), pin));
-
- /* while (pin < 128) */
- while_ctx = aml_while(aml_lless(pin, aml_int(128)));
- {
- Aml *slot = aml_local(2);
- Aml *lnk_idx = aml_local(3);
- Aml *route = aml_local(4);
-
- /* slot = pin >> 2 */
- aml_append(while_ctx,
- aml_store(aml_shiftright(pin, aml_int(2), NULL), slot));
- /* lnk_idx = (slot + pin) & 3 */
- aml_append(while_ctx,
- aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL),
- lnk_idx));
-
- /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */
- aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0));
- if (is_pci0_prt) {
- Aml *if_device_1, *if_pin_4, *else_pin_4;
-
- /* device 1 is the power-management device, needs SCI */
- if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1)));
- {
- if_pin_4 = aml_if(aml_equal(pin, aml_int(4)));
- {
- aml_append(if_pin_4,
- aml_store(build_prt_entry("LNKS"), route));
- }
- aml_append(if_device_1, if_pin_4);
- else_pin_4 = aml_else();
- {
- aml_append(else_pin_4,
- aml_store(build_prt_entry("LNKA"), route));
- }
- aml_append(if_device_1, else_pin_4);
- }
- aml_append(while_ctx, if_device_1);
+ assert(nroutes < 256);
+ rt_pkg = aml_package(nroutes);
+
+ for (pin = 0; pin < nroutes; pin++) {
+ Aml *pkg = aml_package(4);
+ int slot = pin >> 2;
+
+ aml_append(pkg, aml_int((slot << 16) | 0xFFFF));
+ aml_append(pkg, aml_int(pin & 3));
+ /* device 1 is the power-management device, needs SCI */
+ if (is_pci0_prt && pin == 4) {
+ aml_append(pkg, aml_name("%s", "LNKS"));
} else {
- aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, 1));
+ static const char link_name[][5] = {"LNKD", "LNKA", "LNKB", "LNKC"};
+ int hash = (slot + pin) & 3;
+ aml_append(pkg, aml_name("%s", link_name[hash]));
}
- aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2));
- aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3));
-
- /* route[0] = 0x[slot]FFFF */
- aml_append(while_ctx,
- aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF),
- NULL),
- aml_index(route, aml_int(0))));
- /* route[1] = pin & 3 */
- aml_append(while_ctx,
- aml_store(aml_and(pin, aml_int(3), NULL),
- aml_index(route, aml_int(1))));
- /* res[pin] = route */
- aml_append(while_ctx, aml_store(route, aml_index(res, pin)));
- /* pin++ */
- aml_append(while_ctx, aml_increment(pin));
+ aml_append(pkg, aml_int(0));
+ aml_append(rt_pkg, pkg);
}
- aml_append(method, while_ctx);
- /* return res*/
- aml_append(method, aml_return(res));
+
+ aml_append(method, aml_return(rt_pkg));
return method;
}
@@ -1552,6 +1490,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
QLIST_FOREACH(bus, &bus->child, sibling) {
uint8_t bus_num = pci_bus_num(bus);
uint8_t numa_node = pci_bus_numa_node(bus);
+ uint32_t uid;
/* look only for expander root buses */
if (!pci_bus_is_root(bus)) {
@@ -1562,6 +1501,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
root_bus_limit = bus_num - 1;
}
+ uid = object_property_get_uint(OBJECT(bus), "acpi_uid",
+ &error_fatal);
scope = aml_scope("\\_SB");
if (pci_bus_is_cxl(bus)) {
@@ -1569,7 +1510,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
} else {
dev = aml_device("PC%.02X", bus_num);
}
- aml_append(dev, aml_name_decl("_UID", aml_int(bus_num)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
if (pci_bus_is_cxl(bus)) {
struct Aml *aml_pkg = aml_package(2);
@@ -1832,7 +1773,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
PCIBus *b = PCI_HOST_BRIDGE(pci_host)->bus;
scope = aml_scope("\\_SB.PCI0");
- has_pcnt = build_append_notfication_callback(scope, b);
+ has_pcnt = build_append_notification_callback(scope, b);
if (has_pcnt) {
aml_append(dsdt, scope);
}
@@ -2047,7 +1988,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
build_srat_memory(table_data, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
}
- build_srat_generic_pci_initiator(table_data);
+ build_srat_generic_affinity_structures(table_data);
/*
* Entry is required for Windows to enable memory hotplug in OS
@@ -2392,12 +2333,12 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
build_append_int_noprefix(table_data, ivhd_blob->len + 24, 2);
/* DeviceID */
build_append_int_noprefix(table_data,
- object_property_get_int(OBJECT(&s->pci), "addr",
+ object_property_get_int(OBJECT(s->pci), "addr",
&error_abort), 2);
/* Capability offset */
- build_append_int_noprefix(table_data, s->pci.capab_offset, 2);
+ build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
/* IOMMU base address */
- build_append_int_noprefix(table_data, s->mmio.addr, 8);
+ build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
/* PCI Segment Group */
build_append_int_noprefix(table_data, 0, 2);
/* IOMMU info */
@@ -2427,12 +2368,12 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
build_append_int_noprefix(table_data, ivhd_blob->len + 40, 2);
/* DeviceID */
build_append_int_noprefix(table_data,
- object_property_get_int(OBJECT(&s->pci), "addr",
+ object_property_get_int(OBJECT(s->pci), "addr",
&error_abort), 2);
/* Capability offset */
- build_append_int_noprefix(table_data, s->pci.capab_offset, 2);
+ build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
/* IOMMU base address */
- build_append_int_noprefix(table_data, s->mmio.addr, 8);
+ build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
/* PCI Segment Group */
build_append_int_noprefix(table_data, 0, 2);
/* IOMMU info */
@@ -2505,7 +2446,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
uint8_t *u;
GArray *tables_blob = tables->table_data;
AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
- Object *vmgenid_dev;
+ Object *vmgenid_dev, *vmclock_dev;
char *oem_id;
char *oem_table_id;
@@ -2578,6 +2519,13 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
tables->vmgenid, tables->linker, x86ms->oem_id);
}
+ vmclock_dev = find_vmclock_dev();
+ if (vmclock_dev) {
+ acpi_add_table(table_offsets, tables_blob);
+ vmclock_build_acpi(VMCLOCK(vmclock_dev), tables_blob, tables->linker,
+ x86ms->oem_id);
+ }
+
if (misc.has_hpet) {
acpi_add_table(table_offsets, tables_blob);
build_hpet(tables_blob, tables->linker, x86ms->oem_id,
diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h
index 0dce155..275ec05 100644
--- a/hw/i386/acpi-build.h
+++ b/hw/i386/acpi-build.h
@@ -5,7 +5,7 @@
extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio;
-/* PCI Hot-plug registers bases. See docs/spec/acpi_pci_hotplug.txt */
+/* PCI Hot-plug registers' base. See docs/specs/acpi_pci_hotplug.rst */
#define ACPI_PCIHP_SEJ_BASE 0x8
#define ACPI_PCIHP_BNMR_BASE 0x10
diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c
index 0cc2919..7bd0806 100644
--- a/hw/i386/acpi-common.c
+++ b/hw/i386/acpi-common.c
@@ -23,7 +23,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/utils.h"
diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
index 279da6b..bc65717 100644
--- a/hw/i386/acpi-microvm.c
+++ b/hw/i386/acpi-microvm.c
@@ -24,7 +24,7 @@
#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/acpi/aml-build.h"
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 87643d2..963aa24 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -32,6 +32,7 @@
#include "trace.h"
#include "hw/i386/apic-msidef.h"
#include "hw/qdev-properties.h"
+#include "kvm/kvm_i386.h"
/* used AMD-Vi MMIO registers */
const char *amdvi_mmio_low[] = {
@@ -60,8 +61,9 @@ struct AMDVIAddressSpace {
uint8_t bus_num; /* bus number */
uint8_t devfn; /* device function */
AMDVIState *iommu_state; /* AMDVI - one per machine */
- MemoryRegion root; /* AMDVI Root memory map region */
+ MemoryRegion root; /* AMDVI Root memory map region */
IOMMUMemoryRegion iommu; /* Device's address translation region */
+ MemoryRegion iommu_nodma; /* Alias of shared nodma memory region */
MemoryRegion iommu_ir; /* Device's interrupt remapping region */
AddressSpace as; /* device's corresponding address space */
};
@@ -165,11 +167,11 @@ static void amdvi_generate_msi_interrupt(AMDVIState *s)
{
MSIMessage msg = {};
MemTxAttrs attrs = {
- .requester_id = pci_requester_id(&s->pci.dev)
+ .requester_id = pci_requester_id(&s->pci->dev)
};
- if (msi_enabled(&s->pci.dev)) {
- msg = msi_get_message(&s->pci.dev, 0);
+ if (msi_enabled(&s->pci->dev)) {
+ msg = msi_get_message(&s->pci->dev, 0);
address_space_stl_le(&address_space_memory, msg.address, msg.data,
attrs, NULL);
}
@@ -237,7 +239,7 @@ static void amdvi_page_fault(AMDVIState *s, uint16_t devid,
info |= AMDVI_EVENT_IOPF_I | AMDVI_EVENT_IOPF;
amdvi_encode_event(evt, devid, addr, info);
amdvi_log_event(s, evt);
- pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS,
+ pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS,
PCI_STATUS_SIG_TARGET_ABORT);
}
/*
@@ -254,7 +256,7 @@ static void amdvi_log_devtab_error(AMDVIState *s, uint16_t devid,
amdvi_encode_event(evt, devid, devtab, info);
amdvi_log_event(s, evt);
- pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS,
+ pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS,
PCI_STATUS_SIG_TARGET_ABORT);
}
/* log an event trying to access command buffer
@@ -267,7 +269,7 @@ static void amdvi_log_command_error(AMDVIState *s, hwaddr addr)
amdvi_encode_event(evt, 0, addr, info);
amdvi_log_event(s, evt);
- pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS,
+ pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS,
PCI_STATUS_SIG_TARGET_ABORT);
}
/* log an illegal command event
@@ -308,7 +310,7 @@ static void amdvi_log_pagetab_error(AMDVIState *s, uint16_t devid,
info |= AMDVI_EVENT_PAGE_TAB_HW_ERROR;
amdvi_encode_event(evt, devid, addr, info);
amdvi_log_event(s, evt);
- pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS,
+ pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS,
PCI_STATUS_SIG_TARGET_ABORT);
}
@@ -430,6 +432,12 @@ static void amdvi_complete_ppr(AMDVIState *s, uint64_t *cmd)
trace_amdvi_ppr_exec();
}
+static void amdvi_intremap_inval_notify_all(AMDVIState *s, bool global,
+ uint32_t index, uint32_t mask)
+{
+ x86_iommu_iec_notify_all(X86_IOMMU_DEVICE(s), global, index, mask);
+}
+
static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd)
{
if (extract64(cmd[0], 0, 60) || cmd[1]) {
@@ -437,6 +445,9 @@ static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd)
s->cmdbuf + s->cmdbuf_head);
}
+ /* Notify global invalidation */
+ amdvi_intremap_inval_notify_all(s, true, 0, 0);
+
amdvi_iotlb_reset(s);
trace_amdvi_all_inval();
}
@@ -485,6 +496,9 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd)
return;
}
+ /* Notify global invalidation */
+ amdvi_intremap_inval_notify_all(s, true, 0, 0);
+
trace_amdvi_intr_inval();
}
@@ -1295,15 +1309,15 @@ static int amdvi_int_remap_msi(AMDVIState *iommu,
ret = -AMDVI_IR_ERR;
break;
case AMDVI_IOAPIC_INT_TYPE_NMI:
- pass = dte[3] & AMDVI_DEV_NMI_PASS_MASK;
+ pass = dte[2] & AMDVI_DEV_NMI_PASS_MASK;
trace_amdvi_ir_delivery_mode("nmi");
break;
case AMDVI_IOAPIC_INT_TYPE_INIT:
- pass = dte[3] & AMDVI_DEV_INT_PASS_MASK;
+ pass = dte[2] & AMDVI_DEV_INT_PASS_MASK;
trace_amdvi_ir_delivery_mode("init");
break;
case AMDVI_IOAPIC_INT_TYPE_EINT:
- pass = dte[3] & AMDVI_DEV_EINT_PASS_MASK;
+ pass = dte[2] & AMDVI_DEV_EINT_PASS_MASK;
trace_amdvi_ir_delivery_mode("eint");
break;
default:
@@ -1436,13 +1450,13 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
* Memory region relationships looks like (Address range shows
* only lower 32 bits to make it short in length...):
*
- * |-----------------+-------------------+----------|
- * | Name | Address range | Priority |
- * |-----------------+-------------------+----------+
- * | amdvi_root | 00000000-ffffffff | 0 |
- * | amdvi_iommu | 00000000-ffffffff | 1 |
- * | amdvi_iommu_ir | fee00000-feefffff | 64 |
- * |-----------------+-------------------+----------|
+ * |--------------------+-------------------+----------|
+ * | Name | Address range | Priority |
+ * |--------------------+-------------------+----------+
+ * | amdvi-root | 00000000-ffffffff | 0 |
+ * | amdvi-iommu_nodma | 00000000-ffffffff | 0 |
+ * | amdvi-iommu_ir | fee00000-feefffff | 1 |
+ * |--------------------+-------------------+----------|
*/
memory_region_init_iommu(&amdvi_dev_as->iommu,
sizeof(amdvi_dev_as->iommu),
@@ -1452,16 +1466,27 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
memory_region_init(&amdvi_dev_as->root, OBJECT(s),
"amdvi_root", UINT64_MAX);
address_space_init(&amdvi_dev_as->as, &amdvi_dev_as->root, name);
- memory_region_init_io(&amdvi_dev_as->iommu_ir, OBJECT(s),
- &amdvi_ir_ops, s, "amd_iommu_ir",
- AMDVI_INT_ADDR_SIZE);
- memory_region_add_subregion_overlap(&amdvi_dev_as->root,
- AMDVI_INT_ADDR_FIRST,
- &amdvi_dev_as->iommu_ir,
- 64);
memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
MEMORY_REGION(&amdvi_dev_as->iommu),
- 1);
+ 0);
+
+ /* Build the DMA Disabled alias to shared memory */
+ memory_region_init_alias(&amdvi_dev_as->iommu_nodma, OBJECT(s),
+ "amdvi-sys", &s->mr_sys, 0,
+ memory_region_size(&s->mr_sys));
+ memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
+ &amdvi_dev_as->iommu_nodma,
+ 0);
+ /* Build the Interrupt Remapping alias to shared memory */
+ memory_region_init_alias(&amdvi_dev_as->iommu_ir, OBJECT(s),
+ "amdvi-ir", &s->mr_ir, 0,
+ memory_region_size(&s->mr_ir));
+ memory_region_add_subregion_overlap(MEMORY_REGION(&amdvi_dev_as->iommu),
+ AMDVI_INT_ADDR_FIRST,
+ &amdvi_dev_as->iommu_ir, 1);
+
+ memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false);
+ memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), true);
}
return &iommu_as[devfn]->as;
}
@@ -1560,9 +1585,9 @@ static void amdvi_pci_realize(PCIDevice *pdev, Error **errp)
/* reset AMDVI specific capabilities, all r/o */
pci_set_long(pdev->config + s->capab_offset, AMDVI_CAPAB_FEATURES);
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_BAR_LOW,
- AMDVI_BASE_ADDR & ~(0xffff0000));
+ AMDVI_BASE_ADDR & MAKE_64BIT_MASK(14, 18));
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_BAR_HIGH,
- (AMDVI_BASE_ADDR & ~(0xffff)) >> 16);
+ AMDVI_BASE_ADDR >> 32);
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_RANGE,
0xff000000);
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_MISC, 0);
@@ -1574,41 +1599,137 @@ static void amdvi_sysbus_reset(DeviceState *dev)
{
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
- msi_reset(&s->pci.dev);
+ msi_reset(&s->pci->dev);
amdvi_init(s);
}
+static const VMStateDescription vmstate_amdvi_sysbus_migratable = {
+ .name = "amd-iommu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .priority = MIG_PRI_IOMMU,
+ .fields = (VMStateField[]) {
+ /* Updated in amdvi_handle_control_write() */
+ VMSTATE_BOOL(enabled, AMDVIState),
+ VMSTATE_BOOL(ga_enabled, AMDVIState),
+ VMSTATE_BOOL(ats_enabled, AMDVIState),
+ VMSTATE_BOOL(cmdbuf_enabled, AMDVIState),
+ VMSTATE_BOOL(completion_wait_intr, AMDVIState),
+ VMSTATE_BOOL(evtlog_enabled, AMDVIState),
+ VMSTATE_BOOL(evtlog_intr, AMDVIState),
+ /* Updated in amdvi_handle_devtab_write() */
+ VMSTATE_UINT64(devtab, AMDVIState),
+ VMSTATE_UINT64(devtab_len, AMDVIState),
+ /* Updated in amdvi_handle_cmdbase_write() */
+ VMSTATE_UINT64(cmdbuf, AMDVIState),
+ VMSTATE_UINT64(cmdbuf_len, AMDVIState),
+ /* Updated in amdvi_handle_cmdhead_write() */
+ VMSTATE_UINT32(cmdbuf_head, AMDVIState),
+ /* Updated in amdvi_handle_cmdtail_write() */
+ VMSTATE_UINT32(cmdbuf_tail, AMDVIState),
+ /* Updated in amdvi_handle_evtbase_write() */
+ VMSTATE_UINT64(evtlog, AMDVIState),
+ VMSTATE_UINT32(evtlog_len, AMDVIState),
+ /* Updated in amdvi_handle_evthead_write() */
+ VMSTATE_UINT32(evtlog_head, AMDVIState),
+ /* Updated in amdvi_handle_evttail_write() */
+ VMSTATE_UINT32(evtlog_tail, AMDVIState),
+ /* Updated in amdvi_handle_pprbase_write() */
+ VMSTATE_UINT64(ppr_log, AMDVIState),
+ VMSTATE_UINT32(pprlog_len, AMDVIState),
+ /* Updated in amdvi_handle_pprhead_write() */
+ VMSTATE_UINT32(pprlog_head, AMDVIState),
+ /* Updated in amdvi_handle_tailhead_write() */
+ VMSTATE_UINT32(pprlog_tail, AMDVIState),
+ /* MMIO registers */
+ VMSTATE_UINT8_ARRAY(mmior, AMDVIState, AMDVI_MMIO_SIZE),
+ VMSTATE_UINT8_ARRAY(romask, AMDVIState, AMDVI_MMIO_SIZE),
+ VMSTATE_UINT8_ARRAY(w1cmask, AMDVIState, AMDVI_MMIO_SIZE),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
{
+ DeviceClass *dc = (DeviceClass *) object_get_class(OBJECT(dev));
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
MachineState *ms = MACHINE(qdev_get_machine());
PCMachineState *pcms = PC_MACHINE(ms);
X86MachineState *x86ms = X86_MACHINE(ms);
PCIBus *bus = pcms->pcibus;
- s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
- amdvi_uint64_equal, g_free, g_free);
+ if (s->pci_id) {
+ PCIDevice *pdev = NULL;
+ int ret = pci_qdev_find_device(s->pci_id, &pdev);
- /* This device should take care of IOMMU PCI properties */
- if (!qdev_realize(DEVICE(&s->pci), &bus->qbus, errp)) {
- return;
+ if (ret) {
+ error_report("Cannot find PCI device '%s'", s->pci_id);
+ return;
+ }
+
+ if (!object_dynamic_cast(OBJECT(pdev), TYPE_AMD_IOMMU_PCI)) {
+ error_report("Device '%s' must be an AMDVI-PCI device type", s->pci_id);
+ return;
+ }
+
+ s->pci = AMD_IOMMU_PCI(pdev);
+ dc->vmsd = &vmstate_amdvi_sysbus_migratable;
+ } else {
+ s->pci = AMD_IOMMU_PCI(object_new(TYPE_AMD_IOMMU_PCI));
+ /* This device should take care of IOMMU PCI properties */
+ if (!qdev_realize(DEVICE(s->pci), &bus->qbus, errp)) {
+ return;
+ }
}
+ s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
+ amdvi_uint64_equal, g_free, g_free);
+
/* Pseudo address space under root PCI bus. */
x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
/* set up MMIO */
- memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
- AMDVI_MMIO_SIZE);
+ memory_region_init_io(&s->mr_mmio, OBJECT(s), &mmio_mem_ops, s,
+ "amdvi-mmio", AMDVI_MMIO_SIZE);
memory_region_add_subregion(get_system_memory(), AMDVI_BASE_ADDR,
- &s->mmio);
+ &s->mr_mmio);
+
+ /* Create the share memory regions by all devices */
+ memory_region_init(&s->mr_sys, OBJECT(s), "amdvi-sys", UINT64_MAX);
+
+ /* set up the DMA disabled memory region */
+ memory_region_init_alias(&s->mr_nodma, OBJECT(s),
+ "amdvi-nodma", get_system_memory(), 0,
+ memory_region_size(get_system_memory()));
+ memory_region_add_subregion_overlap(&s->mr_sys, 0,
+ &s->mr_nodma, 0);
+
+ /* set up the Interrupt Remapping memory region */
+ memory_region_init_io(&s->mr_ir, OBJECT(s), &amdvi_ir_ops,
+ s, "amdvi-ir", AMDVI_INT_ADDR_SIZE);
+ memory_region_add_subregion_overlap(&s->mr_sys, AMDVI_INT_ADDR_FIRST,
+ &s->mr_ir, 1);
+
+ if (kvm_enabled() && x86ms->apic_id_limit > 255 && !s->xtsup) {
+ error_report("AMD IOMMU with x2APIC configuration requires xtsup=on");
+ exit(EXIT_FAILURE);
+ }
+
+ if (s->xtsup) {
+ if (kvm_irqchip_is_split() && !kvm_enable_x2apic()) {
+ error_report("AMD IOMMU xtsup=on requires x2APIC support on "
+ "the KVM side");
+ exit(EXIT_FAILURE);
+ }
+ }
+
pci_setup_iommu(bus, &amdvi_iommu_ops, s);
amdvi_init(s);
}
-static Property amdvi_properties[] = {
+static const Property amdvi_properties[] = {
DEFINE_PROP_BOOL("xtsup", AMDVIState, xtsup, false),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_STRING("pci-id", AMDVIState, pci_id),
};
static const VMStateDescription vmstate_amdvi_sysbus = {
@@ -1616,25 +1737,16 @@ static const VMStateDescription vmstate_amdvi_sysbus = {
.unmigratable = 1
};
-static void amdvi_sysbus_instance_init(Object *klass)
-{
- AMDVIState *s = AMD_IOMMU_DEVICE(klass);
-
- object_initialize(&s->pci, sizeof(s->pci), TYPE_AMD_IOMMU_PCI);
-}
-
-static void amdvi_sysbus_class_init(ObjectClass *klass, void *data)
+static void amdvi_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
X86IOMMUClass *dc_class = X86_IOMMU_DEVICE_CLASS(klass);
- dc->reset = amdvi_sysbus_reset;
+ device_class_set_legacy_reset(dc, amdvi_sysbus_reset);
dc->vmsd = &vmstate_amdvi_sysbus;
dc->hotpluggable = false;
dc_class->realize = amdvi_sysbus_realize;
dc_class->int_remap = amdvi_int_remap;
- /* Supported by the pc-q35-* machine types */
- dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "AMD IOMMU (AMD-Vi) DMA Remapping device";
device_class_set_props(dc, amdvi_properties);
@@ -1644,16 +1756,16 @@ static const TypeInfo amdvi_sysbus = {
.name = TYPE_AMD_IOMMU_DEVICE,
.parent = TYPE_X86_IOMMU_DEVICE,
.instance_size = sizeof(AMDVIState),
- .instance_init = amdvi_sysbus_instance_init,
.class_init = amdvi_sysbus_class_init
};
-static void amdvi_pci_class_init(ObjectClass *klass, void *data)
+static void amdvi_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->vendor_id = PCI_VENDOR_ID_AMD;
+ k->device_id = 0x1419;
k->class_id = 0x0806;
k->realize = amdvi_pci_realize;
@@ -1666,13 +1778,14 @@ static const TypeInfo amdvi_pci = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(AMDVIPCIState),
.class_init = amdvi_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+static void amdvi_iommu_memory_region_class_init(ObjectClass *klass,
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index 73619fe..5672bde 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -187,7 +187,7 @@
AMDVI_CAPAB_FLAG_HTTUNNEL | AMDVI_CAPAB_EFR_SUP)
/* AMDVI default address */
-#define AMDVI_BASE_ADDR 0xfed80000
+#define AMDVI_BASE_ADDR 0xfed80000ULL
/* page management constants */
#define AMDVI_PAGE_SHIFT 12
@@ -315,7 +315,8 @@ struct AMDVIPCIState {
struct AMDVIState {
X86IOMMUState iommu; /* IOMMU bus device */
- AMDVIPCIState pci; /* IOMMU PCI device */
+ AMDVIPCIState *pci; /* IOMMU PCI device */
+ char *pci_id; /* ID of AMDVI-PCI device, if user created */
uint32_t version;
@@ -328,7 +329,7 @@ struct AMDVIState {
bool excl_enabled;
hwaddr devtab; /* base address device table */
- size_t devtab_len; /* device table length */
+ uint64_t devtab_len; /* device table length */
hwaddr cmdbuf; /* command buffer base address */
uint64_t cmdbuf_len; /* command buffer length */
@@ -353,7 +354,10 @@ struct AMDVIState {
uint32_t pprlog_head; /* ppr log head */
uint32_t pprlog_tail; /* ppr log tail */
- MemoryRegion mmio; /* MMIO region */
+ MemoryRegion mr_mmio; /* MMIO region */
+ MemoryRegion mr_sys;
+ MemoryRegion mr_nodma;
+ MemoryRegion mr_ir;
uint8_t mmior[AMDVI_MMIO_SIZE]; /* read/write MMIO */
uint8_t w1cmask[AMDVI_MMIO_SIZE]; /* read/write 1 clear mask */
uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index 0e44946..5c0bcd5 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -13,7 +13,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
#include "hw/firmware/smbios.h"
@@ -26,7 +26,9 @@
#include CONFIG_DEVICES
#include "target/i386/cpu.h"
-struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
+#if !defined(CONFIG_HPET)
+struct hpet_fw_config hpet_fw_cfg = {.count = UINT8_MAX};
+#endif
const char *fw_cfg_arch_key_name(uint16_t key)
{
@@ -143,13 +145,13 @@ FWCfgState *fw_cfg_arch_create(MachineState *ms,
*/
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, apic_id_limit);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ms->ram_size);
-#ifdef CONFIG_ACPI
- fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
- acpi_tables, acpi_tables_len);
-#endif
+ if (acpi_builtin()) {
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
+ acpi_tables, acpi_tables_len);
+ }
fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, 1);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg));
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_fw_cfg, sizeof(hpet_fw_cfg));
/* allocate memory for the NUMA channel: one (64bit) word for the number
* of nodes, one word for each VCPU->node and one word for each node to
* hold the amount of memory.
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 16d2885..69d72ad 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -32,9 +32,9 @@
#include "hw/i386/apic-msidef.h"
#include "hw/i386/x86-iommu.h"
#include "hw/pci-host/q35.h"
-#include "sysemu/kvm.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
+#include "system/kvm.h"
+#include "system/dma.h"
+#include "system/system.h"
#include "hw/i386/apic_internal.h"
#include "kvm/kvm_i386.h"
#include "migration/vmstate.h"
@@ -48,7 +48,10 @@
/* pe operations */
#define VTD_PE_GET_TYPE(pe) ((pe)->val[0] & VTD_SM_PASID_ENTRY_PGTT)
-#define VTD_PE_GET_LEVEL(pe) (2 + (((pe)->val[0] >> 2) & VTD_SM_PASID_ENTRY_AW))
+#define VTD_PE_GET_FL_LEVEL(pe) \
+ (4 + (((pe)->val[2] >> 2) & VTD_SM_PASID_ENTRY_FLPM))
+#define VTD_PE_GET_SL_LEVEL(pe) \
+ (2 + (((pe)->val[0] >> 2) & VTD_SM_PASID_ENTRY_AW))
/*
* PCI bus number (or SID) is not reliable since the device is usaully
@@ -67,6 +70,11 @@ struct vtd_hiod_key {
uint8_t devfn;
};
+struct vtd_as_raw_key {
+ uint16_t sid;
+ uint32_t pasid;
+};
+
struct vtd_iotlb_key {
uint64_t gfn;
uint32_t pasid;
@@ -284,15 +292,15 @@ static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value,
}
/* The shift of an addr for a certain level of paging structure */
-static inline uint32_t vtd_slpt_level_shift(uint32_t level)
+static inline uint32_t vtd_pt_level_shift(uint32_t level)
{
assert(level != 0);
- return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS;
+ return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_LEVEL_BITS;
}
-static inline uint64_t vtd_slpt_level_page_mask(uint32_t level)
+static inline uint64_t vtd_pt_level_page_mask(uint32_t level)
{
- return ~((1ULL << vtd_slpt_level_shift(level)) - 1);
+ return ~((1ULL << vtd_pt_level_shift(level)) - 1);
}
static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
@@ -302,9 +310,43 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
- return (entry->domain_id == info->domain_id) &&
- (((entry->gfn & info->mask) == gfn) ||
- (entry->gfn == gfn_tlb));
+
+ if (entry->domain_id != info->domain_id) {
+ return false;
+ }
+
+ /*
+ * According to spec, IOTLB entries caching first-stage (PGTT=001b) or
+ * nested (PGTT=011b) mapping associated with specified domain-id are
+ * invalidated. Nested isn't supported yet, so only need to check 001b.
+ */
+ if (entry->pgtt == VTD_SM_PASID_ENTRY_FLT) {
+ return true;
+ }
+
+ return (entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb;
+}
+
+static gboolean vtd_hash_remove_by_page_piotlb(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
+ VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
+ uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
+ uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
+
+ /*
+ * According to spec, PASID-based-IOTLB Invalidation in page granularity
+ * doesn't invalidate IOTLB entries caching second-stage (PGTT=010b)
+ * or pass-through (PGTT=100b) mappings. Nested isn't supported yet,
+ * so only need to check first-stage (PGTT=001b) mappings.
+ */
+ if (entry->pgtt != VTD_SM_PASID_ENTRY_FLT) {
+ return false;
+ }
+
+ return entry->domain_id == info->domain_id && entry->pasid == info->pasid &&
+ ((entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb);
}
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
@@ -349,7 +391,7 @@ static void vtd_reset_caches(IntelIOMMUState *s)
static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level)
{
- return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K;
+ return (addr & vtd_pt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K;
}
/* Must be called with IOMMU lock held */
@@ -360,7 +402,7 @@ static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
VTDIOTLBEntry *entry;
unsigned level;
- for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) {
+ for (level = VTD_PT_LEVEL; level < VTD_PML4_LEVEL; level++) {
key.gfn = vtd_get_iotlb_gfn(addr, level);
key.level = level;
key.sid = source_id;
@@ -377,15 +419,15 @@ out:
/* Must be with IOMMU lock held */
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
- uint16_t domain_id, hwaddr addr, uint64_t slpte,
+ uint16_t domain_id, hwaddr addr, uint64_t pte,
uint8_t access_flags, uint32_t level,
- uint32_t pasid)
+ uint32_t pasid, uint8_t pgtt)
{
VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
struct vtd_iotlb_key *key = g_malloc(sizeof(*key));
uint64_t gfn = vtd_get_iotlb_gfn(addr, level);
- trace_vtd_iotlb_page_update(source_id, addr, slpte, domain_id);
+ trace_vtd_iotlb_page_update(source_id, addr, pte, domain_id);
if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) {
trace_vtd_iotlb_reset("iotlb exceeds size limit");
vtd_reset_iotlb_locked(s);
@@ -393,10 +435,11 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
entry->gfn = gfn;
entry->domain_id = domain_id;
- entry->slpte = slpte;
+ entry->pte = pte;
entry->access_flags = access_flags;
- entry->mask = vtd_slpt_level_page_mask(level);
+ entry->mask = vtd_pt_level_page_mask(level);
entry->pasid = pasid;
+ entry->pgtt = pgtt;
key->gfn = gfn;
key->sid = source_id;
@@ -710,32 +753,32 @@ static inline dma_addr_t vtd_ce_get_slpt_base(VTDContextEntry *ce)
return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR;
}
-static inline uint64_t vtd_get_slpte_addr(uint64_t slpte, uint8_t aw)
+static inline uint64_t vtd_get_pte_addr(uint64_t pte, uint8_t aw)
{
- return slpte & VTD_SL_PT_BASE_ADDR_MASK(aw);
+ return pte & VTD_PT_BASE_ADDR_MASK(aw);
}
/* Whether the pte indicates the address of the page frame */
-static inline bool vtd_is_last_slpte(uint64_t slpte, uint32_t level)
+static inline bool vtd_is_last_pte(uint64_t pte, uint32_t level)
{
- return level == VTD_SL_PT_LEVEL || (slpte & VTD_SL_PT_PAGE_SIZE_MASK);
+ return level == VTD_PT_LEVEL || (pte & VTD_PT_PAGE_SIZE_MASK);
}
-/* Get the content of a spte located in @base_addr[@index] */
-static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index)
+/* Get the content of a pte located in @base_addr[@index] */
+static uint64_t vtd_get_pte(dma_addr_t base_addr, uint32_t index)
{
- uint64_t slpte;
+ uint64_t pte;
- assert(index < VTD_SL_PT_ENTRY_NR);
+ assert(index < VTD_PT_ENTRY_NR);
if (dma_memory_read(&address_space_memory,
- base_addr + index * sizeof(slpte),
- &slpte, sizeof(slpte), MEMTXATTRS_UNSPECIFIED)) {
- slpte = (uint64_t)-1;
- return slpte;
+ base_addr + index * sizeof(pte),
+ &pte, sizeof(pte), MEMTXATTRS_UNSPECIFIED)) {
+ pte = (uint64_t)-1;
+ return pte;
}
- slpte = le64_to_cpu(slpte);
- return slpte;
+ pte = le64_to_cpu(pte);
+ return pte;
}
/* Given an iova and the level of paging structure, return the offset
@@ -743,36 +786,39 @@ static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index)
*/
static inline uint32_t vtd_iova_level_offset(uint64_t iova, uint32_t level)
{
- return (iova >> vtd_slpt_level_shift(level)) &
- ((1ULL << VTD_SL_LEVEL_BITS) - 1);
+ return (iova >> vtd_pt_level_shift(level)) &
+ ((1ULL << VTD_LEVEL_BITS) - 1);
}
/* Check Capability Register to see if the @level of page-table is supported */
-static inline bool vtd_is_level_supported(IntelIOMMUState *s, uint32_t level)
+static inline bool vtd_is_sl_level_supported(IntelIOMMUState *s, uint32_t level)
{
return VTD_CAP_SAGAW_MASK & s->cap &
(1ULL << (level - 2 + VTD_CAP_SAGAW_SHIFT));
}
+static inline bool vtd_is_fl_level_supported(IntelIOMMUState *s, uint32_t level)
+{
+ return level == VTD_PML4_LEVEL;
+}
+
/* Return true if check passed, otherwise false */
-static inline bool vtd_pe_type_check(X86IOMMUState *x86_iommu,
- VTDPASIDEntry *pe)
+static inline bool vtd_pe_type_check(IntelIOMMUState *s, VTDPASIDEntry *pe)
{
switch (VTD_PE_GET_TYPE(pe)) {
case VTD_SM_PASID_ENTRY_FLT:
+ return !!(s->ecap & VTD_ECAP_FLTS);
case VTD_SM_PASID_ENTRY_SLT:
+ return !!(s->ecap & VTD_ECAP_SLTS);
case VTD_SM_PASID_ENTRY_NESTED:
- break;
+ /* Not support NESTED page table type yet */
+ return false;
case VTD_SM_PASID_ENTRY_PT:
- if (!x86_iommu->pt_supported) {
- return false;
- }
- break;
+ return !!(s->ecap & VTD_ECAP_PT);
default:
/* Unknown type */
return false;
}
- return true;
}
static inline bool vtd_pdire_present(VTDPASIDDirEntry *pdire)
@@ -796,7 +842,7 @@ static int vtd_get_pdire_from_pdir_table(dma_addr_t pasid_dir_base,
addr = pasid_dir_base + index * entry_size;
if (dma_memory_read(&address_space_memory, addr,
pdire, entry_size, MEMTXATTRS_UNSPECIFIED)) {
- return -VTD_FR_PASID_TABLE_INV;
+ return -VTD_FR_PASID_DIR_ACCESS_ERR;
}
pdire->val = le64_to_cpu(pdire->val);
@@ -814,28 +860,35 @@ static int vtd_get_pe_in_pasid_leaf_table(IntelIOMMUState *s,
dma_addr_t addr,
VTDPASIDEntry *pe)
{
+ uint8_t pgtt;
uint32_t index;
dma_addr_t entry_size;
- X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
index = VTD_PASID_TABLE_INDEX(pasid);
entry_size = VTD_PASID_ENTRY_SIZE;
addr = addr + index * entry_size;
if (dma_memory_read(&address_space_memory, addr,
pe, entry_size, MEMTXATTRS_UNSPECIFIED)) {
- return -VTD_FR_PASID_TABLE_INV;
+ return -VTD_FR_PASID_TABLE_ACCESS_ERR;
}
for (size_t i = 0; i < ARRAY_SIZE(pe->val); i++) {
pe->val[i] = le64_to_cpu(pe->val[i]);
}
/* Do translation type check */
- if (!vtd_pe_type_check(x86_iommu, pe)) {
- return -VTD_FR_PASID_TABLE_INV;
+ if (!vtd_pe_type_check(s, pe)) {
+ return -VTD_FR_PASID_TABLE_ENTRY_INV;
+ }
+
+ pgtt = VTD_PE_GET_TYPE(pe);
+ if (pgtt == VTD_SM_PASID_ENTRY_SLT &&
+ !vtd_is_sl_level_supported(s, VTD_PE_GET_SL_LEVEL(pe))) {
+ return -VTD_FR_PASID_TABLE_ENTRY_INV;
}
- if (!vtd_is_level_supported(s, VTD_PE_GET_LEVEL(pe))) {
- return -VTD_FR_PASID_TABLE_INV;
+ if (pgtt == VTD_SM_PASID_ENTRY_FLT &&
+ !vtd_is_fl_level_supported(s, VTD_PE_GET_FL_LEVEL(pe))) {
+ return -VTD_FR_PASID_TABLE_ENTRY_INV;
}
return 0;
@@ -876,7 +929,7 @@ static int vtd_get_pe_from_pasid_table(IntelIOMMUState *s,
}
if (!vtd_pdire_present(&pdire)) {
- return -VTD_FR_PASID_TABLE_INV;
+ return -VTD_FR_PASID_DIR_ENTRY_P;
}
ret = vtd_get_pe_from_pdire(s, pasid, &pdire, pe);
@@ -885,7 +938,7 @@ static int vtd_get_pe_from_pasid_table(IntelIOMMUState *s,
}
if (!vtd_pe_present(pe)) {
- return -VTD_FR_PASID_TABLE_INV;
+ return -VTD_FR_PASID_ENTRY_P;
}
return 0;
@@ -938,7 +991,7 @@ static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
}
if (!vtd_pdire_present(&pdire)) {
- return -VTD_FR_PASID_TABLE_INV;
+ return -VTD_FR_PASID_DIR_ENTRY_P;
}
/*
@@ -973,7 +1026,11 @@ static uint32_t vtd_get_iova_level(IntelIOMMUState *s,
if (s->root_scalable) {
vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid);
- return VTD_PE_GET_LEVEL(&pe);
+ if (s->flts) {
+ return VTD_PE_GET_FL_LEVEL(&pe);
+ } else {
+ return VTD_PE_GET_SL_LEVEL(&pe);
+ }
}
return vtd_ce_get_level(ce);
@@ -1041,9 +1098,9 @@ static inline uint64_t vtd_iova_limit(IntelIOMMUState *s,
}
/* Return true if IOVA passes range check, otherwise false. */
-static inline bool vtd_iova_range_check(IntelIOMMUState *s,
- uint64_t iova, VTDContextEntry *ce,
- uint8_t aw, uint32_t pasid)
+static inline bool vtd_iova_sl_range_check(IntelIOMMUState *s,
+ uint64_t iova, VTDContextEntry *ce,
+ uint8_t aw, uint32_t pasid)
{
/*
* Check if @iova is above 2^X-1, where X is the minimum of MGAW
@@ -1060,7 +1117,11 @@ static dma_addr_t vtd_get_iova_pgtbl_base(IntelIOMMUState *s,
if (s->root_scalable) {
vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid);
- return pe.val[0] & VTD_SM_PASID_ENTRY_SLPTPTR;
+ if (s->flts) {
+ return pe.val[2] & VTD_SM_PASID_ENTRY_FLPTPTR;
+ } else {
+ return pe.val[0] & VTD_SM_PASID_ENTRY_SLPTPTR;
+ }
}
return vtd_ce_get_slpt_base(ce);
@@ -1084,17 +1145,17 @@ static bool vtd_slpte_nonzero_rsvd(uint64_t slpte, uint32_t level)
/*
* We should have caught a guest-mis-programmed level earlier,
- * via vtd_is_level_supported.
+ * via vtd_is_sl_level_supported.
*/
assert(level < VTD_SPTE_RSVD_LEN);
/*
- * Zero level doesn't exist. The smallest level is VTD_SL_PT_LEVEL=1 and
- * checked by vtd_is_last_slpte().
+ * Zero level doesn't exist. The smallest level is VTD_PT_LEVEL=1 and
+ * checked by vtd_is_last_pte().
*/
assert(level);
- if ((level == VTD_SL_PD_LEVEL || level == VTD_SL_PDP_LEVEL) &&
- (slpte & VTD_SL_PT_PAGE_SIZE_MASK)) {
+ if ((level == VTD_PD_LEVEL || level == VTD_PDP_LEVEL) &&
+ (slpte & VTD_PT_PAGE_SIZE_MASK)) {
/* large page */
rsvd_mask = vtd_spte_rsvd_large[level];
} else {
@@ -1118,9 +1179,8 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
uint32_t offset;
uint64_t slpte;
uint64_t access_right_check;
- uint64_t xlat, size;
- if (!vtd_iova_range_check(s, iova, ce, aw_bits, pasid)) {
+ if (!vtd_iova_sl_range_check(s, iova, ce, aw_bits, pasid)) {
error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ","
"pasid=0x%" PRIx32 ")", __func__, iova, pasid);
return -VTD_FR_ADDR_BEYOND_MGAW;
@@ -1131,7 +1191,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
while (true) {
offset = vtd_iova_level_offset(iova, level);
- slpte = vtd_get_slpte(addr, offset);
+ slpte = vtd_get_pte(addr, offset);
if (slpte == (uint64_t)-1) {
error_report_once("%s: detected read error on DMAR slpte "
@@ -1162,37 +1222,16 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
return -VTD_FR_PAGING_ENTRY_RSVD;
}
- if (vtd_is_last_slpte(slpte, level)) {
+ if (vtd_is_last_pte(slpte, level)) {
*slptep = slpte;
*slpte_level = level;
break;
}
- addr = vtd_get_slpte_addr(slpte, aw_bits);
+ addr = vtd_get_pte_addr(slpte, aw_bits);
level--;
}
- xlat = vtd_get_slpte_addr(*slptep, aw_bits);
- size = ~vtd_slpt_level_page_mask(level) + 1;
-
- /*
- * From VT-d spec 3.14: Untranslated requests and translation
- * requests that result in an address in the interrupt range will be
- * blocked with condition code LGN.4 or SGN.8.
- */
- if ((xlat > VTD_INTERRUPT_ADDR_LAST ||
- xlat + size - 1 < VTD_INTERRUPT_ADDR_FIRST)) {
- return 0;
- } else {
- error_report_once("%s: xlat address is in interrupt range "
- "(iova=0x%" PRIx64 ", level=0x%" PRIx32 ", "
- "slpte=0x%" PRIx64 ", write=%d, "
- "xlat=0x%" PRIx64 ", size=0x%" PRIx64 ", "
- "pasid=0x%" PRIx32 ")",
- __func__, iova, level, slpte, is_write,
- xlat, size, pasid);
- return s->scalable_mode ? -VTD_FR_SM_INTERRUPT_ADDR :
- -VTD_FR_INTERRUPT_ADDR;
- }
+ return 0;
}
typedef int (*vtd_page_walk_hook)(const IOMMUTLBEvent *event, void *private);
@@ -1323,14 +1362,14 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
trace_vtd_page_walk_level(addr, level, start, end);
- subpage_size = 1ULL << vtd_slpt_level_shift(level);
- subpage_mask = vtd_slpt_level_page_mask(level);
+ subpage_size = 1ULL << vtd_pt_level_shift(level);
+ subpage_mask = vtd_pt_level_page_mask(level);
while (iova < end) {
iova_next = (iova & subpage_mask) + subpage_size;
offset = vtd_iova_level_offset(iova, level);
- slpte = vtd_get_slpte(addr, offset);
+ slpte = vtd_get_pte(addr, offset);
if (slpte == (uint64_t)-1) {
trace_vtd_page_walk_skip_read(iova, iova_next);
@@ -1353,12 +1392,12 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
*/
entry_valid = read_cur | write_cur;
- if (!vtd_is_last_slpte(slpte, level) && entry_valid) {
+ if (!vtd_is_last_pte(slpte, level) && entry_valid) {
/*
* This is a valid PDE (or even bigger than PDE). We need
* to walk one further level.
*/
- ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, info->aw),
+ ret = vtd_page_walk_level(vtd_get_pte_addr(slpte, info->aw),
iova, MIN(iova_next, end), level - 1,
read_cur, write_cur, info);
} else {
@@ -1375,7 +1414,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
event.entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
event.entry.addr_mask = ~subpage_mask;
/* NOTE: this is only meaningful if entry_valid == true */
- event.entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw);
+ event.entry.translated_addr = vtd_get_pte_addr(slpte, info->aw);
event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP :
IOMMU_NOTIFIER_UNMAP;
ret = vtd_page_walk_one(&event, info);
@@ -1409,11 +1448,11 @@ static int vtd_page_walk(IntelIOMMUState *s, VTDContextEntry *ce,
dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid);
uint32_t level = vtd_get_iova_level(s, ce, pasid);
- if (!vtd_iova_range_check(s, start, ce, info->aw, pasid)) {
+ if (!vtd_iova_sl_range_check(s, start, ce, info->aw, pasid)) {
return -VTD_FR_ADDR_BEYOND_MGAW;
}
- if (!vtd_iova_range_check(s, end, ce, info->aw, pasid)) {
+ if (!vtd_iova_sl_range_check(s, end, ce, info->aw, pasid)) {
/* Fix end so that it reaches the maximum */
end = vtd_iova_limit(s, ce, info->aw, pasid);
}
@@ -1528,7 +1567,7 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
/* Check if the programming of context-entry is valid */
if (!s->root_scalable &&
- !vtd_is_level_supported(s, vtd_ce_get_level(ce))) {
+ !vtd_is_sl_level_supported(s, vtd_ce_get_level(ce))) {
error_report_once("%s: invalid context entry: hi=%"PRIx64
", lo=%"PRIx64" (level %d not supported)",
__func__, ce->hi, ce->lo,
@@ -1689,8 +1728,6 @@ static bool vtd_as_pt_enabled(VTDAddressSpace *as)
static bool vtd_switch_address_space(VTDAddressSpace *as)
{
bool use_iommu, pt;
- /* Whether we need to take the BQL on our own */
- bool take_bql = !bql_locked();
assert(as);
@@ -1707,9 +1744,7 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
* from vtd_pt_enable_fast_path(). However the memory APIs need
* it. We'd better make sure we have had it already, or, take it.
*/
- if (take_bql) {
- bql_lock();
- }
+ BQL_LOCK_GUARD();
/* Turn off first then on the other */
if (use_iommu) {
@@ -1762,10 +1797,6 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
memory_region_set_enabled(&as->iommu_ir_fault, false);
}
- if (take_bql) {
- bql_unlock();
- }
-
return use_iommu;
}
@@ -1795,8 +1826,20 @@ static const bool vtd_qualified_faults[] = {
[VTD_FR_ROOT_ENTRY_RSVD] = false,
[VTD_FR_PAGING_ENTRY_RSVD] = true,
[VTD_FR_CONTEXT_ENTRY_TT] = true,
- [VTD_FR_PASID_TABLE_INV] = false,
+ [VTD_FR_PASID_DIR_ACCESS_ERR] = false,
+ [VTD_FR_PASID_DIR_ENTRY_P] = true,
+ [VTD_FR_PASID_TABLE_ACCESS_ERR] = false,
+ [VTD_FR_PASID_ENTRY_P] = true,
+ [VTD_FR_PASID_TABLE_ENTRY_INV] = true,
+ [VTD_FR_FS_PAGING_ENTRY_INV] = true,
+ [VTD_FR_FS_PAGING_ENTRY_P] = true,
+ [VTD_FR_FS_PAGING_ENTRY_RSVD] = true,
+ [VTD_FR_PASID_ENTRY_FSPTPTR_INV] = true,
+ [VTD_FR_FS_NON_CANONICAL] = true,
+ [VTD_FR_FS_PAGING_ENTRY_US] = true,
+ [VTD_FR_SM_WRITE] = true,
[VTD_FR_SM_INTERRUPT_ADDR] = true,
+ [VTD_FR_FS_BIT_UPDATE_FAILED] = true,
[VTD_FR_MAX] = false,
};
@@ -1814,29 +1857,32 @@ static inline bool vtd_is_interrupt_addr(hwaddr addr)
return VTD_INTERRUPT_ADDR_FIRST <= addr && addr <= VTD_INTERRUPT_ADDR_LAST;
}
-static gboolean vtd_find_as_by_sid(gpointer key, gpointer value,
- gpointer user_data)
+static gboolean vtd_find_as_by_sid_and_pasid(gpointer key, gpointer value,
+ gpointer user_data)
{
struct vtd_as_key *as_key = (struct vtd_as_key *)key;
- uint16_t target_sid = *(uint16_t *)user_data;
+ struct vtd_as_raw_key *target = (struct vtd_as_raw_key *)user_data;
uint16_t sid = PCI_BUILD_BDF(pci_bus_num(as_key->bus), as_key->devfn);
- return sid == target_sid;
+
+ return (as_key->pasid == target->pasid) && (sid == target->sid);
}
-static VTDAddressSpace *vtd_get_as_by_sid(IntelIOMMUState *s, uint16_t sid)
+static VTDAddressSpace *vtd_get_as_by_sid_and_pasid(IntelIOMMUState *s,
+ uint16_t sid,
+ uint32_t pasid)
{
- uint8_t bus_num = PCI_BUS_NUM(sid);
- VTDAddressSpace *vtd_as = s->vtd_as_cache[bus_num];
-
- if (vtd_as &&
- (sid == PCI_BUILD_BDF(pci_bus_num(vtd_as->bus), vtd_as->devfn))) {
- return vtd_as;
- }
+ struct vtd_as_raw_key key = {
+ .sid = sid,
+ .pasid = pasid
+ };
- vtd_as = g_hash_table_find(s->vtd_address_spaces, vtd_find_as_by_sid, &sid);
- s->vtd_as_cache[bus_num] = vtd_as;
+ return g_hash_table_find(s->vtd_address_spaces,
+ vtd_find_as_by_sid_and_pasid, &key);
+}
- return vtd_as;
+static VTDAddressSpace *vtd_get_as_by_sid(IntelIOMMUState *s, uint16_t sid)
+{
+ return vtd_get_as_by_sid_and_pasid(s, sid, PCI_NO_PASID);
}
static void vtd_pt_enable_fast_path(IntelIOMMUState *s, uint16_t source_id)
@@ -1858,6 +1904,157 @@ out:
trace_vtd_pt_enable_fast_path(source_id, success);
}
+/*
+ * Rsvd field masks for fpte:
+ * vtd_fpte_rsvd 4k pages
+ * vtd_fpte_rsvd_large large pages
+ *
+ * We support only 4-level page tables.
+ */
+#define VTD_FPTE_RSVD_LEN 5
+static uint64_t vtd_fpte_rsvd[VTD_FPTE_RSVD_LEN];
+static uint64_t vtd_fpte_rsvd_large[VTD_FPTE_RSVD_LEN];
+
+static bool vtd_flpte_nonzero_rsvd(uint64_t flpte, uint32_t level)
+{
+ uint64_t rsvd_mask;
+
+ /*
+ * We should have caught a guest-mis-programmed level earlier,
+ * via vtd_is_fl_level_supported.
+ */
+ assert(level < VTD_FPTE_RSVD_LEN);
+ /*
+ * Zero level doesn't exist. The smallest level is VTD_PT_LEVEL=1 and
+ * checked by vtd_is_last_pte().
+ */
+ assert(level);
+
+ if ((level == VTD_PD_LEVEL || level == VTD_PDP_LEVEL) &&
+ (flpte & VTD_PT_PAGE_SIZE_MASK)) {
+ /* large page */
+ rsvd_mask = vtd_fpte_rsvd_large[level];
+ } else {
+ rsvd_mask = vtd_fpte_rsvd[level];
+ }
+
+ return flpte & rsvd_mask;
+}
+
+static inline bool vtd_flpte_present(uint64_t flpte)
+{
+ return !!(flpte & VTD_FL_P);
+}
+
+/* Return true if IOVA is canonical, otherwise false. */
+static bool vtd_iova_fl_check_canonical(IntelIOMMUState *s, uint64_t iova,
+ VTDContextEntry *ce, uint32_t pasid)
+{
+ uint64_t iova_limit = vtd_iova_limit(s, ce, s->aw_bits, pasid);
+ uint64_t upper_bits_mask = ~(iova_limit - 1);
+ uint64_t upper_bits = iova & upper_bits_mask;
+ bool msb = ((iova & (iova_limit >> 1)) != 0);
+
+ if (msb) {
+ return upper_bits == upper_bits_mask;
+ } else {
+ return !upper_bits;
+ }
+}
+
+static MemTxResult vtd_set_flag_in_pte(dma_addr_t base_addr, uint32_t index,
+ uint64_t pte, uint64_t flag)
+{
+ if (pte & flag) {
+ return MEMTX_OK;
+ }
+ pte |= flag;
+ pte = cpu_to_le64(pte);
+ return dma_memory_write(&address_space_memory,
+ base_addr + index * sizeof(pte),
+ &pte, sizeof(pte),
+ MEMTXATTRS_UNSPECIFIED);
+}
+
+/*
+ * Given the @iova, get relevant @flptep. @flpte_level will be the last level
+ * of the translation, can be used for deciding the size of large page.
+ */
+static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce,
+ uint64_t iova, bool is_write,
+ uint64_t *flptep, uint32_t *flpte_level,
+ bool *reads, bool *writes, uint8_t aw_bits,
+ uint32_t pasid)
+{
+ dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid);
+ uint32_t level = vtd_get_iova_level(s, ce, pasid);
+ uint32_t offset;
+ uint64_t flpte, flag_ad = VTD_FL_A;
+
+ if (!vtd_iova_fl_check_canonical(s, iova, ce, pasid)) {
+ error_report_once("%s: detected non canonical IOVA (iova=0x%" PRIx64 ","
+ "pasid=0x%" PRIx32 ")", __func__, iova, pasid);
+ return -VTD_FR_FS_NON_CANONICAL;
+ }
+
+ while (true) {
+ offset = vtd_iova_level_offset(iova, level);
+ flpte = vtd_get_pte(addr, offset);
+
+ if (flpte == (uint64_t)-1) {
+ if (level == vtd_get_iova_level(s, ce, pasid)) {
+ /* Invalid programming of pasid-entry */
+ return -VTD_FR_PASID_ENTRY_FSPTPTR_INV;
+ } else {
+ return -VTD_FR_FS_PAGING_ENTRY_INV;
+ }
+ }
+
+ if (!vtd_flpte_present(flpte)) {
+ *reads = false;
+ *writes = false;
+ return -VTD_FR_FS_PAGING_ENTRY_P;
+ }
+
+ /* No emulated device supports supervisor privilege request yet */
+ if (!(flpte & VTD_FL_US)) {
+ *reads = false;
+ *writes = false;
+ return -VTD_FR_FS_PAGING_ENTRY_US;
+ }
+
+ *reads = true;
+ *writes = (*writes) && (flpte & VTD_FL_RW);
+ if (is_write && !(flpte & VTD_FL_RW)) {
+ return -VTD_FR_SM_WRITE;
+ }
+ if (vtd_flpte_nonzero_rsvd(flpte, level)) {
+ error_report_once("%s: detected flpte reserved non-zero "
+ "iova=0x%" PRIx64 ", level=0x%" PRIx32
+ "flpte=0x%" PRIx64 ", pasid=0x%" PRIX32 ")",
+ __func__, iova, level, flpte, pasid);
+ return -VTD_FR_FS_PAGING_ENTRY_RSVD;
+ }
+
+ if (vtd_is_last_pte(flpte, level) && is_write) {
+ flag_ad |= VTD_FL_D;
+ }
+
+ if (vtd_set_flag_in_pte(addr, offset, flpte, flag_ad) != MEMTX_OK) {
+ return -VTD_FR_FS_BIT_UPDATE_FAILED;
+ }
+
+ if (vtd_is_last_pte(flpte, level)) {
+ *flptep = flpte;
+ *flpte_level = level;
+ return 0;
+ }
+
+ addr = vtd_get_pte_addr(flpte, aw_bits);
+ level--;
+ }
+}
+
static void vtd_report_fault(IntelIOMMUState *s,
int err, bool is_fpd_set,
uint16_t source_id,
@@ -1894,16 +2091,17 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
VTDContextEntry ce;
uint8_t bus_num = pci_bus_num(bus);
VTDContextCacheEntry *cc_entry;
- uint64_t slpte, page_mask;
+ uint64_t pte, page_mask;
uint32_t level, pasid = vtd_as->pasid;
uint16_t source_id = PCI_BUILD_BDF(bus_num, devfn);
int ret_fr;
bool is_fpd_set = false;
bool reads = true;
bool writes = true;
- uint8_t access_flags;
+ uint8_t access_flags, pgtt;
bool rid2pasid = (pasid == PCI_NO_PASID) && s->root_scalable;
VTDIOTLBEntry *iotlb_entry;
+ uint64_t xlat, size;
/*
* We have standalone memory region for interrupt addresses, we
@@ -1915,13 +2113,13 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
cc_entry = &vtd_as->context_cache_entry;
- /* Try to fetch slpte form IOTLB, we don't need RID2PASID logic */
+ /* Try to fetch pte from IOTLB, we don't need RID2PASID logic */
if (!rid2pasid) {
iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr);
if (iotlb_entry) {
- trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,
+ trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->pte,
iotlb_entry->domain_id);
- slpte = iotlb_entry->slpte;
+ pte = iotlb_entry->pte;
access_flags = iotlb_entry->access_flags;
page_mask = iotlb_entry->mask;
goto out;
@@ -1993,35 +2191,65 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
return true;
}
- /* Try to fetch slpte form IOTLB for RID2PASID slow path */
+ /* Try to fetch pte from IOTLB for RID2PASID slow path */
if (rid2pasid) {
iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr);
if (iotlb_entry) {
- trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte,
+ trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->pte,
iotlb_entry->domain_id);
- slpte = iotlb_entry->slpte;
+ pte = iotlb_entry->pte;
access_flags = iotlb_entry->access_flags;
page_mask = iotlb_entry->mask;
goto out;
}
}
- ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &slpte, &level,
- &reads, &writes, s->aw_bits, pasid);
+ if (s->flts && s->root_scalable) {
+ ret_fr = vtd_iova_to_flpte(s, &ce, addr, is_write, &pte, &level,
+ &reads, &writes, s->aw_bits, pasid);
+ pgtt = VTD_SM_PASID_ENTRY_FLT;
+ } else {
+ ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &pte, &level,
+ &reads, &writes, s->aw_bits, pasid);
+ pgtt = VTD_SM_PASID_ENTRY_SLT;
+ }
+ if (!ret_fr) {
+ xlat = vtd_get_pte_addr(pte, s->aw_bits);
+ size = ~vtd_pt_level_page_mask(level) + 1;
+
+ /*
+ * Per VT-d spec 4.1 section 3.15: Untranslated requests and translation
+ * requests that result in an address in the interrupt range will be
+ * blocked with condition code LGN.4 or SGN.8.
+ */
+ if ((xlat <= VTD_INTERRUPT_ADDR_LAST &&
+ xlat + size - 1 >= VTD_INTERRUPT_ADDR_FIRST)) {
+ error_report_once("%s: xlat address is in interrupt range "
+ "(iova=0x%" PRIx64 ", level=0x%" PRIx32 ", "
+ "pte=0x%" PRIx64 ", write=%d, "
+ "xlat=0x%" PRIx64 ", size=0x%" PRIx64 ", "
+ "pasid=0x%" PRIx32 ")",
+ __func__, addr, level, pte, is_write,
+ xlat, size, pasid);
+ ret_fr = s->scalable_mode ? -VTD_FR_SM_INTERRUPT_ADDR :
+ -VTD_FR_INTERRUPT_ADDR;
+ }
+ }
+
if (ret_fr) {
vtd_report_fault(s, -ret_fr, is_fpd_set, source_id,
addr, is_write, pasid != PCI_NO_PASID, pasid);
goto error;
}
- page_mask = vtd_slpt_level_page_mask(level);
+ page_mask = vtd_pt_level_page_mask(level);
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid),
- addr, slpte, access_flags, level, pasid);
+ addr, pte, access_flags, level, pasid, pgtt);
out:
vtd_iommu_unlock(s);
entry->iova = addr & page_mask;
- entry->translated_addr = vtd_get_slpte_addr(slpte, s->aw_bits) & page_mask;
+ entry->translated_addr = vtd_get_pte_addr(pte, s->aw_bits) & page_mask;
entry->addr_mask = ~page_mask;
entry->perm = access_flags;
return true;
@@ -2215,8 +2443,13 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
}
}
+/*
+ * There is no pasid field in iotlb invalidation descriptor, so PCI_NO_PASID
+ * is passed as parameter. Piotlb invalidation supports pasid, pasid in its
+ * descriptor is passed which should not be PCI_NO_PASID.
+ */
static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
- uint16_t domain_id, hwaddr addr,
+ uint16_t domain_id, hwaddr addr,
uint8_t am, uint32_t pasid)
{
VTDAddressSpace *vtd_as;
@@ -2225,19 +2458,37 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
hwaddr size = (1 << am) * VTD_PAGE_SIZE;
QLIST_FOREACH(vtd_as, &(s->vtd_as_with_notifiers), next) {
- if (pasid != PCI_NO_PASID && pasid != vtd_as->pasid) {
- continue;
- }
ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
vtd_as->devfn, &ce);
if (!ret && domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) {
+ uint32_t rid2pasid = PCI_NO_PASID;
+
+ if (s->root_scalable) {
+ rid2pasid = VTD_CE_GET_RID2PASID(&ce);
+ }
+
+ /*
+ * In legacy mode, vtd_as->pasid == pasid is always true.
+ * In scalable mode, for vtd address space backing a PCI
+ * device without pasid, needs to compare pasid with
+ * rid2pasid of this device.
+ */
+ if (!(vtd_as->pasid == pasid ||
+ (vtd_as->pasid == PCI_NO_PASID && pasid == rid2pasid))) {
+ continue;
+ }
+
if (vtd_as_has_map_notifier(vtd_as)) {
/*
- * As long as we have MAP notifications registered in
- * any of our IOMMU notifiers, we need to sync the
- * shadow page table.
+ * When stage-1 translation is off, as long as we have MAP
+ * notifications registered in any of our IOMMU notifiers,
+ * we need to sync the shadow page table. Otherwise VFIO
+ * device attaches to nested page table instead of shadow
+ * page table, so no need to sync.
*/
- vtd_sync_shadow_page_table_range(vtd_as, &ce, addr, size);
+ if (!s->flts || !s->root_scalable) {
+ vtd_sync_shadow_page_table_range(vtd_as, &ce, addr, size);
+ }
} else {
/*
* For UNMAP-only notifiers, we don't need to walk the
@@ -2532,15 +2783,51 @@ static bool vtd_get_inv_desc(IntelIOMMUState *s,
return true;
}
+static bool vtd_inv_desc_reserved_check(IntelIOMMUState *s,
+ VTDInvDesc *inv_desc,
+ uint64_t mask[4], bool dw,
+ const char *func_name,
+ const char *desc_type)
+{
+ if (s->iq_dw) {
+ if (inv_desc->val[0] & mask[0] || inv_desc->val[1] & mask[1] ||
+ inv_desc->val[2] & mask[2] || inv_desc->val[3] & mask[3]) {
+ error_report("%s: invalid %s desc val[3]: 0x%"PRIx64
+ " val[2]: 0x%"PRIx64" val[1]=0x%"PRIx64
+ " val[0]=0x%"PRIx64" (reserved nonzero)",
+ func_name, desc_type, inv_desc->val[3],
+ inv_desc->val[2], inv_desc->val[1],
+ inv_desc->val[0]);
+ return false;
+ }
+ } else {
+ if (dw) {
+ error_report("%s: 256-bit %s desc in 128-bit invalidation queue",
+ func_name, desc_type);
+ return false;
+ }
+
+ if (inv_desc->lo & mask[0] || inv_desc->hi & mask[1]) {
+ error_report("%s: invalid %s desc: hi=%"PRIx64", lo=%"PRIx64
+ " (reserved nonzero)", func_name, desc_type,
+ inv_desc->hi, inv_desc->lo);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
{
- if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) ||
- (inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) {
- error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
- " (reserved nonzero)", __func__, inv_desc->hi,
- inv_desc->lo);
+ uint64_t mask[4] = {VTD_INV_DESC_WAIT_RSVD_LO, VTD_INV_DESC_WAIT_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "wait")) {
return false;
}
+
if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) {
/* Status Write */
uint32_t status_data = (uint32_t)(inv_desc->lo >>
@@ -2574,13 +2861,14 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
uint16_t sid, fmask;
+ uint64_t mask[4] = {VTD_INV_DESC_CC_RSVD, VTD_INV_DESC_ALL_ONE,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
- if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
- error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
- " (reserved nonzero)", __func__, inv_desc->hi,
- inv_desc->lo);
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "cc inv")) {
return false;
}
+
switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
case VTD_INV_DESC_CC_DOMAIN:
trace_vtd_inv_desc_cc_domain(
@@ -2610,12 +2898,11 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
uint16_t domain_id;
uint8_t am;
hwaddr addr;
+ uint64_t mask[4] = {VTD_INV_DESC_IOTLB_RSVD_LO, VTD_INV_DESC_IOTLB_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
- if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
- (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
- error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
- ", lo=0x%"PRIx64" (reserved bits unzero)",
- __func__, inv_desc->hi, inv_desc->lo);
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "iotlb inv")) {
return false;
}
@@ -2653,9 +2940,117 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
return true;
}
+static gboolean vtd_hash_remove_by_pasid(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
+ VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
+
+ return ((entry->domain_id == info->domain_id) &&
+ (entry->pasid == info->pasid));
+}
+
+static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s,
+ uint16_t domain_id, uint32_t pasid)
+{
+ VTDIOTLBPageInvInfo info;
+ VTDAddressSpace *vtd_as;
+ VTDContextEntry ce;
+
+ info.domain_id = domain_id;
+ info.pasid = pasid;
+
+ vtd_iommu_lock(s);
+ g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_pasid,
+ &info);
+ vtd_iommu_unlock(s);
+
+ QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) {
+ if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
+ vtd_as->devfn, &ce) &&
+ domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) {
+ uint32_t rid2pasid = VTD_CE_GET_RID2PASID(&ce);
+
+ if ((vtd_as->pasid != PCI_NO_PASID || pasid != rid2pasid) &&
+ vtd_as->pasid != pasid) {
+ continue;
+ }
+
+ if (!s->flts || !vtd_as_has_map_notifier(vtd_as)) {
+ vtd_address_space_sync(vtd_as);
+ }
+ }
+ }
+}
+
+static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
+ uint32_t pasid, hwaddr addr, uint8_t am)
+{
+ VTDIOTLBPageInvInfo info;
+
+ info.domain_id = domain_id;
+ info.pasid = pasid;
+ info.addr = addr;
+ info.mask = ~((1 << am) - 1);
+
+ vtd_iommu_lock(s);
+ g_hash_table_foreach_remove(s->iotlb,
+ vtd_hash_remove_by_page_piotlb, &info);
+ vtd_iommu_unlock(s);
+
+ vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am, pasid);
+}
+
+static bool vtd_process_piotlb_desc(IntelIOMMUState *s,
+ VTDInvDesc *inv_desc)
+{
+ uint16_t domain_id;
+ uint32_t pasid;
+ hwaddr addr;
+ uint8_t am;
+ uint64_t mask[4] = {VTD_INV_DESC_PIOTLB_RSVD_VAL0,
+ VTD_INV_DESC_PIOTLB_RSVD_VAL1,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, true,
+ __func__, "piotlb inv")) {
+ return false;
+ }
+
+ domain_id = VTD_INV_DESC_PIOTLB_DID(inv_desc->val[0]);
+ pasid = VTD_INV_DESC_PIOTLB_PASID(inv_desc->val[0]);
+ switch (inv_desc->val[0] & VTD_INV_DESC_PIOTLB_G) {
+ case VTD_INV_DESC_PIOTLB_ALL_IN_PASID:
+ vtd_piotlb_pasid_invalidate(s, domain_id, pasid);
+ break;
+
+ case VTD_INV_DESC_PIOTLB_PSI_IN_PASID:
+ am = VTD_INV_DESC_PIOTLB_AM(inv_desc->val[1]);
+ addr = (hwaddr) VTD_INV_DESC_PIOTLB_ADDR(inv_desc->val[1]);
+ vtd_piotlb_page_invalidate(s, domain_id, pasid, addr, am);
+ break;
+
+ default:
+ error_report_once("%s: invalid piotlb inv desc: hi=0x%"PRIx64
+ ", lo=0x%"PRIx64" (type mismatch: 0x%llx)",
+ __func__, inv_desc->val[1], inv_desc->val[0],
+ inv_desc->val[0] & VTD_INV_DESC_IOTLB_G);
+ return false;
+ }
+ return true;
+}
+
static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
+ uint64_t mask[4] = {VTD_INV_DESC_IEC_RSVD, VTD_INV_DESC_ALL_ONE,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "iec inv")) {
+ return false;
+ }
+
trace_vtd_inv_desc_iec(inv_desc->iec.granularity,
inv_desc->iec.index,
inv_desc->iec.index_mask);
@@ -2698,6 +3093,49 @@ static void do_invalidate_device_tlb(VTDAddressSpace *vtd_dev_as,
memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event);
}
+static bool vtd_process_device_piotlb_desc(IntelIOMMUState *s,
+ VTDInvDesc *inv_desc)
+{
+ uint16_t sid;
+ VTDAddressSpace *vtd_dev_as;
+ bool size;
+ bool global;
+ hwaddr addr;
+ uint32_t pasid;
+ uint64_t mask[4] = {VTD_INV_DESC_PASID_DEVICE_IOTLB_RSVD_VAL0,
+ VTD_INV_DESC_PASID_DEVICE_IOTLB_RSVD_VAL1,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, true,
+ __func__, "device piotlb inv")) {
+ return false;
+ }
+
+ global = VTD_INV_DESC_PASID_DEVICE_IOTLB_GLOBAL(inv_desc->hi);
+ size = VTD_INV_DESC_PASID_DEVICE_IOTLB_SIZE(inv_desc->hi);
+ addr = VTD_INV_DESC_PASID_DEVICE_IOTLB_ADDR(inv_desc->hi);
+ sid = VTD_INV_DESC_PASID_DEVICE_IOTLB_SID(inv_desc->lo);
+ if (global) {
+ QLIST_FOREACH(vtd_dev_as, &s->vtd_as_with_notifiers, next) {
+ if ((vtd_dev_as->pasid != PCI_NO_PASID) &&
+ (PCI_BUILD_BDF(pci_bus_num(vtd_dev_as->bus),
+ vtd_dev_as->devfn) == sid)) {
+ do_invalidate_device_tlb(vtd_dev_as, size, addr);
+ }
+ }
+ } else {
+ pasid = VTD_INV_DESC_PASID_DEVICE_IOTLB_PASID(inv_desc->lo);
+ vtd_dev_as = vtd_get_as_by_sid_and_pasid(s, sid, pasid);
+ if (!vtd_dev_as) {
+ return true;
+ }
+
+ do_invalidate_device_tlb(vtd_dev_as, size, addr);
+ }
+
+ return true;
+}
+
static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
@@ -2705,19 +3143,19 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
hwaddr addr;
uint16_t sid;
bool size;
+ uint64_t mask[4] = {VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO,
+ VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "dev-iotlb inv")) {
+ return false;
+ }
addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi);
sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo);
size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi);
- if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) ||
- (inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) {
- error_report_once("%s: invalid dev-iotlb inv desc: hi=%"PRIx64
- ", lo=%"PRIx64" (reserved nonzero)", __func__,
- inv_desc->hi, inv_desc->lo);
- return false;
- }
-
/*
* Using sid is OK since the guest should have finished the
* initialization of both the bus and device.
@@ -2744,7 +3182,7 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
return false;
}
- desc_type = inv_desc.lo & VTD_INV_DESC_TYPE;
+ desc_type = VTD_INV_DESC_TYPE(inv_desc.lo);
/* FIXME: should update at first or at last? */
s->iq_last_desc_type = desc_type;
@@ -2763,15 +3201,11 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
- /*
- * TODO: the entity of below two cases will be implemented in future series.
- * To make guest (which integrates scalable mode support patch set in
- * iommu driver) work, just return true is enough so far.
- */
- case VTD_INV_DESC_PC:
- break;
-
case VTD_INV_DESC_PIOTLB:
+ trace_vtd_inv_desc("p-iotlb", inv_desc.val[1], inv_desc.val[0]);
+ if (!vtd_process_piotlb_desc(s, &inv_desc)) {
+ return false;
+ }
break;
case VTD_INV_DESC_WAIT:
@@ -2788,6 +3222,13 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
+ case VTD_INV_DESC_DEV_PIOTLB:
+ trace_vtd_inv_desc("device-piotlb", inv_desc.hi, inv_desc.lo);
+ if (!vtd_process_device_piotlb_desc(s, &inv_desc)) {
+ return false;
+ }
+ break;
+
case VTD_INV_DESC_DEVICE:
trace_vtd_inv_desc("device", inv_desc.hi, inv_desc.lo);
if (!vtd_process_device_iotlb_desc(s, &inv_desc)) {
@@ -2795,6 +3236,16 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
+ /*
+ * TODO: the entity of below two cases will be implemented in future series.
+ * To make guest (which integrates scalable mode support patch set in
+ * iommu driver) work, just return true is enough so far.
+ */
+ case VTD_INV_DESC_PC:
+ if (s->scalable_mode) {
+ break;
+ }
+ /* fallthrough */
default:
error_report_once("%s: invalid inv desc: hi=%"PRIx64", lo=%"PRIx64
" (unknown type)", __func__, inv_desc.hi,
@@ -2847,6 +3298,7 @@ static void vtd_handle_iqt_write(IntelIOMMUState *s)
if (s->iq_dw && (val & VTD_IQT_QT_256_RSV_BIT)) {
error_report_once("%s: RSV bit is set: val=0x%"PRIx64,
__func__, val);
+ vtd_handle_inv_queue_error(s);
return;
}
s->iq_tail = VTD_IQT_QT(s->iq_dw, val);
@@ -3359,7 +3811,7 @@ static const MemoryRegionOps vtd_mem_ops = {
},
};
-static Property vtd_properties[] = {
+static const Property vtd_properties[] = {
DEFINE_PROP_UINT32("version", IntelIOMMUState, version, 0),
DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim,
ON_OFF_AUTO_AUTO),
@@ -3368,11 +3820,13 @@ static Property vtd_properties[] = {
VTD_HOST_ADDRESS_WIDTH),
DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE),
DEFINE_PROP_BOOL("x-scalable-mode", IntelIOMMUState, scalable_mode, FALSE),
+ DEFINE_PROP_BOOL("x-flts", IntelIOMMUState, flts, FALSE),
DEFINE_PROP_BOOL("snoop-control", IntelIOMMUState, snoop_control, false),
DEFINE_PROP_BOOL("x-pasid-mode", IntelIOMMUState, pasid, false),
DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
DEFINE_PROP_BOOL("dma-translation", IntelIOMMUState, dma_translation, true),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("stale-tm", IntelIOMMUState, stale_tm, false),
+ DEFINE_PROP_BOOL("fs1gp", IntelIOMMUState, fs1gp, true),
};
/* Read IRTE entry with specific index */
@@ -3751,9 +4205,30 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
VTDAddressSpace *vtd_dev_as;
char name[128];
+ vtd_iommu_lock(s);
vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key);
+ vtd_iommu_unlock(s);
+
if (!vtd_dev_as) {
- struct vtd_as_key *new_key = g_malloc(sizeof(*new_key));
+ struct vtd_as_key *new_key;
+ /* Slow path */
+
+ /*
+ * memory_region_add_subregion_overlap requires the bql,
+ * make sure we own it.
+ */
+ BQL_LOCK_GUARD();
+ vtd_iommu_lock(s);
+
+ /* Check again as we released the lock for a moment */
+ vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key);
+ if (vtd_dev_as) {
+ vtd_iommu_unlock(s);
+ return vtd_dev_as;
+ }
+
+ /* Still nothing, allocate a new address space */
+ new_key = g_malloc(sizeof(*new_key));
new_key->bus = bus;
new_key->devfn = devfn;
@@ -3844,6 +4319,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
vtd_switch_address_space(vtd_dev_as);
g_hash_table_insert(s->vtd_address_spaces, new_key, vtd_dev_as);
+
+ vtd_iommu_unlock(s);
}
return vtd_dev_as;
}
@@ -3869,7 +4346,13 @@ static bool vtd_check_hiod(IntelIOMMUState *s, HostIOMMUDevice *hiod,
return false;
}
- return true;
+ if (!s->flts) {
+ /* All checks requested by VTD stage-2 translation pass */
+ return true;
+ }
+
+ error_setg(errp, "host device is uncompatible with stage-1 translation");
+ return false;
}
static bool vtd_dev_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
@@ -4047,8 +4530,6 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn),
PCI_FUNC(vtd_as->devfn));
}
-
- return;
}
static void vtd_cap_init(IntelIOMMUState *s)
@@ -4092,7 +4573,12 @@ static void vtd_cap_init(IntelIOMMUState *s)
}
/* TODO: read cap/ecap from host to decide which cap to be exposed. */
- if (s->scalable_mode) {
+ if (s->flts) {
+ s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_FLTS;
+ if (s->fs1gp) {
+ s->cap |= VTD_CAP_FS1GP;
+ }
+ } else if (s->scalable_mode) {
s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_SLTS;
}
@@ -4138,15 +4624,27 @@ static void vtd_init(IntelIOMMUState *s)
*/
vtd_spte_rsvd[0] = ~0ULL;
vtd_spte_rsvd[1] = VTD_SPTE_PAGE_L1_RSVD_MASK(s->aw_bits,
- x86_iommu->dt_supported);
+ x86_iommu->dt_supported && s->stale_tm);
vtd_spte_rsvd[2] = VTD_SPTE_PAGE_L2_RSVD_MASK(s->aw_bits);
vtd_spte_rsvd[3] = VTD_SPTE_PAGE_L3_RSVD_MASK(s->aw_bits);
vtd_spte_rsvd[4] = VTD_SPTE_PAGE_L4_RSVD_MASK(s->aw_bits);
vtd_spte_rsvd_large[2] = VTD_SPTE_LPAGE_L2_RSVD_MASK(s->aw_bits,
- x86_iommu->dt_supported);
+ x86_iommu->dt_supported && s->stale_tm);
vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits,
- x86_iommu->dt_supported);
+ x86_iommu->dt_supported && s->stale_tm);
+
+ /*
+ * Rsvd field masks for fpte
+ */
+ vtd_fpte_rsvd[0] = ~0ULL;
+ vtd_fpte_rsvd[1] = VTD_FPTE_PAGE_L1_RSVD_MASK(s->aw_bits);
+ vtd_fpte_rsvd[2] = VTD_FPTE_PAGE_L2_RSVD_MASK(s->aw_bits);
+ vtd_fpte_rsvd[3] = VTD_FPTE_PAGE_L3_RSVD_MASK(s->aw_bits);
+ vtd_fpte_rsvd[4] = VTD_FPTE_PAGE_L4_RSVD_MASK(s->aw_bits);
+
+ vtd_fpte_rsvd_large[2] = VTD_FPTE_LPAGE_L2_RSVD_MASK(s->aw_bits);
+ vtd_fpte_rsvd_large[3] = VTD_FPTE_LPAGE_L3_RSVD_MASK(s->aw_bits);
if (s->scalable_mode || s->snoop_control) {
vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP;
@@ -4212,10 +4710,11 @@ static void vtd_init(IntelIOMMUState *s)
/* Should not reset address_spaces when reset because devices will still use
* the address space they got at first (won't ask the bus again).
*/
-static void vtd_reset(DeviceState *dev)
+static void vtd_reset_exit(Object *obj, ResetType type)
{
- IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev);
+ IntelIOMMUState *s = INTEL_IOMMU_DEVICE(obj);
+ trace_vtd_reset_exit();
vtd_init(s);
vtd_address_space_refresh_all(s);
}
@@ -4259,14 +4758,26 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
}
}
- /* Currently only address widths supported are 39 and 48 bits */
- if ((s->aw_bits != VTD_HOST_AW_39BIT) &&
- (s->aw_bits != VTD_HOST_AW_48BIT)) {
- error_setg(errp, "Supported values for aw-bits are: %d, %d",
+ if (!s->scalable_mode && s->flts) {
+ error_setg(errp, "x-flts is only available in scalable mode");
+ return false;
+ }
+
+ if (!s->flts && s->aw_bits != VTD_HOST_AW_39BIT &&
+ s->aw_bits != VTD_HOST_AW_48BIT) {
+ error_setg(errp, "%s: supported values for aw-bits are: %d, %d",
+ s->scalable_mode ? "Scalable mode(flts=off)" : "Legacy mode",
VTD_HOST_AW_39BIT, VTD_HOST_AW_48BIT);
return false;
}
+ if (s->flts && s->aw_bits != VTD_HOST_AW_48BIT) {
+ error_setg(errp,
+ "Scalable mode(flts=on): supported value for aw-bits is: %d",
+ VTD_HOST_AW_48BIT);
+ return false;
+ }
+
if (s->scalable_mode && !s->dma_drain) {
error_setg(errp, "Need to set dma_drain for scalable mode");
return false;
@@ -4363,19 +4874,22 @@ static void vtd_realize(DeviceState *dev, Error **errp)
qemu_add_machine_init_done_notifier(&vtd_machine_done_notify);
}
-static void vtd_class_init(ObjectClass *klass, void *data)
+static void vtd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
X86IOMMUClass *x86_class = X86_IOMMU_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
- dc->reset = vtd_reset;
+ /*
+ * Use 'exit' reset phase to make sure all DMA requests
+ * have been quiesced during 'enter' or 'hold' phase
+ */
+ rc->phases.exit = vtd_reset_exit;
dc->vmsd = &vtd_vmstate;
device_class_set_props(dc, vtd_properties);
dc->hotpluggable = false;
x86_class->realize = vtd_realize;
x86_class->int_remap = vtd_int_remap;
- /* Supported by the pc-q35-* machine types */
- dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "Intel IOMMU (VT-d) DMA Remapping device";
}
@@ -4388,7 +4902,7 @@ static const TypeInfo vtd_info = {
};
static void vtd_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index 5f32c36..e8b211e 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -195,6 +195,7 @@
#define VTD_ECAP_PASID (1ULL << 40)
#define VTD_ECAP_SMTS (1ULL << 43)
#define VTD_ECAP_SLTS (1ULL << 46)
+#define VTD_ECAP_FLTS (1ULL << 47)
/* CAP_REG */
/* (offset >> 4) << 24 */
@@ -211,6 +212,7 @@
#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
#define VTD_CAP_DRAIN_WRITE (1ULL << 54)
#define VTD_CAP_DRAIN_READ (1ULL << 55)
+#define VTD_CAP_FS1GP (1ULL << 56)
#define VTD_CAP_DRAIN (VTD_CAP_DRAIN_READ | VTD_CAP_DRAIN_WRITE)
#define VTD_CAP_CM (1ULL << 7)
#define VTD_PASID_ID_SHIFT 20
@@ -311,10 +313,28 @@ typedef enum VTDFaultReason {
* request while disabled */
VTD_FR_IR_SID_ERR = 0x26, /* Invalid Source-ID */
- VTD_FR_PASID_TABLE_INV = 0x58, /*Invalid PASID table entry */
+ /* PASID directory entry access failure */
+ VTD_FR_PASID_DIR_ACCESS_ERR = 0x50,
+ /* The Present(P) field of pasid directory entry is 0 */
+ VTD_FR_PASID_DIR_ENTRY_P = 0x51,
+ VTD_FR_PASID_TABLE_ACCESS_ERR = 0x58, /* PASID table entry access failure */
+ /* The Present(P) field of pasid table entry is 0 */
+ VTD_FR_PASID_ENTRY_P = 0x59,
+ VTD_FR_PASID_TABLE_ENTRY_INV = 0x5b, /*Invalid PASID table entry */
+
+ /* Fail to access a first-level paging entry (not FS_PML4E) */
+ VTD_FR_FS_PAGING_ENTRY_INV = 0x70,
+ VTD_FR_FS_PAGING_ENTRY_P = 0x71,
+ /* Non-zero reserved field in present first-stage paging entry */
+ VTD_FR_FS_PAGING_ENTRY_RSVD = 0x72,
+ VTD_FR_PASID_ENTRY_FSPTPTR_INV = 0x73, /* Invalid FSPTPTR in PASID entry */
+ VTD_FR_FS_NON_CANONICAL = 0x80, /* SNG.1 : Address for FS not canonical.*/
+ VTD_FR_FS_PAGING_ENTRY_US = 0x81, /* Privilege violation */
+ VTD_FR_SM_WRITE = 0x85, /* No write permission */
/* Output address in the interrupt address range for scalable mode */
VTD_FR_SM_INTERRUPT_ADDR = 0x87,
+ VTD_FR_FS_BIT_UPDATE_FAILED = 0x91, /* SFS.10 */
VTD_FR_MAX, /* Guard */
} VTDFaultReason;
@@ -356,7 +376,9 @@ union VTDInvDesc {
typedef union VTDInvDesc VTDInvDesc;
/* Masks for struct VTDInvDesc */
-#define VTD_INV_DESC_TYPE 0xf
+#define VTD_INV_DESC_ALL_ONE -1ULL
+#define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \
+ ((val) & 0xfULL))
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
#define VTD_INV_DESC_IOTLB 0x2
#define VTD_INV_DESC_DEVICE 0x3
@@ -365,6 +387,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */
#define VTD_INV_DESC_PIOTLB 0x6 /* PASID-IOTLB Invalidate Desc */
#define VTD_INV_DESC_PC 0x7 /* PASID-cache Invalidate Desc */
+#define VTD_INV_DESC_DEV_PIOTLB 0x8 /* PASID-based-DIOTLB inv_desc*/
#define VTD_INV_DESC_NONE 0 /* Not an Invalidate Descriptor */
/* Masks for Invalidation Wait Descriptor*/
@@ -372,7 +395,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_WAIT_IF (1ULL << 4)
#define VTD_INV_DESC_WAIT_FN (1ULL << 6)
#define VTD_INV_DESC_WAIT_DATA_SHIFT 32
-#define VTD_INV_DESC_WAIT_RSVD_LO 0Xffffff80ULL
+#define VTD_INV_DESC_WAIT_RSVD_LO 0Xfffff180ULL
#define VTD_INV_DESC_WAIT_RSVD_HI 3ULL
/* Masks for Context-cache Invalidation Descriptor */
@@ -383,7 +406,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_CC_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_CC_SID(val) (((val) >> 32) & 0xffffUL)
#define VTD_INV_DESC_CC_FM(val) (((val) >> 48) & 3UL)
-#define VTD_INV_DESC_CC_RSVD 0xfffc00000000ffc0ULL
+#define VTD_INV_DESC_CC_RSVD 0xfffc00000000f1c0ULL
/* Masks for IOTLB Invalidate Descriptor */
#define VTD_INV_DESC_IOTLB_G (3ULL << 4)
@@ -393,26 +416,34 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_IOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_IOTLB_ADDR(val) ((val) & ~0xfffULL)
#define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL)
-#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL
+#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
-#define VTD_INV_DESC_IOTLB_PASID_PASID (2ULL << 4)
-#define VTD_INV_DESC_IOTLB_PASID_PAGE (3ULL << 4)
-#define VTD_INV_DESC_IOTLB_PASID(val) (((val) >> 32) & VTD_PASID_ID_MASK)
-#define VTD_INV_DESC_IOTLB_PASID_RSVD_LO 0xfff00000000001c0ULL
-#define VTD_INV_DESC_IOTLB_PASID_RSVD_HI 0xf80ULL
/* Mask for Device IOTLB Invalidate Descriptor */
#define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL)
#define VTD_INV_DESC_DEVICE_IOTLB_SIZE(val) ((val) & 0x1)
#define VTD_INV_DESC_DEVICE_IOTLB_SID(val) (((val) >> 32) & 0xFFFFULL)
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL
-#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0fff8
+#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0f1f0
+
+/* Masks for Interrupt Entry Invalidate Descriptor */
+#define VTD_INV_DESC_IEC_RSVD 0xffff000007fff1e0ULL
+
+/* Masks for PASID based Device IOTLB Invalidate Descriptor */
+#define VTD_INV_DESC_PASID_DEVICE_IOTLB_ADDR(val) ((val) & \
+ 0xfffffffffffff000ULL)
+#define VTD_INV_DESC_PASID_DEVICE_IOTLB_SIZE(val) ((val >> 11) & 0x1)
+#define VTD_INV_DESC_PASID_DEVICE_IOTLB_GLOBAL(val) ((val) & 0x1)
+#define VTD_INV_DESC_PASID_DEVICE_IOTLB_SID(val) (((val) >> 16) & 0xffffULL)
+#define VTD_INV_DESC_PASID_DEVICE_IOTLB_PASID(val) ((val >> 32) & 0xfffffULL)
+#define VTD_INV_DESC_PASID_DEVICE_IOTLB_RSVD_VAL0 0xfff000000000f000ULL
+#define VTD_INV_DESC_PASID_DEVICE_IOTLB_RSVD_VAL1 0x7feULL
/* Rsvd field masks for spte */
#define VTD_SPTE_SNP 0x800ULL
-#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, dt_supported) \
- dt_supported ? \
+#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, stale_tm) \
+ stale_tm ? \
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
#define VTD_SPTE_PAGE_L2_RSVD_MASK(aw) \
@@ -422,15 +453,43 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_SPTE_PAGE_L4_RSVD_MASK(aw) \
(0x880ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
-#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, dt_supported) \
- dt_supported ? \
+#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, stale_tm) \
+ stale_tm ? \
(0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
-#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, dt_supported) \
- dt_supported ? \
+#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, stale_tm) \
+ stale_tm ? \
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
+/* Rsvd field masks for fpte */
+#define VTD_FS_UPPER_IGNORED 0xfff0000000000000ULL
+#define VTD_FPTE_PAGE_L1_RSVD_MASK(aw) \
+ (~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
+#define VTD_FPTE_PAGE_L2_RSVD_MASK(aw) \
+ (~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
+#define VTD_FPTE_PAGE_L3_RSVD_MASK(aw) \
+ (~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
+#define VTD_FPTE_PAGE_L4_RSVD_MASK(aw) \
+ (0x80ULL | ~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
+
+#define VTD_FPTE_LPAGE_L2_RSVD_MASK(aw) \
+ (0x1fe000ULL | ~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
+#define VTD_FPTE_LPAGE_L3_RSVD_MASK(aw) \
+ (0x3fffe000ULL | ~(VTD_HAW_MASK(aw) | VTD_FS_UPPER_IGNORED))
+
+/* Masks for PIOTLB Invalidate Descriptor */
+#define VTD_INV_DESC_PIOTLB_G (3ULL << 4)
+#define VTD_INV_DESC_PIOTLB_ALL_IN_PASID (2ULL << 4)
+#define VTD_INV_DESC_PIOTLB_PSI_IN_PASID (3ULL << 4)
+#define VTD_INV_DESC_PIOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
+#define VTD_INV_DESC_PIOTLB_PASID(val) (((val) >> 32) & 0xfffffULL)
+#define VTD_INV_DESC_PIOTLB_AM(val) ((val) & 0x3fULL)
+#define VTD_INV_DESC_PIOTLB_IH(val) (((val) >> 6) & 0x1)
+#define VTD_INV_DESC_PIOTLB_ADDR(val) ((val) & ~0xfffULL)
+#define VTD_INV_DESC_PIOTLB_RSVD_VAL0 0xfff000000000f1c0ULL
+#define VTD_INV_DESC_PIOTLB_RSVD_VAL1 0xf80ULL
+
/* Information about page-selective IOTLB invalidate */
struct VTDIOTLBPageInvInfo {
uint16_t domain_id;
@@ -514,27 +573,38 @@ typedef struct VTDRootEntry VTDRootEntry;
#define VTD_SM_PASID_ENTRY_AW 7ULL /* Adjusted guest-address-width */
#define VTD_SM_PASID_ENTRY_DID(val) ((val) & VTD_DOMAIN_ID_MASK)
+#define VTD_SM_PASID_ENTRY_FLPM 3ULL
+#define VTD_SM_PASID_ENTRY_FLPTPTR (~0xfffULL)
+
+/* First Level Paging Structure */
+/* Masks for First Level Paging Entry */
+#define VTD_FL_P 1ULL
+#define VTD_FL_RW (1ULL << 1)
+#define VTD_FL_US (1ULL << 2)
+#define VTD_FL_A (1ULL << 5)
+#define VTD_FL_D (1ULL << 6)
+
/* Second Level Page Translation Pointer*/
#define VTD_SM_PASID_ENTRY_SLPTPTR (~0xfffULL)
-/* Paging Structure common */
-#define VTD_SL_PT_PAGE_SIZE_MASK (1ULL << 7)
-/* Bits to decide the offset for each level */
-#define VTD_SL_LEVEL_BITS 9
-
/* Second Level Paging Structure */
-#define VTD_SL_PML4_LEVEL 4
-#define VTD_SL_PDP_LEVEL 3
-#define VTD_SL_PD_LEVEL 2
-#define VTD_SL_PT_LEVEL 1
-#define VTD_SL_PT_ENTRY_NR 512
-
/* Masks for Second Level Paging Entry */
#define VTD_SL_RW_MASK 3ULL
#define VTD_SL_R 1ULL
#define VTD_SL_W (1ULL << 1)
-#define VTD_SL_PT_BASE_ADDR_MASK(aw) (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK(aw))
#define VTD_SL_IGN_COM 0xbff0000000000000ULL
#define VTD_SL_TM (1ULL << 62)
+/* Common for both First Level and Second Level */
+#define VTD_PML4_LEVEL 4
+#define VTD_PDP_LEVEL 3
+#define VTD_PD_LEVEL 2
+#define VTD_PT_LEVEL 1
+#define VTD_PT_ENTRY_NR 512
+#define VTD_PT_PAGE_SIZE_MASK (1ULL << 7)
+#define VTD_PT_BASE_ADDR_MASK(aw) (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK(aw))
+
+/* Bits to decide the offset for each level */
+#define VTD_LEVEL_BITS 9
+
#endif
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index a72c28e..1be9bfe 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -14,9 +14,10 @@
#include "qemu/module.h"
#include "hw/i386/apic_internal.h"
#include "hw/pci/msi.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/kvm.h"
+#include "system/hw_accel.h"
+#include "system/kvm.h"
#include "kvm/kvm_i386.h"
+#include "kvm/tdx.h"
static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
int reg_id, uint32_t val)
@@ -141,6 +142,10 @@ static void kvm_apic_put(CPUState *cs, run_on_cpu_data data)
struct kvm_lapic_state kapic;
int ret;
+ if (is_tdx_vm()) {
+ return;
+ }
+
kvm_put_apicbase(s->cpu, s->apicbase);
kvm_put_apic_state(s, &kapic);
@@ -214,7 +219,7 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr,
static const MemoryRegionOps kvm_apic_io_ops = {
.read = kvm_apic_mem_read,
.write = kvm_apic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void kvm_apic_reset(APICCommonState *s)
@@ -240,7 +245,7 @@ static void kvm_apic_unrealize(DeviceState *dev)
{
}
-static void kvm_apic_class_init(ObjectClass *klass, void *data)
+static void kvm_apic_class_init(ObjectClass *klass, const void *data)
{
APICCommonClass *k = APIC_COMMON_CLASS(klass);
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index 40aa9a3..f563827 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -16,9 +16,9 @@
#include "qemu/osdep.h"
#include "qemu/host-utils.h"
#include "qemu/module.h"
-#include "sysemu/kvm.h"
-#include "sysemu/runstate.h"
-#include "sysemu/hw_accel.h"
+#include "system/kvm.h"
+#include "system/runstate.h"
+#include "system/hw_accel.h"
#include "kvm/kvm_i386.h"
#include "migration/vmstate.h"
#include "hw/sysbus.h"
@@ -27,7 +27,6 @@
#include "qapi/error.h"
#include <linux/kvm.h>
-#include "standard-headers/asm-x86/kvm_para.h"
#include "qom/object.h"
#define TYPE_KVM_CLOCK "kvmclock"
@@ -305,13 +304,12 @@ static const VMStateDescription kvmclock_vmsd = {
}
};
-static Property kvmclock_properties[] = {
+static const Property kvmclock_properties[] = {
DEFINE_PROP_BOOL("x-mach-use-reliable-get-clock", KVMClockState,
mach_use_reliable_get_clock, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void kvmclock_class_init(ObjectClass *klass, void *data)
+static void kvmclock_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -334,8 +332,8 @@ void kvmclock_create(bool create_always)
assert(kvm_enabled());
if (create_always ||
- cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
- (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
+ cpu->env.features[FEAT_KVM] & (CPUID_KVM_CLOCK |
+ CPUID_KVM_CLOCK2)) {
sysbus_create_simple(TYPE_KVM_CLOCK, -1, NULL);
}
}
diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c
index e49b9c4..14b78f3 100644
--- a/hw/i386/kvm/i8254.c
+++ b/hw/i386/kvm/i8254.c
@@ -29,11 +29,11 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/timer/i8254.h"
#include "hw/timer/i8254_internal.h"
#include "hw/qdev-properties-system.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "target/i386/kvm/kvm_i386.h"
#include "qom/object.h"
@@ -287,13 +287,12 @@ static void kvm_pit_realizefn(DeviceState *dev, Error **errp)
kpc->parent_realize(dev, errp);
}
-static Property kvm_pit_properties[] = {
+static const Property kvm_pit_properties[] = {
DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
lost_tick_policy, LOST_TICK_POLICY_DELAY),
- DEFINE_PROP_END_OF_LIST(),
};
-static void kvm_pit_class_init(ObjectClass *klass, void *data)
+static void kvm_pit_class_init(ObjectClass *klass, const void *data)
{
KVMPITClass *kpc = KVM_PIT_CLASS(klass);
PITCommonClass *k = PIT_COMMON_CLASS(klass);
@@ -303,7 +302,7 @@ static void kvm_pit_class_init(ObjectClass *klass, void *data)
&kpc->parent_realize);
k->set_channel_gate = kvm_pit_set_gate;
k->get_channel_info = kvm_pit_get_channel_info;
- dc->reset = kvm_pit_reset;
+ device_class_set_legacy_reset(dc, kvm_pit_reset);
device_class_set_props(dc, kvm_pit_properties);
}
diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c
index 3ca0e1f..8a72d6e 100644
--- a/hw/i386/kvm/i8259.c
+++ b/hw/i386/kvm/i8259.c
@@ -16,7 +16,7 @@
#include "qemu/module.h"
#include "hw/intc/kvm_irqcount.h"
#include "hw/irq.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "qom/object.h"
#define TYPE_KVM_I8259 "kvm-i8259"
@@ -139,13 +139,13 @@ qemu_irq *kvm_i8259_init(ISABus *bus)
return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
}
-static void kvm_i8259_class_init(ObjectClass *klass, void *data)
+static void kvm_i8259_class_init(ObjectClass *klass, const void *data)
{
KVMPICClass *kpc = KVM_PIC_CLASS(klass);
PICCommonClass *k = PIC_COMMON_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = kvm_pic_reset;
+ device_class_set_legacy_reset(dc, kvm_pic_reset);
device_class_set_parent_realize(dc, kvm_pic_realize, &kpc->parent_realize);
k->pre_save = kvm_pic_get;
k->post_load = kvm_pic_put;
diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c
index b96fe84..693ee97 100644
--- a/hw/i386/kvm/ioapic.c
+++ b/hw/i386/kvm/ioapic.c
@@ -15,7 +15,7 @@
#include "hw/qdev-properties.h"
#include "hw/intc/ioapic_internal.h"
#include "hw/intc/kvm_irqcount.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm/kvm_i386.h"
/* PC Utility function */
@@ -133,12 +133,11 @@ static void kvm_ioapic_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(dev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
}
-static Property kvm_ioapic_properties[] = {
+static const Property kvm_ioapic_properties[] = {
DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
+static void kvm_ioapic_class_init(ObjectClass *klass, const void *data)
{
IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -146,7 +145,7 @@ static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
k->realize = kvm_ioapic_realize;
k->pre_save = kvm_ioapic_get;
k->post_load = kvm_ioapic_put;
- dc->reset = kvm_ioapic_reset;
+ device_class_set_legacy_reset(dc, kvm_ioapic_reset);
device_class_set_props(dc, kvm_ioapic_properties);
}
diff --git a/hw/i386/kvm/xen-stubs.c b/hw/i386/kvm/xen-stubs.c
index d03131e..ce73119 100644
--- a/hw/i386/kvm/xen-stubs.c
+++ b/hw/i386/kvm/xen-stubs.c
@@ -12,7 +12,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc-target.h"
#include "xen_evtchn.h"
#include "xen_primary_console.h"
@@ -38,15 +37,3 @@ void xen_primary_console_create(void)
void xen_primary_console_set_be_port(uint16_t port)
{
}
-#ifdef TARGET_I386
-EvtchnInfoList *qmp_xen_event_list(Error **errp)
-{
- error_setg(errp, "Xen event channel emulation not enabled");
- return NULL;
-}
-
-void qmp_xen_event_inject(uint32_t port, Error **errp)
-{
- error_setg(errp, "Xen event channel emulation not enabled");
-}
-#endif
diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c
index 07bd0c9..dd566c4 100644
--- a/hw/i386/kvm/xen_evtchn.c
+++ b/hw/i386/kvm/xen_evtchn.c
@@ -19,11 +19,11 @@
#include "monitor/monitor.h"
#include "monitor/hmp.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc-target.h"
-#include "qapi/qmp/qdict.h"
+#include "qapi/qapi-commands-misc-i386.h"
+#include "qobject/qdict.h"
#include "qom/object.h"
#include "exec/target_page.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "migration/vmstate.h"
#include "trace.h"
@@ -41,8 +41,8 @@
#include "xen_overlay.h"
#include "xen_xenstore.h"
-#include "sysemu/kvm.h"
-#include "sysemu/kvm_xen.h"
+#include "system/kvm.h"
+#include "system/kvm_xen.h"
#include <linux/kvm.h>
#include <sys/eventfd.h>
@@ -140,6 +140,8 @@ struct XenEvtchnState {
uint64_t callback_param;
bool evtchn_in_kernel;
+ bool setting_callback_gsi;
+ int extern_gsi_level;
uint32_t callback_gsi;
QEMUBH *gsi_bh;
@@ -269,7 +271,7 @@ static const VMStateDescription xen_evtchn_vmstate = {
}
};
-static void xen_evtchn_class_init(ObjectClass *klass, void *data)
+static void xen_evtchn_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -431,9 +433,22 @@ void xen_evtchn_set_callback_level(int level)
}
if (s->callback_gsi && s->callback_gsi < s->nr_callback_gsis) {
- qemu_set_irq(s->callback_gsis[s->callback_gsi], level);
- if (level) {
- /* Ensure the vCPU polls for deassertion */
+ /*
+ * Ugly, but since we hold the BQL we can set this flag so that
+ * xen_evtchn_set_gsi() can tell the difference between this code
+ * setting the GSI, and an external device (PCI INTx) doing so.
+ */
+ s->setting_callback_gsi = true;
+ /* Do not deassert the line if an external device is asserting it. */
+ qemu_set_irq(s->callback_gsis[s->callback_gsi],
+ level || s->extern_gsi_level);
+ s->setting_callback_gsi = false;
+
+ /*
+ * If the callback GSI is the only one asserted, ensure the status
+ * is polled for deassertion in kvm_arch_post_run().
+ */
+ if (level && !s->extern_gsi_level) {
kvm_xen_set_callback_asserted();
}
}
@@ -1596,7 +1611,7 @@ static int allocate_pirq(XenEvtchnState *s, int type, int gsi)
return pirq;
}
-bool xen_evtchn_set_gsi(int gsi, int level)
+bool xen_evtchn_set_gsi(int gsi, int *level)
{
XenEvtchnState *s = xen_evtchn_singleton;
int pirq;
@@ -1608,16 +1623,35 @@ bool xen_evtchn_set_gsi(int gsi, int level)
}
/*
- * Check that that it *isn't* the event channel GSI, and thus
- * that we are not recursing and it's safe to take s->port_lock.
- *
- * Locking aside, it's perfectly sane to bail out early for that
- * special case, as it would make no sense for the event channel
- * GSI to be routed back to event channels, when the delivery
- * method is to raise the GSI... that recursion wouldn't *just*
- * be a locking issue.
+ * For the callback_gsi we need to implement a logical OR of the event
+ * channel GSI and the external input (e.g. from PCI INTx), because
+ * QEMU itself doesn't support shared level interrupts via demux or
+ * resamplers.
*/
if (gsi && gsi == s->callback_gsi) {
+ /* Remember the external state of the GSI pin (e.g. from PCI INTx) */
+ if (!s->setting_callback_gsi) {
+ s->extern_gsi_level = *level;
+
+ /*
+ * Don't allow the external device to deassert the line if the
+ * eveht channel GSI should still be asserted.
+ */
+ if (!s->extern_gsi_level) {
+ struct vcpu_info *vi = kvm_xen_get_vcpu_info_hva(0);
+ if (vi && vi->evtchn_upcall_pending) {
+ /* Need to poll for deassertion */
+ kvm_xen_set_callback_asserted();
+ *level = 1;
+ }
+ }
+ }
+
+ /*
+ * The event channel GSI cannot be routed to PIRQ, as that would make
+ * no sense. It could also deadlock on s->port_lock, if we proceed.
+ * So bail out now.
+ */
return false;
}
@@ -1628,7 +1662,7 @@ bool xen_evtchn_set_gsi(int gsi, int level)
return false;
}
- if (level) {
+ if (*level) {
int port = s->pirq[pirq].port;
s->pirq_gsi_set |= (1U << gsi);
diff --git a/hw/i386/kvm/xen_evtchn.h b/hw/i386/kvm/xen_evtchn.h
index b740acf..0521ebc 100644
--- a/hw/i386/kvm/xen_evtchn.h
+++ b/hw/i386/kvm/xen_evtchn.h
@@ -23,7 +23,7 @@ void xen_evtchn_set_callback_level(int level);
int xen_evtchn_set_port(uint16_t port);
-bool xen_evtchn_set_gsi(int gsi, int level);
+bool xen_evtchn_set_gsi(int gsi, int *level);
void xen_evtchn_snoop_msi(PCIDevice *dev, bool is_msix, unsigned int vector,
uint64_t addr, uint32_t data, bool is_masked);
void xen_evtchn_remove_pci_device(PCIDevice *dev);
diff --git a/hw/i386/kvm/xen_gnttab.c b/hw/i386/kvm/xen_gnttab.c
index 245e4b1..4b9e272 100644
--- a/hw/i386/kvm/xen_gnttab.c
+++ b/hw/i386/kvm/xen_gnttab.c
@@ -17,7 +17,7 @@
#include "qapi/error.h"
#include "qom/object.h"
#include "exec/target_page.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "migration/vmstate.h"
#include "hw/sysbus.h"
@@ -27,8 +27,8 @@
#include "xen_gnttab.h"
#include "xen_primary_console.h"
-#include "sysemu/kvm.h"
-#include "sysemu/kvm_xen.h"
+#include "system/kvm.h"
+#include "system/kvm_xen.h"
#include "hw/xen/interface/memory.h"
#include "hw/xen/interface/grant_table.h"
@@ -135,7 +135,7 @@ static const VMStateDescription xen_gnttab_vmstate = {
}
};
-static void xen_gnttab_class_init(ObjectClass *klass, void *data)
+static void xen_gnttab_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/i386/kvm/xen_overlay.c b/hw/i386/kvm/xen_overlay.c
index c68e78a..3cb7361 100644
--- a/hw/i386/kvm/xen_overlay.c
+++ b/hw/i386/kvm/xen_overlay.c
@@ -16,15 +16,15 @@
#include "qapi/error.h"
#include "qom/object.h"
#include "exec/target_page.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "migration/vmstate.h"
#include "hw/sysbus.h"
#include "hw/xen/xen.h"
#include "xen_overlay.h"
-#include "sysemu/kvm.h"
-#include "sysemu/kvm_xen.h"
+#include "system/kvm.h"
+#include "system/kvm_xen.h"
#include <linux/kvm.h>
#include "hw/xen/interface/memory.h"
@@ -151,11 +151,11 @@ static void xen_overlay_reset(DeviceState *dev)
kvm_xen_soft_reset();
}
-static void xen_overlay_class_init(ObjectClass *klass, void *data)
+static void xen_overlay_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xen_overlay_reset;
+ device_class_set_legacy_reset(dc, xen_overlay_reset);
dc->realize = xen_overlay_realize;
dc->vmsd = &xen_overlay_vmstate;
}
diff --git a/hw/i386/kvm/xen_primary_console.c b/hw/i386/kvm/xen_primary_console.c
index abe79f5..6e9d641 100644
--- a/hw/i386/kvm/xen_primary_console.c
+++ b/hw/i386/kvm/xen_primary_console.c
@@ -20,8 +20,8 @@
#include "xen_overlay.h"
#include "xen_primary_console.h"
-#include "sysemu/kvm.h"
-#include "sysemu/kvm_xen.h"
+#include "system/kvm.h"
+#include "system/kvm_xen.h"
#include "trace.h"
@@ -67,7 +67,7 @@ static void xen_primary_console_realize(DeviceState *dev, Error **errp)
xen_primary_console_singleton = s;
}
-static void xen_primary_console_class_init(ObjectClass *klass, void *data)
+static void xen_primary_console_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c
index 1a9bc34..42955cc 100644
--- a/hw/i386/kvm/xen_xenstore.c
+++ b/hw/i386/kvm/xen_xenstore.c
@@ -28,8 +28,8 @@
#include "xen_primary_console.h"
#include "xen_xenstore.h"
-#include "sysemu/kvm.h"
-#include "sysemu/kvm_xen.h"
+#include "system/kvm.h"
+#include "system/kvm_xen.h"
#include "trace.h"
@@ -209,7 +209,6 @@ static int xen_xenstore_post_load(void *opaque, int ver)
{
XenXenstoreState *s = opaque;
GByteArray *save;
- int ret;
/*
* As qemu/dom0, rebind to the guest's port. The Windows drivers may
@@ -231,8 +230,7 @@ static int xen_xenstore_post_load(void *opaque, int ver)
s->impl_state = NULL;
s->impl_state_size = 0;
- ret = xs_impl_deserialize(s->impl, save, xen_domid, fire_watch_cb, s);
- return ret;
+ return xs_impl_deserialize(s->impl, save, xen_domid, fire_watch_cb, s);
}
static const VMStateDescription xen_xenstore_vmstate = {
@@ -261,7 +259,7 @@ static const VMStateDescription xen_xenstore_vmstate = {
}
};
-static void xen_xenstore_class_init(ObjectClass *klass, void *data)
+static void xen_xenstore_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -532,6 +530,10 @@ static void xs_read(XenXenstoreState *s, unsigned int req_id,
return;
}
+ if (!len) {
+ return;
+ }
+
memcpy(&rsp_data[rsp->len], data->data, len);
rsp->len += len;
}
diff --git a/hw/i386/meson.build b/hw/i386/meson.build
index 03aad10..7896f34 100644
--- a/hw/i386/meson.build
+++ b/hw/i386/meson.build
@@ -15,6 +15,7 @@ i386_ss.add(when: 'CONFIG_AMD_IOMMU', if_true: files('amd_iommu.c'),
if_false: files('amd_iommu-stub.c'))
i386_ss.add(when: 'CONFIG_I440FX', if_true: files('pc_piix.c'))
i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('x86-common.c', 'microvm.c', 'acpi-microvm.c', 'microvm-dt.c'))
+i386_ss.add(when: 'CONFIG_NITRO_ENCLAVE', if_true: files('nitro_enclave.c'))
i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
@@ -31,6 +32,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files(
'port92.c'))
i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'),
if_false: files('pc_sysfw_ovmf-stubs.c'))
+i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c'))
subdir('kvm')
subdir('xen')
diff --git a/hw/i386/microvm-dt.c b/hw/i386/microvm-dt.c
index b3049e4..cb27dfd 100644
--- a/hw/i386/microvm-dt.c
+++ b/hw/i386/microvm-dt.c
@@ -33,8 +33,8 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "sysemu/device_tree.h"
-#include "hw/char/serial.h"
+#include "system/device_tree.h"
+#include "hw/char/serial-isa.h"
#include "hw/i386/fw_cfg.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/sysbus.h"
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 40edcee..e0daf0d 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -22,11 +22,11 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qapi/qapi-visit-common.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/numa.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/cpus.h"
+#include "system/numa.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "acpi-microvm.h"
#include "microvm-dt.h"
@@ -39,7 +39,7 @@
#include "hw/intc/i8259.h"
#include "hw/timer/i8254.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/display/ramfb.h"
#include "hw/i386/topology.h"
#include "hw/i386/e820_memory_layout.h"
@@ -139,7 +139,7 @@ static void create_gpex(MicrovmMachineState *mms)
mms->gpex.mmio64.base, mmio64_alias);
}
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
x86ms->gsi[mms->gpex.irq + i]);
}
@@ -283,6 +283,7 @@ static void microvm_devices_init(MicrovmMachineState *mms)
static void microvm_memory_init(MicrovmMachineState *mms)
{
+ MicrovmMachineClass *mmc = MICROVM_MACHINE_GET_CLASS(mms);
MachineState *machine = MACHINE(mms);
X86MachineState *x86ms = X86_MACHINE(mms);
MemoryRegion *ram_below_4g, *ram_above_4g;
@@ -328,7 +329,7 @@ static void microvm_memory_init(MicrovmMachineState *mms)
rom_set_fw(fw_cfg);
if (machine->kernel_filename != NULL) {
- x86_load_linux(x86ms, fw_cfg, 0, true);
+ mmc->x86_load_linux(x86ms, fw_cfg, 0, true);
}
if (mms->option_roms) {
@@ -450,11 +451,44 @@ static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
return NULL;
}
+static void microvm_machine_done(Notifier *notifier, void *data)
+{
+ MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
+ machine_done);
+ X86MachineState *x86ms = X86_MACHINE(mms);
+
+ acpi_setup_microvm(mms);
+ dt_setup_microvm(mms);
+ fw_cfg_add_e820(x86ms->fw_cfg);
+}
+
+static void microvm_powerdown_req(Notifier *notifier, void *data)
+{
+ MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
+ powerdown_req);
+ X86MachineState *x86ms = X86_MACHINE(mms);
+
+ if (x86ms->acpi_dev) {
+ Object *obj = OBJECT(x86ms->acpi_dev);
+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
+ adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
+ ACPI_POWER_DOWN_STATUS);
+ }
+}
+
static void microvm_machine_state_init(MachineState *machine)
{
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
X86MachineState *x86ms = X86_MACHINE(machine);
+ /* State */
+ mms->kernel_cmdline_fixed = false;
+
+ mms->machine_done.notify = microvm_machine_done;
+ qemu_add_machine_init_done_notifier(&mms->machine_done);
+ mms->powerdown_req.notify = microvm_powerdown_req;
+ qemu_register_powerdown_notifier(&mms->powerdown_req);
+
microvm_memory_init(mms);
x86_cpus_init(x86ms, CPU_VERSION_LATEST);
@@ -462,7 +496,7 @@ static void microvm_machine_state_init(MachineState *machine)
microvm_devices_init(mms);
}
-static void microvm_machine_reset(MachineState *machine, ShutdownCause reason)
+static void microvm_machine_reset(MachineState *machine, ResetType type)
{
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
CPUState *cs;
@@ -475,7 +509,7 @@ static void microvm_machine_reset(MachineState *machine, ShutdownCause reason)
mms->kernel_cmdline_fixed = true;
}
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
CPU_FOREACH(cs) {
cpu = X86_CPU(cs);
@@ -580,31 +614,6 @@ static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value,
mms->auto_kernel_cmdline = value;
}
-static void microvm_machine_done(Notifier *notifier, void *data)
-{
- MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
- machine_done);
- X86MachineState *x86ms = X86_MACHINE(mms);
-
- acpi_setup_microvm(mms);
- dt_setup_microvm(mms);
- fw_cfg_add_e820(x86ms->fw_cfg);
-}
-
-static void microvm_powerdown_req(Notifier *notifier, void *data)
-{
- MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
- powerdown_req);
- X86MachineState *x86ms = X86_MACHINE(mms);
-
- if (x86ms->acpi_dev) {
- Object *obj = OBJECT(x86ms->acpi_dev);
- AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
- adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
- ACPI_POWER_DOWN_STATUS);
- }
-}
-
static void microvm_machine_initfn(Object *obj)
{
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
@@ -616,14 +625,6 @@ static void microvm_machine_initfn(Object *obj)
mms->isa_serial = true;
mms->option_roms = true;
mms->auto_kernel_cmdline = true;
-
- /* State */
- mms->kernel_cmdline_fixed = false;
-
- mms->machine_done.notify = microvm_machine_done;
- qemu_add_machine_init_done_notifier(&mms->machine_done);
- mms->powerdown_req.notify = microvm_powerdown_req;
- qemu_register_powerdown_notifier(&mms->powerdown_req);
}
GlobalProperty microvm_properties[] = {
@@ -634,12 +635,15 @@ GlobalProperty microvm_properties[] = {
{ "pcie-root-port", "io-reserve", "0" },
};
-static void microvm_class_init(ObjectClass *oc, void *data)
+static void microvm_class_init(ObjectClass *oc, const void *data)
{
X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
+ MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+ mmc->x86_load_linux = x86_load_linux;
+
mc->init = microvm_machine_state_init;
mc->family = "microvm_i386";
@@ -722,7 +726,7 @@ static const TypeInfo microvm_machine_info = {
.instance_init = microvm_machine_initfn,
.class_size = sizeof(MicrovmMachineClass),
.class_init = microvm_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
},
diff --git a/hw/i386/monitor.c b/hw/i386/monitor.c
index 1ebd356..79df965 100644
--- a/hw/i386/monitor.c
+++ b/hw/i386/monitor.c
@@ -24,9 +24,9 @@
#include "qemu/osdep.h"
#include "monitor/monitor.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc-target.h"
+#include "qapi/qapi-commands-misc-i386.h"
#include "hw/i386/x86.h"
#include "hw/rtc/mc146818rtc.h"
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
index 3332712..6e6b96b 100644
--- a/hw/i386/multiboot.c
+++ b/hw/i386/multiboot.c
@@ -29,7 +29,8 @@
#include "multiboot.h"
#include "hw/loader.h"
#include "elf.h"
-#include "sysemu/sysemu.h"
+#include "exec/target_page.h"
+#include "system/system.h"
#include "qemu/error-report.h"
/* Show multiboot debug output */
@@ -133,9 +134,9 @@ static void mb_add_mod(MultibootState *s,
p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
- stl_p(p + MB_MOD_START, start);
- stl_p(p + MB_MOD_END, end);
- stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+ stl_le_p(p + MB_MOD_START, start);
+ stl_le_p(p + MB_MOD_END, end);
+ stl_le_p(p + MB_MOD_CMDLINE, cmdline_phys);
mb_debug("mod%02d: "HWADDR_FMT_plx" - "HWADDR_FMT_plx,
s->mb_mods_count, start, end);
@@ -168,9 +169,9 @@ int load_multiboot(X86MachineState *x86ms,
/* Ok, let's see if it is a multiboot image.
The header is 12x32bit long, so the latest entry may be 8192 - 48. */
for (i = 0; i < (8192 - 48); i += 4) {
- if (ldl_p(header+i) == 0x1BADB002) {
- uint32_t checksum = ldl_p(header+i+8);
- flags = ldl_p(header+i+4);
+ if (ldl_le_p(header + i) == 0x1BADB002) {
+ uint32_t checksum = ldl_le_p(header + i + 8);
+ flags = ldl_le_p(header + i + 4);
checksum += flags;
checksum += (uint32_t)0x1BADB002;
if (!checksum) {
@@ -202,8 +203,8 @@ int load_multiboot(X86MachineState *x86ms,
}
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
- &elf_low, &elf_high, NULL, 0, I386_ELF_MACHINE,
- 0, 0);
+ &elf_low, &elf_high, NULL,
+ ELFDATA2LSB, I386_ELF_MACHINE, 0, 0);
if (kernel_size < 0) {
error_report("Error while loading elf kernel");
exit(1);
@@ -223,11 +224,11 @@ int load_multiboot(X86MachineState *x86ms,
mb_kernel_size, (size_t)mh_entry_addr);
} else {
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
- uint32_t mh_header_addr = ldl_p(header+i+12);
- uint32_t mh_load_end_addr = ldl_p(header+i+20);
- uint32_t mh_bss_end_addr = ldl_p(header+i+24);
+ uint32_t mh_header_addr = ldl_le_p(header + i + 12);
+ uint32_t mh_load_end_addr = ldl_le_p(header + i + 20);
+ uint32_t mh_bss_end_addr = ldl_le_p(header + i + 24);
- mh_load_addr = ldl_p(header+i+16);
+ mh_load_addr = ldl_le_p(header + i + 16);
if (mh_header_addr < mh_load_addr) {
error_report("invalid load_addr address");
exit(1);
@@ -239,7 +240,7 @@ int load_multiboot(X86MachineState *x86ms,
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
uint32_t mb_load_size = 0;
- mh_entry_addr = ldl_p(header+i+28);
+ mh_entry_addr = ldl_le_p(header + i + 28);
if (mh_load_end_addr) {
if (mh_load_end_addr < mh_load_addr) {
@@ -364,22 +365,21 @@ int load_multiboot(X86MachineState *x86ms,
/* Commandline support */
kcmdline = g_strdup_printf("%s %s", kernel_filename, kernel_cmdline);
- stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
-
- stl_p(bootinfo + MBI_BOOTLOADER, mb_add_bootloader(&mbs, bootloader_name));
-
- stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
- stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
+ stl_le_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+ stl_le_p(bootinfo + MBI_BOOTLOADER, mb_add_bootloader(&mbs,
+ bootloader_name));
+ stl_le_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
+ stl_le_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
/* the kernel is where we want it to be now */
- stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+ stl_le_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
| MULTIBOOT_FLAGS_BOOT_DEVICE
| MULTIBOOT_FLAGS_CMDLINE
| MULTIBOOT_FLAGS_MODULES
| MULTIBOOT_FLAGS_MMAP
| MULTIBOOT_FLAGS_BOOTLOADER);
- stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
- stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
+ stl_le_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
+ stl_le_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
mb_debug("multiboot: entry_addr = %#x", mh_entry_addr);
mb_debug(" mb_buf_phys = "HWADDR_FMT_plx, mbs.mb_buf_phys);
diff --git a/hw/i386/nitro_enclave.c b/hw/i386/nitro_enclave.c
new file mode 100644
index 0000000..5ee50f3
--- /dev/null
+++ b/hw/i386/nitro_enclave.c
@@ -0,0 +1,353 @@
+/*
+ * AWS nitro-enclave machine
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qom/object_interfaces.h"
+
+#include "chardev/char.h"
+#include "hw/sysbus.h"
+#include "hw/core/eif.h"
+#include "hw/i386/x86.h"
+#include "hw/i386/microvm.h"
+#include "hw/i386/nitro_enclave.h"
+#include "hw/virtio/virtio-mmio.h"
+#include "hw/virtio/virtio-nsm.h"
+#include "hw/virtio/vhost-user-vsock.h"
+#include "system/hostmem.h"
+
+static BusState *find_free_virtio_mmio_bus(void)
+{
+ BusChild *kid;
+ BusState *bus = sysbus_get_default();
+
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
+ if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO)) {
+ VirtIOMMIOProxy *mmio = VIRTIO_MMIO(OBJECT(dev));
+ VirtioBusState *mmio_virtio_bus = &mmio->bus;
+ BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
+ if (QTAILQ_EMPTY(&mmio_bus->children)) {
+ return mmio_bus;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void vhost_user_vsock_init(NitroEnclaveMachineState *nems)
+{
+ DeviceState *dev = qdev_new(TYPE_VHOST_USER_VSOCK);
+ VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
+ BusState *bus;
+
+ if (!nems->vsock) {
+ error_report("A valid chardev id for vhost-user-vsock device must be "
+ "provided using the 'vsock' machine option");
+ exit(1);
+ }
+
+ bus = find_free_virtio_mmio_bus();
+ if (!bus) {
+ error_report("Failed to find bus for vhost-user-vsock device");
+ exit(1);
+ }
+
+ Chardev *chardev = qemu_chr_find(nems->vsock);
+ if (!chardev) {
+ error_report("Failed to find chardev with id %s", nems->vsock);
+ exit(1);
+ }
+
+ vsock->conf.chardev.chr = chardev;
+
+ qdev_realize_and_unref(dev, bus, &error_fatal);
+}
+
+static void virtio_nsm_init(NitroEnclaveMachineState *nems)
+{
+ DeviceState *dev = qdev_new(TYPE_VIRTIO_NSM);
+ VirtIONSM *vnsm = VIRTIO_NSM(dev);
+ BusState *bus = find_free_virtio_mmio_bus();
+
+ if (!bus) {
+ error_report("Failed to find bus for virtio-nsm device.");
+ exit(1);
+ }
+
+ qdev_prop_set_string(dev, "module-id", nems->id);
+
+ qdev_realize_and_unref(dev, bus, &error_fatal);
+ nems->vnsm = vnsm;
+}
+
+static void nitro_enclave_devices_init(NitroEnclaveMachineState *nems)
+{
+ vhost_user_vsock_init(nems);
+ virtio_nsm_init(nems);
+}
+
+static void nitro_enclave_machine_state_init(MachineState *machine)
+{
+ NitroEnclaveMachineClass *ne_class =
+ NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
+ NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
+
+ ne_class->parent_init(machine);
+ nitro_enclave_devices_init(ne_state);
+}
+
+static void nitro_enclave_machine_reset(MachineState *machine, ResetType type)
+{
+ NitroEnclaveMachineClass *ne_class =
+ NITRO_ENCLAVE_MACHINE_GET_CLASS(machine);
+ NitroEnclaveMachineState *ne_state = NITRO_ENCLAVE_MACHINE(machine);
+
+ ne_class->parent_reset(machine, type);
+
+ memset(ne_state->vnsm->pcrs, 0, sizeof(ne_state->vnsm->pcrs));
+
+ /* PCR0 */
+ ne_state->vnsm->extend_pcr(ne_state->vnsm, 0, ne_state->image_hash,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384);
+ /* PCR1 */
+ ne_state->vnsm->extend_pcr(ne_state->vnsm, 1, ne_state->bootstrap_hash,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384);
+ /* PCR2 */
+ ne_state->vnsm->extend_pcr(ne_state->vnsm, 2, ne_state->app_hash,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384);
+ /* PCR3 */
+ if (ne_state->parent_role) {
+ ne_state->vnsm->extend_pcr(ne_state->vnsm, 3,
+ (uint8_t *) ne_state->parent_role,
+ strlen(ne_state->parent_role));
+ }
+ /* PCR4 */
+ if (ne_state->parent_id) {
+ ne_state->vnsm->extend_pcr(ne_state->vnsm, 4,
+ (uint8_t *) ne_state->parent_id,
+ strlen(ne_state->parent_id));
+ }
+ /* PCR8 */
+ if (ne_state->signature_found) {
+ ne_state->vnsm->extend_pcr(ne_state->vnsm, 8,
+ ne_state->fingerprint_hash,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384);
+ }
+
+ /* First 16 PCRs are locked from boot and reserved for nitro enclave */
+ for (int i = 0; i < 16; ++i) {
+ ne_state->vnsm->lock_pcr(ne_state->vnsm, i);
+ }
+}
+
+static void nitro_enclave_machine_initfn(Object *obj)
+{
+ MicrovmMachineState *mms = MICROVM_MACHINE(obj);
+ X86MachineState *x86ms = X86_MACHINE(obj);
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ nems->id = g_strdup("i-234-enc5678");
+
+ /* AWS nitro enclaves have PCIE and ACPI disabled */
+ mms->pcie = ON_OFF_AUTO_OFF;
+ x86ms->acpi = ON_OFF_AUTO_OFF;
+}
+
+static void x86_load_eif(X86MachineState *x86ms, FWCfgState *fw_cfg,
+ int acpi_data_size, bool pvh_enabled)
+{
+ Error *err = NULL;
+ char *eif_kernel, *eif_initrd, *eif_cmdline;
+ MachineState *machine = MACHINE(x86ms);
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(x86ms);
+
+ if (!read_eif_file(machine->kernel_filename, machine->initrd_filename,
+ &eif_kernel, &eif_initrd, &eif_cmdline,
+ nems->image_hash, nems->bootstrap_hash,
+ nems->app_hash, nems->fingerprint_hash,
+ &(nems->signature_found), &err)) {
+ error_report_err(err);
+ exit(1);
+ }
+
+ g_free(machine->kernel_filename);
+ machine->kernel_filename = eif_kernel;
+ g_free(machine->initrd_filename);
+ machine->initrd_filename = eif_initrd;
+
+ /*
+ * If kernel cmdline argument was provided, let's concatenate it to the
+ * extracted EIF kernel cmdline.
+ */
+ if (machine->kernel_cmdline != NULL) {
+ char *cmd = g_strdup_printf("%s %s", eif_cmdline,
+ machine->kernel_cmdline);
+ g_free(eif_cmdline);
+ g_free(machine->kernel_cmdline);
+ machine->kernel_cmdline = cmd;
+ } else {
+ machine->kernel_cmdline = eif_cmdline;
+ }
+
+ x86_load_linux(x86ms, fw_cfg, 0, true);
+
+ unlink(machine->kernel_filename);
+ unlink(machine->initrd_filename);
+}
+
+static bool create_memfd_backend(MachineState *ms, const char *path,
+ Error **errp)
+{
+ Object *obj;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ bool r = false;
+
+ obj = object_new(TYPE_MEMORY_BACKEND_MEMFD);
+ if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
+ goto out;
+ }
+ object_property_add_child(object_get_objects_root(), mc->default_ram_id,
+ obj);
+
+ if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
+ goto out;
+ }
+ r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
+
+out:
+ object_unref(obj);
+ return r;
+}
+
+static char *nitro_enclave_get_vsock_chardev_id(Object *obj, Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ return g_strdup(nems->vsock);
+}
+
+static void nitro_enclave_set_vsock_chardev_id(Object *obj, const char *value,
+ Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ g_free(nems->vsock);
+ nems->vsock = g_strdup(value);
+}
+
+static char *nitro_enclave_get_id(Object *obj, Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ return g_strdup(nems->id);
+}
+
+static void nitro_enclave_set_id(Object *obj, const char *value,
+ Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ g_free(nems->id);
+ nems->id = g_strdup(value);
+}
+
+static char *nitro_enclave_get_parent_role(Object *obj, Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ return g_strdup(nems->parent_role);
+}
+
+static void nitro_enclave_set_parent_role(Object *obj, const char *value,
+ Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ g_free(nems->parent_role);
+ nems->parent_role = g_strdup(value);
+}
+
+static char *nitro_enclave_get_parent_id(Object *obj, Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ return g_strdup(nems->parent_id);
+}
+
+static void nitro_enclave_set_parent_id(Object *obj, const char *value,
+ Error **errp)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ g_free(nems->parent_id);
+ nems->parent_id = g_strdup(value);
+}
+
+static void nitro_enclave_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc);
+ NitroEnclaveMachineClass *nemc = NITRO_ENCLAVE_MACHINE_CLASS(oc);
+
+ mmc->x86_load_linux = x86_load_eif;
+
+ mc->family = "nitro_enclave_i386";
+ mc->desc = "AWS Nitro Enclave";
+
+ nemc->parent_init = mc->init;
+ mc->init = nitro_enclave_machine_state_init;
+
+ nemc->parent_reset = mc->reset;
+ mc->reset = nitro_enclave_machine_reset;
+
+ mc->create_default_memdev = create_memfd_backend;
+
+ object_class_property_add_str(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
+ nitro_enclave_get_vsock_chardev_id,
+ nitro_enclave_set_vsock_chardev_id);
+ object_class_property_set_description(oc, NITRO_ENCLAVE_VSOCK_CHARDEV_ID,
+ "Set chardev id for vhost-user-vsock "
+ "device");
+
+ object_class_property_add_str(oc, NITRO_ENCLAVE_ID, nitro_enclave_get_id,
+ nitro_enclave_set_id);
+ object_class_property_set_description(oc, NITRO_ENCLAVE_ID,
+ "Set enclave identifier");
+
+ object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ROLE,
+ nitro_enclave_get_parent_role,
+ nitro_enclave_set_parent_role);
+ object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ROLE,
+ "Set parent instance IAM role ARN");
+
+ object_class_property_add_str(oc, NITRO_ENCLAVE_PARENT_ID,
+ nitro_enclave_get_parent_id,
+ nitro_enclave_set_parent_id);
+ object_class_property_set_description(oc, NITRO_ENCLAVE_PARENT_ID,
+ "Set parent instance identifier");
+}
+
+static const TypeInfo nitro_enclave_machine_info = {
+ .name = TYPE_NITRO_ENCLAVE_MACHINE,
+ .parent = TYPE_MICROVM_MACHINE,
+ .instance_size = sizeof(NitroEnclaveMachineState),
+ .instance_init = nitro_enclave_machine_initfn,
+ .class_size = sizeof(NitroEnclaveMachineClass),
+ .class_init = nitro_enclave_class_init,
+};
+
+static void nitro_enclave_machine_init(void)
+{
+ type_register_static(&nitro_enclave_machine_info);
+}
+type_init(nitro_enclave_machine_init);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 7779c88..b211633 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -24,13 +24,14 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "exec/target_page.h"
#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/char/parallel.h"
#include "hw/hyperv/hv-balloon.h"
#include "hw/i386/fw_cfg.h"
#include "hw/i386/vmport.h"
-#include "sysemu/cpus.h"
+#include "system/cpus.h"
#include "hw/ide/ide-bus.h"
#include "hw/timer/hpet.h"
#include "hw/loader.h"
@@ -39,12 +40,13 @@
#include "hw/timer/i8254.h"
#include "hw/input/i8042.h"
#include "hw/audio/pcspk.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/xen.h"
-#include "sysemu/reset.h"
+#include "system/system.h"
+#include "system/xen.h"
+#include "system/reset.h"
#include "kvm/kvm_i386.h"
+#include "kvm/tdx.h"
#include "hw/xen/xen.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qemu/error-report.h"
#include "hw/acpi/cpu_hotplug.h"
#include "acpi-build.h"
@@ -79,6 +81,20 @@
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
+GlobalProperty pc_compat_10_0[] = {};
+const size_t pc_compat_10_0_len = G_N_ELEMENTS(pc_compat_10_0);
+
+GlobalProperty pc_compat_9_2[] = {};
+const size_t pc_compat_9_2_len = G_N_ELEMENTS(pc_compat_9_2);
+
+GlobalProperty pc_compat_9_1[] = {
+ { "ICH9-LPC", "x-smi-swsmi-timer", "off" },
+ { "ICH9-LPC", "x-smi-periodic-timer", "off" },
+ { TYPE_INTEL_IOMMU_DEVICE, "stale-tm", "on" },
+ { TYPE_INTEL_IOMMU_DEVICE, "aw-bits", "39" },
+};
+const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1);
+
GlobalProperty pc_compat_9_0[] = {
{ TYPE_X86_CPU, "x-amd-topoext-features-only", "false" },
{ TYPE_X86_CPU, "x-l1-cache-per-thread", "false" },
@@ -244,28 +260,6 @@ GlobalProperty pc_compat_2_6[] = {
};
const size_t pc_compat_2_6_len = G_N_ELEMENTS(pc_compat_2_6);
-GlobalProperty pc_compat_2_5[] = {};
-const size_t pc_compat_2_5_len = G_N_ELEMENTS(pc_compat_2_5);
-
-GlobalProperty pc_compat_2_4[] = {
- PC_CPU_MODEL_IDS("2.4.0")
- { "Haswell-" TYPE_X86_CPU, "abm", "off" },
- { "Haswell-noTSX-" TYPE_X86_CPU, "abm", "off" },
- { "Broadwell-" TYPE_X86_CPU, "abm", "off" },
- { "Broadwell-noTSX-" TYPE_X86_CPU, "abm", "off" },
- { "host" "-" TYPE_X86_CPU, "host-cache-info", "on" },
- { TYPE_X86_CPU, "check", "off" },
- { "qemu64" "-" TYPE_X86_CPU, "sse4a", "on" },
- { "qemu64" "-" TYPE_X86_CPU, "abm", "on" },
- { "qemu64" "-" TYPE_X86_CPU, "popcnt", "on" },
- { "qemu32" "-" TYPE_X86_CPU, "popcnt", "on" },
- { "Opteron_G2" "-" TYPE_X86_CPU, "rdtscp", "on" },
- { "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "on" },
- { "Opteron_G4" "-" TYPE_X86_CPU, "rdtscp", "on" },
- { "Opteron_G5" "-" TYPE_X86_CPU, "rdtscp", "on", }
-};
-const size_t pc_compat_2_4_len = G_N_ELEMENTS(pc_compat_2_4);
-
/*
* @PC_FW_DATA:
* Size of the chunk of memory at the top of RAM for the BIOS ACPI tables
@@ -453,7 +447,7 @@ static int check_fdc(Object *obj, void *opaque)
}
static const char * const fdc_container_path[] = {
- "/unattached", "/peripheral", "/peripheral-anon"
+ "unattached", "peripheral", "peripheral-anon"
};
/*
@@ -467,7 +461,7 @@ static ISADevice *pc_find_fdc0(void)
CheckFdcState state = { 0 };
for (i = 0; i < ARRAY_SIZE(fdc_container_path); i++) {
- container = container_get(qdev_get_machine(), fdc_container_path[i]);
+ container = machine_get_container(fdc_container_path[i]);
object_child_foreach(container, check_fdc, &state);
}
@@ -621,7 +615,8 @@ void pc_machine_done(Notifier *notifier, void *data)
/* set the number of CPUs */
x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
- fw_cfg_add_extra_pci_roots(pcms->pcibus, x86ms->fw_cfg);
+ pci_bus_add_fw_cfg_extra_pci_roots(x86ms->fw_cfg, pcms->pcibus,
+ &error_abort);
acpi_setup();
if (x86ms->fw_cfg) {
@@ -960,21 +955,23 @@ void pc_memory_init(PCMachineState *pcms,
/* Initialize PC system firmware */
pc_system_firmware_init(pcms, rom_memory);
- option_rom_mr = g_malloc(sizeof(*option_rom_mr));
- if (machine_require_guest_memfd(machine)) {
- memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
- PC_ROM_SIZE, &error_fatal);
- } else {
- memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
- &error_fatal);
- if (pcmc->pci_enabled) {
- memory_region_set_readonly(option_rom_mr, true);
+ if (!is_tdx_vm()) {
+ option_rom_mr = g_malloc(sizeof(*option_rom_mr));
+ if (machine_require_guest_memfd(machine)) {
+ memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
+ PC_ROM_SIZE, &error_fatal);
+ } else {
+ memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
+ &error_fatal);
+ if (pcmc->pci_enabled) {
+ memory_region_set_readonly(option_rom_mr, true);
+ }
}
+ memory_region_add_subregion_overlap(rom_memory,
+ PC_ROM_MIN_VGA,
+ option_rom_mr,
+ 1);
}
- memory_region_add_subregion_overlap(rom_memory,
- PC_ROM_MIN_VGA,
- option_rom_mr,
- 1);
fw_cfg = fw_cfg_arch_create(machine,
x86ms->boot_cpus, x86ms->apic_id_limit);
@@ -983,14 +980,13 @@ void pc_memory_init(PCMachineState *pcms,
if (machine->device_memory) {
uint64_t *val = g_malloc(sizeof(*val));
- uint64_t res_mem_end = machine->device_memory->base;
-
- if (!pcmc->broken_reserved_end) {
- res_mem_end += memory_region_size(&machine->device_memory->mr);
- }
+ uint64_t res_mem_end;
if (pcms->cxl_devices_state.is_enabled) {
res_mem_end = cxl_resv_end;
+ } else {
+ res_mem_end = machine->device_memory->base
+ + memory_region_size(&machine->device_memory->mr);
}
*val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB));
fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
@@ -1028,9 +1024,7 @@ uint64_t pc_pci_hole64_start(void)
hole64_start = pc_get_cxl_range_end(pcms);
} else if (pcmc->has_reserved_memory && (ms->ram_size < ms->maxram_size)) {
pc_get_device_memory_range(pcms, &hole64_start, &size);
- if (!pcmc->broken_reserved_end) {
- hole64_start += size;
- }
+ hole64_start += size;
} else {
hole64_start = pc_above_4g_end(pcms);
}
@@ -1042,7 +1036,6 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
{
DeviceState *dev = NULL;
- rom_set_order_override(FW_CFG_ORDER_OVERRIDE_VGA);
if (pci_bus) {
PCIDevice *pcidev = pci_vga_init(pci_bus);
dev = pcidev ? &pcidev->qdev : NULL;
@@ -1050,14 +1043,14 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
ISADevice *isadev = isa_vga_init(isa_bus);
dev = isadev ? DEVICE(isadev) : NULL;
}
- rom_reset_order_override();
+
return dev;
}
static const MemoryRegionOps ioport80_io_ops = {
.write = ioport80_write,
.read = ioport80_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 1,
.max_access_size = 1,
@@ -1067,7 +1060,7 @@ static const MemoryRegionOps ioport80_io_ops = {
static const MemoryRegionOps ioportF0_io_ops = {
.write = ioportF0_write,
.read = ioportF0_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 1,
.max_access_size = 1,
@@ -1221,7 +1214,6 @@ void pc_basic_device_init(struct PCMachineState *pcms,
isa_realize_and_unref(pcms->pcspk, isa_bus, &error_fatal);
}
- assert(pcms->vmport >= 0 && pcms->vmport < ON_OFF_AUTO__MAX);
if (pcms->vmport == ON_OFF_AUTO_AUTO) {
pcms->vmport = (xen_enabled() || !pcms->i8042_enabled)
? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
@@ -1230,6 +1222,9 @@ void pc_basic_device_init(struct PCMachineState *pcms,
/* Super I/O */
pc_superio_init(isa_bus, create_fdctrl, pcms->i8042_enabled,
pcms->vmport != ON_OFF_AUTO_ON, &error_fatal);
+
+ pcms->machine_done.notify = pc_machine_done;
+ qemu_add_machine_init_done_notifier(&pcms->machine_done);
}
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
@@ -1238,16 +1233,14 @@ void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
bool default_is_ne2k = g_str_equal(mc->default_nic, TYPE_ISA_NE2000);
NICInfo *nd;
- rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC);
-
while ((nd = qemu_find_nic_info(TYPE_ISA_NE2000, default_is_ne2k, NULL))) {
pc_init_ne2k_isa(isa_bus, nd, &error_fatal);
}
/* Anything remaining should be a PCI NIC */
- pci_init_nic_devices(pci_bus, mc->default_nic);
-
- rom_reset_order_override();
+ if (pci_bus) {
+ pci_init_nic_devices(pci_bus, mc->default_nic);
+ }
}
void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs)
@@ -1688,7 +1681,7 @@ static void pc_machine_initfn(Object *obj)
pcms->sata_enabled = true;
pcms->i8042_enabled = true;
pcms->max_fw_size = 8 * MiB;
-#ifdef CONFIG_HPET
+#if defined(CONFIG_HPET)
pcms->hpet_enabled = true;
#endif
pcms->fd_bootchk = true;
@@ -1701,17 +1694,14 @@ static void pc_machine_initfn(Object *obj)
if (pcmc->pci_enabled) {
cxl_machine_init(obj, &pcms->cxl_devices_state);
}
-
- pcms->machine_done.notify = pc_machine_done;
- qemu_add_machine_init_done_notifier(&pcms->machine_done);
}
-static void pc_machine_reset(MachineState *machine, ShutdownCause reason)
+static void pc_machine_reset(MachineState *machine, ResetType type)
{
CPUState *cs;
X86CPU *cpu;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/* Reset APIC after devices have been reset to cancel
* any changes that qemu_devices_reset() might have done.
@@ -1726,7 +1716,7 @@ static void pc_machine_reset(MachineState *machine, ShutdownCause reason)
static void pc_machine_wakeup(MachineState *machine)
{
cpu_synchronize_all_states();
- pc_machine_reset(machine, SHUTDOWN_CAUSE_NONE);
+ pc_machine_reset(machine, RESET_TYPE_WAKEUP);
cpu_synchronize_all_post_reset();
}
@@ -1749,7 +1739,7 @@ static bool pc_hotplug_allowed(MachineState *ms, DeviceState *dev, Error **errp)
return true;
}
-static void pc_machine_class_init(ObjectClass *oc, void *data)
+static void pc_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
@@ -1785,6 +1775,10 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
mc->nvdimm_supported = true;
mc->smp_props.dies_supported = true;
mc->smp_props.modules_supported = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1D] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1I] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L2] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L3] = true;
mc->default_ram_id = "pc.ram";
pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_AUTO;
@@ -1817,6 +1811,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, PC_MACHINE_I8042,
pc_machine_get_i8042, pc_machine_set_i8042);
+ object_class_property_set_description(oc, PC_MACHINE_I8042,
+ "Enable/disable Intel 8042 PS/2 controller emulation");
object_class_property_add_bool(oc, "default-bus-bypass-iommu",
pc_machine_get_default_bus_bypass_iommu,
@@ -1847,7 +1843,7 @@ static const TypeInfo pc_machine_info = {
.instance_init = pc_machine_initfn,
.class_size = sizeof(PCMachineClass),
.class_init = pc_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
},
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 347afa4..ea7572e 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -43,15 +43,15 @@
#include "hw/ide/isa.h"
#include "hw/ide/pci.h"
#include "hw/irq.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "hw/i386/kvm/clock.h"
#include "hw/sysbus.h"
#include "hw/i2c/smbus_eeprom.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/acpi/acpi.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "sysemu/xen.h"
+#include "system/xen.h"
#ifdef CONFIG_XEN
#include <xen/hvm/hvm_info_table.h>
#include "hw/xen/xen_pt.h"
@@ -61,10 +61,11 @@
#include "hw/xen/xen.h"
#include "migration/global_state.h"
#include "migration/misc.h"
-#include "sysemu/runstate.h"
-#include "sysemu/numa.h"
+#include "system/runstate.h"
+#include "system/numa.h"
#include "hw/hyperv/vmbus-bridge.h"
#include "hw/mem/nvdimm.h"
+#include "hw/uefi/var-service-api.h"
#include "hw/i386/acpi-build.h"
#include "target/i386/cpu.h"
@@ -284,6 +285,8 @@ static void pc_init1(MachineState *machine, const char *pci_type)
pcms->idebus[0] = qdev_get_child_bus(dev, "ide.0");
pcms->idebus[1] = qdev_get_child_bus(dev, "ide.1");
} else {
+ uint32_t irq;
+
isa_bus = isa_bus_new(NULL, system_memory, system_io,
&error_abort);
isa_bus_register_input_irqs(isa_bus, x86ms->gsi);
@@ -291,6 +294,9 @@ static void pc_init1(MachineState *machine, const char *pci_type)
x86ms->rtc = isa_new(TYPE_MC146818_RTC);
qdev_prop_set_int32(DEVICE(x86ms->rtc), "base_year", 2000);
isa_realize_and_unref(x86ms->rtc, isa_bus, &error_fatal);
+ irq = object_property_get_uint(OBJECT(x86ms->rtc), "irq",
+ &error_fatal);
+ isa_connect_gpio_out(ISA_DEVICE(x86ms->rtc), 0, irq);
i8257_dma_init(OBJECT(machine), isa_bus, 0);
pcms->hpet_enabled = false;
@@ -446,7 +452,10 @@ static void pc_i440fx_init(MachineState *machine)
}
#define DEFINE_I440FX_MACHINE(major, minor) \
- DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, major, minor);
+ DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, false, NULL, major, minor);
+
+#define DEFINE_I440FX_MACHINE_AS_LATEST(major, minor) \
+ DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, true, "pc", major, minor);
static void pc_i440fx_machine_options(MachineClass *m)
{
@@ -465,6 +474,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
m->no_parallel = !module_object_class_by_name(TYPE_ISA_PARALLEL);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
+ machine_class_allow_dynamic_sysbus_dev(m, TYPE_UEFI_VARS_X64);
object_class_property_add_enum(oc, "x-south-bridge", "PCSouthBridgeOption",
&PCSouthBridgeOption_lookup,
@@ -474,11 +484,36 @@ static void pc_i440fx_machine_options(MachineClass *m)
"Use a different south bridge than PIIX3");
}
-static void pc_i440fx_machine_9_1_options(MachineClass *m)
+static void pc_i440fx_machine_10_1_options(MachineClass *m)
{
pc_i440fx_machine_options(m);
- m->alias = "pc";
- m->is_default = true;
+}
+
+DEFINE_I440FX_MACHINE_AS_LATEST(10, 1);
+
+static void pc_i440fx_machine_10_0_options(MachineClass *m)
+{
+ pc_i440fx_machine_10_1_options(m);
+ compat_props_add(m->compat_props, hw_compat_10_0, hw_compat_10_0_len);
+ compat_props_add(m->compat_props, pc_compat_10_0, pc_compat_10_0_len);
+}
+
+DEFINE_I440FX_MACHINE(10, 0);
+
+static void pc_i440fx_machine_9_2_options(MachineClass *m)
+{
+ pc_i440fx_machine_10_0_options(m);
+ compat_props_add(m->compat_props, hw_compat_9_2, hw_compat_9_2_len);
+ compat_props_add(m->compat_props, pc_compat_9_2, pc_compat_9_2_len);
+}
+
+DEFINE_I440FX_MACHINE(9, 2);
+
+static void pc_i440fx_machine_9_1_options(MachineClass *m)
+{
+ pc_i440fx_machine_9_2_options(m);
+ compat_props_add(m->compat_props, hw_compat_9_1, hw_compat_9_1_len);
+ compat_props_add(m->compat_props, pc_compat_9_1, pc_compat_9_1_len);
}
DEFINE_I440FX_MACHINE(9, 1);
@@ -488,8 +523,6 @@ static void pc_i440fx_machine_9_0_options(MachineClass *m)
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_machine_9_1_options(m);
- m->alias = NULL;
- m->is_default = false;
m->smbios_memory_device_size = 16 * GiB;
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
@@ -750,32 +783,6 @@ static void pc_i440fx_machine_2_6_options(MachineClass *m)
DEFINE_I440FX_MACHINE(2, 6);
-static void pc_i440fx_machine_2_5_options(MachineClass *m)
-{
- X86MachineClass *x86mc = X86_MACHINE_CLASS(m);
-
- pc_i440fx_machine_2_6_options(m);
- x86mc->save_tsc_khz = false;
- m->legacy_fw_cfg_order = 1;
- compat_props_add(m->compat_props, hw_compat_2_5, hw_compat_2_5_len);
- compat_props_add(m->compat_props, pc_compat_2_5, pc_compat_2_5_len);
-}
-
-DEFINE_I440FX_MACHINE(2, 5);
-
-static void pc_i440fx_machine_2_4_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
-
- pc_i440fx_machine_2_5_options(m);
- m->hw_version = "2.4.0";
- pcmc->broken_reserved_end = true;
- compat_props_add(m->compat_props, hw_compat_2_4, hw_compat_2_4_len);
- compat_props_add(m->compat_props, pc_compat_2_4, pc_compat_2_4_len);
-}
-
-DEFINE_I440FX_MACHINE(2, 4);
-
#ifdef CONFIG_ISAPC
static void isapc_machine_options(MachineClass *m)
{
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index f2d8edf..33211b1 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -35,8 +35,8 @@
#include "hw/loader.h"
#include "hw/i2c/smbus_eeprom.h"
#include "hw/rtc/mc146818rtc.h"
-#include "sysemu/tcg.h"
-#include "sysemu/kvm.h"
+#include "system/tcg.h"
+#include "system/kvm.h"
#include "hw/i386/kvm/clock.h"
#include "hw/pci-host/q35.h"
#include "hw/pci/pcie_port.h"
@@ -55,9 +55,10 @@
#include "hw/usb/hcd-uhci.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#include "hw/hyperv/vmbus-bridge.h"
#include "hw/mem/nvdimm.h"
+#include "hw/uefi/var-service-api.h"
#include "hw/i386/acpi-build.h"
#include "target/i386/cpu.h"
@@ -327,10 +328,13 @@ static void pc_q35_init(MachineState *machine)
}
#define DEFINE_Q35_MACHINE(major, minor) \
- DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, major, minor);
+ DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, NULL, major, minor);
+
+#define DEFINE_Q35_MACHINE_AS_LATEST(major, minor) \
+ DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, "q35", major, minor);
#define DEFINE_Q35_MACHINE_BUGFIX(major, minor, micro) \
- DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, major, minor, micro);
+ DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, NULL, major, minor, micro);
static void pc_q35_machine_options(MachineClass *m)
{
@@ -352,14 +356,41 @@ static void pc_q35_machine_options(MachineClass *m)
machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
+ machine_class_allow_dynamic_sysbus_dev(m, TYPE_UEFI_VARS_X64);
compat_props_add(m->compat_props,
pc_q35_compat_defaults, pc_q35_compat_defaults_len);
}
-static void pc_q35_machine_9_1_options(MachineClass *m)
+static void pc_q35_machine_10_1_options(MachineClass *m)
{
pc_q35_machine_options(m);
- m->alias = "q35";
+}
+
+DEFINE_Q35_MACHINE_AS_LATEST(10, 1);
+
+static void pc_q35_machine_10_0_options(MachineClass *m)
+{
+ pc_q35_machine_10_1_options(m);
+ compat_props_add(m->compat_props, hw_compat_10_0, hw_compat_10_0_len);
+ compat_props_add(m->compat_props, pc_compat_10_0, pc_compat_10_0_len);
+}
+
+DEFINE_Q35_MACHINE(10, 0);
+
+static void pc_q35_machine_9_2_options(MachineClass *m)
+{
+ pc_q35_machine_10_0_options(m);
+ compat_props_add(m->compat_props, hw_compat_9_2, hw_compat_9_2_len);
+ compat_props_add(m->compat_props, pc_compat_9_2, pc_compat_9_2_len);
+}
+
+DEFINE_Q35_MACHINE(9, 2);
+
+static void pc_q35_machine_9_1_options(MachineClass *m)
+{
+ pc_q35_machine_9_2_options(m);
+ compat_props_add(m->compat_props, hw_compat_9_1, hw_compat_9_1_len);
+ compat_props_add(m->compat_props, pc_compat_9_1, pc_compat_9_1_len);
}
DEFINE_Q35_MACHINE(9, 1);
@@ -368,7 +399,6 @@ static void pc_q35_machine_9_0_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_machine_9_1_options(m);
- m->alias = NULL;
m->smbios_memory_device_size = 16 * GiB;
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
@@ -642,29 +672,3 @@ static void pc_q35_machine_2_6_options(MachineClass *m)
}
DEFINE_Q35_MACHINE(2, 6);
-
-static void pc_q35_machine_2_5_options(MachineClass *m)
-{
- X86MachineClass *x86mc = X86_MACHINE_CLASS(m);
-
- pc_q35_machine_2_6_options(m);
- x86mc->save_tsc_khz = false;
- m->legacy_fw_cfg_order = 1;
- compat_props_add(m->compat_props, hw_compat_2_5, hw_compat_2_5_len);
- compat_props_add(m->compat_props, pc_compat_2_5, pc_compat_2_5_len);
-}
-
-DEFINE_Q35_MACHINE(2, 5);
-
-static void pc_q35_machine_2_4_options(MachineClass *m)
-{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
-
- pc_q35_machine_2_5_options(m);
- m->hw_version = "2.4.0";
- pcmc->broken_reserved_end = true;
- compat_props_add(m->compat_props, hw_compat_2_4, hw_compat_2_4_len);
- compat_props_add(m->compat_props, pc_compat_2_4, pc_compat_2_4_len);
-}
-
-DEFINE_Q35_MACHINE(2, 4);
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index ef80281..821396c 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
#include "qemu/units.h"
@@ -35,8 +35,9 @@
#include "hw/loader.h"
#include "hw/qdev-properties.h"
#include "hw/block/flash.h"
-#include "sysemu/kvm.h"
-#include "sev.h"
+#include "system/kvm.h"
+#include "target/i386/sev.h"
+#include "kvm/tdx.h"
#define FLASH_SECTOR_SIZE 4096
@@ -280,5 +281,11 @@ void x86_firmware_configure(hwaddr gpa, void *ptr, int size)
}
sev_encrypt_flash(gpa, ptr, size, &error_fatal);
+ } else if (is_tdx_vm()) {
+ ret = tdx_parse_tdvf(ptr, size);
+ if (ret) {
+ error_report("failed to parse TDVF for TDX VM");
+ exit(1);
+ }
}
}
diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c
index 07a4c26..da947c3 100644
--- a/hw/i386/pc_sysfw_ovmf.c
+++ b/hw/i386/pc_sysfw_ovmf.c
@@ -26,6 +26,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/i386/pc.h"
+#include "exec/target_page.h"
#include "cpu.h"
#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"
diff --git a/hw/i386/port92.c b/hw/i386/port92.c
index b25157f..39b6f31 100644
--- a/hw/i386/port92.c
+++ b/hw/i386/port92.c
@@ -7,7 +7,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "hw/isa/isa.h"
@@ -97,12 +97,12 @@ static void port92_realizefn(DeviceState *dev, Error **errp)
isa_register_ioport(isadev, &s->io, 0x92);
}
-static void port92_class_initfn(ObjectClass *klass, void *data)
+static void port92_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = port92_realizefn;
- dc->reset = port92_reset;
+ device_class_set_legacy_reset(dc, port92_reset);
dc->vmsd = &vmstate_port92_isa;
/*
* Reason: unlike ordinary ISA devices, this one needs additional
diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index d664829..2b3b282 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -17,14 +17,13 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "target/i386/cpu.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
-static Property sgx_epc_properties[] = {
+static const Property sgx_epc_properties[] = {
DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0),
DEFINE_PROP_UINT32(SGX_EPC_NUMA_NODE_PROP, SGXEPCDevice, node, 0),
DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem,
TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *),
- DEFINE_PROP_END_OF_LIST(),
};
static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name,
@@ -148,7 +147,7 @@ static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md,
info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC;
}
-static void sgx_epc_class_init(ObjectClass *oc, void *data)
+static void sgx_epc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
@@ -174,7 +173,7 @@ static const TypeInfo sgx_epc_info = {
.instance_init = sgx_epc_init,
.class_init = sgx_epc_class_init,
.class_size = sizeof(DeviceClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_MEMORY_DEVICE },
{ }
},
diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c
index 38ff75e..d295e54 100644
--- a/hw/i386/sgx-stub.c
+++ b/hw/i386/sgx-stub.c
@@ -3,20 +3,20 @@
#include "monitor/hmp-target.h"
#include "hw/i386/pc.h"
#include "hw/i386/sgx-epc.h"
+#include "qapi/qapi-commands-misc-i386.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc-target.h"
void sgx_epc_build_srat(GArray *table_data)
{
}
-SGXInfo *qmp_query_sgx(Error **errp)
+SgxInfo *qmp_query_sgx(Error **errp)
{
error_setg(errp, "SGX support is not compiled in");
return NULL;
}
-SGXInfo *qmp_query_sgx_capabilities(Error **errp)
+SgxInfo *qmp_query_sgx_capabilities(Error **errp)
{
error_setg(errp, "SGX support is not compiled in");
return NULL;
diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c
index 4900dd4..e280154 100644
--- a/hw/i386/sgx.c
+++ b/hw/i386/sgx.c
@@ -19,10 +19,10 @@
#include "monitor/hmp-target.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "qapi/qapi-commands-misc-target.h"
-#include "exec/address-spaces.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/reset.h"
+#include "qapi/qapi-commands-misc-i386.h"
+#include "system/address-spaces.h"
+#include "system/hw_accel.h"
+#include "system/reset.h"
#include <sys/ioctl.h>
#include "hw/acpi/aml-build.h"
@@ -84,10 +84,10 @@ static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
((high & MAKE_64BIT_MASK(0, 20)) << 32);
}
-static SGXEPCSectionList *sgx_calc_host_epc_sections(void)
+static SgxEpcSectionList *sgx_calc_host_epc_sections(void)
{
- SGXEPCSectionList *head = NULL, **tail = &head;
- SGXEPCSection *section;
+ SgxEpcSectionList *head = NULL, **tail = &head;
+ SgxEpcSection *section;
uint32_t i, type;
uint32_t eax, ebx, ecx, edx;
uint32_t j = 0;
@@ -104,7 +104,7 @@ static SGXEPCSectionList *sgx_calc_host_epc_sections(void)
break;
}
- section = g_new0(SGXEPCSection, 1);
+ section = g_new0(SgxEpcSection, 1);
section->node = j++;
section->size = sgx_calc_section_metric(ecx, edx);
QAPI_LIST_APPEND(tail, section);
@@ -153,9 +153,9 @@ static void sgx_epc_reset(void *opaque)
}
}
-SGXInfo *qmp_query_sgx_capabilities(Error **errp)
+SgxInfo *qmp_query_sgx_capabilities(Error **errp)
{
- SGXInfo *info = NULL;
+ SgxInfo *info = NULL;
uint32_t eax, ebx, ecx, edx;
Error *local_err = NULL;
@@ -166,7 +166,7 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp)
return NULL;
}
- info = g_new0(SGXInfo, 1);
+ info = g_new0(SgxInfo, 1);
host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx);
info->sgx = ebx & (1U << 2) ? true : false;
@@ -183,17 +183,17 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp)
return info;
}
-static SGXEPCSectionList *sgx_get_epc_sections_list(void)
+static SgxEpcSectionList *sgx_get_epc_sections_list(void)
{
GSList *device_list = sgx_epc_get_device_list();
- SGXEPCSectionList *head = NULL, **tail = &head;
- SGXEPCSection *section;
+ SgxEpcSectionList *head = NULL, **tail = &head;
+ SgxEpcSection *section;
for (; device_list; device_list = device_list->next) {
DeviceState *dev = device_list->data;
Object *obj = OBJECT(dev);
- section = g_new0(SGXEPCSection, 1);
+ section = g_new0(SgxEpcSection, 1);
section->node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP,
&error_abort);
section->size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP,
@@ -205,9 +205,9 @@ static SGXEPCSectionList *sgx_get_epc_sections_list(void)
return head;
}
-SGXInfo *qmp_query_sgx(Error **errp)
+SgxInfo *qmp_query_sgx(Error **errp)
{
- SGXInfo *info = NULL;
+ SgxInfo *info = NULL;
X86MachineState *x86ms;
PCMachineState *pcms =
(PCMachineState *)object_dynamic_cast(qdev_get_machine(),
@@ -223,7 +223,7 @@ SGXInfo *qmp_query_sgx(Error **errp)
return NULL;
}
- info = g_new0(SGXInfo, 1);
+ info = g_new0(SgxInfo, 1);
info->sgx = true;
info->sgx1 = true;
@@ -237,8 +237,8 @@ SGXInfo *qmp_query_sgx(Error **errp)
void hmp_info_sgx(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
- SGXEPCSectionList *section_list, *section;
- g_autoptr(SGXInfo) info = qmp_query_sgx(&err);
+ SgxEpcSectionList *section_list, *section;
+ g_autoptr(SgxInfo) info = qmp_query_sgx(&err);
uint64_t size = 0;
if (err) {
diff --git a/hw/i386/tdvf-hob.c b/hw/i386/tdvf-hob.c
new file mode 100644
index 0000000..782b3d1
--- /dev/null
+++ b/hw/i386/tdvf-hob.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2025 Intel Corporation
+ * Author: Isaku Yamahata <isaku.yamahata at gmail.com>
+ * <isaku.yamahata at intel.com>
+ * Xiaoyao Li <xiaoyao.li@intel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "standard-headers/uefi/uefi.h"
+#include "hw/pci/pcie_host.h"
+#include "tdvf-hob.h"
+
+typedef struct TdvfHob {
+ hwaddr hob_addr;
+ void *ptr;
+ int size;
+
+ /* working area */
+ void *current;
+ void *end;
+} TdvfHob;
+
+static uint64_t tdvf_current_guest_addr(const TdvfHob *hob)
+{
+ return hob->hob_addr + (hob->current - hob->ptr);
+}
+
+static void tdvf_align(TdvfHob *hob, size_t align)
+{
+ hob->current = QEMU_ALIGN_PTR_UP(hob->current, align);
+}
+
+static void *tdvf_get_area(TdvfHob *hob, uint64_t size)
+{
+ void *ret;
+
+ if (hob->current + size > hob->end) {
+ error_report("TD_HOB overrun, size = 0x%" PRIx64, size);
+ exit(1);
+ }
+
+ ret = hob->current;
+ hob->current += size;
+ tdvf_align(hob, 8);
+ return ret;
+}
+
+static void tdvf_hob_add_memory_resources(TdxGuest *tdx, TdvfHob *hob)
+{
+ EFI_HOB_RESOURCE_DESCRIPTOR *region;
+ EFI_RESOURCE_ATTRIBUTE_TYPE attr;
+ EFI_RESOURCE_TYPE resource_type;
+
+ TdxRamEntry *e;
+ int i;
+
+ for (i = 0; i < tdx->nr_ram_entries; i++) {
+ e = &tdx->ram_entries[i];
+
+ if (e->type == TDX_RAM_UNACCEPTED) {
+ resource_type = EFI_RESOURCE_MEMORY_UNACCEPTED;
+ attr = EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED;
+ } else if (e->type == TDX_RAM_ADDED) {
+ resource_type = EFI_RESOURCE_SYSTEM_MEMORY;
+ attr = EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE;
+ } else {
+ error_report("unknown TDX_RAM_ENTRY type %d", e->type);
+ exit(1);
+ }
+
+ region = tdvf_get_area(hob, sizeof(*region));
+ *region = (EFI_HOB_RESOURCE_DESCRIPTOR) {
+ .Header = {
+ .HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,
+ .HobLength = cpu_to_le16(sizeof(*region)),
+ .Reserved = cpu_to_le32(0),
+ },
+ .Owner = EFI_HOB_OWNER_ZERO,
+ .ResourceType = cpu_to_le32(resource_type),
+ .ResourceAttribute = cpu_to_le32(attr),
+ .PhysicalStart = cpu_to_le64(e->address),
+ .ResourceLength = cpu_to_le64(e->length),
+ };
+ }
+}
+
+void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob)
+{
+ TdvfHob hob = {
+ .hob_addr = td_hob->address,
+ .size = td_hob->size,
+ .ptr = td_hob->mem_ptr,
+
+ .current = td_hob->mem_ptr,
+ .end = td_hob->mem_ptr + td_hob->size,
+ };
+
+ EFI_HOB_GENERIC_HEADER *last_hob;
+ EFI_HOB_HANDOFF_INFO_TABLE *hit;
+
+ /* Note, Efi{Free}Memory{Bottom,Top} are ignored, leave 'em zeroed. */
+ hit = tdvf_get_area(&hob, sizeof(*hit));
+ *hit = (EFI_HOB_HANDOFF_INFO_TABLE) {
+ .Header = {
+ .HobType = EFI_HOB_TYPE_HANDOFF,
+ .HobLength = cpu_to_le16(sizeof(*hit)),
+ .Reserved = cpu_to_le32(0),
+ },
+ .Version = cpu_to_le32(EFI_HOB_HANDOFF_TABLE_VERSION),
+ .BootMode = cpu_to_le32(0),
+ .EfiMemoryTop = cpu_to_le64(0),
+ .EfiMemoryBottom = cpu_to_le64(0),
+ .EfiFreeMemoryTop = cpu_to_le64(0),
+ .EfiFreeMemoryBottom = cpu_to_le64(0),
+ .EfiEndOfHobList = cpu_to_le64(0), /* initialized later */
+ };
+
+ tdvf_hob_add_memory_resources(tdx, &hob);
+
+ last_hob = tdvf_get_area(&hob, sizeof(*last_hob));
+ *last_hob = (EFI_HOB_GENERIC_HEADER) {
+ .HobType = EFI_HOB_TYPE_END_OF_HOB_LIST,
+ .HobLength = cpu_to_le16(sizeof(*last_hob)),
+ .Reserved = cpu_to_le32(0),
+ };
+ hit->EfiEndOfHobList = tdvf_current_guest_addr(&hob);
+}
diff --git a/hw/i386/tdvf-hob.h b/hw/i386/tdvf-hob.h
new file mode 100644
index 0000000..4fc6a37
--- /dev/null
+++ b/hw/i386/tdvf-hob.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef HW_I386_TD_HOB_H
+#define HW_I386_TD_HOB_H
+
+#include "hw/i386/tdvf.h"
+#include "target/i386/kvm/tdx.h"
+
+void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob);
+
+#define EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE \
+ (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED)
+
+#define EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED \
+ (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED)
+
+#define EFI_RESOURCE_ATTRIBUTE_TDVF_MMIO \
+ (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE)
+
+#endif
diff --git a/hw/i386/tdvf.c b/hw/i386/tdvf.c
new file mode 100644
index 0000000..645d9d1
--- /dev/null
+++ b/hw/i386/tdvf.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2025 Intel Corporation
+ * Author: Isaku Yamahata <isaku.yamahata at gmail.com>
+ * <isaku.yamahata at intel.com>
+ * Xiaoyao Li <xiaoyao.li@intel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+
+#include "hw/i386/pc.h"
+#include "hw/i386/tdvf.h"
+#include "system/kvm.h"
+
+#define TDX_METADATA_OFFSET_GUID "e47a6535-984a-4798-865e-4685a7bf8ec2"
+#define TDX_METADATA_VERSION 1
+#define TDVF_SIGNATURE 0x46564454 /* TDVF as little endian */
+#define TDVF_ALIGNMENT 4096
+
+/*
+ * the raw structs read from TDVF keeps the name convention in
+ * TDVF Design Guide spec.
+ */
+typedef struct {
+ uint32_t DataOffset;
+ uint32_t RawDataSize;
+ uint64_t MemoryAddress;
+ uint64_t MemoryDataSize;
+ uint32_t Type;
+ uint32_t Attributes;
+} TdvfSectionEntry;
+
+typedef struct {
+ uint32_t Signature;
+ uint32_t Length;
+ uint32_t Version;
+ uint32_t NumberOfSectionEntries;
+ TdvfSectionEntry SectionEntries[];
+} TdvfMetadata;
+
+struct tdx_metadata_offset {
+ uint32_t offset;
+};
+
+static TdvfMetadata *tdvf_get_metadata(void *flash_ptr, int size)
+{
+ TdvfMetadata *metadata;
+ uint32_t offset = 0;
+ uint8_t *data;
+
+ if ((uint32_t) size != size) {
+ return NULL;
+ }
+
+ if (pc_system_ovmf_table_find(TDX_METADATA_OFFSET_GUID, &data, NULL)) {
+ offset = size - le32_to_cpu(((struct tdx_metadata_offset *)data)->offset);
+
+ if (offset + sizeof(*metadata) > size) {
+ return NULL;
+ }
+ } else {
+ error_report("Cannot find TDX_METADATA_OFFSET_GUID");
+ return NULL;
+ }
+
+ metadata = flash_ptr + offset;
+
+ /* Finally, verify the signature to determine if this is a TDVF image. */
+ metadata->Signature = le32_to_cpu(metadata->Signature);
+ if (metadata->Signature != TDVF_SIGNATURE) {
+ error_report("Invalid TDVF signature in metadata!");
+ return NULL;
+ }
+
+ /* Sanity check that the TDVF doesn't overlap its own metadata. */
+ metadata->Length = le32_to_cpu(metadata->Length);
+ if (offset + metadata->Length > size) {
+ return NULL;
+ }
+
+ /* Only version 1 is supported/defined. */
+ metadata->Version = le32_to_cpu(metadata->Version);
+ if (metadata->Version != TDX_METADATA_VERSION) {
+ return NULL;
+ }
+
+ return metadata;
+}
+
+static int tdvf_parse_and_check_section_entry(const TdvfSectionEntry *src,
+ TdxFirmwareEntry *entry)
+{
+ entry->data_offset = le32_to_cpu(src->DataOffset);
+ entry->data_len = le32_to_cpu(src->RawDataSize);
+ entry->address = le64_to_cpu(src->MemoryAddress);
+ entry->size = le64_to_cpu(src->MemoryDataSize);
+ entry->type = le32_to_cpu(src->Type);
+ entry->attributes = le32_to_cpu(src->Attributes);
+
+ /* sanity check */
+ if (entry->size < entry->data_len) {
+ error_report("Broken metadata RawDataSize 0x%x MemoryDataSize 0x%"PRIx64,
+ entry->data_len, entry->size);
+ return -1;
+ }
+ if (!QEMU_IS_ALIGNED(entry->address, TDVF_ALIGNMENT)) {
+ error_report("MemoryAddress 0x%"PRIx64" not page aligned", entry->address);
+ return -1;
+ }
+ if (!QEMU_IS_ALIGNED(entry->size, TDVF_ALIGNMENT)) {
+ error_report("MemoryDataSize 0x%"PRIx64" not page aligned", entry->size);
+ return -1;
+ }
+
+ switch (entry->type) {
+ case TDVF_SECTION_TYPE_BFV:
+ case TDVF_SECTION_TYPE_CFV:
+ /* The sections that must be copied from firmware image to TD memory */
+ if (entry->data_len == 0) {
+ error_report("%d section with RawDataSize == 0", entry->type);
+ return -1;
+ }
+ break;
+ case TDVF_SECTION_TYPE_TD_HOB:
+ case TDVF_SECTION_TYPE_TEMP_MEM:
+ /* The sections that no need to be copied from firmware image */
+ if (entry->data_len != 0) {
+ error_report("%d section with RawDataSize 0x%x != 0",
+ entry->type, entry->data_len);
+ return -1;
+ }
+ break;
+ default:
+ error_report("TDVF contains unsupported section type %d", entry->type);
+ return -1;
+ }
+
+ return 0;
+}
+
+int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size)
+{
+ g_autofree TdvfSectionEntry *sections = NULL;
+ TdvfMetadata *metadata;
+ ssize_t entries_size;
+ int i;
+
+ metadata = tdvf_get_metadata(flash_ptr, size);
+ if (!metadata) {
+ return -EINVAL;
+ }
+
+ /* load and parse metadata entries */
+ fw->nr_entries = le32_to_cpu(metadata->NumberOfSectionEntries);
+ if (fw->nr_entries < 2) {
+ error_report("Invalid number of fw entries (%u) in TDVF Metadata",
+ fw->nr_entries);
+ return -EINVAL;
+ }
+
+ entries_size = fw->nr_entries * sizeof(TdvfSectionEntry);
+ if (metadata->Length != sizeof(*metadata) + entries_size) {
+ error_report("TDVF metadata len (0x%x) mismatch, expected (0x%x)",
+ metadata->Length,
+ (uint32_t)(sizeof(*metadata) + entries_size));
+ return -EINVAL;
+ }
+
+ fw->entries = g_new(TdxFirmwareEntry, fw->nr_entries);
+ sections = g_new(TdvfSectionEntry, fw->nr_entries);
+
+ memcpy(sections, (void *)metadata + sizeof(*metadata), entries_size);
+
+ for (i = 0; i < fw->nr_entries; i++) {
+ if (tdvf_parse_and_check_section_entry(&sections[i], &fw->entries[i])) {
+ goto err;
+ }
+ }
+
+ fw->mem_ptr = flash_ptr;
+ return 0;
+
+err:
+ fw->entries = 0;
+ g_free(fw->entries);
+ return -EINVAL;
+}
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 53c02d7..ac9e1a1 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -68,6 +68,7 @@ vtd_frr_new(int index, uint64_t hi, uint64_t lo) "index %d high 0x%"PRIx64" low
vtd_warn_invalid_qi_tail(uint16_t tail) "tail 0x%"PRIx16
vtd_warn_ir_vector(uint16_t sid, int index, int vec, int target) "sid 0x%"PRIx16" index %d vec %d (should be: %d)"
vtd_warn_ir_trigger(uint16_t sid, int index, int trig, int target) "sid 0x%"PRIx16" index %d trigger %d (should be: %d)"
+vtd_reset_exit(void) ""
# amd_iommu.c
amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 0x%"PRIx64" + offset 0x%"PRIx32
diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c
index f5b1db7..0c1c92c 100644
--- a/hw/i386/vapic.c
+++ b/hw/i386/vapic.c
@@ -11,12 +11,13 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/kvm.h"
-#include "sysemu/runstate.h"
-#include "exec/address-spaces.h"
+#include "exec/target_page.h"
+#include "system/system.h"
+#include "system/cpus.h"
+#include "system/hw_accel.h"
+#include "system/kvm.h"
+#include "system/runstate.h"
+#include "system/address-spaces.h"
#include "hw/i386/apic_internal.h"
#include "hw/sysbus.h"
#include "hw/boards.h"
@@ -718,7 +719,7 @@ static uint64_t vapic_read(void *opaque, hwaddr addr, unsigned size)
static const MemoryRegionOps vapic_ops = {
.write = vapic_write,
.read = vapic_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void vapic_realize(DeviceState *dev, Error **errp)
@@ -846,11 +847,11 @@ static const VMStateDescription vmstate_vapic = {
}
};
-static void vapic_class_init(ObjectClass *klass, void *data)
+static void vapic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = vapic_reset;
+ device_class_set_legacy_reset(dc, vapic_reset);
dc->vmsd = &vmstate_vapic;
dc->realize = vapic_realize;
}
diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index a8d014d..3896159 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -317,17 +317,16 @@ static void vmmouse_realizefn(DeviceState *dev, Error **errp)
vmport_register(VMPORT_CMD_VMMOUSE_DATA, vmmouse_ioport_read, s);
}
-static Property vmmouse_properties[] = {
+static const Property vmmouse_properties[] = {
DEFINE_PROP_LINK("i8042", VMMouseState, i8042, TYPE_I8042, ISAKBDState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vmmouse_class_initfn(ObjectClass *klass, void *data)
+static void vmmouse_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = vmmouse_realizefn;
- dc->reset = vmmouse_reset;
+ device_class_set_legacy_reset(dc, vmmouse_reset);
dc->vmsd = &vmstate_vmmouse;
device_class_set_props(dc, vmmouse_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c
index 7cc75db..6d93457 100644
--- a/hw/i386/vmport.c
+++ b/hw/i386/vmport.c
@@ -33,9 +33,9 @@
#include "hw/i386/vmport.h"
#include "hw/qdev-properties.h"
#include "hw/boards.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/qtest.h"
+#include "system/system.h"
+#include "system/hw_accel.h"
+#include "system/qtest.h"
#include "qemu/log.h"
#include "trace.h"
#include "qom/object.h"
@@ -252,7 +252,7 @@ static void vmport_realizefn(DeviceState *dev, Error **errp)
}
}
-static Property vmport_properties[] = {
+static const Property vmport_properties[] = {
/* Used to enforce compatibility for migration */
DEFINE_PROP_BIT("x-read-set-eax", VMPortState, compat_flags,
VMPORT_COMPAT_READ_SET_EAX_BIT, true),
@@ -284,11 +284,9 @@ static Property vmport_properties[] = {
* 5 - ACE 1.x (Deprecated)
*/
DEFINE_PROP_UINT8("vmware-vmx-type", VMPortState, vmware_vmx_type, 2),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void vmport_class_initfn(ObjectClass *klass, void *data)
+static void vmport_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index c0c66a0..b1b5f11 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -26,9 +26,9 @@
#include "qemu/units.h"
#include "qemu/datadir.h"
#include "qapi/error.h"
-#include "sysemu/numa.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/xen.h"
+#include "system/numa.h"
+#include "system/system.h"
+#include "system/xen.h"
#include "trace.h"
#include "hw/i386/x86.h"
@@ -44,6 +44,7 @@
#include "standard-headers/asm-x86/bootparam.h"
#include CONFIG_DEVICES
#include "kvm/kvm_i386.h"
+#include "kvm/tdx.h"
#ifdef CONFIG_XEN_EMU
#include "hw/xen/xen.h"
@@ -248,9 +249,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
CPUX86State *env = &cpu->env;
MachineState *ms = MACHINE(hotplug_dev);
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
- unsigned int smp_cores = ms->smp.cores;
- unsigned int smp_threads = ms->smp.threads;
- X86CPUTopoInfo topo_info;
+ X86CPUTopoInfo *topo_info = &env->topo_info;
if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
@@ -269,16 +268,14 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
}
}
- init_topo_info(&topo_info, x86ms);
+ init_topo_info(topo_info, x86ms);
if (ms->smp.modules > 1) {
- env->nr_modules = ms->smp.modules;
- set_bit(CPU_TOPO_LEVEL_MODULE, env->avail_cpu_topo);
+ set_bit(CPU_TOPOLOGY_LEVEL_MODULE, env->avail_cpu_topo);
}
if (ms->smp.dies > 1) {
- env->nr_dies = ms->smp.dies;
- set_bit(CPU_TOPO_LEVEL_DIE, env->avail_cpu_topo);
+ set_bit(CPU_TOPOLOGY_LEVEL_DIE, env->avail_cpu_topo);
}
/*
@@ -329,17 +326,17 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
if (cpu->core_id < 0) {
error_setg(errp, "CPU core-id is not set");
return;
- } else if (cpu->core_id > (smp_cores - 1)) {
+ } else if (cpu->core_id > (ms->smp.cores - 1)) {
error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
- cpu->core_id, smp_cores - 1);
+ cpu->core_id, ms->smp.cores - 1);
return;
}
if (cpu->thread_id < 0) {
error_setg(errp, "CPU thread-id is not set");
return;
- } else if (cpu->thread_id > (smp_threads - 1)) {
+ } else if (cpu->thread_id > (ms->smp.threads - 1)) {
error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
- cpu->thread_id, smp_threads - 1);
+ cpu->thread_id, ms->smp.threads - 1);
return;
}
@@ -348,12 +345,12 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
topo_ids.module_id = cpu->module_id;
topo_ids.core_id = cpu->core_id;
topo_ids.smt_id = cpu->thread_id;
- cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
+ cpu->apic_id = x86_apicid_from_topo_ids(topo_info, &topo_ids);
}
cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
if (!cpu_slot) {
- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
+ x86_topo_ids_from_apicid(cpu->apic_id, topo_info, &topo_ids);
error_setg(errp,
"Invalid CPU [socket: %u, die: %u, module: %u, core: %u, thread: %u]"
@@ -376,7 +373,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
/* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
* once -smp refactoring is complete and there will be CPU private
* CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
+ x86_topo_ids_from_apicid(cpu->apic_id, topo_info, &topo_ids);
if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
" 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
@@ -450,8 +447,27 @@ static long get_file_size(FILE *f)
void gsi_handler(void *opaque, int n, int level)
{
GSIState *s = opaque;
+ bool bypass_ioapic = false;
trace_x86_gsi_interrupt(n, level);
+
+#ifdef CONFIG_XEN_EMU
+ /*
+ * Xen delivers the GSI to the Legacy PIC (not that Legacy PIC
+ * routing actually works properly under Xen). And then to
+ * *either* the PIRQ handling or the I/OAPIC depending on whether
+ * the former wants it.
+ *
+ * Additionally, this hook allows the Xen event channel GSI to
+ * work around QEMU's lack of support for shared level interrupts,
+ * by keeping track of the externally driven state of the pin and
+ * implementing a logical OR with the state of the evtchn GSI.
+ */
+ if (xen_mode == XEN_EMULATE) {
+ bypass_ioapic = xen_evtchn_set_gsi(n, &level);
+ }
+#endif
+
switch (n) {
case 0 ... ISA_NUM_IRQS - 1:
if (s->i8259_irq[n]) {
@@ -460,18 +476,9 @@ void gsi_handler(void *opaque, int n, int level)
}
/* fall through */
case ISA_NUM_IRQS ... IOAPIC_NUM_PINS - 1:
-#ifdef CONFIG_XEN_EMU
- /*
- * Xen delivers the GSI to the Legacy PIC (not that Legacy PIC
- * routing actually works properly under Xen). And then to
- * *either* the PIRQ handling or the I/OAPIC depending on
- * whether the former wants it.
- */
- if (xen_mode == XEN_EMULATE && xen_evtchn_set_gsi(n, level)) {
- break;
+ if (!bypass_ioapic) {
+ qemu_set_irq(s->ioapic_irq[n], level);
}
-#endif
- qemu_set_irq(s->ioapic_irq[n], level);
break;
case IO_APIC_SECONDARY_IRQBASE
... IO_APIC_SECONDARY_IRQBASE + IOAPIC_NUM_PINS - 1:
@@ -586,7 +593,7 @@ static bool load_elfboot(const char *kernel_filename,
uint64_t elf_low, elf_high;
int kernel_size;
- if (ldl_p(header) != 0x464c457f) {
+ if (ldl_le_p(header) != 0x464c457f) {
return false; /* no elfboot */
}
@@ -602,8 +609,8 @@ static bool load_elfboot(const char *kernel_filename,
uint64_t elf_note_type = XEN_ELFNOTE_PHYS32_ENTRY;
kernel_size = load_elf(kernel_filename, read_pvh_start_addr,
NULL, &elf_note_type, &elf_entry,
- &elf_low, &elf_high, NULL, 0, I386_ELF_MACHINE,
- 0, 0);
+ &elf_low, &elf_high, NULL,
+ ELFDATA2LSB, I386_ELF_MACHINE, 0, 0);
if (kernel_size < 0) {
error_report("Error while loading elf kernel");
@@ -665,9 +672,12 @@ void x86_load_linux(X86MachineState *x86ms,
exit(1);
}
- /* kernel protocol version */
- if (ldl_p(header + 0x202) == 0x53726448) {
- protocol = lduw_p(header + 0x206);
+ /*
+ * kernel protocol version.
+ * Please see https://www.kernel.org/doc/Documentation/x86/boot.txt
+ */
+ if (ldl_le_p(header + 0x202) == 0x53726448) /* Magic signature "HdrS" */ {
+ protocol = lduw_le_p(header + 0x206);
} else {
/*
* This could be a multiboot kernel. If it is, let's stop treating it
@@ -694,9 +704,11 @@ void x86_load_linux(X86MachineState *x86ms,
strlen(kernel_cmdline) + 1);
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
+ setup = g_memdup2(header, sizeof(header));
+
fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, sizeof(header));
fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA,
- header, sizeof(header));
+ setup, sizeof(header));
/* load initrd */
if (initrd_filename) {
@@ -759,7 +771,7 @@ void x86_load_linux(X86MachineState *x86ms,
/* highest address for loading the initrd */
if (protocol >= 0x20c &&
- lduw_p(header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) {
+ lduw_le_p(header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) {
/*
* Linux has supported initrd up to 4 GB for a very long time (2007,
* long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013),
@@ -778,7 +790,7 @@ void x86_load_linux(X86MachineState *x86ms,
*/
initrd_max = UINT32_MAX;
} else if (protocol >= 0x203) {
- initrd_max = ldl_p(header + 0x22c);
+ initrd_max = ldl_le_p(header + 0x22c);
} else {
initrd_max = 0x37ffffff;
}
@@ -794,10 +806,10 @@ void x86_load_linux(X86MachineState *x86ms,
sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1;
if (protocol >= 0x202) {
- stl_p(header + 0x228, cmdline_addr);
+ stl_le_p(header + 0x228, cmdline_addr);
} else {
- stw_p(header + 0x20, 0xA33F);
- stw_p(header + 0x22, cmdline_addr - real_addr);
+ stw_le_p(header + 0x20, 0xA33F);
+ stw_le_p(header + 0x22, cmdline_addr - real_addr);
}
/* handle vga= parameter */
@@ -821,7 +833,7 @@ void x86_load_linux(X86MachineState *x86ms,
exit(1);
}
}
- stw_p(header + 0x1fa, video_mode);
+ stw_le_p(header + 0x1fa, video_mode);
}
/* loader type */
@@ -836,7 +848,7 @@ void x86_load_linux(X86MachineState *x86ms,
/* heap */
if (protocol >= 0x201) {
header[0x211] |= 0x80; /* CAN_USE_HEAP */
- stw_p(header + 0x224, cmdline_addr - real_addr - 0x200);
+ stw_le_p(header + 0x224, cmdline_addr - real_addr - 0x200);
}
/* load initrd */
@@ -876,8 +888,8 @@ void x86_load_linux(X86MachineState *x86ms,
sev_load_ctx.initrd_data = initrd_data;
sev_load_ctx.initrd_size = initrd_size;
- stl_p(header + 0x218, initrd_addr);
- stl_p(header + 0x21c, initrd_size);
+ stl_le_p(header + 0x218, initrd_addr);
+ stl_le_p(header + 0x21c, initrd_size);
}
/* load kernel and setup */
@@ -890,7 +902,6 @@ void x86_load_linux(X86MachineState *x86ms,
fprintf(stderr, "qemu: invalid kernel header\n");
exit(1);
}
- kernel_size -= setup_size;
setup = g_malloc(setup_size);
kernel = g_malloc(kernel_size);
@@ -899,6 +910,7 @@ void x86_load_linux(X86MachineState *x86ms,
fprintf(stderr, "fread() failed\n");
exit(1);
}
+ fseek(f, 0, SEEK_SET);
if (fread(kernel, 1, kernel_size, f) != kernel_size) {
fprintf(stderr, "fread() failed\n");
exit(1);
@@ -923,7 +935,7 @@ void x86_load_linux(X86MachineState *x86ms,
kernel_size = setup_data_offset + sizeof(struct setup_data) + dtb_size;
kernel = g_realloc(kernel, kernel_size);
- stq_p(header + 0x250, prot_addr + setup_data_offset);
+ stq_le_p(header + 0x250, prot_addr + setup_data_offset);
setup_data = (struct setup_data *)(kernel + setup_data_offset);
setup_data->next = 0;
@@ -940,15 +952,16 @@ void x86_load_linux(X86MachineState *x86ms,
* kernel on the other side of the fw_cfg interface matches the hash of the
* file the user passed in.
*/
- if (!sev_enabled()) {
+ if (!sev_enabled() && protocol > 0) {
memcpy(setup, header, MIN(sizeof(header), setup_size));
}
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
- sev_load_ctx.kernel_data = (char *)kernel;
- sev_load_ctx.kernel_size = kernel_size;
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size - setup_size);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+ kernel + setup_size, kernel_size - setup_size);
+ sev_load_ctx.kernel_data = (char *)kernel + setup_size;
+ sev_load_ctx.kernel_size = kernel_size - setup_size;
fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
@@ -956,6 +969,25 @@ void x86_load_linux(X86MachineState *x86ms,
sev_load_ctx.setup_data = (char *)setup;
sev_load_ctx.setup_size = setup_size;
+ /* kernel without setup header patches */
+ fw_cfg_add_file(fw_cfg, "etc/boot/kernel", kernel, kernel_size);
+
+ if (machine->shim_filename) {
+ GMappedFile *mapped_file;
+ GError *gerr = NULL;
+
+ mapped_file = g_mapped_file_new(machine->shim_filename, false, &gerr);
+ if (!mapped_file) {
+ fprintf(stderr, "qemu: error reading shim %s: %s\n",
+ machine->shim_filename, gerr->message);
+ exit(1);
+ }
+
+ fw_cfg_add_file(fw_cfg, "etc/boot/shim",
+ g_mapped_file_get_contents(mapped_file),
+ g_mapped_file_get_length(mapped_file));
+ }
+
if (sev_enabled()) {
sev_add_kernel_loader_hashes(&sev_load_ctx, &error_fatal);
}
@@ -1004,11 +1036,14 @@ void x86_bios_rom_init(X86MachineState *x86ms, const char *default_firmware,
if (machine_require_guest_memfd(MACHINE(x86ms))) {
memory_region_init_ram_guest_memfd(&x86ms->bios, NULL, "pc.bios",
bios_size, &error_fatal);
+ if (is_tdx_vm()) {
+ tdx_set_tdvf_region(&x86ms->bios);
+ }
} else {
memory_region_init_ram(&x86ms->bios, NULL, "pc.bios",
bios_size, &error_fatal);
}
- if (sev_enabled()) {
+ if (sev_enabled() || is_tdx_vm()) {
/*
* The concept of a "reset" simply doesn't exist for
* confidential computing guests, we have to destroy and
diff --git a/hw/i386/x86-cpu.c b/hw/i386/x86-cpu.c
index ab29205..c876e67 100644
--- a/hw/i386/x86-cpu.c
+++ b/hw/i386/x86-cpu.c
@@ -21,15 +21,15 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
-#include "sysemu/whpx.h"
-#include "sysemu/cpu-timers.h"
+#include "system/whpx.h"
+#include "system/cpu-timers.h"
#include "trace.h"
#include "hw/i386/x86.h"
#include "target/i386/cpu.h"
#include "hw/intc/i8259.h"
#include "hw/irq.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c
index 60af896..d34a684 100644
--- a/hw/i386/x86-iommu.c
+++ b/hw/i386/x86-iommu.c
@@ -25,7 +25,7 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "trace.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
void x86_iommu_iec_register_notifier(X86IOMMUState *iommu,
iec_notify_fn fn, void *data)
@@ -125,15 +125,14 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
}
}
-static Property x86_iommu_properties[] = {
+static const Property x86_iommu_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("intremap", X86IOMMUState,
intr_supported, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("device-iotlb", X86IOMMUState, dt_supported, false),
DEFINE_PROP_BOOL("pt", X86IOMMUState, pt_supported, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void x86_iommu_class_init(ObjectClass *klass, void *data)
+static void x86_iommu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = x86_iommu_realize;
@@ -147,7 +146,7 @@ bool x86_iommu_ir_supported(X86IOMMUState *s)
static const TypeInfo x86_iommu_info = {
.name = TYPE_X86_IOMMU_DEVICE,
- .parent = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
.instance_size = sizeof(X86IOMMUState),
.class_init = x86_iommu_class_init,
.class_size = sizeof(X86IOMMUClass),
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 01fc5e6..f80533d 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -27,8 +27,8 @@
#include "qapi/qapi-visit-common.h"
#include "qapi/qapi-visit-machine.h"
#include "qapi/visitor.h"
-#include "sysemu/qtest.h"
-#include "sysemu/numa.h"
+#include "system/qtest.h"
+#include "system/numa.h"
#include "trace.h"
#include "hw/acpi/aml-build.h"
@@ -372,7 +372,7 @@ static void x86_machine_initfn(Object *obj)
x86ms->above_4g_mem_start = 4 * GiB;
}
-static void x86_machine_class_init(ObjectClass *oc, void *data)
+static void x86_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
@@ -382,7 +382,6 @@ static void x86_machine_class_init(ObjectClass *oc, void *data)
mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
mc->kvm_type = x86_kvm_type;
- x86mc->save_tsc_khz = true;
x86mc->fwcfg_dma_enabled = true;
nc->nmi_monitor_handler = x86_nmi;
@@ -450,7 +449,7 @@ static const TypeInfo x86_machine_info = {
.instance_init = x86_machine_initfn,
.class_size = sizeof(X86MachineClass),
.class_init = x86_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NMI },
{ }
},
diff --git a/hw/i386/xen/meson.build b/hw/i386/xen/meson.build
index 3f0df8b..c73c62b 100644
--- a/hw/i386/xen/meson.build
+++ b/hw/i386/xen/meson.build
@@ -4,6 +4,7 @@ i386_ss.add(when: 'CONFIG_XEN', if_true: files(
))
i386_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
'xen-hvm.c',
+ 'xen-pvh.c',
))
i386_ss.add(when: 'CONFIG_XEN_BUS', if_true: files(
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 4f64466..ceb2242 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -10,10 +10,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-migration.h"
#include "trace.h"
+#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/irq.h"
#include "hw/i386/apic-msidef.h"
@@ -24,6 +26,10 @@
#include "hw/xen/arch_hvm.h"
#include <xen/hvm/e820.h>
#include "exec/target_page.h"
+#include "target/i386/cpu.h"
+#include "system/runstate.h"
+#include "system/xen-mapcache.h"
+#include "system/xen.h"
static MemoryRegion ram_640k, ram_lo, ram_hi;
static MemoryRegion *framebuffer;
@@ -614,7 +620,9 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory)
state = g_new0(XenIOState, 1);
- xen_register_ioreq(state, max_cpus, &xen_memory_listener);
+ xen_register_ioreq(state, max_cpus,
+ HVM_IOREQSRV_BUFIOREQ_ATOMIC,
+ &xen_memory_listener);
xen_is_stubdomain = xen_check_stubdomain(state->xenstore);
@@ -750,6 +758,4 @@ void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
default:
hw_error("Invalid ioreq type 0x%x\n", req->type);
}
-
- return;
}
diff --git a/hw/i386/xen/xen-pvh.c b/hw/i386/xen/xen-pvh.c
new file mode 100644
index 0000000..067f73e
--- /dev/null
+++ b/hw/i386/xen/xen-pvh.c
@@ -0,0 +1,125 @@
+/*
+ * QEMU Xen PVH x86 Machine
+ *
+ * Copyright (c) 2024 Advanced Micro Devices, Inc.
+ * Written by Edgar E. Iglesias <edgar.iglesias@amd.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "hw/boards.h"
+#include "system/system.h"
+#include "hw/xen/arch_hvm.h"
+#include <xen/hvm/hvm_info_table.h>
+#include "hw/xen/xen-pvh-common.h"
+#include "target/i386/cpu.h"
+
+#define TYPE_XEN_PVH_X86 MACHINE_TYPE_NAME("xenpvh")
+OBJECT_DECLARE_SIMPLE_TYPE(XenPVHx86State, XEN_PVH_X86)
+
+struct XenPVHx86State {
+ /*< private >*/
+ XenPVHMachineState parent;
+
+ DeviceState **cpu;
+};
+
+static DeviceState *xen_pvh_cpu_new(MachineState *ms,
+ int64_t apic_id)
+{
+ Object *cpu = object_new(ms->cpu_type);
+
+ object_property_add_child(OBJECT(ms), "cpu[*]", cpu);
+ object_property_set_uint(cpu, "apic-id", apic_id, &error_fatal);
+ qdev_realize(DEVICE(cpu), NULL, &error_fatal);
+ object_unref(cpu);
+
+ return DEVICE(cpu);
+}
+
+static void xen_pvh_init(MachineState *ms)
+{
+ XenPVHx86State *xp = XEN_PVH_X86(ms);
+ int i;
+
+ /* Create dummy cores. This will indirectly create the APIC MSI window. */
+ xp->cpu = g_malloc(sizeof xp->cpu[0] * ms->smp.max_cpus);
+ for (i = 0; i < ms->smp.max_cpus; i++) {
+ xp->cpu[i] = xen_pvh_cpu_new(ms, i);
+ }
+}
+
+static void xen_pvh_instance_init(Object *obj)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(obj);
+
+ /* Default values. */
+ s->cfg.ram_low = (MemMapEntry) { 0x0, 0x80000000U };
+ s->cfg.ram_high = (MemMapEntry) { 0xC000000000ULL, 0x4000000000ULL };
+ s->cfg.pci_intx_irq_base = 16;
+}
+
+/*
+ * Deliver INTX interrupts to Xen guest.
+ */
+static void xen_pvh_set_pci_intx_irq(void *opaque, int irq, int level)
+{
+ /*
+ * Since QEMU emulates all of the swizziling
+ * We don't want Xen to do any additional swizzling in
+ * xen_set_pci_intx_level() so we always set device to 0.
+ */
+ if (xen_set_pci_intx_level(xen_domid, 0, 0, 0, irq, level)) {
+ error_report("xendevicemodel_set_pci_intx_level failed");
+ }
+}
+
+static void xen_pvh_machine_class_init(ObjectClass *oc, const void *data)
+{
+ XenPVHMachineClass *xpc = XEN_PVH_MACHINE_CLASS(oc);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Xen PVH x86 machine";
+ mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
+
+ /* mc->max_cpus holds the MAX value allowed in the -smp cmd-line opts. */
+ mc->max_cpus = HVM_MAX_VCPUS;
+
+ /* We have an implementation specific init to create CPU objects. */
+ xpc->init = xen_pvh_init;
+
+ /* Enable buffered IOREQs. */
+ xpc->handle_bufioreq = HVM_IOREQSRV_BUFIOREQ_ATOMIC;
+
+ /*
+ * PCI INTX routing.
+ *
+ * We describe the mapping between the 4 INTX interrupt and GSIs
+ * using xen_set_pci_link_route(). xen_pvh_set_pci_intx_irq is
+ * used to deliver the interrupt.
+ */
+ xpc->set_pci_intx_irq = xen_pvh_set_pci_intx_irq;
+ xpc->set_pci_link_route = xen_set_pci_link_route;
+
+ /* List of supported features known to work on PVH x86. */
+ xpc->has_pci = true;
+
+ xen_pvh_class_setup_common_props(xpc);
+}
+
+static const TypeInfo xen_pvh_x86_machine_type = {
+ .name = TYPE_XEN_PVH_X86,
+ .parent = TYPE_XEN_PVH_MACHINE,
+ .class_init = xen_pvh_machine_class_init,
+ .instance_init = xen_pvh_instance_init,
+ .instance_size = sizeof(XenPVHx86State),
+};
+
+static void xen_pvh_machine_register_types(void)
+{
+ type_register_static(&xen_pvh_x86_machine_type);
+}
+
+type_init(xen_pvh_machine_register_types)
diff --git a/hw/i386/xen/xen_apic.c b/hw/i386/xen/xen_apic.c
index 101e16a..f30398f 100644
--- a/hw/i386/xen/xen_apic.c
+++ b/hw/i386/xen/xen_apic.c
@@ -36,7 +36,7 @@ static void xen_apic_mem_write(void *opaque, hwaddr addr,
static const MemoryRegionOps xen_apic_io_ops = {
.read = xen_apic_mem_read,
.write = xen_apic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void xen_apic_realize(DeviceState *dev, Error **errp)
@@ -76,7 +76,7 @@ static void xen_send_msi(MSIMessage *msi)
xen_hvm_inject_msi(msi->address, msi->data);
}
-static void xen_apic_class_init(ObjectClass *klass, void *data)
+static void xen_apic_class_init(ObjectClass *klass, const void *data)
{
APICCommonClass *k = APIC_COMMON_CLASS(klass);
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index 708488a..c8b852b 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -30,8 +30,8 @@
#include "migration/vmstate.h"
#include "net/net.h"
#include "trace.h"
-#include "sysemu/xen.h"
-#include "sysemu/block-backend.h"
+#include "system/xen.h"
+#include "system/block-backend.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qom/object.h"
@@ -514,7 +514,7 @@ static void platform_mmio_write(void *opaque, hwaddr addr,
static const MemoryRegionOps platform_mmio_handler = {
.read = &platform_mmio_read,
.write = &platform_mmio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void platform_mmio_setup(PCIXenPlatformState *d)
@@ -581,7 +581,7 @@ static void platform_reset(DeviceState *dev)
platform_fixed_ioport_reset(s);
}
-static void xen_platform_class_init(ObjectClass *klass, void *data)
+static void xen_platform_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -595,7 +595,7 @@ static void xen_platform_class_init(ObjectClass *klass, void *data)
k->revision = 1;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "XEN platform pci device";
- dc->reset = platform_reset;
+ device_class_set_legacy_reset(dc, platform_reset);
dc->vmsd = &vmstate_xen_platform;
}
@@ -604,7 +604,7 @@ static const TypeInfo xen_platform_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIXenPlatformState),
.class_init = xen_platform_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/i386/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c
index ed62153..87a974a 100644
--- a/hw/i386/xen/xen_pvdevice.c
+++ b/hw/i386/xen/xen_pvdevice.c
@@ -115,15 +115,14 @@ static void xen_pv_realize(PCIDevice *pci_dev, Error **errp)
&d->mmio);
}
-static Property xen_pv_props[] = {
+static const Property xen_pv_props[] = {
DEFINE_PROP_UINT16("vendor-id", XenPVDevice, vendor_id, PCI_VENDOR_ID_XEN),
DEFINE_PROP_UINT16("device-id", XenPVDevice, device_id, 0xffff),
DEFINE_PROP_UINT8("revision", XenPVDevice, revision, 0x01),
DEFINE_PROP_UINT32("size", XenPVDevice, size, 0x400000),
- DEFINE_PROP_END_OF_LIST()
};
-static void xen_pv_class_init(ObjectClass *klass, void *data)
+static void xen_pv_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -140,7 +139,7 @@ static const TypeInfo xen_pv_type_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(XenPVDevice),
.class_init = xen_pv_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/ide/Kconfig b/hw/ide/Kconfig
index 6dfc5a2..b55507b 100644
--- a/hw/ide/Kconfig
+++ b/hw/ide/Kconfig
@@ -43,12 +43,6 @@ config IDE_VIA
bool
select IDE_PCI
-config MICRODRIVE
- bool
- select IDE_BUS
- select IDE_DEV
- depends on PCMCIA
-
config AHCI
bool
select IDE_BUS
@@ -60,6 +54,10 @@ config AHCI_ICH9
depends on PCI
select AHCI
+config AHCI_SYSBUS
+ bool
+ select AHCI
+
config IDE_SII3112
bool
select IDE_PCI
diff --git a/hw/ide/ahci-allwinner.c b/hw/ide/ahci-allwinner.c
index 9620de8..bc7a116 100644
--- a/hw/ide/ahci-allwinner.c
+++ b/hw/ide/ahci-allwinner.c
@@ -18,7 +18,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "migration/vmstate.h"
#include "hw/ide/ahci-sysbus.h"
@@ -103,7 +103,7 @@ static const VMStateDescription vmstate_allwinner_ahci = {
}
};
-static void allwinner_ahci_class_init(ObjectClass *klass, void *data)
+static void allwinner_ahci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ide/ahci-internal.h b/hw/ide/ahci-internal.h
index 7e63ea2..a318f36 100644
--- a/hw/ide/ahci-internal.h
+++ b/hw/ide/ahci-internal.h
@@ -25,7 +25,6 @@
#define HW_IDE_AHCI_INTERNAL_H
#include "hw/ide/ahci.h"
-#include "hw/pci/pci_device.h"
#include "ide-internal.h"
#define AHCI_MEM_BAR_SIZE 0x1000
diff --git a/hw/ide/ahci-sysbus.c b/hw/ide/ahci-sysbus.c
new file mode 100644
index 0000000..210818d
--- /dev/null
+++ b/hw/ide/ahci-sysbus.c
@@ -0,0 +1,90 @@
+/*
+ * QEMU AHCI Emulation (MMIO-mapped devices)
+ *
+ * Copyright (c) 2010 qiaochong@loongson.cn
+ * Copyright (c) 2010 Roland Elek <elek.roland@gmail.com>
+ * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
+ * Copyright (c) 2010 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "system/address-spaces.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+#include "hw/ide/ahci-sysbus.h"
+#include "ahci-internal.h"
+
+static const VMStateDescription vmstate_sysbus_ahci = {
+ .name = "sysbus-ahci",
+ .fields = (const VMStateField[]) {
+ VMSTATE_AHCI(ahci, SysbusAHCIState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void sysbus_ahci_reset(DeviceState *dev)
+{
+ SysbusAHCIState *s = SYSBUS_AHCI(dev);
+
+ ahci_reset(&s->ahci);
+}
+
+static void sysbus_ahci_init(Object *obj)
+{
+ SysbusAHCIState *s = SYSBUS_AHCI(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ ahci_init(&s->ahci, DEVICE(obj));
+
+ sysbus_init_mmio(sbd, &s->ahci.mem);
+ sysbus_init_irq(sbd, &s->ahci.irq);
+}
+
+static void sysbus_ahci_realize(DeviceState *dev, Error **errp)
+{
+ SysbusAHCIState *s = SYSBUS_AHCI(dev);
+
+ ahci_realize(&s->ahci, dev, &address_space_memory);
+}
+
+static const Property sysbus_ahci_properties[] = {
+ DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, ahci.ports, 1),
+};
+
+static void sysbus_ahci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = sysbus_ahci_realize;
+ dc->vmsd = &vmstate_sysbus_ahci;
+ device_class_set_props(dc, sysbus_ahci_properties);
+ device_class_set_legacy_reset(dc, sysbus_ahci_reset);
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+}
+
+static const TypeInfo sysbus_ahci_types[] = {
+ {
+ .name = TYPE_SYSBUS_AHCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysbusAHCIState),
+ .instance_init = sysbus_ahci_init,
+ .class_init = sysbus_ahci_class_init,
+ },
+};
+
+DEFINE_TYPES(sysbus_ahci_types)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index bfefad2..1303c21 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -23,20 +23,13 @@
#include "qemu/osdep.h"
#include "hw/irq.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pci.h"
-#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
-#include "qemu/module.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
-#include "hw/ide/pci.h"
-#include "hw/ide/ahci-pci.h"
-#include "hw/ide/ahci-sysbus.h"
+#include "system/block-backend.h"
+#include "system/dma.h"
#include "ahci-internal.h"
#include "ide-internal.h"
@@ -179,34 +172,6 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
return val;
}
-static void ahci_irq_raise(AHCIState *s)
-{
- DeviceState *dev_state = s->container;
- PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
- TYPE_PCI_DEVICE);
-
- trace_ahci_irq_raise(s);
-
- if (pci_dev && msi_enabled(pci_dev)) {
- msi_notify(pci_dev, 0);
- } else {
- qemu_irq_raise(s->irq);
- }
-}
-
-static void ahci_irq_lower(AHCIState *s)
-{
- DeviceState *dev_state = s->container;
- PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
- TYPE_PCI_DEVICE);
-
- trace_ahci_irq_lower(s);
-
- if (!pci_dev || !msi_enabled(pci_dev)) {
- qemu_irq_lower(s->irq);
- }
-}
-
static void ahci_check_irq(AHCIState *s)
{
int i;
@@ -222,9 +187,11 @@ static void ahci_check_irq(AHCIState *s)
trace_ahci_check_irq(s, old_irq, s->control_regs.irqstatus);
if (s->control_regs.irqstatus &&
(s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
- ahci_irq_raise(s);
+ trace_ahci_irq_raise(s);
+ qemu_irq_raise(s->irq);
} else {
- ahci_irq_lower(s);
+ trace_ahci_irq_lower(s);
+ qemu_irq_lower(s->irq);
}
}
@@ -948,7 +915,6 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
uint64_t sum = 0;
int off_idx = -1;
int64_t off_pos = -1;
- int tbl_entry_size;
IDEBus *bus = &ad->port;
BusState *qbus = BUS(bus);
@@ -976,6 +942,8 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
/* Get entries in the PRDT, init a qemu sglist accordingly */
if (prdtl > 0) {
AHCI_SG *tbl = (AHCI_SG *)prdt;
+ int tbl_entry_size = 0;
+
sum = 0;
for (i = 0; i < prdtl; i++) {
tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);
@@ -1607,7 +1575,6 @@ static const IDEDMAOps ahci_dma_ops = {
void ahci_init(AHCIState *s, DeviceState *qdev)
{
- s->container = qdev;
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
memory_region_init_io(&s->mem, OBJECT(qdev), &ahci_mem_ops, s,
"ahci", AHCI_MEM_BAR_SIZE);
@@ -1833,70 +1800,6 @@ const VMStateDescription vmstate_ahci = {
},
};
-static const VMStateDescription vmstate_sysbus_ahci = {
- .name = "sysbus-ahci",
- .fields = (const VMStateField[]) {
- VMSTATE_AHCI(ahci, SysbusAHCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static void sysbus_ahci_reset(DeviceState *dev)
-{
- SysbusAHCIState *s = SYSBUS_AHCI(dev);
-
- ahci_reset(&s->ahci);
-}
-
-static void sysbus_ahci_init(Object *obj)
-{
- SysbusAHCIState *s = SYSBUS_AHCI(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- ahci_init(&s->ahci, DEVICE(obj));
-
- sysbus_init_mmio(sbd, &s->ahci.mem);
- sysbus_init_irq(sbd, &s->ahci.irq);
-}
-
-static void sysbus_ahci_realize(DeviceState *dev, Error **errp)
-{
- SysbusAHCIState *s = SYSBUS_AHCI(dev);
-
- ahci_realize(&s->ahci, dev, &address_space_memory);
-}
-
-static Property sysbus_ahci_properties[] = {
- DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, ahci.ports, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = sysbus_ahci_realize;
- dc->vmsd = &vmstate_sysbus_ahci;
- device_class_set_props(dc, sysbus_ahci_properties);
- dc->reset = sysbus_ahci_reset;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo sysbus_ahci_info = {
- .name = TYPE_SYSBUS_AHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysbusAHCIState),
- .instance_init = sysbus_ahci_init,
- .class_init = sysbus_ahci_class_init,
-};
-
-static void sysbus_ahci_register_types(void)
-{
- type_register_static(&sysbus_ahci_info);
-}
-
-type_init(sysbus_ahci_register_types)
-
void ahci_ide_create_devs(AHCIState *ahci, DriveInfo **hd)
{
int i;
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index e82959d..a42b748 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -26,7 +26,7 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "hw/scsi/scsi.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "scsi/constants.h"
#include "ide-internal.h"
#include "trace.h"
diff --git a/hw/ide/cf.c b/hw/ide/cf.c
index 2a425cb..f87cd41 100644
--- a/hw/ide/cf.c
+++ b/hw/ide/cf.c
@@ -24,15 +24,14 @@ static void ide_cf_realize(IDEDevice *dev, Error **errp)
ide_dev_initfn(dev, IDE_CFATA, errp);
}
-static Property ide_cf_properties[] = {
+static const Property ide_cf_properties[] = {
DEFINE_IDE_DEV_PROPERTIES(),
DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ide_cf_class_init(ObjectClass *klass, void *data)
+static void ide_cf_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 8cebd1b..2a59516 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -29,8 +29,8 @@
#include "migration/vmstate.h"
#include "qemu/module.h"
#include "hw/isa/isa.h"
-#include "sysemu/dma.h"
-#include "sysemu/reset.h"
+#include "system/dma.h"
+#include "system/reset.h"
#include "hw/ide/pci.h"
#include "ide-internal.h"
@@ -313,17 +313,16 @@ static void pci_cmd646_ide_exitfn(PCIDevice *dev)
}
}
-static Property cmd646_ide_properties[] = {
+static const Property cmd646_ide_properties[] = {
DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cmd646_ide_class_init(ObjectClass *klass, void *data)
+static void cmd646_ide_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = cmd646_reset;
+ device_class_set_legacy_reset(dc, cmd646_reset);
dc->vmsd = &vmstate_ide_pci;
k->realize = pci_cmd646_ide_realize;
k->exit = pci_cmd646_ide_exitfn;
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 08d9218..b14983e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -32,15 +32,15 @@
#include "qemu/timer.h"
#include "qemu/hw-version.h"
#include "qemu/memalign.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/dma.h"
+#include "system/system.h"
+#include "system/blockdev.h"
+#include "system/dma.h"
#include "hw/block/block.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
-#include "sysemu/replay.h"
-#include "sysemu/runstate.h"
+#include "system/replay.h"
+#include "system/runstate.h"
#include "ide-internal.h"
#include "trace.h"
@@ -968,8 +968,7 @@ static void ide_dma_cb(void *opaque, int ret)
BDRV_SECTOR_SIZE, ide_dma_cb, s);
break;
case IDE_DMA_TRIM:
- s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk),
- &s->sg, offset, BDRV_SECTOR_SIZE,
+ s->bus->dma->aiocb = dma_blk_io(&s->sg, offset, BDRV_SECTOR_SIZE,
ide_issue_trim, s, ide_dma_cb, s,
DMA_DIRECTION_TO_DEVICE);
break;
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 9b909c8..4cade0d 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -61,13 +61,12 @@
*/
#include "qemu/osdep.h"
-#include "hw/irq.h"
#include "hw/pci/msi.h"
#include "hw/pci/pci.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
#include "hw/isa/isa.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/ide/pci.h"
#include "hw/ide/ahci-pci.h"
#include "ahci-internal.h"
@@ -91,6 +90,19 @@ static const VMStateDescription vmstate_ich9_ahci = {
},
};
+static void pci_ich9_ahci_update_irq(void *opaque, int irq_num, int level)
+{
+ PCIDevice *pci_dev = opaque;
+
+ if (msi_enabled(pci_dev)) {
+ if (level) {
+ msi_notify(pci_dev, 0);
+ }
+ } else {
+ pci_set_irq(pci_dev, level);
+ }
+}
+
static void pci_ich9_reset(DeviceState *dev)
{
AHCIPCIState *d = ICH9_AHCI(dev);
@@ -102,7 +114,9 @@ static void pci_ich9_ahci_init(Object *obj)
{
AHCIPCIState *d = ICH9_AHCI(obj);
+ qemu_init_irq(&d->irq, pci_ich9_ahci_update_irq, d, 0);
ahci_init(&d->ahci, DEVICE(obj));
+ d->ahci.irq = &d->irq;
}
static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
@@ -125,8 +139,6 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
/* XXX Software should program this register */
dev->config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
- d->ahci.irq = pci_allocate_irq(dev);
-
pci_register_bar(dev, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO,
&d->ahci.idp);
pci_register_bar(dev, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY,
@@ -161,10 +173,9 @@ static void pci_ich9_uninit(PCIDevice *dev)
msi_uninit(dev);
ahci_uninit(&d->ahci);
- qemu_free_irq(d->ahci.irq);
}
-static void ich_ahci_class_init(ObjectClass *klass, void *data)
+static void ich_ahci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -176,7 +187,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
k->revision = 0x02;
k->class_id = PCI_CLASS_STORAGE_SATA;
dc->vmsd = &vmstate_ich9_ahci;
- dc->reset = pci_ich9_reset;
+ device_class_set_legacy_reset(dc, pci_ich9_reset);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
@@ -186,7 +197,7 @@ static const TypeInfo ich_ahci_info = {
.instance_size = sizeof(AHCIPCIState),
.instance_init = pci_ich9_ahci_init,
.class_init = ich_ahci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/ide/ide-bus.c b/hw/ide/ide-bus.c
index 37d003d..b24e4d1 100644
--- a/hw/ide/ide-bus.c
+++ b/hw/ide/ide-bus.c
@@ -21,15 +21,15 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/runstate.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
+#include "system/runstate.h"
#include "ide-internal.h"
static char *idebus_get_fw_dev_path(DeviceState *dev);
static void idebus_unrealize(BusState *qdev);
-static void ide_bus_class_init(ObjectClass *klass, void *data)
+static void ide_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
diff --git a/hw/ide/ide-dev.c b/hw/ide/ide-dev.c
index 03f7967..5d47858 100644
--- a/hw/ide/ide-dev.c
+++ b/hw/ide/ide-dev.c
@@ -23,16 +23,15 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "hw/ide/ide-dev.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
+#include "system/system.h"
#include "qapi/visitor.h"
#include "ide-internal.h"
-static Property ide_props[] = {
+static const Property ide_props[] = {
DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
DEFINE_PROP_BOOL("win2k-install-hack", IDEDevice, win2k_install_hack, false),
- DEFINE_PROP_END_OF_LIST(),
};
static void ide_qdev_realize(DeviceState *qdev, Error **errp)
@@ -191,16 +190,15 @@ static void ide_cd_realize(IDEDevice *dev, Error **errp)
ide_dev_initfn(dev, IDE_CD, errp);
}
-static Property ide_hd_properties[] = {
+static const Property ide_hd_properties[] = {
DEFINE_IDE_DEV_PROPERTIES(),
DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
DEFINE_PROP_UINT16("rotation_rate", IDEDrive, dev.rotation_rate, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ide_hd_class_init(ObjectClass *klass, void *data)
+static void ide_hd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
@@ -218,12 +216,11 @@ static const TypeInfo ide_hd_info = {
.class_init = ide_hd_class_init,
};
-static Property ide_cd_properties[] = {
+static const Property ide_cd_properties[] = {
DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ide_cd_class_init(ObjectClass *klass, void *data)
+static void ide_cd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
@@ -241,7 +238,7 @@ static const TypeInfo ide_cd_info = {
.class_init = ide_cd_class_init,
};
-static void ide_device_class_init(ObjectClass *klass, void *data)
+static void ide_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = ide_qdev_realize;
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 934c458..5f41841 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -29,7 +29,7 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/module.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/ide/isa.h"
#include "qom/object.h"
@@ -101,20 +101,19 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int irqnum,
return isadev;
}
-static Property isa_ide_properties[] = {
+static const Property isa_ide_properties[] = {
DEFINE_PROP_UINT32("iobase", ISAIDEState, iobase, 0x1f0),
DEFINE_PROP_UINT32("iobase2", ISAIDEState, iobase2, 0x3f6),
DEFINE_PROP_UINT32("irq", ISAIDEState, irqnum, 14),
- DEFINE_PROP_END_OF_LIST(),
};
-static void isa_ide_class_initfn(ObjectClass *klass, void *data)
+static void isa_ide_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = isa_ide_realizefn;
dc->fw_name = "ide";
- dc->reset = isa_ide_reset;
+ device_class_set_legacy_reset(dc, isa_ide_reset);
device_class_set_props(dc, isa_ide_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index e84bf2c..c23bf32 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -30,8 +30,8 @@
#include "migration/vmstate.h"
#include "qemu/module.h"
#include "hw/misc/macio/macio.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
+#include "system/block-backend.h"
+#include "system/dma.h"
#include "ide-internal.h"
@@ -119,9 +119,6 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
return;
done:
- dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
- io->dir, io->dma_len);
-
if (ret < 0) {
block_acct_failed(blk_get_stats(s->blk), &s->acct);
} else {
@@ -190,8 +187,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
pmac_ide_transfer_cb, io);
break;
case IDE_DMA_TRIM:
- s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), &s->sg,
- offset, 0x1, ide_issue_trim, s,
+ s->bus->dma->aiocb = dma_blk_io(&s->sg, offset, 0x1, ide_issue_trim, s,
pmac_ide_transfer_cb, io,
DMA_DIRECTION_TO_DEVICE);
break;
@@ -202,9 +198,6 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
return;
done:
- dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
- io->dir, io->dma_len);
-
if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
if (ret < 0) {
block_acct_failed(blk_get_stats(s->blk), &s->acct);
@@ -465,18 +458,17 @@ static void macio_ide_initfn(Object *obj)
qdev_prop_allow_set_link_before_realize, 0);
}
-static Property macio_ide_properties[] = {
+static const Property macio_ide_properties[] = {
DEFINE_PROP_UINT32("channel", MACIOIDEState, channel, 0),
DEFINE_PROP_UINT32("addr", MACIOIDEState, addr, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void macio_ide_class_init(ObjectClass *oc, void *data)
+static void macio_ide_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = macio_ide_realizefn;
- dc->reset = macio_ide_reset;
+ device_class_set_legacy_reset(dc, macio_ide_reset);
device_class_set_props(dc, macio_ide_properties);
dc->vmsd = &vmstate_pmac;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/ide/meson.build b/hw/ide/meson.build
index d09705c..ddd7066 100644
--- a/hw/ide/meson.build
+++ b/hw/ide/meson.build
@@ -1,5 +1,6 @@
system_ss.add(when: 'CONFIG_AHCI', if_true: files('ahci.c'))
system_ss.add(when: 'CONFIG_AHCI_ICH9', if_true: files('ich.c'))
+system_ss.add(when: 'CONFIG_AHCI_SYSBUS', if_true: files('ahci-sysbus.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('ahci-allwinner.c'))
system_ss.add(when: 'CONFIG_IDE_BUS', if_true: files('ide-bus.c'))
system_ss.add(when: 'CONFIG_IDE_CF', if_true: files('cf.c'))
@@ -13,4 +14,3 @@ system_ss.add(when: 'CONFIG_IDE_PCI', if_true: files('pci.c'))
system_ss.add(when: 'CONFIG_IDE_PIIX', if_true: files('piix.c', 'ioport.c'))
system_ss.add(when: 'CONFIG_IDE_SII3112', if_true: files('sii3112.c'))
system_ss.add(when: 'CONFIG_IDE_VIA', if_true: files('via.c'))
-system_ss.add(when: 'CONFIG_MICRODRIVE', if_true: files('microdrive.c'))
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
deleted file mode 100644
index 3bb152b..0000000
--- a/hw/ide/microdrive.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * QEMU IDE Emulation: microdrive (CF / PCMCIA)
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/pcmcia.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "sysemu/dma.h"
-#include "hw/irq.h"
-
-#include "qom/object.h"
-#include "ide-internal.h"
-
-#define TYPE_MICRODRIVE "microdrive"
-OBJECT_DECLARE_SIMPLE_TYPE(MicroDriveState, MICRODRIVE)
-
-/***********************************************************/
-/* CF-ATA Microdrive */
-
-#define METADATA_SIZE 0x20
-
-/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface. */
-
-struct MicroDriveState {
- /*< private >*/
- PCMCIACardState parent_obj;
- /*< public >*/
-
- IDEBus bus;
- uint32_t attr_base;
- uint32_t io_base;
-
- /* Card state */
- uint8_t opt;
- uint8_t stat;
- uint8_t pins;
-
- uint8_t ctrl;
- uint16_t io;
- uint8_t cycle;
-};
-
-/* Register bitfields */
-enum md_opt {
- OPT_MODE_MMAP = 0,
- OPT_MODE_IOMAP16 = 1,
- OPT_MODE_IOMAP1 = 2,
- OPT_MODE_IOMAP2 = 3,
- OPT_MODE = 0x3f,
- OPT_LEVIREQ = 0x40,
- OPT_SRESET = 0x80,
-};
-enum md_cstat {
- STAT_INT = 0x02,
- STAT_PWRDWN = 0x04,
- STAT_XE = 0x10,
- STAT_IOIS8 = 0x20,
- STAT_SIGCHG = 0x40,
- STAT_CHANGED = 0x80,
-};
-enum md_pins {
- PINS_MRDY = 0x02,
- PINS_CRDY = 0x20,
-};
-enum md_ctrl {
- CTRL_IEN = 0x02,
- CTRL_SRST = 0x04,
-};
-
-static inline void md_interrupt_update(MicroDriveState *s)
-{
- PCMCIACardState *card = PCMCIA_CARD(s);
-
- if (card->slot == NULL) {
- return;
- }
-
- qemu_set_irq(card->slot->irq,
- !(s->stat & STAT_INT) && /* Inverted */
- !(s->ctrl & (CTRL_IEN | CTRL_SRST)) &&
- !(s->opt & OPT_SRESET));
-}
-
-static void md_set_irq(void *opaque, int irq, int level)
-{
- MicroDriveState *s = opaque;
-
- if (level) {
- s->stat |= STAT_INT;
- } else {
- s->stat &= ~STAT_INT;
- }
-
- md_interrupt_update(s);
-}
-
-static void md_reset(DeviceState *dev)
-{
- MicroDriveState *s = MICRODRIVE(dev);
-
- s->opt = OPT_MODE_MMAP;
- s->stat = 0;
- s->pins = 0;
- s->cycle = 0;
- s->ctrl = 0;
- ide_bus_reset(&s->bus);
-}
-
-static uint8_t md_attr_read(PCMCIACardState *card, uint32_t at)
-{
- MicroDriveState *s = MICRODRIVE(card);
- PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card);
-
- if (at < s->attr_base) {
- if (at < pcc->cis_len) {
- return pcc->cis[at];
- } else {
- return 0x00;
- }
- }
-
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- return s->opt;
- case 0x02: /* Card Configuration Status Register */
- if (s->ctrl & CTRL_IEN) {
- return s->stat & ~STAT_INT;
- } else {
- return s->stat;
- }
- case 0x04: /* Pin Replacement Register */
- return (s->pins & PINS_CRDY) | 0x0c;
- case 0x06: /* Socket and Copy Register */
- return 0x00;
-#ifdef VERBOSE
- default:
- printf("%s: Bad attribute space register %02x\n", __func__, at);
-#endif
- }
-
- return 0;
-}
-
-static void md_attr_write(PCMCIACardState *card, uint32_t at, uint8_t value)
-{
- MicroDriveState *s = MICRODRIVE(card);
-
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- s->opt = value & 0xcf;
- if (value & OPT_SRESET) {
- device_cold_reset(DEVICE(s));
- }
- md_interrupt_update(s);
- break;
- case 0x02: /* Card Configuration Status Register */
- if ((s->stat ^ value) & STAT_PWRDWN) {
- s->pins |= PINS_CRDY;
- }
- s->stat &= 0x82;
- s->stat |= value & 0x74;
- md_interrupt_update(s);
- /* Word 170 in Identify Device must be equal to STAT_XE */
- break;
- case 0x04: /* Pin Replacement Register */
- s->pins &= PINS_CRDY;
- s->pins |= value & PINS_MRDY;
- break;
- case 0x06: /* Socket and Copy Register */
- break;
- default:
- printf("%s: Bad attribute space register %02x\n", __func__, at);
- }
-}
-
-static uint16_t md_common_read(PCMCIACardState *card, uint32_t at)
-{
- MicroDriveState *s = MICRODRIVE(card);
- IDEState *ifs;
- uint16_t ret;
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400) {
- at = 0;
- }
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0) {
- at -= 0x3e8;
- } else if ((at & ~0xf) == 0x1f0) {
- at -= 0x1f0;
- }
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370) {
- at -= 0x368;
- } else if ((at & ~0xf) == 0x170) {
- at -= 0x170;
- }
- }
-
- switch (at) {
- case 0x0: /* Even RD Data */
- case 0x8:
- return ide_data_readw(&s->bus, 0);
-
- /* TODO: 8-bit accesses */
- if (s->cycle) {
- ret = s->io >> 8;
- } else {
- s->io = ide_data_readw(&s->bus, 0);
- ret = s->io & 0xff;
- }
- s->cycle = !s->cycle;
- return ret;
- case 0x9: /* Odd RD Data */
- return s->io >> 8;
- case 0xd: /* Error */
- return ide_ioport_read(&s->bus, 0x1);
- case 0xe: /* Alternate Status */
- ifs = ide_bus_active_if(&s->bus);
- if (ifs->blk) {
- return ifs->status;
- } else {
- return 0;
- }
- case 0xf: /* Device Address */
- ifs = ide_bus_active_if(&s->bus);
- return 0xc2 | ((~ifs->select << 2) & 0x3c);
- default:
- return ide_ioport_read(&s->bus, at);
- }
-
- return 0;
-}
-
-static void md_common_write(PCMCIACardState *card, uint32_t at, uint16_t value)
-{
- MicroDriveState *s = MICRODRIVE(card);
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400) {
- at = 0;
- }
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0) {
- at -= 0x3e8;
- } else if ((at & ~0xf) == 0x1f0) {
- at -= 0x1f0;
- }
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370) {
- at -= 0x368;
- } else if ((at & ~0xf) == 0x170) {
- at -= 0x170;
- }
- }
-
- switch (at) {
- case 0x0: /* Even WR Data */
- case 0x8:
- ide_data_writew(&s->bus, 0, value);
- break;
-
- /* TODO: 8-bit accesses */
- if (s->cycle) {
- ide_data_writew(&s->bus, 0, s->io | (value << 8));
- } else {
- s->io = value & 0xff;
- }
- s->cycle = !s->cycle;
- break;
- case 0x9:
- s->io = value & 0xff;
- s->cycle = !s->cycle;
- break;
- case 0xd: /* Features */
- ide_ioport_write(&s->bus, 0x1, value);
- break;
- case 0xe: /* Device Control */
- s->ctrl = value;
- if (value & CTRL_SRST) {
- device_cold_reset(DEVICE(s));
- }
- md_interrupt_update(s);
- break;
- default:
- if (s->stat & STAT_PWRDWN) {
- s->pins |= PINS_CRDY;
- s->stat &= ~STAT_PWRDWN;
- }
- ide_ioport_write(&s->bus, at, value);
- }
-}
-
-static const VMStateDescription vmstate_microdrive = {
- .name = "microdrive",
- .version_id = 3,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(opt, MicroDriveState),
- VMSTATE_UINT8(stat, MicroDriveState),
- VMSTATE_UINT8(pins, MicroDriveState),
- VMSTATE_UINT8(ctrl, MicroDriveState),
- VMSTATE_UINT16(io, MicroDriveState),
- VMSTATE_UINT8(cycle, MicroDriveState),
- VMSTATE_IDE_BUS(bus, MicroDriveState),
- VMSTATE_IDE_DRIVES(bus.ifs, MicroDriveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const uint8_t dscm1xxxx_cis[0x14a] = {
- [0x000] = CISTPL_DEVICE, /* 5V Device Information */
- [0x002] = 0x03, /* Tuple length = 4 bytes */
- [0x004] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x006] = 0x01, /* Size = 2K bytes */
- [0x008] = CISTPL_ENDMARK,
-
- [0x00a] = CISTPL_DEVICE_OC, /* Additional Device Information */
- [0x00c] = 0x04, /* Tuple length = 4 byest */
- [0x00e] = 0x03, /* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */
- [0x010] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x012] = 0x01, /* Size = 2K bytes */
- [0x014] = CISTPL_ENDMARK,
-
- [0x016] = CISTPL_JEDEC_C, /* JEDEC ID */
- [0x018] = 0x02, /* Tuple length = 2 bytes */
- [0x01a] = 0xdf, /* PC Card ATA with no Vpp required */
- [0x01c] = 0x01,
-
- [0x01e] = CISTPL_MANFID, /* Manufacture ID */
- [0x020] = 0x04, /* Tuple length = 4 bytes */
- [0x022] = 0xa4, /* TPLMID_MANF = 00a4 (IBM) */
- [0x024] = 0x00,
- [0x026] = 0x00, /* PLMID_CARD = 0000 */
- [0x028] = 0x00,
-
- [0x02a] = CISTPL_VERS_1, /* Level 1 Version */
- [0x02c] = 0x12, /* Tuple length = 23 bytes */
- [0x02e] = 0x04, /* Major Version = JEIDA 4.2 / PCMCIA 2.1 */
- [0x030] = 0x01, /* Minor Version = 1 */
- [0x032] = 'I',
- [0x034] = 'B',
- [0x036] = 'M',
- [0x038] = 0x00,
- [0x03a] = 'm',
- [0x03c] = 'i',
- [0x03e] = 'c',
- [0x040] = 'r',
- [0x042] = 'o',
- [0x044] = 'd',
- [0x046] = 'r',
- [0x048] = 'i',
- [0x04a] = 'v',
- [0x04c] = 'e',
- [0x04e] = 0x00,
- [0x050] = CISTPL_ENDMARK,
-
- [0x052] = CISTPL_FUNCID, /* Function ID */
- [0x054] = 0x02, /* Tuple length = 2 bytes */
- [0x056] = 0x04, /* TPLFID_FUNCTION = Fixed Disk */
- [0x058] = 0x01, /* TPLFID_SYSINIT: POST = 1, ROM = 0 */
-
- [0x05a] = CISTPL_FUNCE, /* Function Extension */
- [0x05c] = 0x02, /* Tuple length = 2 bytes */
- [0x05e] = 0x01, /* TPLFE_TYPE = Disk Device Interface */
- [0x060] = 0x01, /* TPLFE_DATA = PC Card ATA Interface */
-
- [0x062] = CISTPL_FUNCE, /* Function Extension */
- [0x064] = 0x03, /* Tuple length = 3 bytes */
- [0x066] = 0x02, /* TPLFE_TYPE = Basic PC Card ATA Interface */
- [0x068] = 0x08, /* TPLFE_DATA: Rotating, Unique, Single */
- [0x06a] = 0x0f, /* TPLFE_DATA: Sleep, Standby, Idle, Auto */
-
- [0x06c] = CISTPL_CONFIG, /* Configuration */
- [0x06e] = 0x05, /* Tuple length = 5 bytes */
- [0x070] = 0x01, /* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */
- [0x072] = 0x07, /* TPCC_LAST = 7 */
- [0x074] = 0x00, /* TPCC_RADR = 0200 */
- [0x076] = 0x02,
- [0x078] = 0x0f, /* TPCC_RMSK = 200, 202, 204, 206 */
-
- [0x07a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x07c] = 0x0b, /* Tuple length = 11 bytes */
- [0x07e] = 0xc0, /* TPCE_INDX = Memory Mode, Default, Iface */
- [0x080] = 0xc0, /* TPCE_IF = Memory, no BVDs, no WP, READY */
- [0x082] = 0xa1, /* TPCE_FS = Vcc only, no I/O, Memory, Misc */
- [0x084] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x086] = 0x55, /* NomV: 5.0 V */
- [0x088] = 0x4d, /* MinV: 4.5 V */
- [0x08a] = 0x5d, /* MaxV: 5.5 V */
- [0x08c] = 0x4e, /* Peakl: 450 mA */
- [0x08e] = 0x08, /* TPCE_MS = 1 window, 1 byte, Host address */
- [0x090] = 0x00, /* Window descriptor: Window length = 0 */
- [0x092] = 0x20, /* TPCE_MI: support power down mode, RW */
-
- [0x094] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x096] = 0x06, /* Tuple length = 6 bytes */
- [0x098] = 0x00, /* TPCE_INDX = Memory Mode, no Default */
- [0x09a] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x09c] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x09e] = 0xb5, /* NomV: 3.3 V */
- [0x0a0] = 0x1e,
- [0x0a2] = 0x3e, /* Peakl: 350 mA */
-
- [0x0a4] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0a6] = 0x0d, /* Tuple length = 13 bytes */
- [0x0a8] = 0xc1, /* TPCE_INDX = I/O and Memory Mode, Default */
- [0x0aa] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0ac] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0ae] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0b0] = 0x55, /* NomV: 5.0 V */
- [0x0b2] = 0x4d, /* MinV: 4.5 V */
- [0x0b4] = 0x5d, /* MaxV: 5.5 V */
- [0x0b6] = 0x4e, /* Peakl: 450 mA */
- [0x0b8] = 0x64, /* TPCE_IO = 16-byte boundary, 16/8 accesses */
- [0x0ba] = 0xf0, /* TPCE_IR = MASK, Level, Pulse, Share */
- [0x0bc] = 0xff, /* IRQ0..IRQ7 supported */
- [0x0be] = 0xff, /* IRQ8..IRQ15 supported */
- [0x0c0] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0c2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0c4] = 0x06, /* Tuple length = 6 bytes */
- [0x0c6] = 0x01, /* TPCE_INDX = I/O and Memory Mode */
- [0x0c8] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x0ca] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x0cc] = 0xb5, /* NomV: 3.3 V */
- [0x0ce] = 0x1e,
- [0x0d0] = 0x3e, /* Peakl: 350 mA */
-
- [0x0d2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0d4] = 0x12, /* Tuple length = 18 bytes */
- [0x0d6] = 0xc2, /* TPCE_INDX = I/O Primary Mode */
- [0x0d8] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0da] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0dc] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0de] = 0x55, /* NomV: 5.0 V */
- [0x0e0] = 0x4d, /* MinV: 4.5 V */
- [0x0e2] = 0x5d, /* MaxV: 5.5 V */
- [0x0e4] = 0x4e, /* Peakl: 450 mA */
- [0x0e6] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x0e8] = 0x61, /* Range: 2 fields, 2 bytes addr, 1 byte len */
- [0x0ea] = 0xf0, /* Field 1 address = 0x01f0 */
- [0x0ec] = 0x01,
- [0x0ee] = 0x07, /* Address block length = 8 */
- [0x0f0] = 0xf6, /* Field 2 address = 0x03f6 */
- [0x0f2] = 0x03,
- [0x0f4] = 0x01, /* Address block length = 2 */
- [0x0f6] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x0f8] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0fa] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0fc] = 0x06, /* Tuple length = 6 bytes */
- [0x0fe] = 0x02, /* TPCE_INDX = I/O Primary Mode, no Default */
- [0x100] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x102] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x104] = 0xb5, /* NomV: 3.3 V */
- [0x106] = 0x1e,
- [0x108] = 0x3e, /* Peakl: 350 mA */
-
- [0x10a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x10c] = 0x12, /* Tuple length = 18 bytes */
- [0x10e] = 0xc3, /* TPCE_INDX = I/O Secondary Mode, Default */
- [0x110] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x112] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x114] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x116] = 0x55, /* NomV: 5.0 V */
- [0x118] = 0x4d, /* MinV: 4.5 V */
- [0x11a] = 0x5d, /* MaxV: 5.5 V */
- [0x11c] = 0x4e, /* Peakl: 450 mA */
- [0x11e] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x120] = 0x61, /* Range: 2 fields, 2 byte addr, 1 byte len */
- [0x122] = 0x70, /* Field 1 address = 0x0170 */
- [0x124] = 0x01,
- [0x126] = 0x07, /* Address block length = 8 */
- [0x128] = 0x76, /* Field 2 address = 0x0376 */
- [0x12a] = 0x03,
- [0x12c] = 0x01, /* Address block length = 2 */
- [0x12e] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x130] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x132] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x134] = 0x06, /* Tuple length = 6 bytes */
- [0x136] = 0x03, /* TPCE_INDX = I/O Secondary Mode */
- [0x138] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x13a] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x13c] = 0xb5, /* NomV: 3.3 V */
- [0x13e] = 0x1e,
- [0x140] = 0x3e, /* Peakl: 350 mA */
-
- [0x142] = CISTPL_NO_LINK, /* No Link */
- [0x144] = 0x00, /* Tuple length = 0 bytes */
-
- [0x146] = CISTPL_END, /* Tuple End */
-};
-
-#define TYPE_DSCM1XXXX "dscm1xxxx"
-
-static int dscm1xxxx_attach(PCMCIACardState *card)
-{
- MicroDriveState *md = MICRODRIVE(card);
- PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card);
-
- md->attr_base = pcc->cis[0x74] | (pcc->cis[0x76] << 8);
- md->io_base = 0x0;
-
- device_cold_reset(DEVICE(md));
- md_interrupt_update(md);
-
- return 0;
-}
-
-static int dscm1xxxx_detach(PCMCIACardState *card)
-{
- MicroDriveState *md = MICRODRIVE(card);
-
- device_cold_reset(DEVICE(md));
- return 0;
-}
-
-PCMCIACardState *dscm1xxxx_init(DriveInfo *dinfo)
-{
- MicroDriveState *md;
-
- md = MICRODRIVE(object_new(TYPE_DSCM1XXXX));
- qdev_realize(DEVICE(md), NULL, &error_fatal);
-
- if (dinfo != NULL) {
- ide_bus_create_drive(&md->bus, 0, dinfo);
- }
- md->bus.ifs[0].drive_kind = IDE_CFATA;
- md->bus.ifs[0].mdata_size = METADATA_SIZE;
- md->bus.ifs[0].mdata_storage = g_malloc0(METADATA_SIZE);
-
- return PCMCIA_CARD(md);
-}
-
-static void dscm1xxxx_class_init(ObjectClass *oc, void *data)
-{
- PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- pcc->cis = dscm1xxxx_cis;
- pcc->cis_len = sizeof(dscm1xxxx_cis);
-
- pcc->attach = dscm1xxxx_attach;
- pcc->detach = dscm1xxxx_detach;
- /* Reason: Needs to be wired-up in code, see dscm1xxxx_init() */
- dc->user_creatable = false;
-}
-
-static const TypeInfo dscm1xxxx_type_info = {
- .name = TYPE_DSCM1XXXX,
- .parent = TYPE_MICRODRIVE,
- .class_init = dscm1xxxx_class_init,
-};
-
-static void microdrive_realize(DeviceState *dev, Error **errp)
-{
- MicroDriveState *md = MICRODRIVE(dev);
-
- ide_bus_init_output_irq(&md->bus, qemu_allocate_irq(md_set_irq, md, 0));
-}
-
-static void microdrive_init(Object *obj)
-{
- MicroDriveState *md = MICRODRIVE(obj);
-
- ide_bus_init(&md->bus, sizeof(md->bus), DEVICE(obj), 0, 1);
-}
-
-static void microdrive_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc);
-
- pcc->attr_read = md_attr_read;
- pcc->attr_write = md_attr_write;
- pcc->common_read = md_common_read;
- pcc->common_write = md_common_write;
- pcc->io_read = md_common_read;
- pcc->io_write = md_common_write;
-
- dc->realize = microdrive_realize;
- dc->reset = md_reset;
- dc->vmsd = &vmstate_microdrive;
-}
-
-static const TypeInfo microdrive_type_info = {
- .name = TYPE_MICRODRIVE,
- .parent = TYPE_PCMCIA_CARD,
- .instance_size = sizeof(MicroDriveState),
- .instance_init = microdrive_init,
- .abstract = true,
- .class_init = microdrive_class_init,
-};
-
-static void microdrive_register_types(void)
-{
- type_register_static(&microdrive_type_info);
- type_register_static(&dscm1xxxx_type_info);
-}
-
-type_init(microdrive_register_types)
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index 8736281..699874d 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -27,7 +27,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/ide/mmio.h"
#include "hw/qdev-properties.h"
@@ -141,17 +141,16 @@ static void mmio_ide_initfn(Object *obj)
sysbus_init_irq(d, &s->irq);
}
-static Property mmio_ide_properties[] = {
+static const Property mmio_ide_properties[] = {
DEFINE_PROP_UINT32("shift", MMIOIDEState, shift, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void mmio_ide_class_init(ObjectClass *oc, void *data)
+static void mmio_ide_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mmio_ide_realizefn;
- dc->reset = mmio_ide_reset;
+ device_class_set_legacy_reset(dc, mmio_ide_reset);
device_class_set_props(dc, mmio_ide_properties);
dc->vmsd = &vmstate_ide_mmio;
}
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index a008fe7..1e50bb9 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -27,7 +27,7 @@
#include "hw/irq.h"
#include "hw/pci/pci.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "hw/ide/pci.h"
@@ -625,7 +625,7 @@ static const TypeInfo pci_ide_type_info = {
.instance_size = sizeof(PCIIDEState),
.instance_init = pci_ide_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 80efc63..a0f2709 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -178,12 +178,12 @@ static void pci_piix_ide_exitfn(PCIDevice *dev)
}
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-static void piix3_ide_class_init(ObjectClass *klass, void *data)
+static void piix3_ide_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = piix_ide_reset;
+ device_class_set_legacy_reset(dc, piix_ide_reset);
dc->vmsd = &vmstate_ide_pci;
k->realize = pci_piix_ide_realize;
k->exit = pci_piix_ide_exitfn;
@@ -201,12 +201,12 @@ static const TypeInfo piix3_ide_info = {
};
/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
-static void piix4_ide_class_init(ObjectClass *klass, void *data)
+static void piix4_ide_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = piix_ide_reset;
+ device_class_set_legacy_reset(dc, piix_ide_reset);
dc->vmsd = &vmstate_ide_pci;
k->realize = pci_piix_ide_realize;
k->exit = pci_piix_ide_exitfn;
diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c
index af17384..9b28c69 100644
--- a/hw/ide/sii3112.c
+++ b/hw/ide/sii3112.c
@@ -290,7 +290,7 @@ static void sii3112_pci_realize(PCIDevice *dev, Error **errp)
}
}
-static void sii3112_pci_class_init(ObjectClass *klass, void *data)
+static void sii3112_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pd = PCI_DEVICE_CLASS(klass);
@@ -300,7 +300,7 @@ static void sii3112_pci_class_init(ObjectClass *klass, void *data)
pd->class_id = PCI_CLASS_STORAGE_RAID;
pd->revision = 1;
pd->realize = sii3112_pci_realize;
- dc->reset = sii3112_reset;
+ device_class_set_legacy_reset(dc, sii3112_reset);
dc->desc = "SiI3112A SATA controller";
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/ide/via.c b/hw/ide/via.c
index a32f56b..dedc267 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -29,7 +29,7 @@
#include "migration/vmstate.h"
#include "qemu/module.h"
#include "qemu/range.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/isa/vt82c686.h"
#include "hw/ide/pci.h"
#include "hw/irq.h"
@@ -245,12 +245,12 @@ static void via_ide_exitfn(PCIDevice *dev)
}
}
-static void via_ide_class_init(ObjectClass *klass, void *data)
+static void via_ide_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = via_ide_reset;
+ device_class_set_legacy_reset(dc, via_ide_reset);
dc->vmsd = &vmstate_ide_pci;
/* Reason: only works as function of VIA southbridge */
dc->user_creatable = false;
diff --git a/hw/input/Kconfig b/hw/input/Kconfig
index f86e98c..a116cb8 100644
--- a/hw/input/Kconfig
+++ b/hw/input/Kconfig
@@ -1,13 +1,6 @@
config ADB
bool
-config ADS7846
- bool
-
-config LM832X
- bool
- depends on I2C
-
config PCKBD
bool
select PS2
@@ -23,9 +16,6 @@ config PS2
config STELLARIS_GAMEPAD
bool
-config TSC2005
- bool
-
config VIRTIO_INPUT
bool
default y
@@ -41,8 +31,5 @@ config VHOST_USER_INPUT
default y
depends on VIRTIO_INPUT && VHOST_USER
-config TSC210X
- bool
-
config LASIPS2
select PS2
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 758fa6d..507557d 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -375,7 +375,7 @@ static void adb_kbd_initfn(Object *obj)
d->devaddr = ADB_DEVID_KEYBOARD;
}
-static void adb_kbd_class_init(ObjectClass *oc, void *data)
+static void adb_kbd_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
@@ -387,7 +387,7 @@ static void adb_kbd_class_init(ObjectClass *oc, void *data)
adc->devreq = adb_kbd_request;
adc->devhasdata = adb_kbd_has_data;
- dc->reset = adb_kbd_reset;
+ device_class_set_legacy_reset(dc, adb_kbd_reset);
dc->vmsd = &vmstate_adb_kbd;
}
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index 144a0cc..373ef3f 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -38,6 +38,7 @@ struct MouseState {
ADBDevice parent_obj;
/*< private >*/
+ QemuInputHandlerState *hs;
int buttons_state, last_buttons_state;
int dx, dy, dz;
};
@@ -51,17 +52,57 @@ struct ADBMouseClass {
DeviceRealize parent_realize;
};
-static void adb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
+#define ADB_MOUSE_BUTTON_LEFT 0x01
+#define ADB_MOUSE_BUTTON_RIGHT 0x02
+
+static void adb_mouse_handle_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- MouseState *s = opaque;
+ MouseState *s = (MouseState *)dev;
+ InputMoveEvent *move;
+ InputBtnEvent *btn;
+ static const int bmap[INPUT_BUTTON__MAX] = {
+ [INPUT_BUTTON_LEFT] = ADB_MOUSE_BUTTON_LEFT,
+ [INPUT_BUTTON_RIGHT] = ADB_MOUSE_BUTTON_RIGHT,
+ };
+
+ switch (evt->type) {
+ case INPUT_EVENT_KIND_REL:
+ move = evt->u.rel.data;
+ if (move->axis == INPUT_AXIS_X) {
+ s->dx += move->value;
+ } else if (move->axis == INPUT_AXIS_Y) {
+ s->dy += move->value;
+ }
+ break;
+
+ case INPUT_EVENT_KIND_BTN:
+ btn = evt->u.btn.data;
+ if (bmap[btn->button]) {
+ if (btn->down) {
+ s->buttons_state |= bmap[btn->button];
+ } else {
+ s->buttons_state &= ~bmap[btn->button];
+ }
+ }
+ break;
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
+ default:
+ /* keep gcc happy */
+ break;
+ }
}
+static const QemuInputHandler adb_mouse_handler = {
+ .name = "QEMU ADB Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+ .event = adb_mouse_handle_event,
+ /*
+ * We do not need the .sync handler because unlike e.g. PS/2 where async
+ * mouse events are sent over the serial port, an ADB mouse is constantly
+ * polled by the host via the adb_mouse_poll() callback.
+ */
+};
static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
{
@@ -94,10 +135,10 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
dx &= 0x7f;
dy &= 0x7f;
- if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) {
+ if (!(s->buttons_state & ADB_MOUSE_BUTTON_LEFT)) {
dy |= 0x80;
}
- if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) {
+ if (!(s->buttons_state & ADB_MOUSE_BUTTON_RIGHT)) {
dx |= 0x80;
}
@@ -236,7 +277,7 @@ static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
amc->parent_realize(dev, errp);
- qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
+ s->hs = qemu_input_handler_register(dev, &adb_mouse_handler);
}
static void adb_mouse_initfn(Object *obj)
@@ -246,7 +287,7 @@ static void adb_mouse_initfn(Object *obj)
d->devaddr = ADB_DEVID_MOUSE;
}
-static void adb_mouse_class_init(ObjectClass *oc, void *data)
+static void adb_mouse_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
@@ -258,7 +299,7 @@ static void adb_mouse_class_init(ObjectClass *oc, void *data)
adc->devreq = adb_mouse_request;
adc->devhasdata = adb_mouse_has_data;
- dc->reset = adb_mouse_reset;
+ device_class_set_legacy_reset(dc, adb_mouse_reset);
dc->vmsd = &vmstate_adb_mouse;
}
diff --git a/hw/input/adb.c b/hw/input/adb.c
index aff7130..bcb11ed 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -259,7 +259,7 @@ static void adb_bus_unrealize(BusState *qbus)
vmstate_unregister(NULL, &vmstate_adb_bus, adb_bus);
}
-static void adb_bus_class_init(ObjectClass *klass, void *data)
+static void adb_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -299,7 +299,7 @@ static void adb_device_realizefn(DeviceState *dev, Error **errp)
bus->devices[bus->nb_devices++] = d;
}
-static void adb_device_class_init(ObjectClass *oc, void *data)
+static void adb_device_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/input/ads7846.c b/hw/input/ads7846.c
deleted file mode 100644
index cde3892..0000000
--- a/hw/input/ads7846.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * TI ADS7846 / TSC2046 chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "ui/console.h"
-#include "qom/object.h"
-
-struct ADS7846State {
- SSIPeripheral ssidev;
- qemu_irq interrupt;
-
- int input[8];
- int pressure;
- int noise;
-
- int cycle;
- int output;
-};
-
-#define TYPE_ADS7846 "ads7846"
-OBJECT_DECLARE_SIMPLE_TYPE(ADS7846State, ADS7846)
-
-/* Control-byte bitfields */
-#define CB_PD0 (1 << 0)
-#define CB_PD1 (1 << 1)
-#define CB_SER (1 << 2)
-#define CB_MODE (1 << 3)
-#define CB_A0 (1 << 4)
-#define CB_A1 (1 << 5)
-#define CB_A2 (1 << 6)
-#define CB_START (1 << 7)
-
-#define X_AXIS_DMAX 3470
-#define X_AXIS_MIN 290
-#define Y_AXIS_DMAX 3450
-#define Y_AXIS_MIN 200
-
-#define ADS_VBAT 2000
-#define ADS_VAUX 2000
-#define ADS_TEMP0 2000
-#define ADS_TEMP1 3000
-#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
-#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
-#define ADS_Z1POS(x, y) 600
-#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y))
-
-static void ads7846_int_update(ADS7846State *s)
-{
- if (s->interrupt)
- qemu_set_irq(s->interrupt, s->pressure == 0);
-}
-
-static uint32_t ads7846_transfer(SSIPeripheral *dev, uint32_t value)
-{
- ADS7846State *s = ADS7846(dev);
-
- switch (s->cycle ++) {
- case 0:
- if (!(value & CB_START)) {
- s->cycle = 0;
- break;
- }
-
- s->output = s->input[(value >> 4) & 7];
-
- /* Imitate the ADC noise, some drivers expect this. */
- s->noise = (s->noise + 3) & 7;
- switch ((value >> 4) & 7) {
- case 1: s->output += s->noise ^ 2; break;
- case 3: s->output += s->noise ^ 0; break;
- case 4: s->output += s->noise ^ 7; break;
- case 5: s->output += s->noise ^ 5; break;
- }
-
- if (value & CB_MODE)
- s->output >>= 4; /* 8 bits instead of 12 */
-
- break;
- case 1:
- s->cycle = 0;
- break;
- }
- return s->output;
-}
-
-static void ads7846_ts_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- ADS7846State *s = opaque;
-
- if (buttons_state) {
- x = 0x7fff - x;
- s->input[1] = ADS_XPOS(x, y);
- s->input[3] = ADS_Z1POS(x, y);
- s->input[4] = ADS_Z2POS(x, y);
- s->input[5] = ADS_YPOS(x, y);
- }
-
- if (s->pressure == !buttons_state) {
- s->pressure = !!buttons_state;
-
- ads7846_int_update(s);
- }
-}
-
-static int ads7856_post_load(void *opaque, int version_id)
-{
- ADS7846State *s = opaque;
-
- s->pressure = 0;
- ads7846_int_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_ads7846 = {
- .name = "ads7846",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ads7856_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, ADS7846State),
- VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
- VMSTATE_INT32(noise, ADS7846State),
- VMSTATE_INT32(cycle, ADS7846State),
- VMSTATE_INT32(output, ADS7846State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ads7846_realize(SSIPeripheral *d, Error **errp)
-{
- DeviceState *dev = DEVICE(d);
- ADS7846State *s = ADS7846(d);
-
- qdev_init_gpio_out(dev, &s->interrupt, 1);
-
- s->input[0] = ADS_TEMP0; /* TEMP0 */
- s->input[2] = ADS_VBAT; /* VBAT */
- s->input[6] = ADS_VAUX; /* VAUX */
- s->input[7] = ADS_TEMP1; /* TEMP1 */
-
- /* We want absolute coordinates */
- qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
- "QEMU ADS7846-driven Touchscreen");
-
- ads7846_int_update(s);
-
- vmstate_register_any(NULL, &vmstate_ads7846, s);
-}
-
-static void ads7846_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = ads7846_realize;
- k->transfer = ads7846_transfer;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo ads7846_info = {
- .name = TYPE_ADS7846,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(ADS7846State),
- .class_init = ads7846_class_init,
-};
-
-static void ads7846_register_types(void)
-{
- type_register_static(&ads7846_info);
-}
-
-type_init(ads7846_register_types)
diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c
index d9f8c36..de62572 100644
--- a/hw/input/lasips2.c
+++ b/hw/input/lasips2.c
@@ -29,7 +29,7 @@
#include "hw/input/lasips2.h"
#include "exec/hwaddr.h"
#include "trace.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "qapi/error.h"
@@ -306,7 +306,7 @@ static void lasips2_init(Object *obj)
"lasips2-port-input-irq", 2);
}
-static void lasips2_class_init(ObjectClass *klass, void *data)
+static void lasips2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -347,7 +347,7 @@ static void lasips2_port_init(Object *obj)
"ps2-input-irq", 1);
}
-static void lasips2_port_class_init(ObjectClass *klass, void *data)
+static void lasips2_port_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -397,7 +397,7 @@ static void lasips2_kbd_port_init(Object *obj)
lp->lasips2 = container_of(s, LASIPS2State, kbd_port);
}
-static void lasips2_kbd_port_class_init(ObjectClass *klass, void *data)
+static void lasips2_kbd_port_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass);
@@ -447,7 +447,7 @@ static void lasips2_mouse_port_init(Object *obj)
lp->lasips2 = container_of(s, LASIPS2State, mouse_port);
}
-static void lasips2_mouse_port_class_init(ObjectClass *klass, void *data)
+static void lasips2_mouse_port_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass);
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
deleted file mode 100644
index 59e5567..0000000
--- a/hw/input/lm832x.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/input/lm832x.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "qom/object.h"
-
-OBJECT_DECLARE_SIMPLE_TYPE(LM823KbdState, LM8323)
-
-struct LM823KbdState {
- I2CSlave parent_obj;
-
- uint8_t i2c_dir;
- uint8_t i2c_cycle;
- uint8_t reg;
-
- qemu_irq nirq;
- uint16_t model;
-
- struct {
- qemu_irq out[2];
- int in[2][2];
- } mux;
-
- uint8_t config;
- uint8_t status;
- uint8_t acttime;
- uint8_t error;
- uint8_t clock;
-
- struct {
- uint16_t pull;
- uint16_t mask;
- uint16_t dir;
- uint16_t level;
- qemu_irq out[16];
- } gpio;
-
- struct {
- uint8_t dbnctime;
- uint8_t size;
- uint8_t start;
- uint8_t len;
- uint8_t fifo[16];
- } kbd;
-
- struct {
- uint16_t file[256];
- uint8_t faddr;
- uint8_t addr[3];
- QEMUTimer *tm[3];
- } pwm;
-};
-
-#define INT_KEYPAD (1 << 0)
-#define INT_ERROR (1 << 3)
-#define INT_NOINIT (1 << 4)
-#define INT_PWMEND(n) (1 << (5 + n))
-
-#define ERR_BADPAR (1 << 0)
-#define ERR_CMDUNK (1 << 1)
-#define ERR_KEYOVR (1 << 2)
-#define ERR_FIFOOVR (1 << 6)
-
-static void lm_kbd_irq_update(LM823KbdState *s)
-{
- qemu_set_irq(s->nirq, !s->status);
-}
-
-static void lm_kbd_gpio_update(LM823KbdState *s)
-{
-}
-
-static void lm_kbd_reset(DeviceState *dev)
-{
- LM823KbdState *s = LM8323(dev);
-
- s->config = 0x80;
- s->status = INT_NOINIT;
- s->acttime = 125;
- s->kbd.dbnctime = 3;
- s->kbd.size = 0x33;
- s->clock = 0x08;
-
- lm_kbd_irq_update(s);
- lm_kbd_gpio_update(s);
-}
-
-static void lm_kbd_error(LM823KbdState *s, int err)
-{
- s->error |= err;
- s->status |= INT_ERROR;
- lm_kbd_irq_update(s);
-}
-
-static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
-{
-}
-
-static void lm_kbd_pwm_start(LM823KbdState *s, int line)
-{
- lm_kbd_pwm_tick(s, line);
-}
-
-static void lm_kbd_pwm0_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 0);
-}
-static void lm_kbd_pwm1_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 1);
-}
-static void lm_kbd_pwm2_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 2);
-}
-
-enum {
- LM832x_CMD_READ_ID = 0x80, /* Read chip ID. */
- LM832x_CMD_WRITE_CFG = 0x81, /* Set configuration item. */
- LM832x_CMD_READ_INT = 0x82, /* Get interrupt status. */
- LM832x_CMD_RESET = 0x83, /* Reset, same as external one */
- LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */
- LM832x_CMD_WRITE_PORT_SEL = 0x85, /* Select GPIO in/out. */
- LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */
- LM832x_CMD_READ_PORT_SEL = 0x87, /* Get GPIO in/out. */
- LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */
- LM832x_CMD_READ_FIFO = 0x89, /* Read byte from FIFO. */
- LM832x_CMD_RPT_READ_FIFO = 0x8a, /* Read FIFO (no increment). */
- LM832x_CMD_SET_ACTIVE = 0x8b, /* Set active time. */
- LM832x_CMD_READ_ERROR = 0x8c, /* Get error status. */
- LM832x_CMD_READ_ROTATOR = 0x8e, /* Read rotator status. */
- LM832x_CMD_SET_DEBOUNCE = 0x8f, /* Set debouncing time. */
- LM832x_CMD_SET_KEY_SIZE = 0x90, /* Set keypad size. */
- LM832x_CMD_READ_KEY_SIZE = 0x91, /* Get keypad size. */
- LM832x_CMD_READ_CFG = 0x92, /* Get configuration item. */
- LM832x_CMD_WRITE_CLOCK = 0x93, /* Set clock config. */
- LM832x_CMD_READ_CLOCK = 0x94, /* Get clock config. */
- LM832x_CMD_PWM_WRITE = 0x95, /* Write PWM script. */
- LM832x_CMD_PWM_START = 0x96, /* Start PWM engine. */
- LM832x_CMD_PWM_STOP = 0x97, /* Stop PWM engine. */
- LM832x_GENERAL_ERROR = 0xff, /* There was one error.
- Previously was represented by -1
- This is not a command */
-};
-
-#define LM832x_MAX_KPX 8
-#define LM832x_MAX_KPY 12
-
-static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
-{
- int ret;
-
- switch (reg) {
- case LM832x_CMD_READ_ID:
- ret = 0x0400;
- break;
-
- case LM832x_CMD_READ_INT:
- ret = s->status;
- if (!(s->status & INT_NOINIT)) {
- s->status = 0;
- lm_kbd_irq_update(s);
- }
- break;
-
- case LM832x_CMD_READ_PORT_SEL:
- ret = s->gpio.dir;
- break;
- case LM832x_CMD_READ_PORT_STATE:
- ret = s->gpio.mask;
- break;
-
- case LM832x_CMD_READ_FIFO:
- if (s->kbd.len <= 1)
- return 0x00;
-
- /* Example response from the two commands after a INT_KEYPAD
- * interrupt caused by the key 0x3c being pressed:
- * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- * READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- *
- * 55 is the code of the key release event serviced in the previous
- * interrupt handling.
- *
- * TODO: find out whether the FIFO is advanced a single character
- * before reading every byte or the whole size of the FIFO at the
- * last LM832x_CMD_READ_FIFO. This affects LM832x_CMD_RPT_READ_FIFO
- * output in cases where there are more than one event in the FIFO.
- * Assume 0xbc and 0x3c events are in the FIFO:
- * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
- * READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
- * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
- */
- s->kbd.start ++;
- s->kbd.start &= sizeof(s->kbd.fifo) - 1;
- s->kbd.len --;
-
- return s->kbd.fifo[s->kbd.start];
- case LM832x_CMD_RPT_READ_FIFO:
- if (byte >= s->kbd.len)
- return 0x00;
-
- return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
-
- case LM832x_CMD_READ_ERROR:
- return s->error;
-
- case LM832x_CMD_READ_ROTATOR:
- return 0;
-
- case LM832x_CMD_READ_KEY_SIZE:
- return s->kbd.size;
-
- case LM832x_CMD_READ_CFG:
- return s->config & 0xf;
-
- case LM832x_CMD_READ_CLOCK:
- return (s->clock & 0xfc) | 2;
-
- default:
- lm_kbd_error(s, ERR_CMDUNK);
- fprintf(stderr, "%s: unknown command %02x\n", __func__, reg);
- return 0x00;
- }
-
- return ret >> (byte << 3);
-}
-
-static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
-{
- switch (reg) {
- case LM832x_CMD_WRITE_CFG:
- s->config = value;
- /* This must be done whenever s->mux.in is updated (never). */
- if ((s->config >> 1) & 1) /* MUX1EN */
- qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
- if ((s->config >> 3) & 1) /* MUX2EN */
- qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
- /* TODO: check that this is issued only following the chip reset
- * and not in the middle of operation and that it is followed by
- * the GPIO ports re-resablishing through WRITE_PORT_SEL and
- * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
- * warnings. */
- s->status = 0;
- lm_kbd_irq_update(s);
- s->kbd.len = 0;
- s->kbd.start = 0;
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM832x_CMD_RESET:
- if (value == 0xaa)
- lm_kbd_reset(DEVICE(s));
- else
- lm_kbd_error(s, ERR_BADPAR);
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM823x_CMD_WRITE_PULL_DOWN:
- if (!byte)
- s->gpio.pull = value;
- else {
- s->gpio.pull |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_WRITE_PORT_SEL:
- if (!byte)
- s->gpio.dir = value;
- else {
- s->gpio.dir |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_WRITE_PORT_STATE:
- if (!byte)
- s->gpio.mask = value;
- else {
- s->gpio.mask |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
-
- case LM832x_CMD_SET_ACTIVE:
- s->acttime = value;
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM832x_CMD_SET_DEBOUNCE:
- s->kbd.dbnctime = value;
- s->reg = LM832x_GENERAL_ERROR;
- if (!value)
- lm_kbd_error(s, ERR_BADPAR);
- break;
-
- case LM832x_CMD_SET_KEY_SIZE:
- s->kbd.size = value;
- s->reg = LM832x_GENERAL_ERROR;
- if (
- (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
- (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
- lm_kbd_error(s, ERR_BADPAR);
- break;
-
- case LM832x_CMD_WRITE_CLOCK:
- s->clock = value;
- s->reg = LM832x_GENERAL_ERROR;
- if ((value & 3) && (value & 3) != 3) {
- lm_kbd_error(s, ERR_BADPAR);
- fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
- __func__);
- }
- /* TODO: Validate that the command is only issued once */
- break;
-
- case LM832x_CMD_PWM_WRITE:
- if (byte == 0) {
- if (!(value & 3) || (value >> 2) > 59) {
- lm_kbd_error(s, ERR_BADPAR);
- s->reg = LM832x_GENERAL_ERROR;
- break;
- }
-
- s->pwm.faddr = value;
- s->pwm.file[s->pwm.faddr] = 0;
- } else if (byte == 1) {
- s->pwm.file[s->pwm.faddr] |= value << 8;
- } else if (byte == 2) {
- s->pwm.file[s->pwm.faddr] |= value << 0;
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_PWM_START:
- s->reg = LM832x_GENERAL_ERROR;
- if (!(value & 3) || (value >> 2) > 59) {
- lm_kbd_error(s, ERR_BADPAR);
- break;
- }
-
- s->pwm.addr[(value & 3) - 1] = value >> 2;
- lm_kbd_pwm_start(s, (value & 3) - 1);
- break;
- case LM832x_CMD_PWM_STOP:
- s->reg = LM832x_GENERAL_ERROR;
- if (!(value & 3)) {
- lm_kbd_error(s, ERR_BADPAR);
- break;
- }
-
- timer_del(s->pwm.tm[(value & 3) - 1]);
- break;
-
- case LM832x_GENERAL_ERROR:
- lm_kbd_error(s, ERR_BADPAR);
- break;
- default:
- lm_kbd_error(s, ERR_CMDUNK);
- fprintf(stderr, "%s: unknown command %02x\n", __func__, reg);
- break;
- }
-}
-
-static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
-{
- LM823KbdState *s = LM8323(i2c);
-
- switch (event) {
- case I2C_START_RECV:
- case I2C_START_SEND:
- s->i2c_cycle = 0;
- s->i2c_dir = (event == I2C_START_SEND);
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-static uint8_t lm_i2c_rx(I2CSlave *i2c)
-{
- LM823KbdState *s = LM8323(i2c);
-
- return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
-}
-
-static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
-{
- LM823KbdState *s = LM8323(i2c);
-
- if (!s->i2c_cycle)
- s->reg = data;
- else
- lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
- s->i2c_cycle ++;
-
- return 0;
-}
-
-static int lm_kbd_post_load(void *opaque, int version_id)
-{
- LM823KbdState *s = opaque;
-
- lm_kbd_irq_update(s);
- lm_kbd_gpio_update(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm_kbd = {
- .name = "LM8323",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = lm_kbd_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState),
- VMSTATE_UINT8(i2c_dir, LM823KbdState),
- VMSTATE_UINT8(i2c_cycle, LM823KbdState),
- VMSTATE_UINT8(reg, LM823KbdState),
- VMSTATE_UINT8(config, LM823KbdState),
- VMSTATE_UINT8(status, LM823KbdState),
- VMSTATE_UINT8(acttime, LM823KbdState),
- VMSTATE_UINT8(error, LM823KbdState),
- VMSTATE_UINT8(clock, LM823KbdState),
- VMSTATE_UINT16(gpio.pull, LM823KbdState),
- VMSTATE_UINT16(gpio.mask, LM823KbdState),
- VMSTATE_UINT16(gpio.dir, LM823KbdState),
- VMSTATE_UINT16(gpio.level, LM823KbdState),
- VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
- VMSTATE_UINT8(kbd.size, LM823KbdState),
- VMSTATE_UINT8(kbd.start, LM823KbdState),
- VMSTATE_UINT8(kbd.len, LM823KbdState),
- VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
- VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
- VMSTATE_UINT8(pwm.faddr, LM823KbdState),
- VMSTATE_BUFFER(pwm.addr, LM823KbdState),
- VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-static void lm8323_realize(DeviceState *dev, Error **errp)
-{
- LM823KbdState *s = LM8323(dev);
-
- s->model = 0x8323;
- s->pwm.tm[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm0_tick, s);
- s->pwm.tm[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm1_tick, s);
- s->pwm.tm[2] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm2_tick, s);
- qdev_init_gpio_out(dev, &s->nirq, 1);
-}
-
-void lm832x_key_event(DeviceState *dev, int key, int state)
-{
- LM823KbdState *s = LM8323(dev);
-
- if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
- return;
-
- if (s->kbd.len >= sizeof(s->kbd.fifo)) {
- lm_kbd_error(s, ERR_FIFOOVR);
- return;
- }
-
- s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
- key | (state << 7);
-
- /* We never set ERR_KEYOVR because we support multiple keys fine. */
- s->status |= INT_KEYPAD;
- lm_kbd_irq_update(s);
-}
-
-static void lm8323_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- dc->reset = lm_kbd_reset;
- dc->realize = lm8323_realize;
- k->event = lm_i2c_event;
- k->recv = lm_i2c_rx;
- k->send = lm_i2c_tx;
- dc->vmsd = &vmstate_lm_kbd;
-}
-
-static const TypeInfo lm8323_info = {
- .name = TYPE_LM8323,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(LM823KbdState),
- .class_init = lm8323_class_init,
-};
-
-static void lm832x_register_types(void)
-{
- type_register_static(&lm8323_info);
-}
-
-type_init(lm832x_register_types)
diff --git a/hw/input/meson.build b/hw/input/meson.build
index 3cc8ab8..90a2149 100644
--- a/hw/input/meson.build
+++ b/hw/input/meson.build
@@ -1,17 +1,12 @@
system_ss.add(files('hid.c'))
system_ss.add(when: 'CONFIG_ADB', if_true: files('adb.c', 'adb-mouse.c', 'adb-kbd.c'))
-system_ss.add(when: 'CONFIG_ADS7846', if_true: files('ads7846.c'))
-system_ss.add(when: 'CONFIG_LM832X', if_true: files('lm832x.c'))
system_ss.add(when: 'CONFIG_PCKBD', if_true: files('pckbd.c'))
system_ss.add(when: 'CONFIG_PL050', if_true: files('pl050.c'))
system_ss.add(when: 'CONFIG_PS2', if_true: files('ps2.c'))
system_ss.add(when: 'CONFIG_STELLARIS_GAMEPAD', if_true: files('stellaris_gamepad.c'))
-system_ss.add(when: 'CONFIG_TSC2005', if_true: files('tsc2005.c'))
system_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input.c'))
system_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-hid.c'))
system_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c'))
-system_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c'))
system_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c'))
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 74f10b6..71f5f97 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -34,8 +34,8 @@
#include "hw/irq.h"
#include "hw/input/i8042.h"
#include "hw/qdev-properties.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "trace.h"
@@ -735,10 +735,9 @@ static void i8042_mmio_init(Object *obj)
"ps2-mouse-input-irq", 1);
}
-static Property i8042_mmio_properties[] = {
+static const Property i8042_mmio_properties[] = {
DEFINE_PROP_UINT64("mask", MMIOKBDState, kbd.mask, UINT64_MAX),
DEFINE_PROP_UINT32("size", MMIOKBDState, size, -1),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_kbd_mmio = {
@@ -751,12 +750,12 @@ static const VMStateDescription vmstate_kbd_mmio = {
}
};
-static void i8042_mmio_class_init(ObjectClass *klass, void *data)
+static void i8042_mmio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = i8042_mmio_realize;
- dc->reset = i8042_mmio_reset;
+ device_class_set_legacy_reset(dc, i8042_mmio_reset);
dc->vmsd = &vmstate_kbd_mmio;
device_class_set_props(dc, i8042_mmio_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
@@ -933,21 +932,20 @@ static void i8042_build_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(scope, mou);
}
-static Property i8042_properties[] = {
+static const Property i8042_properties[] = {
DEFINE_PROP_BOOL("extended-state", ISAKBDState, kbd.extended_state, true),
DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false),
DEFINE_PROP_UINT8("kbd-irq", ISAKBDState, kbd_irq, 1),
DEFINE_PROP_UINT8("mouse-irq", ISAKBDState, mouse_irq, 12),
- DEFINE_PROP_END_OF_LIST(),
};
-static void i8042_class_initfn(ObjectClass *klass, void *data)
+static void i8042_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
device_class_set_props(dc, i8042_properties);
- dc->reset = i8042_reset;
+ device_class_set_legacy_reset(dc, i8042_reset);
dc->realize = i8042_realizefn;
dc->vmsd = &vmstate_kbd_isa;
adevc->build_dev_aml = i8042_build_aml;
@@ -960,7 +958,7 @@ static const TypeInfo i8042_info = {
.instance_size = sizeof(ISAKBDState),
.instance_init = i8042_initfn,
.class_init = i8042_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/input/pl050.c b/hw/input/pl050.c
index 6519e26..c5f4a3f 100644
--- a/hw/input/pl050.c
+++ b/hw/input/pl050.c
@@ -203,7 +203,7 @@ static void pl050_mouse_init(Object *obj)
object_initialize_child(obj, "mouse", &s->mouse, TYPE_PS2_MOUSE_DEVICE);
}
-static void pl050_kbd_class_init(ObjectClass *oc, void *data)
+static void pl050_kbd_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PL050DeviceClass *pdc = PL050_CLASS(oc);
@@ -220,7 +220,7 @@ static const TypeInfo pl050_kbd_info = {
.class_init = pl050_kbd_class_init,
};
-static void pl050_mouse_class_init(ObjectClass *oc, void *data)
+static void pl050_mouse_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PL050DeviceClass *pdc = PL050_CLASS(oc);
@@ -249,7 +249,7 @@ static void pl050_init(Object *obj)
qdev_init_gpio_in_named(DEVICE(obj), pl050_set_irq, "ps2-input-irq", 1);
}
-static void pl050_class_init(ObjectClass *oc, void *data)
+static void pl050_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index d6f8344..7f7b1fc 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -30,8 +30,8 @@
#include "migration/vmstate.h"
#include "ui/console.h"
#include "ui/input.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "qapi/error.h"
#include "trace.h"
@@ -1254,7 +1254,7 @@ static void ps2_mouse_realize(DeviceState *dev, Error **errp)
qemu_input_handler_register(dev, &ps2_mouse_handler);
}
-static void ps2_kbd_class_init(ObjectClass *klass, void *data)
+static void ps2_kbd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -1273,7 +1273,7 @@ static const TypeInfo ps2_kbd_info = {
.class_init = ps2_kbd_class_init
};
-static void ps2_mouse_class_init(ObjectClass *klass, void *data)
+static void ps2_mouse_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -1299,7 +1299,7 @@ static void ps2_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), &s->irq, 1);
}
-static void ps2_class_init(ObjectClass *klass, void *data)
+static void ps2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c
deleted file mode 100644
index 3858648..0000000
--- a/hw/input/pxa2xx_keypad.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Intel PXA27X Keypad Controller emulation.
- *
- * Copyright (c) 2007 MontaVista Software, Inc
- * Written by Armin Kuster <akuster@kama-aina.net>
- * or <Akuster@mvista.com>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "ui/console.h"
-
-/*
- * Keypad
- */
-#define KPC 0x00 /* Keypad Interface Control register */
-#define KPDK 0x08 /* Keypad Interface Direct Key register */
-#define KPREC 0x10 /* Keypad Interface Rotary Encoder register */
-#define KPMK 0x18 /* Keypad Interface Matrix Key register */
-#define KPAS 0x20 /* Keypad Interface Automatic Scan register */
-#define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 0 */
-#define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 1 */
-#define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 2 */
-#define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 3 */
-#define KPKDI 0x48 /* Keypad Interface Key Debounce Interval
- register */
-
-/* Keypad defines */
-#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
-#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
-#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
-#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
-#define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */
-#define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */
-#define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */
-#define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */
-#define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */
-#define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */
-#define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */
-#define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */
-#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
-#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
-#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
-#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
-#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
-#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
-#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
-#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
-#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
-
-#define KPDK_DKP (0x1 << 31)
-#define KPDK_DK7 (0x1 << 7)
-#define KPDK_DK6 (0x1 << 6)
-#define KPDK_DK5 (0x1 << 5)
-#define KPDK_DK4 (0x1 << 4)
-#define KPDK_DK3 (0x1 << 3)
-#define KPDK_DK2 (0x1 << 2)
-#define KPDK_DK1 (0x1 << 1)
-#define KPDK_DK0 (0x1 << 0)
-
-#define KPREC_OF1 (0x1 << 31)
-#define KPREC_UF1 (0x1 << 30)
-#define KPREC_OF0 (0x1 << 15)
-#define KPREC_UF0 (0x1 << 14)
-
-#define KPMK_MKP (0x1 << 31)
-#define KPAS_SO (0x1 << 31)
-#define KPASMKPx_SO (0x1 << 31)
-
-
-#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
-
-#define PXAKBD_MAXROW 8
-#define PXAKBD_MAXCOL 8
-
-struct PXA2xxKeyPadState {
- MemoryRegion iomem;
- qemu_irq irq;
- const struct keymap *map;
- int pressed_cnt;
- int alt_code;
-
- uint32_t kpc;
- uint32_t kpdk;
- uint32_t kprec;
- uint32_t kpmk;
- uint32_t kpas;
- uint32_t kpasmkp[4];
- uint32_t kpkdi;
-};
-
-static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
-{
- int i;
- for (i = 0; i < 4; i++)
- {
- *col = i * 2;
- for (*row = 0; *row < 8; (*row)++) {
- if (kp->kpasmkp[i] & (1 << *row))
- return;
- }
- *col = i * 2 + 1;
- for (*row = 0; *row < 8; (*row)++) {
- if (kp->kpasmkp[i] & (1 << (*row + 16)))
- return;
- }
- }
-}
-
-static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
-{
- int row, col, rel, assert_irq = 0;
- uint32_t val;
-
- if (keycode == 0xe0) {
- kp->alt_code = 1;
- return;
- }
-
- if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
- return;
-
- rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
- keycode &= ~0x80; /* strip qemu key release bit */
- if (kp->alt_code) {
- keycode |= 0x80;
- kp->alt_code = 0;
- }
-
- row = kp->map[keycode].row;
- col = kp->map[keycode].column;
- if (row == -1 || col == -1) {
- return;
- }
-
- val = KPASMKPx_MKC(row, col);
- if (rel) {
- if (kp->kpasmkp[col / 2] & val) {
- kp->kpasmkp[col / 2] &= ~val;
- kp->pressed_cnt--;
- assert_irq = 1;
- }
- } else {
- if (!(kp->kpasmkp[col / 2] & val)) {
- kp->kpasmkp[col / 2] |= val;
- kp->pressed_cnt++;
- assert_irq = 1;
- }
- }
- kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
- if (kp->pressed_cnt == 1) {
- kp->kpas &= ~((0xf << 4) | 0xf);
- if (rel) {
- pxa27x_keypad_find_pressed_key(kp, &row, &col);
- }
- kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
- }
-
- if (!(kp->kpc & (KPC_AS | KPC_ASACT)))
- assert_irq = 0;
-
- if (assert_irq && (kp->kpc & KPC_MIE)) {
- kp->kpc |= KPC_MI;
- qemu_irq_raise(kp->irq);
- }
-}
-
-static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
- uint32_t tmp;
-
- switch (offset) {
- case KPC:
- tmp = s->kpc;
- if(tmp & KPC_MI)
- s->kpc &= ~(KPC_MI);
- if(tmp & KPC_DI)
- s->kpc &= ~(KPC_DI);
- qemu_irq_lower(s->irq);
- return tmp;
- case KPDK:
- return s->kpdk;
- case KPREC:
- tmp = s->kprec;
- if(tmp & KPREC_OF1)
- s->kprec &= ~(KPREC_OF1);
- if(tmp & KPREC_UF1)
- s->kprec &= ~(KPREC_UF1);
- if(tmp & KPREC_OF0)
- s->kprec &= ~(KPREC_OF0);
- if(tmp & KPREC_UF0)
- s->kprec &= ~(KPREC_UF0);
- return tmp;
- case KPMK:
- tmp = s->kpmk;
- if(tmp & KPMK_MKP)
- s->kpmk &= ~(KPMK_MKP);
- return tmp;
- case KPAS:
- return s->kpas;
- case KPASMKP0:
- return s->kpasmkp[0];
- case KPASMKP1:
- return s->kpasmkp[1];
- case KPASMKP2:
- return s->kpasmkp[2];
- case KPASMKP3:
- return s->kpasmkp[3];
- case KPKDI:
- return s->kpkdi;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-
- switch (offset) {
- case KPC:
- s->kpc = value;
- if (s->kpc & KPC_AS) {
- s->kpc &= ~(KPC_AS);
- }
- break;
- case KPDK:
- s->kpdk = value;
- break;
- case KPREC:
- s->kprec = value;
- break;
- case KPMK:
- s->kpmk = value;
- break;
- case KPAS:
- s->kpas = value;
- break;
- case KPASMKP0:
- s->kpasmkp[0] = value;
- break;
- case KPASMKP1:
- s->kpasmkp[1] = value;
- break;
- case KPASMKP2:
- s->kpasmkp[2] = value;
- break;
- case KPASMKP3:
- s->kpasmkp[3] = value;
- break;
- case KPKDI:
- s->kpkdi = value;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_keypad_ops = {
- .read = pxa2xx_keypad_read,
- .write = pxa2xx_keypad_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_keypad = {
- .name = "pxa2xx_keypad",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
- VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
- VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
- VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq)
-{
- PXA2xxKeyPadState *s;
-
- s = g_new0(PXA2xxKeyPadState, 1);
- s->irq = irq;
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_keypad_ops, s,
- "pxa2xx-keypad", 0x00100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
-
- return s;
-}
-
-void pxa27x_register_keypad(PXA2xxKeyPadState *kp,
- const struct keymap *map, int size)
-{
- if(!map || size < 0x80) {
- fprintf(stderr, "%s - No PXA keypad map defined\n", __func__);
- exit(-1);
- }
-
- kp->map = map;
- qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
-}
diff --git a/hw/input/stellaris_gamepad.c b/hw/input/stellaris_gamepad.c
index 17ee42b..fec1161 100644
--- a/hw/input/stellaris_gamepad.c
+++ b/hw/input/stellaris_gamepad.c
@@ -77,13 +77,12 @@ static void stellaris_gamepad_reset_enter(Object *obj, ResetType type)
memset(s->pressed, 0, s->num_buttons * sizeof(uint8_t));
}
-static Property stellaris_gamepad_properties[] = {
+static const Property stellaris_gamepad_properties[] = {
DEFINE_PROP_ARRAY("keycodes", StellarisGamepad, num_buttons,
keycodes, qdev_prop_uint32, uint32_t),
- DEFINE_PROP_END_OF_LIST(),
};
-static void stellaris_gamepad_class_init(ObjectClass *klass, void *data)
+static void stellaris_gamepad_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 29001a8..1484625 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -46,9 +46,6 @@ ps2_mouse_reset(void *opaque) "%p"
hid_kbd_queue_full(void) "queue full"
hid_kbd_queue_empty(void) "queue empty"
-# tsc2005.c
-tsc2005_sense(const char *state) "touchscreen sense %s"
-
# virtio-input.c
virtio_input_queue_full(void) "queue full"
diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c
deleted file mode 100644
index 54a15d2..0000000
--- a/hw/input/tsc2005.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * TI TSC2005 emulator.
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "qemu/timer.h"
-#include "sysemu/reset.h"
-#include "ui/console.h"
-#include "hw/input/tsc2xxx.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-
-#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10)))
-
-typedef struct {
- qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */
- QEMUTimer *timer;
- uint16_t model;
-
- int32_t x, y;
- bool pressure;
-
- uint8_t reg, state;
- bool irq, command;
- uint16_t data, dav;
-
- bool busy;
- bool enabled;
- bool host_mode;
- int8_t function;
- int8_t nextfunction;
- bool precision;
- bool nextprecision;
- uint16_t filter;
- uint8_t pin_func;
- uint16_t timing[2];
- uint8_t noise;
- bool reset;
- bool pdst;
- bool pnd0;
- uint16_t temp_thr[2];
- uint16_t aux_thr[2];
-
- int32_t tr[8];
-} TSC2005State;
-
-enum {
- TSC_MODE_XYZ_SCAN = 0x0,
- TSC_MODE_XY_SCAN,
- TSC_MODE_X,
- TSC_MODE_Y,
- TSC_MODE_Z,
- TSC_MODE_AUX,
- TSC_MODE_TEMP1,
- TSC_MODE_TEMP2,
- TSC_MODE_AUX_SCAN,
- TSC_MODE_X_TEST,
- TSC_MODE_Y_TEST,
- TSC_MODE_TS_TEST,
- TSC_MODE_RESERVED,
- TSC_MODE_XX_DRV,
- TSC_MODE_YY_DRV,
- TSC_MODE_YX_DRV,
-};
-
-static const uint16_t mode_regs[16] = {
- 0xf000, /* X, Y, Z scan */
- 0xc000, /* X, Y scan */
- 0x8000, /* X */
- 0x4000, /* Y */
- 0x3000, /* Z */
- 0x0800, /* AUX */
- 0x0400, /* TEMP1 */
- 0x0200, /* TEMP2 */
- 0x0800, /* AUX scan */
- 0x0040, /* X test */
- 0x0020, /* Y test */
- 0x0080, /* Short-circuit test */
- 0x0000, /* Reserved */
- 0x0000, /* X+, X- drivers */
- 0x0000, /* Y+, Y- drivers */
- 0x0000, /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s) \
- ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s) \
- ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s) \
- ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s) \
- ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */
-#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */
-#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */
-
-static uint16_t tsc2005_read(TSC2005State *s, int reg)
-{
- uint16_t ret;
-
- switch (reg) {
- case 0x0: /* X */
- s->dav &= ~mode_regs[TSC_MODE_X];
- return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
- (s->noise & 3);
- case 0x1: /* Y */
- s->dav &= ~mode_regs[TSC_MODE_Y];
- s->noise++;
- return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
- (s->noise & 3);
- case 0x2: /* Z1 */
- s->dav &= 0xdfff;
- return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
- (s->noise & 3);
- case 0x3: /* Z2 */
- s->dav &= 0xefff;
- return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
- (s->noise & 3);
-
- case 0x4: /* AUX */
- s->dav &= ~mode_regs[TSC_MODE_AUX];
- return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
-
- case 0x5: /* TEMP1 */
- s->dav &= ~mode_regs[TSC_MODE_TEMP1];
- return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
- (s->noise & 5);
- case 0x6: /* TEMP2 */
- s->dav &= 0xdfff;
- s->dav &= ~mode_regs[TSC_MODE_TEMP2];
- return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
- (s->noise & 3);
-
- case 0x7: /* Status */
- ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
- s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
- mode_regs[TSC_MODE_TS_TEST]);
- s->reset = true;
- return ret;
-
- case 0x8: /* AUX high threshold */
- return s->aux_thr[1];
- case 0x9: /* AUX low threshold */
- return s->aux_thr[0];
-
- case 0xa: /* TEMP high threshold */
- return s->temp_thr[1];
- case 0xb: /* TEMP low threshold */
- return s->temp_thr[0];
-
- case 0xc: /* CFR0 */
- return (s->pressure << 15) | ((!s->busy) << 14) |
- (s->nextprecision << 13) | s->timing[0];
- case 0xd: /* CFR1 */
- return s->timing[1];
- case 0xe: /* CFR2 */
- return (s->pin_func << 14) | s->filter;
-
- case 0xf: /* Function select status */
- return s->function >= 0 ? 1 << s->function : 0;
- }
-
- /* Never gets here */
- return 0xffff;
-}
-
-static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
-{
- switch (reg) {
- case 0x8: /* AUX high threshold */
- s->aux_thr[1] = data;
- break;
- case 0x9: /* AUX low threshold */
- s->aux_thr[0] = data;
- break;
-
- case 0xa: /* TEMP high threshold */
- s->temp_thr[1] = data;
- break;
- case 0xb: /* TEMP low threshold */
- s->temp_thr[0] = data;
- break;
-
- case 0xc: /* CFR0 */
- s->host_mode = (data >> 15) != 0;
- if (s->enabled != !(data & 0x4000)) {
- s->enabled = !(data & 0x4000);
- trace_tsc2005_sense(s->enabled ? "enabled" : "disabled");
- if (s->busy && !s->enabled) {
- timer_del(s->timer);
- }
- s->busy = s->busy && s->enabled;
- }
- s->nextprecision = (data >> 13) & 1;
- s->timing[0] = data & 0x1fff;
- if ((s->timing[0] >> 11) == 3) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "tsc2005_write: illegal conversion clock setting\n");
- }
- break;
- case 0xd: /* CFR1 */
- s->timing[1] = data & 0xf07;
- break;
- case 0xe: /* CFR2 */
- s->pin_func = (data >> 14) & 3;
- s->filter = data & 0x3fff;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: write into read-only register 0x%x\n",
- __func__, reg);
- }
-}
-
-/* This handles most of the chip's logic. */
-static void tsc2005_pin_update(TSC2005State *s)
-{
- int64_t expires;
- bool pin_state;
-
- switch (s->pin_func) {
- case 0:
- pin_state = !s->pressure && !!s->dav;
- break;
- case 1:
- case 3:
- default:
- pin_state = !s->dav;
- break;
- case 2:
- pin_state = !s->pressure;
- }
-
- if (pin_state != s->irq) {
- s->irq = pin_state;
- qemu_set_irq(s->pint, s->irq);
- }
-
- switch (s->nextfunction) {
- case TSC_MODE_XYZ_SCAN:
- case TSC_MODE_XY_SCAN:
- if (!s->host_mode && s->dav) {
- s->enabled = false;
- }
- if (!s->pressure) {
- return;
- }
- /* Fall through */
- case TSC_MODE_AUX_SCAN:
- break;
-
- case TSC_MODE_X:
- case TSC_MODE_Y:
- case TSC_MODE_Z:
- if (!s->pressure) {
- return;
- }
- /* Fall through */
- case TSC_MODE_AUX:
- case TSC_MODE_TEMP1:
- case TSC_MODE_TEMP2:
- case TSC_MODE_X_TEST:
- case TSC_MODE_Y_TEST:
- case TSC_MODE_TS_TEST:
- if (s->dav) {
- s->enabled = false;
- }
- break;
-
- case TSC_MODE_RESERVED:
- case TSC_MODE_XX_DRV:
- case TSC_MODE_YY_DRV:
- case TSC_MODE_YX_DRV:
- default:
- return;
- }
-
- if (!s->enabled || s->busy) {
- return;
- }
-
- s->busy = true;
- s->precision = s->nextprecision;
- s->function = s->nextfunction;
- s->pdst = !s->pnd0; /* Synchronised on internal clock */
- expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND >> 7);
- timer_mod(s->timer, expires);
-}
-
-static void tsc2005_reset(TSC2005State *s)
-{
- s->state = 0;
- s->pin_func = 0;
- s->enabled = false;
- s->busy = false;
- s->nextprecision = false;
- s->nextfunction = 0;
- s->timing[0] = 0;
- s->timing[1] = 0;
- s->irq = false;
- s->dav = 0;
- s->reset = false;
- s->pdst = true;
- s->pnd0 = false;
- s->function = -1;
- s->temp_thr[0] = 0x000;
- s->temp_thr[1] = 0xfff;
- s->aux_thr[0] = 0x000;
- s->aux_thr[1] = 0xfff;
-
- tsc2005_pin_update(s);
-}
-
-static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
-{
- TSC2005State *s = opaque;
- uint32_t ret = 0;
-
- switch (s->state++) {
- case 0:
- if (value & 0x80) {
- /* Command */
- if (value & (1 << 1))
- tsc2005_reset(s);
- else {
- s->nextfunction = (value >> 3) & 0xf;
- s->nextprecision = (value >> 2) & 1;
- if (s->enabled != !(value & 1)) {
- s->enabled = !(value & 1);
- trace_tsc2005_sense(s->enabled ? "enabled" : "disabled");
- if (s->busy && !s->enabled) {
- timer_del(s->timer);
- }
- s->busy = s->busy && s->enabled;
- }
- tsc2005_pin_update(s);
- }
-
- s->state = 0;
- } else if (value) {
- /* Data transfer */
- s->reg = (value >> 3) & 0xf;
- s->pnd0 = (value >> 1) & 1;
- s->command = value & 1;
-
- if (s->command) {
- /* Read */
- s->data = tsc2005_read(s, s->reg);
- tsc2005_pin_update(s);
- } else
- s->data = 0;
- } else
- s->state = 0;
- break;
-
- case 1:
- if (s->command) {
- ret = (s->data >> 8) & 0xff;
- } else {
- s->data |= value << 8;
- }
- break;
-
- case 2:
- if (s->command)
- ret = s->data & 0xff;
- else {
- s->data |= value;
- tsc2005_write(s, s->reg, s->data);
- tsc2005_pin_update(s);
- }
-
- s->state = 0;
- break;
- }
-
- return ret;
-}
-
-uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
-{
- uint32_t ret = 0;
-
- len &= ~7;
- while (len > 0) {
- len -= 8;
- ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
- }
-
- return ret;
-}
-
-static void tsc2005_timer_tick(void *opaque)
-{
- TSC2005State *s = opaque;
- unsigned int function = s->function;
-
- assert(function < ARRAY_SIZE(mode_regs));
-
- /* Timer ticked -- a set of conversions has been finished. */
-
- if (!s->busy) {
- return;
- }
-
- s->busy = false;
- s->dav |= mode_regs[function];
- s->function = -1;
- tsc2005_pin_update(s);
-}
-
-static void tsc2005_touchscreen_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- TSC2005State *s = opaque;
- int p = s->pressure;
-
- if (buttons_state) {
- s->x = x;
- s->y = y;
- }
- s->pressure = !!buttons_state;
-
- /*
- * Note: We would get better responsiveness in the guest by
- * signaling TS events immediately, but for now we simulate
- * the first conversion delay for sake of correctness.
- */
- if (p != s->pressure) {
- tsc2005_pin_update(s);
- }
-}
-
-static int tsc2005_post_load(void *opaque, int version_id)
-{
- TSC2005State *s = (TSC2005State *) opaque;
-
- s->busy = timer_pending(s->timer);
- tsc2005_pin_update(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_tsc2005 = {
- .name = "tsc2005",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = tsc2005_post_load,
- .fields = (const VMStateField []) {
- VMSTATE_BOOL(pressure, TSC2005State),
- VMSTATE_BOOL(irq, TSC2005State),
- VMSTATE_BOOL(command, TSC2005State),
- VMSTATE_BOOL(enabled, TSC2005State),
- VMSTATE_BOOL(host_mode, TSC2005State),
- VMSTATE_BOOL(reset, TSC2005State),
- VMSTATE_BOOL(pdst, TSC2005State),
- VMSTATE_BOOL(pnd0, TSC2005State),
- VMSTATE_BOOL(precision, TSC2005State),
- VMSTATE_BOOL(nextprecision, TSC2005State),
- VMSTATE_UINT8(reg, TSC2005State),
- VMSTATE_UINT8(state, TSC2005State),
- VMSTATE_UINT16(data, TSC2005State),
- VMSTATE_UINT16(dav, TSC2005State),
- VMSTATE_UINT16(filter, TSC2005State),
- VMSTATE_INT8(nextfunction, TSC2005State),
- VMSTATE_INT8(function, TSC2005State),
- VMSTATE_INT32(x, TSC2005State),
- VMSTATE_INT32(y, TSC2005State),
- VMSTATE_TIMER_PTR(timer, TSC2005State),
- VMSTATE_UINT8(pin_func, TSC2005State),
- VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2),
- VMSTATE_UINT8(noise, TSC2005State),
- VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2),
- VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2),
- VMSTATE_INT32_ARRAY(tr, TSC2005State, 8),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void *tsc2005_init(qemu_irq pintdav)
-{
- TSC2005State *s;
-
- s = g_new0(TSC2005State, 1);
- s->x = 400;
- s->y = 240;
- s->pressure = false;
- s->precision = s->nextprecision = false;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
- s->pint = pintdav;
- s->model = 0x2005;
-
- s->tr[0] = 0;
- s->tr[1] = 1;
- s->tr[2] = 1;
- s->tr[3] = 0;
- s->tr[4] = 1;
- s->tr[5] = 0;
- s->tr[6] = 1;
- s->tr[7] = 0;
-
- tsc2005_reset(s);
-
- qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
- "QEMU TSC2005-driven Touchscreen");
-
- qemu_register_reset((void *) tsc2005_reset, s);
- vmstate_register(NULL, 0, &vmstate_tsc2005, s);
-
- return s;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen. Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info)
-{
- TSC2005State *s = (TSC2005State *) opaque;
-
- /* This version assumes touchscreen X & Y axis are parallel or
- * perpendicular to LCD's X & Y axis in some way. */
- if (abs(info->a[0]) > abs(info->a[1])) {
- s->tr[0] = 0;
- s->tr[1] = -info->a[6] * info->x;
- s->tr[2] = info->a[0];
- s->tr[3] = -info->a[2] / info->a[0];
- s->tr[4] = info->a[6] * info->y;
- s->tr[5] = 0;
- s->tr[6] = info->a[4];
- s->tr[7] = -info->a[5] / info->a[4];
- } else {
- s->tr[0] = info->a[6] * info->y;
- s->tr[1] = 0;
- s->tr[2] = info->a[1];
- s->tr[3] = -info->a[2] / info->a[1];
- s->tr[4] = 0;
- s->tr[5] = -info->a[6] * info->x;
- s->tr[6] = info->a[3];
- s->tr[7] = -info->a[5] / info->a[3];
- }
-
- s->tr[0] >>= 11;
- s->tr[1] >>= 11;
- s->tr[3] <<= 4;
- s->tr[4] >>= 11;
- s->tr[5] >>= 11;
- s->tr[7] <<= 4;
-}
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
deleted file mode 100644
index c4e32c7..0000000
--- a/hw/input/tsc210x.c
+++ /dev/null
@@ -1,1241 +0,0 @@
-/*
- * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
- * TI TSC2301 (touchscreen/sensors/keypad).
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-#include "sysemu/reset.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h" /* For I2SCodec */
-#include "hw/boards.h" /* for current_machine */
-#include "hw/input/tsc2xxx.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-
-#define TSC_DATA_REGISTERS_PAGE 0x0
-#define TSC_CONTROL_REGISTERS_PAGE 0x1
-#define TSC_AUDIO_REGISTERS_PAGE 0x2
-
-#define TSC_VERBOSE
-
-#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - resolution[p]))
-
-typedef struct {
- qemu_irq pint;
- qemu_irq kbint;
- qemu_irq davint;
- QEMUTimer *timer;
- QEMUSoundCard card;
- uWireSlave chip;
- I2SCodec codec;
- uint8_t in_fifo[16384];
- uint8_t out_fifo[16384];
- uint16_t model;
-
- int32_t x, y;
- bool pressure;
-
- uint8_t page, offset;
- uint16_t dav;
-
- bool state;
- bool irq;
- bool command;
- bool busy;
- bool enabled;
- bool host_mode;
- uint8_t function, nextfunction;
- uint8_t precision, nextprecision;
- uint8_t filter;
- uint8_t pin_func;
- uint8_t ref;
- uint8_t timing;
- uint8_t noise;
-
- uint16_t audio_ctrl1;
- uint16_t audio_ctrl2;
- uint16_t audio_ctrl3;
- uint16_t pll[3];
- uint16_t volume;
- int64_t volume_change;
- bool softstep;
- uint16_t dac_power;
- int64_t powerdown;
- uint16_t filter_data[0x14];
-
- const char *name;
- SWVoiceIn *adc_voice[1];
- SWVoiceOut *dac_voice[1];
- int i2s_rx_rate;
- int i2s_tx_rate;
-
- int tr[8];
-
- struct {
- uint16_t down;
- uint16_t mask;
- int scan;
- int debounce;
- int mode;
- int intr;
- } kb;
- int64_t now; /* Time at migration */
-} TSC210xState;
-
-static const int resolution[4] = { 12, 8, 10, 12 };
-
-#define TSC_MODE_NO_SCAN 0x0
-#define TSC_MODE_XY_SCAN 0x1
-#define TSC_MODE_XYZ_SCAN 0x2
-#define TSC_MODE_X 0x3
-#define TSC_MODE_Y 0x4
-#define TSC_MODE_Z 0x5
-#define TSC_MODE_BAT1 0x6
-#define TSC_MODE_BAT2 0x7
-#define TSC_MODE_AUX 0x8
-#define TSC_MODE_AUX_SCAN 0x9
-#define TSC_MODE_TEMP1 0xa
-#define TSC_MODE_PORT_SCAN 0xb
-#define TSC_MODE_TEMP2 0xc
-#define TSC_MODE_XX_DRV 0xd
-#define TSC_MODE_YY_DRV 0xe
-#define TSC_MODE_YX_DRV 0xf
-
-static const uint16_t mode_regs[16] = {
- 0x0000, /* No scan */
- 0x0600, /* X, Y scan */
- 0x0780, /* X, Y, Z scan */
- 0x0400, /* X */
- 0x0200, /* Y */
- 0x0180, /* Z */
- 0x0040, /* BAT1 */
- 0x0030, /* BAT2 */
- 0x0010, /* AUX */
- 0x0010, /* AUX scan */
- 0x0004, /* TEMP1 */
- 0x0070, /* Port scan */
- 0x0002, /* TEMP2 */
- 0x0000, /* X+, X- drivers */
- 0x0000, /* Y+, Y- drivers */
- 0x0000, /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s) \
- ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s) \
- ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s) \
- ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s) \
- ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define BAT1_VAL 0x8660
-#define BAT2_VAL 0x0000
-#define AUX1_VAL 0x35c0
-#define AUX2_VAL 0xffff
-#define TEMP1_VAL 0x8c70
-#define TEMP2_VAL 0xa5b0
-
-#define TSC_POWEROFF_DELAY 50
-#define TSC_SOFTSTEP_DELAY 50
-
-static void tsc210x_reset(TSC210xState *s)
-{
- s->state = false;
- s->pin_func = 2;
- s->enabled = false;
- s->busy = false;
- s->nextfunction = 0;
- s->ref = 0;
- s->timing = 0;
- s->irq = false;
- s->dav = 0;
-
- s->audio_ctrl1 = 0x0000;
- s->audio_ctrl2 = 0x4410;
- s->audio_ctrl3 = 0x0000;
- s->pll[0] = 0x1004;
- s->pll[1] = 0x0000;
- s->pll[2] = 0x1fff;
- s->volume = 0xffff;
- s->dac_power = 0x8540;
- s->softstep = true;
- s->volume_change = 0;
- s->powerdown = 0;
- s->filter_data[0x00] = 0x6be3;
- s->filter_data[0x01] = 0x9666;
- s->filter_data[0x02] = 0x675d;
- s->filter_data[0x03] = 0x6be3;
- s->filter_data[0x04] = 0x9666;
- s->filter_data[0x05] = 0x675d;
- s->filter_data[0x06] = 0x7d83;
- s->filter_data[0x07] = 0x84ee;
- s->filter_data[0x08] = 0x7d83;
- s->filter_data[0x09] = 0x84ee;
- s->filter_data[0x0a] = 0x6be3;
- s->filter_data[0x0b] = 0x9666;
- s->filter_data[0x0c] = 0x675d;
- s->filter_data[0x0d] = 0x6be3;
- s->filter_data[0x0e] = 0x9666;
- s->filter_data[0x0f] = 0x675d;
- s->filter_data[0x10] = 0x7d83;
- s->filter_data[0x11] = 0x84ee;
- s->filter_data[0x12] = 0x7d83;
- s->filter_data[0x13] = 0x84ee;
-
- s->i2s_tx_rate = 0;
- s->i2s_rx_rate = 0;
-
- s->kb.scan = 1;
- s->kb.debounce = 0;
- s->kb.mask = 0x0000;
- s->kb.mode = 3;
- s->kb.intr = 0;
-
- qemu_set_irq(s->pint, !s->irq);
- qemu_set_irq(s->davint, !s->dav);
- qemu_irq_raise(s->kbint);
-}
-
-typedef struct {
- int rate;
- int dsor;
- int fsref;
-} TSC210xRateInfo;
-
-/* { rate, dsor, fsref } */
-static const TSC210xRateInfo tsc2102_rates[] = {
- /* Fsref / 6.0 */
- { 7350, 63, 1 },
- { 8000, 63, 0 },
- /* Fsref / 6.0 */
- { 7350, 54, 1 },
- { 8000, 54, 0 },
- /* Fsref / 5.0 */
- { 8820, 45, 1 },
- { 9600, 45, 0 },
- /* Fsref / 4.0 */
- { 11025, 36, 1 },
- { 12000, 36, 0 },
- /* Fsref / 3.0 */
- { 14700, 27, 1 },
- { 16000, 27, 0 },
- /* Fsref / 2.0 */
- { 22050, 18, 1 },
- { 24000, 18, 0 },
- /* Fsref / 1.5 */
- { 29400, 9, 1 },
- { 32000, 9, 0 },
- /* Fsref */
- { 44100, 0, 1 },
- { 48000, 0, 0 },
-
- { 0, 0, 0 },
-};
-
-static inline void tsc210x_out_flush(TSC210xState *s, int len)
-{
- uint8_t *data = s->codec.out.fifo + s->codec.out.start;
- uint8_t *end = data + len;
-
- while (data < end)
- data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
-
- s->codec.out.len -= len;
- if (s->codec.out.len)
- memmove(s->codec.out.fifo, end, s->codec.out.len);
- s->codec.out.start = 0;
-}
-
-static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
-{
- if (s->codec.out.len >= free_b) {
- tsc210x_out_flush(s, free_b);
- return;
- }
-
- s->codec.out.size = MIN(free_b, 16384);
- qemu_irq_raise(s->codec.tx_start);
-}
-
-static void tsc2102_audio_rate_update(TSC210xState *s)
-{
- const TSC210xRateInfo *rate;
-
- s->codec.tx_rate = 0;
- s->codec.rx_rate = 0;
- if (s->dac_power & (1 << 15)) /* PWDNC */
- return;
-
- for (rate = tsc2102_rates; rate->rate; rate ++)
- if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */
- rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
- break;
- if (!rate->rate) {
- printf("%s: unknown sampling rate configured\n", __func__);
- return;
- }
-
- s->codec.tx_rate = rate->rate;
-}
-
-static void tsc2102_audio_output_update(TSC210xState *s)
-{
- int enable;
- struct audsettings fmt;
-
- if (s->dac_voice[0]) {
- tsc210x_out_flush(s, s->codec.out.len);
- s->codec.out.size = 0;
- AUD_set_active_out(s->dac_voice[0], 0);
- AUD_close_out(&s->card, s->dac_voice[0]);
- s->dac_voice[0] = NULL;
- }
- s->codec.cts = 0;
-
- enable =
- (~s->dac_power & (1 << 15)) && /* PWDNC */
- (~s->dac_power & (1 << 10)); /* DAPWDN */
- if (!enable || !s->codec.tx_rate)
- return;
-
- /* Force our own sampling rate even in slave DAC mode */
- fmt.endianness = 0;
- fmt.nchannels = 2;
- fmt.freq = s->codec.tx_rate;
- fmt.fmt = AUDIO_FORMAT_S16;
-
- s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
- "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
- if (s->dac_voice[0]) {
- s->codec.cts = 1;
- AUD_set_active_out(s->dac_voice[0], 1);
- }
-}
-
-static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
-{
- switch (reg) {
- case 0x00: /* X */
- s->dav &= 0xfbff;
- return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
- (s->noise & 3);
-
- case 0x01: /* Y */
- s->noise ++;
- s->dav &= 0xfdff;
- return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
- (s->noise & 3);
-
- case 0x02: /* Z1 */
- s->dav &= 0xfeff;
- return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
- (s->noise & 3);
-
- case 0x03: /* Z2 */
- s->dav &= 0xff7f;
- return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
- (s->noise & 3);
-
- case 0x04: /* KPData */
- if ((s->model & 0xff00) == 0x2300) {
- if (s->kb.intr && (s->kb.mode & 2)) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
- return s->kb.down;
- }
-
- return 0xffff;
-
- case 0x05: /* BAT1 */
- s->dav &= 0xffbf;
- return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
- (s->noise & 6);
-
- case 0x06: /* BAT2 */
- s->dav &= 0xffdf;
- return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
-
- case 0x07: /* AUX1 */
- s->dav &= 0xffef;
- return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
-
- case 0x08: /* AUX2 */
- s->dav &= 0xfff7;
- return 0xffff;
-
- case 0x09: /* TEMP1 */
- s->dav &= 0xfffb;
- return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
- (s->noise & 5);
-
- case 0x0a: /* TEMP2 */
- s->dav &= 0xfffd;
- return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
- (s->noise & 3);
-
- case 0x0b: /* DAC */
- s->dav &= 0xfffe;
- return 0xffff;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_data_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static uint16_t tsc2102_control_register_read(
- TSC210xState *s, int reg)
-{
- switch (reg) {
- case 0x00: /* TSC ADC */
- return (s->pressure << 15) | ((!s->busy) << 14) |
- (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter;
-
- case 0x01: /* Status / Keypad Control */
- if ((s->model & 0xff00) == 0x2100)
- return (s->pin_func << 14) | ((!s->enabled) << 13) |
- (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
- else
- return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
- (s->kb.debounce << 11);
-
- case 0x02: /* DAC Control */
- if ((s->model & 0xff00) == 0x2300)
- return s->dac_power & 0x8000;
- else
- goto bad_reg;
-
- case 0x03: /* Reference */
- return s->ref;
-
- case 0x04: /* Reset */
- return 0xffff;
-
- case 0x05: /* Configuration */
- return s->timing;
-
- case 0x06: /* Secondary configuration */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
-
- case 0x10: /* Keypad Mask */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- return s->kb.mask;
-
- default:
- bad_reg:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_control_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
-{
- int l_ch, r_ch;
- uint16_t val;
-
- switch (reg) {
- case 0x00: /* Audio Control 1 */
- return s->audio_ctrl1;
-
- case 0x01:
- return 0xff00;
-
- case 0x02: /* DAC Volume Control */
- return s->volume;
-
- case 0x03:
- return 0x8b00;
-
- case 0x04: /* Audio Control 2 */
- l_ch = 1;
- r_ch = 1;
- if (s->softstep && !(s->dac_power & (1 << 10))) {
- l_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->volume_change + TSC_SOFTSTEP_DELAY);
- r_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->volume_change + TSC_SOFTSTEP_DELAY);
- }
-
- return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
-
- case 0x05: /* Stereo DAC Power Control */
- return 0x2aa0 | s->dac_power |
- (((s->dac_power & (1 << 10)) &&
- (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->powerdown + TSC_POWEROFF_DELAY)) << 6);
-
- case 0x06: /* Audio Control 3 */
- val = s->audio_ctrl3 | 0x0001;
- s->audio_ctrl3 &= 0xff3f;
- return val;
-
- case 0x07: /* LCH_BASS_BOOST_N0 */
- case 0x08: /* LCH_BASS_BOOST_N1 */
- case 0x09: /* LCH_BASS_BOOST_N2 */
- case 0x0a: /* LCH_BASS_BOOST_N3 */
- case 0x0b: /* LCH_BASS_BOOST_N4 */
- case 0x0c: /* LCH_BASS_BOOST_N5 */
- case 0x0d: /* LCH_BASS_BOOST_D1 */
- case 0x0e: /* LCH_BASS_BOOST_D2 */
- case 0x0f: /* LCH_BASS_BOOST_D4 */
- case 0x10: /* LCH_BASS_BOOST_D5 */
- case 0x11: /* RCH_BASS_BOOST_N0 */
- case 0x12: /* RCH_BASS_BOOST_N1 */
- case 0x13: /* RCH_BASS_BOOST_N2 */
- case 0x14: /* RCH_BASS_BOOST_N3 */
- case 0x15: /* RCH_BASS_BOOST_N4 */
- case 0x16: /* RCH_BASS_BOOST_N5 */
- case 0x17: /* RCH_BASS_BOOST_D1 */
- case 0x18: /* RCH_BASS_BOOST_D2 */
- case 0x19: /* RCH_BASS_BOOST_D4 */
- case 0x1a: /* RCH_BASS_BOOST_D5 */
- return s->filter_data[reg - 0x07];
-
- case 0x1b: /* PLL Programmability 1 */
- return s->pll[0];
-
- case 0x1c: /* PLL Programmability 2 */
- return s->pll[1];
-
- case 0x1d: /* Audio Control 4 */
- return (!s->softstep) << 14;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_audio_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static void tsc2102_data_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* X */
- case 0x01: /* Y */
- case 0x02: /* Z1 */
- case 0x03: /* Z2 */
- case 0x05: /* BAT1 */
- case 0x06: /* BAT2 */
- case 0x07: /* AUX1 */
- case 0x08: /* AUX2 */
- case 0x09: /* TEMP1 */
- case 0x0a: /* TEMP2 */
- return;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "tsc2102_data_register_write: "
- "no such register: 0x%02x\n", reg);
- }
-}
-
-static void tsc2102_control_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* TSC ADC */
- s->host_mode = value >> 15;
- s->enabled = !(value & 0x4000);
- if (s->busy && !s->enabled)
- timer_del(s->timer);
- s->busy = s->busy && s->enabled;
- s->nextfunction = (value >> 10) & 0xf;
- s->nextprecision = (value >> 8) & 3;
- s->filter = value & 0xff;
- return;
-
- case 0x01: /* Status / Keypad Control */
- if ((s->model & 0xff00) == 0x2100)
- s->pin_func = value >> 14;
- else {
- s->kb.scan = (value >> 14) & 1;
- s->kb.debounce = (value >> 11) & 7;
- if (s->kb.intr && s->kb.scan) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
- }
- return;
-
- case 0x02: /* DAC Control */
- if ((s->model & 0xff00) == 0x2300) {
- s->dac_power &= 0x7fff;
- s->dac_power |= 0x8000 & value;
- } else
- goto bad_reg;
- break;
-
- case 0x03: /* Reference */
- s->ref = value & 0x1f;
- return;
-
- case 0x04: /* Reset */
- if (value == 0xbb00) {
- if (s->busy)
- timer_del(s->timer);
- tsc210x_reset(s);
-#ifdef TSC_VERBOSE
- } else {
- fprintf(stderr, "tsc2102_control_register_write: "
- "wrong value written into RESET\n");
-#endif
- }
- return;
-
- case 0x05: /* Configuration */
- s->timing = value & 0x3f;
-#ifdef TSC_VERBOSE
- if (value & ~0x3f)
- fprintf(stderr, "tsc2102_control_register_write: "
- "wrong value written into CONFIG\n");
-#endif
- return;
-
- case 0x06: /* Secondary configuration */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- s->kb.mode = value >> 14;
- s->pll[2] = value & 0x3ffff;
- return;
-
- case 0x10: /* Keypad Mask */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- s->kb.mask = value;
- return;
-
- default:
- bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR, "tsc2102_control_register_write: "
- "no such register: 0x%02x\n", reg);
- }
-}
-
-static void tsc2102_audio_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* Audio Control 1 */
- s->audio_ctrl1 = value & 0x0f3f;
-#ifdef TSC_VERBOSE
- if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 1\n");
-#endif
- tsc2102_audio_rate_update(s);
- tsc2102_audio_output_update(s);
- return;
-
- case 0x01:
-#ifdef TSC_VERBOSE
- if (value != 0xff00)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into reg 0x01\n");
-#endif
- return;
-
- case 0x02: /* DAC Volume Control */
- s->volume = value;
- s->volume_change = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- return;
-
- case 0x03:
-#ifdef TSC_VERBOSE
- if (value != 0x8b00)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into reg 0x03\n");
-#endif
- return;
-
- case 0x04: /* Audio Control 2 */
- s->audio_ctrl2 = value & 0xf7f2;
-#ifdef TSC_VERBOSE
- if (value & ~0xf7fd)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 2\n");
-#endif
- return;
-
- case 0x05: /* Stereo DAC Power Control */
- if ((value & ~s->dac_power) & (1 << 10))
- s->powerdown = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- s->dac_power = value & 0x9543;
-#ifdef TSC_VERBOSE
- if ((value & ~0x9543) != 0x2aa0)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Power\n");
-#endif
- tsc2102_audio_rate_update(s);
- tsc2102_audio_output_update(s);
- return;
-
- case 0x06: /* Audio Control 3 */
- s->audio_ctrl3 &= 0x00c0;
- s->audio_ctrl3 |= value & 0xf800;
-#ifdef TSC_VERBOSE
- if (value & ~0xf8c7)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 3\n");
-#endif
- tsc2102_audio_output_update(s);
- return;
-
- case 0x07: /* LCH_BASS_BOOST_N0 */
- case 0x08: /* LCH_BASS_BOOST_N1 */
- case 0x09: /* LCH_BASS_BOOST_N2 */
- case 0x0a: /* LCH_BASS_BOOST_N3 */
- case 0x0b: /* LCH_BASS_BOOST_N4 */
- case 0x0c: /* LCH_BASS_BOOST_N5 */
- case 0x0d: /* LCH_BASS_BOOST_D1 */
- case 0x0e: /* LCH_BASS_BOOST_D2 */
- case 0x0f: /* LCH_BASS_BOOST_D4 */
- case 0x10: /* LCH_BASS_BOOST_D5 */
- case 0x11: /* RCH_BASS_BOOST_N0 */
- case 0x12: /* RCH_BASS_BOOST_N1 */
- case 0x13: /* RCH_BASS_BOOST_N2 */
- case 0x14: /* RCH_BASS_BOOST_N3 */
- case 0x15: /* RCH_BASS_BOOST_N4 */
- case 0x16: /* RCH_BASS_BOOST_N5 */
- case 0x17: /* RCH_BASS_BOOST_D1 */
- case 0x18: /* RCH_BASS_BOOST_D2 */
- case 0x19: /* RCH_BASS_BOOST_D4 */
- case 0x1a: /* RCH_BASS_BOOST_D5 */
- s->filter_data[reg - 0x07] = value;
- return;
-
- case 0x1b: /* PLL Programmability 1 */
- s->pll[0] = value & 0xfffc;
-#ifdef TSC_VERBOSE
- if (value & ~0xfffc)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into PLL 1\n");
-#endif
- return;
-
- case 0x1c: /* PLL Programmability 2 */
- s->pll[1] = value & 0xfffc;
-#ifdef TSC_VERBOSE
- if (value & ~0xfffc)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into PLL 2\n");
-#endif
- return;
-
- case 0x1d: /* Audio Control 4 */
- s->softstep = !(value & 0x4000);
-#ifdef TSC_VERBOSE
- if (value & ~0x4000)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 4\n");
-#endif
- return;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "tsc2102_audio_register_write: "
- "no such register: 0x%02x\n", reg);
- }
-}
-
-/* This handles most of the chip logic. */
-static void tsc210x_pin_update(TSC210xState *s)
-{
- int64_t expires;
- bool pin_state;
-
- switch (s->pin_func) {
- case 0:
- pin_state = s->pressure;
- break;
- case 1:
- pin_state = !!s->dav;
- break;
- case 2:
- default:
- pin_state = s->pressure && !s->dav;
- }
-
- if (!s->enabled)
- pin_state = false;
-
- if (pin_state != s->irq) {
- s->irq = pin_state;
- qemu_set_irq(s->pint, !s->irq);
- }
-
- switch (s->nextfunction) {
- case TSC_MODE_XY_SCAN:
- case TSC_MODE_XYZ_SCAN:
- if (!s->pressure)
- return;
- break;
-
- case TSC_MODE_X:
- case TSC_MODE_Y:
- case TSC_MODE_Z:
- if (!s->pressure)
- return;
- /* Fall through */
- case TSC_MODE_BAT1:
- case TSC_MODE_BAT2:
- case TSC_MODE_AUX:
- case TSC_MODE_TEMP1:
- case TSC_MODE_TEMP2:
- if (s->dav)
- s->enabled = false;
- break;
-
- case TSC_MODE_AUX_SCAN:
- case TSC_MODE_PORT_SCAN:
- break;
-
- case TSC_MODE_NO_SCAN:
- case TSC_MODE_XX_DRV:
- case TSC_MODE_YY_DRV:
- case TSC_MODE_YX_DRV:
- default:
- return;
- }
-
- if (!s->enabled || s->busy || s->dav)
- return;
-
- s->busy = true;
- s->precision = s->nextprecision;
- s->function = s->nextfunction;
- expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND >> 10);
- timer_mod(s->timer, expires);
-}
-
-static uint16_t tsc210x_read(TSC210xState *s)
-{
- uint16_t ret = 0x0000;
-
- if (!s->command)
- fprintf(stderr, "tsc210x_read: SPI underrun!\n");
-
- switch (s->page) {
- case TSC_DATA_REGISTERS_PAGE:
- ret = tsc2102_data_register_read(s, s->offset);
- if (!s->dav)
- qemu_irq_raise(s->davint);
- break;
- case TSC_CONTROL_REGISTERS_PAGE:
- ret = tsc2102_control_register_read(s, s->offset);
- break;
- case TSC_AUDIO_REGISTERS_PAGE:
- ret = tsc2102_audio_register_read(s, s->offset);
- break;
- default:
- hw_error("tsc210x_read: wrong memory page\n");
- }
-
- tsc210x_pin_update(s);
-
- /* Allow sequential reads. */
- s->offset ++;
- s->state = false;
- return ret;
-}
-
-static void tsc210x_write(TSC210xState *s, uint16_t value)
-{
- /*
- * This is a two-state state machine for reading
- * command and data every second time.
- */
- if (!s->state) {
- s->command = (value >> 15) != 0;
- s->page = (value >> 11) & 0x0f;
- s->offset = (value >> 5) & 0x3f;
- s->state = true;
- } else {
- if (s->command)
- fprintf(stderr, "tsc210x_write: SPI overrun!\n");
- else
- switch (s->page) {
- case TSC_DATA_REGISTERS_PAGE:
- tsc2102_data_register_write(s, s->offset, value);
- break;
- case TSC_CONTROL_REGISTERS_PAGE:
- tsc2102_control_register_write(s, s->offset, value);
- break;
- case TSC_AUDIO_REGISTERS_PAGE:
- tsc2102_audio_register_write(s, s->offset, value);
- break;
- default:
- hw_error("tsc210x_write: wrong memory page\n");
- }
-
- tsc210x_pin_update(s);
- s->state = false;
- }
-}
-
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
-{
- TSC210xState *s = opaque;
- uint32_t ret = 0;
-
- if (len != 16) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: bad SPI word width %i\n", __func__, len);
- return 0;
- }
-
- /* TODO: sequential reads etc - how do we make sure the host doesn't
- * unintentionally read out a conversion result from a register while
- * transmitting the command word of the next command? */
- if (!value || (s->state && s->command))
- ret = tsc210x_read(s);
- if (value || (s->state && !s->command))
- tsc210x_write(s, value);
-
- return ret;
-}
-
-static void tsc210x_timer_tick(void *opaque)
-{
- TSC210xState *s = opaque;
-
- /* Timer ticked -- a set of conversions has been finished. */
-
- if (!s->busy)
- return;
-
- s->busy = false;
- s->dav |= mode_regs[s->function];
- tsc210x_pin_update(s);
- qemu_irq_lower(s->davint);
-}
-
-static void tsc210x_touchscreen_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- TSC210xState *s = opaque;
- int p = s->pressure;
-
- if (buttons_state) {
- s->x = x;
- s->y = y;
- }
- s->pressure = !!buttons_state;
-
- /*
- * Note: We would get better responsiveness in the guest by
- * signaling TS events immediately, but for now we simulate
- * the first conversion delay for sake of correctness.
- */
- if (p != s->pressure)
- tsc210x_pin_update(s);
-}
-
-static void tsc210x_i2s_swallow(TSC210xState *s)
-{
- if (s->dac_voice[0])
- tsc210x_out_flush(s, s->codec.out.len);
- else
- s->codec.out.len = 0;
-}
-
-static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
-{
- s->i2s_tx_rate = out;
- s->i2s_rx_rate = in;
-}
-
-static int tsc210x_pre_save(void *opaque)
-{
- TSC210xState *s = (TSC210xState *) opaque;
- s->now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- return 0;
-}
-
-static int tsc210x_post_load(void *opaque, int version_id)
-{
- TSC210xState *s = (TSC210xState *) opaque;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if (s->function >= ARRAY_SIZE(mode_regs)) {
- return -EINVAL;
- }
- if (s->nextfunction >= ARRAY_SIZE(mode_regs)) {
- return -EINVAL;
- }
- if (s->precision >= ARRAY_SIZE(resolution)) {
- return -EINVAL;
- }
- if (s->nextprecision >= ARRAY_SIZE(resolution)) {
- return -EINVAL;
- }
-
- s->volume_change -= s->now;
- s->volume_change += now;
- s->powerdown -= s->now;
- s->powerdown += now;
-
- s->busy = timer_pending(s->timer);
- qemu_set_irq(s->pint, !s->irq);
- qemu_set_irq(s->davint, !s->dav);
-
- return 0;
-}
-
-static const VMStateField vmstatefields_tsc210x[] = {
- VMSTATE_BOOL(enabled, TSC210xState),
- VMSTATE_BOOL(host_mode, TSC210xState),
- VMSTATE_BOOL(irq, TSC210xState),
- VMSTATE_BOOL(command, TSC210xState),
- VMSTATE_BOOL(pressure, TSC210xState),
- VMSTATE_BOOL(softstep, TSC210xState),
- VMSTATE_BOOL(state, TSC210xState),
- VMSTATE_UINT16(dav, TSC210xState),
- VMSTATE_INT32(x, TSC210xState),
- VMSTATE_INT32(y, TSC210xState),
- VMSTATE_UINT8(offset, TSC210xState),
- VMSTATE_UINT8(page, TSC210xState),
- VMSTATE_UINT8(filter, TSC210xState),
- VMSTATE_UINT8(pin_func, TSC210xState),
- VMSTATE_UINT8(ref, TSC210xState),
- VMSTATE_UINT8(timing, TSC210xState),
- VMSTATE_UINT8(noise, TSC210xState),
- VMSTATE_UINT8(function, TSC210xState),
- VMSTATE_UINT8(nextfunction, TSC210xState),
- VMSTATE_UINT8(precision, TSC210xState),
- VMSTATE_UINT8(nextprecision, TSC210xState),
- VMSTATE_UINT16(audio_ctrl1, TSC210xState),
- VMSTATE_UINT16(audio_ctrl2, TSC210xState),
- VMSTATE_UINT16(audio_ctrl3, TSC210xState),
- VMSTATE_UINT16_ARRAY(pll, TSC210xState, 3),
- VMSTATE_UINT16(volume, TSC210xState),
- VMSTATE_UINT16(dac_power, TSC210xState),
- VMSTATE_INT64(volume_change, TSC210xState),
- VMSTATE_INT64(powerdown, TSC210xState),
- VMSTATE_INT64(now, TSC210xState),
- VMSTATE_UINT16_ARRAY(filter_data, TSC210xState, 0x14),
- VMSTATE_TIMER_PTR(timer, TSC210xState),
- VMSTATE_END_OF_LIST()
-};
-
-static const VMStateDescription vmstate_tsc2102 = {
- .name = "tsc2102",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = tsc210x_pre_save,
- .post_load = tsc210x_post_load,
- .fields = vmstatefields_tsc210x,
-};
-
-static const VMStateDescription vmstate_tsc2301 = {
- .name = "tsc2301",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = tsc210x_pre_save,
- .post_load = tsc210x_post_load,
- .fields = vmstatefields_tsc210x,
-};
-
-static void tsc210x_init(TSC210xState *s,
- const char *name,
- const VMStateDescription *vmsd)
-{
- s->tr[0] = 0;
- s->tr[1] = 1;
- s->tr[2] = 1;
- s->tr[3] = 0;
- s->tr[4] = 1;
- s->tr[5] = 0;
- s->tr[6] = 1;
- s->tr[7] = 0;
-
- s->chip.opaque = s;
- s->chip.send = (void *) tsc210x_write;
- s->chip.receive = (void *) tsc210x_read;
-
- s->codec.opaque = s;
- s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
- s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
- s->codec.in.fifo = s->in_fifo;
- s->codec.out.fifo = s->out_fifo;
-
- tsc210x_reset(s);
-
- qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, name);
-
- if (current_machine->audiodev) {
- s->card.name = g_strdup(current_machine->audiodev);
- s->card.state = audio_state_by_name(s->card.name, &error_fatal);
- }
- AUD_register_card(s->name, &s->card, &error_fatal);
-
- qemu_register_reset((void *) tsc210x_reset, s);
- vmstate_register(NULL, 0, vmsd, s);
-}
-
-uWireSlave *tsc2102_init(qemu_irq pint)
-{
- TSC210xState *s;
-
- s = g_new0(TSC210xState, 1);
- s->x = 160;
- s->y = 160;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s);
- s->pint = pint;
- s->model = 0x2102;
- s->name = "tsc2102";
-
- tsc210x_init(s, "QEMU TSC2102-driven Touchscreen", &vmstate_tsc2102);
-
- return &s->chip;
-}
-
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
-{
- TSC210xState *s;
-
- s = g_new0(TSC210xState, 1);
- s->x = 400;
- s->y = 240;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s);
- s->pint = penirq;
- s->kbint = kbirq;
- s->davint = dav;
- s->model = 0x2301;
- s->name = "tsc2301";
-
- tsc210x_init(s, "QEMU TSC2301-driven Touchscreen", &vmstate_tsc2301);
-
- return &s->chip;
-}
-
-I2SCodec *tsc210x_codec(uWireSlave *chip)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-
- return &s->codec;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen. Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-#if 0
- int64_t ltr[8];
-
- ltr[0] = (int64_t) info->a[1] * info->y;
- ltr[1] = (int64_t) info->a[4] * info->x;
- ltr[2] = (int64_t) info->a[1] * info->a[3] -
- (int64_t) info->a[4] * info->a[0];
- ltr[3] = (int64_t) info->a[2] * info->a[4] -
- (int64_t) info->a[5] * info->a[1];
- ltr[4] = (int64_t) info->a[0] * info->y;
- ltr[5] = (int64_t) info->a[3] * info->x;
- ltr[6] = (int64_t) info->a[4] * info->a[0] -
- (int64_t) info->a[1] * info->a[3];
- ltr[7] = (int64_t) info->a[2] * info->a[3] -
- (int64_t) info->a[5] * info->a[0];
-
- /* Avoid integer overflow */
- s->tr[0] = ltr[0] >> 11;
- s->tr[1] = ltr[1] >> 11;
- s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
- s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
- s->tr[4] = ltr[4] >> 11;
- s->tr[5] = ltr[5] >> 11;
- s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
- s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
-#else
-
- /* This version assumes touchscreen X & Y axis are parallel or
- * perpendicular to LCD's X & Y axis in some way. */
- if (abs(info->a[0]) > abs(info->a[1])) {
- s->tr[0] = 0;
- s->tr[1] = -info->a[6] * info->x;
- s->tr[2] = info->a[0];
- s->tr[3] = -info->a[2] / info->a[0];
- s->tr[4] = info->a[6] * info->y;
- s->tr[5] = 0;
- s->tr[6] = info->a[4];
- s->tr[7] = -info->a[5] / info->a[4];
- } else {
- s->tr[0] = info->a[6] * info->y;
- s->tr[1] = 0;
- s->tr[2] = info->a[1];
- s->tr[3] = -info->a[2] / info->a[1];
- s->tr[4] = 0;
- s->tr[5] = -info->a[6] * info->x;
- s->tr[6] = info->a[3];
- s->tr[7] = -info->a[5] / info->a[3];
- }
-
- s->tr[0] >>= 11;
- s->tr[1] >>= 11;
- s->tr[3] <<= 4;
- s->tr[4] >>= 11;
- s->tr[5] >>= 11;
- s->tr[7] <<= 4;
-#endif
-}
-
-void tsc210x_key_event(uWireSlave *chip, int key, int down)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-
- if (down)
- s->kb.down |= 1 << key;
- else
- s->kb.down &= ~(1 << key);
-
- if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
- s->kb.intr = 1;
- qemu_irq_lower(s->kbint);
- } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
- !(s->kb.mode & 1)) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
-}
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 45e4d4c..d986c3c 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -237,13 +237,12 @@ static void virtio_input_hid_handle_status(VirtIOInput *vinput,
}
}
-static Property virtio_input_hid_properties[] = {
+static const Property virtio_input_hid_properties[] = {
DEFINE_PROP_STRING("display", VirtIOInputHID, display),
DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
+static void virtio_input_hid_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
@@ -380,12 +379,11 @@ static struct virtio_input_config virtio_mouse_config_v2[] = {
{ /* end of list */ },
};
-static Property virtio_mouse_properties[] = {
+static const Property virtio_mouse_properties[] = {
DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_mouse_class_init(ObjectClass *klass, void *data)
+static void virtio_mouse_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -505,12 +503,11 @@ static struct virtio_input_config virtio_tablet_config_v2[] = {
{ /* end of list */ },
};
-static Property virtio_tablet_properties[] = {
+static const Property virtio_tablet_properties[] = {
DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_tablet_class_init(ObjectClass *klass, void *data)
+static void virtio_tablet_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c
index fea7139..bbfee9d 100644
--- a/hw/input/virtio-input-host.c
+++ b/hw/input/virtio-input-host.c
@@ -178,7 +178,6 @@ static void virtio_input_host_realize(DeviceState *dev, Error **errp)
err_close:
close(vih->fd);
vih->fd = -1;
- return;
}
static void virtio_input_host_unrealize(DeviceState *dev)
@@ -221,12 +220,11 @@ static const VMStateDescription vmstate_virtio_input_host = {
.unmigratable = 1,
};
-static Property virtio_input_host_properties[] = {
+static const Property virtio_input_host_properties[] = {
DEFINE_PROP_STRING("evdev", VirtIOInputHost, evdev),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_input_host_class_init(ObjectClass *klass, void *data)
+static void virtio_input_host_class_init(ObjectClass *klass, const void *data)
{
VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
index 3bcdae4..a3f554f 100644
--- a/hw/input/virtio-input.c
+++ b/hw/input/virtio-input.c
@@ -189,7 +189,7 @@ static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f,
return f;
}
-static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
+static int virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
@@ -202,6 +202,7 @@ static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
}
}
}
+ return 0;
}
static void virtio_input_reset(VirtIODevice *vdev)
@@ -300,12 +301,11 @@ static const VMStateDescription vmstate_virtio_input = {
.post_load = virtio_input_post_load,
};
-static Property virtio_input_properties[] = {
+static const Property virtio_input_properties[] = {
DEFINE_PROP_STRING("serial", VirtIOInput, serial),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_input_class_init(ObjectClass *klass, void *data)
+static void virtio_input_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index dd405bd..7547528 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -23,13 +23,13 @@ config APIC
config ARM_GIC
bool
- select ARM_GICV3_TCG if TCG
+ select ARM_GICV3 if TCG
select ARM_GIC_KVM if KVM
select MSI_NONBROKEN
-config ARM_GICV3_TCG
+config ARM_GICV3
bool
- depends on ARM_GIC && TCG
+ depends on ARM_GIC
config ARM_GIC_KVM
bool
diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c
index cea559c..0409734 100644
--- a/hw/intc/allwinner-a10-pic.c
+++ b/hw/intc/allwinner-a10-pic.c
@@ -135,7 +135,7 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
static const MemoryRegionOps aw_a10_pic_ops = {
.read = aw_a10_pic_read,
.write = aw_a10_pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static const VMStateDescription vmstate_aw_a10_pic = {
@@ -187,11 +187,11 @@ static void aw_a10_pic_reset(DeviceState *d)
}
}
-static void aw_a10_pic_class_init(ObjectClass *klass, void *data)
+static void aw_a10_pic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = aw_a10_pic_reset;
+ device_class_set_legacy_reset(dc, aw_a10_pic_reset);
dc->desc = "allwinner a10 pic";
dc->vmsd = &vmstate_aw_a10_pic;
}
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 4186c57..bcb1035 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -26,7 +26,7 @@
#include "hw/intc/kvm_irqcount.h"
#include "hw/pci/msi.h"
#include "qemu/host-utils.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "trace.h"
#include "hw/i386/apic-msidef.h"
#include "qapi/error.h"
@@ -350,9 +350,8 @@ static int apic_set_base(APICCommonState *s, uint64_t val)
return -1;
}
- s->apicbase = (val & 0xfffff000) |
+ s->apicbase = (val & MSR_IA32_APICBASE_BASE) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
- /* if disabled, cannot be enabled again */
if (!(val & MSR_IA32_APICBASE_ENABLE)) {
s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
cpu_clear_apic_feature(&s->cpu->env);
@@ -1177,7 +1176,7 @@ static void apic_unrealize(DeviceState *dev)
local_apics[s->initial_apic_id] = NULL;
}
-static void apic_class_init(ObjectClass *klass, void *data)
+static void apic_class_init(ObjectClass *klass, const void *data)
{
APICCommonClass *k = APIC_COMMON_CLASS(klass);
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index c13cdd7..37a7a70 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -28,7 +28,7 @@
#include "hw/intc/kvm_irqcount.h"
#include "trace.h"
#include "hw/boards.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
@@ -408,13 +408,12 @@ static const VMStateDescription vmstate_apic_common = {
}
};
-static Property apic_properties_common[] = {
+static const Property apic_properties_common[] = {
DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
true),
DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id,
false),
- DEFINE_PROP_END_OF_LIST(),
};
static void apic_common_get_id(Object *obj, Visitor *v, const char *name,
@@ -467,11 +466,11 @@ static void apic_common_initfn(Object *obj)
apic_common_set_id, NULL, NULL);
}
-static void apic_common_class_init(ObjectClass *klass, void *data)
+static void apic_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = apic_reset_common;
+ device_class_set_legacy_reset(dc, apic_reset_common);
device_class_set_props(dc, apic_properties_common);
dc->realize = apic_common_realize;
dc->unrealize = apic_common_unrealize;
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 8068324..899f133 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -27,8 +27,8 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
-#include "sysemu/kvm.h"
-#include "sysemu/qtest.h"
+#include "system/kvm.h"
+#include "system/qtest.h"
/* #define DEBUG_GIC */
@@ -59,7 +59,7 @@ static const uint8_t gic_id_gicv2[] = {
static inline int gic_get_current_cpu(GICState *s)
{
if (!qtest_enabled() && s->num_cpu > 1) {
- return current_cpu->cpu_index;
+ return current_cpu->cpu_index - s->first_cpu_index;
}
return 0;
}
@@ -1263,9 +1263,14 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
trace_gic_enable_irq(irq + i);
}
GIC_DIST_SET_ENABLED(irq + i, cm);
- /* If a raised level triggered IRQ enabled then mark
- is as pending. */
- if (GIC_DIST_TEST_LEVEL(irq + i, mask)
+ /*
+ * If a raised level triggered IRQ enabled then mark
+ * it as pending on 11MPCore. For other GIC revisions we
+ * handle the "level triggered and line asserted" check
+ * at the other end in gic_test_pending().
+ */
+ if (s->revision == REV_11MPCORE
+ && GIC_DIST_TEST_LEVEL(irq + i, mask)
&& !GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) {
DPRINTF("Set %d pending mask %x\n", irq + i, mask);
GIC_DIST_SET_PENDING(irq + i, mask);
@@ -2157,7 +2162,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
}
-static void arm_gic_class_init(ObjectClass *klass, void *data)
+static void arm_gic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ARMGICClass *agc = ARM_GIC_CLASS(klass);
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
index 53fb2c4..ed5be05 100644
--- a/hw/intc/arm_gic_common.c
+++ b/hw/intc/arm_gic_common.c
@@ -26,7 +26,7 @@
#include "hw/arm/linux-boot-if.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
static int gic_pre_save(void *opaque)
{
@@ -348,8 +348,9 @@ static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
}
}
-static Property arm_gic_common_properties[] = {
+static const Property arm_gic_common_properties[] = {
DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
+ DEFINE_PROP_UINT32("first-cpu-index", GICState, first_cpu_index, 0),
DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
/* Revision can be 1 or 2 for GIC architecture specification
* versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC.
@@ -360,10 +361,9 @@ static Property arm_gic_common_properties[] = {
/* True if the GIC should implement the virtualization extensions */
DEFINE_PROP_BOOL("has-virtualization-extensions", GICState, virt_extn, 0),
DEFINE_PROP_UINT32("num-priority-bits", GICState, n_prio_bits, 8),
- DEFINE_PROP_END_OF_LIST(),
};
-static void arm_gic_common_class_init(ObjectClass *klass, void *data)
+static void arm_gic_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -383,7 +383,7 @@ static const TypeInfo arm_gic_common_type = {
.class_size = sizeof(ARMGICCommonClass),
.class_init = arm_gic_common_class_init,
.abstract = true,
- .interfaces = (InterfaceInfo []) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ARM_LINUX_BOOT_IF },
{ },
},
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index 53defee..1e9232f 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -23,7 +23,7 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "migration/blocker.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_arm.h"
#include "gic_internal.h"
#include "vgic_common.h"
@@ -547,17 +547,10 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true,
&error_abort);
}
- } else if (kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
+ } else {
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
error_append_hint(errp,
"Perhaps the host CPU does not support GICv2?\n");
- } else if (ret != -ENODEV && ret != -ENOTSUP) {
- /*
- * Very ancient kernel without KVM_CAP_DEVICE_CTRL: assume that
- * ENODEV or ENOTSUP mean "can't create GICv2 with KVM_CREATE_DEVICE",
- * and that we will get a GICv2 via KVM_CREATE_IRQCHIP.
- */
- error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
return;
}
@@ -591,7 +584,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
}
}
-static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
+static void kvm_arm_gic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/intc/arm_gicv2m.c b/hw/intc/arm_gicv2m.c
index d564b85..cef0688 100644
--- a/hw/intc/arm_gicv2m.c
+++ b/hw/intc/arm_gicv2m.c
@@ -31,7 +31,7 @@
#include "hw/irq.h"
#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qom/object.h"
@@ -170,13 +170,12 @@ static void gicv2m_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property gicv2m_properties[] = {
+static const Property gicv2m_properties[] = {
DEFINE_PROP_UINT32("base-spi", ARMGICv2mState, base_spi, 0),
DEFINE_PROP_UINT32("num-spi", ARMGICv2mState, num_spi, 64),
- DEFINE_PROP_END_OF_LIST(),
};
-static void gicv2m_class_init(ObjectClass *klass, void *data)
+static void gicv2m_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 58e18ff..6059ce9 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -452,7 +452,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
gicv3_init_cpuif(s);
}
-static void arm_gicv3_class_init(ObjectClass *klass, void *data)
+static void arm_gicv3_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index bd50a1b..1cee681 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -31,7 +31,7 @@
#include "migration/vmstate.h"
#include "gicv3_internal.h"
#include "hw/arm/linux-boot-if.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
static void gicv3_gicd_no_migration_shift_bug_post_load(GICv3State *cs)
@@ -605,7 +605,7 @@ static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
}
}
-static Property arm_gicv3_common_properties[] = {
+static const Property arm_gicv3_common_properties[] = {
DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
@@ -621,10 +621,9 @@ static Property arm_gicv3_common_properties[] = {
redist_region_count, qdev_prop_uint32, uint32_t),
DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION,
MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void arm_gicv3_common_class_init(ObjectClass *klass, void *data)
+static void arm_gicv3_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -645,7 +644,7 @@ static const TypeInfo arm_gicv3_common_type = {
.class_init = arm_gicv3_common_class_init,
.instance_finalize = arm_gicv3_finalize,
.abstract = true,
- .interfaces = (InterfaceInfo []) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ARM_LINUX_BOOT_IF },
{ },
},
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index bdb13b0..4b4cf09 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -22,8 +22,9 @@
#include "cpu.h"
#include "target/arm/cpregs.h"
#include "target/arm/cpu-features.h"
-#include "sysemu/tcg.h"
-#include "sysemu/qtest.h"
+#include "target/arm/internals.h"
+#include "system/tcg.h"
+#include "system/qtest.h"
/*
* Special case return value from hppvi_index(); must be larger than
@@ -583,7 +584,6 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
}
gicv3_cpuif_virt_irq_fiq_update(cs);
- return;
}
static uint64_t icv_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -781,7 +781,7 @@ static void icv_activate_irq(GICv3CPUState *cs, int idx, int grp)
if (nmi) {
cs->ich_apr[grp][regno] |= ICV_AP1R_EL1_NMI;
} else {
- cs->ich_apr[grp][regno] |= (1 << regbit);
+ cs->ich_apr[grp][regno] |= (1U << regbit);
}
}
@@ -793,7 +793,7 @@ static void icv_activate_vlpi(GICv3CPUState *cs)
int regno = aprbit / 32;
int regbit = aprbit % 32;
- cs->ich_apr[cs->hppvlpi.grp][regno] |= (1 << regbit);
+ cs->ich_apr[cs->hppvlpi.grp][regno] |= (1U << regbit);
gicv3_redist_vlpi_pending(cs, cs->hppvlpi.irq, 0);
}
@@ -1170,7 +1170,7 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
if (nmi) {
cs->icc_apr[cs->hppi.grp][regno] |= ICC_AP1R_EL1_NMI;
} else {
- cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
+ cs->icc_apr[cs->hppi.grp][regno] |= (1U << regbit);
}
if (irq < GIC_INTERNAL) {
@@ -2291,7 +2291,7 @@ static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
r = CP_ACCESS_TRAP_EL3;
break;
case 3:
- if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
+ if (!arm_is_el3_or_mon(env)) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -2300,9 +2300,6 @@ static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
}
}
- if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
- r = CP_ACCESS_TRAP;
- }
return r;
}
@@ -2356,7 +2353,7 @@ static CPAccessResult gicv3_fiq_access(CPUARMState *env,
r = CP_ACCESS_TRAP_EL3;
break;
case 3:
- if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
+ if (!arm_is_el3_or_mon(env)) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -2365,9 +2362,6 @@ static CPAccessResult gicv3_fiq_access(CPUARMState *env,
}
}
- if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
- r = CP_ACCESS_TRAP;
- }
return r;
}
@@ -2395,7 +2389,7 @@ static CPAccessResult gicv3_irq_access(CPUARMState *env,
r = CP_ACCESS_TRAP_EL3;
break;
case 3:
- if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
+ if (!arm_is_el3_or_mon(env)) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -2404,9 +2398,6 @@ static CPAccessResult gicv3_irq_access(CPUARMState *env,
}
}
- if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
- r = CP_ACCESS_TRAP;
- }
return r;
}
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index bf31158..577b445 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -465,7 +465,7 @@ static ItsCmdResult lookup_vte(GICv3ITSState *s, const char *who,
static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite,
int irqlevel)
{
- CTEntry cte;
+ CTEntry cte = {};
ItsCmdResult cmdres;
cmdres = lookup_cte(s, __func__, ite->icid, &cte);
@@ -479,7 +479,7 @@ static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite,
static ItsCmdResult process_its_cmd_virt(GICv3ITSState *s, const ITEntry *ite,
int irqlevel)
{
- VTEntry vte;
+ VTEntry vte = {};
ItsCmdResult cmdres;
cmdres = lookup_vte(s, __func__, ite->vpeid, &vte);
@@ -514,8 +514,8 @@ static ItsCmdResult process_its_cmd_virt(GICv3ITSState *s, const ITEntry *ite,
static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
uint32_t eventid, ItsCmdType cmd)
{
- DTEntry dte;
- ITEntry ite;
+ DTEntry dte = {};
+ ITEntry ite = {};
ItsCmdResult cmdres;
int irqlevel;
@@ -583,8 +583,8 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
uint32_t pIntid = 0;
uint64_t num_eventids;
uint16_t icid = 0;
- DTEntry dte;
- ITEntry ite;
+ DTEntry dte = {};
+ ITEntry ite = {};
devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
eventid = cmdpkt[1] & EVENTID_MASK;
@@ -651,8 +651,8 @@ static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt,
{
uint32_t devid, eventid, vintid, doorbell, vpeid;
uint32_t num_eventids;
- DTEntry dte;
- ITEntry ite;
+ DTEntry dte = {};
+ ITEntry ite = {};
if (!its_feature_virtual(s)) {
return CMD_CONTINUE;
@@ -761,7 +761,7 @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
{
uint16_t icid;
- CTEntry cte;
+ CTEntry cte = {};
icid = cmdpkt[2] & ICID_MASK;
cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
@@ -822,7 +822,7 @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
{
uint32_t devid;
- DTEntry dte;
+ DTEntry dte = {};
devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
dte.size = cmdpkt[1] & SIZE_MASK;
@@ -886,9 +886,9 @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
{
uint32_t devid, eventid;
uint16_t new_icid;
- DTEntry dte;
- CTEntry old_cte, new_cte;
- ITEntry old_ite;
+ DTEntry dte = {};
+ CTEntry old_cte = {}, new_cte = {};
+ ITEntry old_ite = {};
ItsCmdResult cmdres;
devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
@@ -965,7 +965,7 @@ static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte)
static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt)
{
- VTEntry vte;
+ VTEntry vte = {};
uint32_t vpeid;
if (!its_feature_virtual(s)) {
@@ -1030,7 +1030,7 @@ static void vmovp_callback(gpointer data, gpointer opaque)
*/
GICv3ITSState *s = data;
VmovpCallbackData *cbdata = opaque;
- VTEntry vte;
+ VTEntry vte = {};
ItsCmdResult cmdres;
cmdres = lookup_vte(s, __func__, cbdata->vpeid, &vte);
@@ -1085,9 +1085,9 @@ static ItsCmdResult process_vmovi(GICv3ITSState *s, const uint64_t *cmdpkt)
{
uint32_t devid, eventid, vpeid, doorbell;
bool doorbell_valid;
- DTEntry dte;
- ITEntry ite;
- VTEntry old_vte, new_vte;
+ DTEntry dte = {};
+ ITEntry ite = {};
+ VTEntry old_vte = {}, new_vte = {};
ItsCmdResult cmdres;
if (!its_feature_virtual(s)) {
@@ -1186,10 +1186,10 @@ static ItsCmdResult process_vinvall(GICv3ITSState *s, const uint64_t *cmdpkt)
static ItsCmdResult process_inv(GICv3ITSState *s, const uint64_t *cmdpkt)
{
uint32_t devid, eventid;
- ITEntry ite;
- DTEntry dte;
- CTEntry cte;
- VTEntry vte;
+ ITEntry ite = {};
+ DTEntry dte = {};
+ CTEntry cte = {};
+ VTEntry vte = {};
ItsCmdResult cmdres;
devid = FIELD_EX64(cmdpkt[0], INV_0, DEVICEID);
@@ -2002,13 +2002,12 @@ static void gicv3_its_post_load(GICv3ITSState *s)
}
}
-static Property gicv3_its_props[] = {
+static const Property gicv3_its_props[] = {
DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
GICv3State *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void gicv3_its_class_init(ObjectClass *klass, void *data)
+static void gicv3_its_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
index 0b97362..e946e3f 100644
--- a/hw/intc/arm_gicv3_its_common.c
+++ b/hw/intc/arm_gicv3_its_common.c
@@ -24,7 +24,7 @@
#include "hw/intc/arm_gicv3_its_common.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
static int gicv3_its_pre_save(void *opaque)
{
@@ -135,7 +135,7 @@ static void gicv3_its_common_reset_hold(Object *obj, ResetType type)
memset(&s->baser, 0, sizeof(s->baser));
}
-static void gicv3_its_common_class_init(ObjectClass *klass, void *data)
+static void gicv3_its_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
index 35539c0..9812d50 100644
--- a/hw/intc/arm_gicv3_its_kvm.c
+++ b/hw/intc/arm_gicv3_its_kvm.c
@@ -24,8 +24,8 @@
#include "qemu/error-report.h"
#include "hw/intc/arm_gicv3_its_common.h"
#include "hw/qdev-properties.h"
-#include "sysemu/runstate.h"
-#include "sysemu/kvm.h"
+#include "system/runstate.h"
+#include "system/kvm.h"
#include "kvm_arm.h"
#include "migration/blocker.h"
#include "qom/object.h"
@@ -234,13 +234,12 @@ static void kvm_arm_its_reset_hold(Object *obj, ResetType type)
}
}
-static Property kvm_arm_its_props[] = {
+static const Property kvm_arm_its_props[] = {
DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3",
GICv3State *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
+static void kvm_arm_its_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 9ea6b8e..3be3bf6 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -24,8 +24,8 @@
#include "hw/intc/arm_gicv3_common.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "sysemu/kvm.h"
-#include "sysemu/runstate.h"
+#include "system/kvm.h"
+#include "system/runstate.h"
#include "kvm_arm.h"
#include "gicv3_internal.h"
#include "vgic_common.h"
@@ -893,7 +893,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
}
}
-static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
+static void kvm_arm_gicv3_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 404a445..83ff74f 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -18,11 +18,11 @@
#include "hw/intc/armv7m_nvic.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-#include "sysemu/tcg.h"
-#include "sysemu/runstate.h"
+#include "system/tcg.h"
+#include "system/runstate.h"
#include "target/arm/cpu.h"
#include "target/arm/cpu-features.h"
-#include "exec/exec-all.h"
+#include "exec/cputlb.h"
#include "exec/memop.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -2569,7 +2569,7 @@ static const VMStateDescription vmstate_nvic = {
}
};
-static Property props_nvic[] = {
+static const Property props_nvic[] = {
/* Number of external IRQ lines (so excluding the 16 internal exceptions) */
DEFINE_PROP_UINT32("num-irq", NVICState, num_irq, 64),
/*
@@ -2577,7 +2577,6 @@ static Property props_nvic[] = {
* to use a reasonable default.
*/
DEFINE_PROP_UINT8("num-prio-bits", NVICState, num_prio_bits, 0),
- DEFINE_PROP_END_OF_LIST()
};
static void armv7m_nvic_reset(DeviceState *dev)
@@ -2731,13 +2730,13 @@ static void armv7m_nvic_instance_init(Object *obj)
qdev_init_gpio_in_named(dev, nvic_nmi_trigger, "NMI", 1);
}
-static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+static void armv7m_nvic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_nvic;
device_class_set_props(dc, props_nvic);
- dc->reset = armv7m_nvic_reset;
+ device_class_set_legacy_reset(dc, armv7m_nvic_reset);
dc->realize = armv7m_nvic_realize;
}
diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c
index 7515558..5cd786d 100644
--- a/hw/intc/aspeed_intc.c
+++ b/hw/intc/aspeed_intc.c
@@ -14,72 +14,291 @@
#include "hw/registerfields.h"
#include "qapi/error.h"
-/* INTC Registers */
-REG32(GICINT128_EN, 0x1000)
-REG32(GICINT128_STATUS, 0x1004)
-REG32(GICINT129_EN, 0x1100)
-REG32(GICINT129_STATUS, 0x1104)
-REG32(GICINT130_EN, 0x1200)
-REG32(GICINT130_STATUS, 0x1204)
-REG32(GICINT131_EN, 0x1300)
-REG32(GICINT131_STATUS, 0x1304)
-REG32(GICINT132_EN, 0x1400)
-REG32(GICINT132_STATUS, 0x1404)
-REG32(GICINT133_EN, 0x1500)
-REG32(GICINT133_STATUS, 0x1504)
-REG32(GICINT134_EN, 0x1600)
-REG32(GICINT134_STATUS, 0x1604)
-REG32(GICINT135_EN, 0x1700)
-REG32(GICINT135_STATUS, 0x1704)
-REG32(GICINT136_EN, 0x1800)
-REG32(GICINT136_STATUS, 0x1804)
-
-#define GICINT_STATUS_BASE R_GICINT128_STATUS
-
-static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
+/*
+ * INTC Registers
+ *
+ * values below are offset by - 0x1000 from datasheet
+ * because its memory region is start at 0x1000
+ *
+ */
+REG32(GICINT128_EN, 0x000)
+REG32(GICINT128_STATUS, 0x004)
+REG32(GICINT129_EN, 0x100)
+REG32(GICINT129_STATUS, 0x104)
+REG32(GICINT130_EN, 0x200)
+REG32(GICINT130_STATUS, 0x204)
+REG32(GICINT131_EN, 0x300)
+REG32(GICINT131_STATUS, 0x304)
+REG32(GICINT132_EN, 0x400)
+REG32(GICINT132_STATUS, 0x404)
+REG32(GICINT133_EN, 0x500)
+REG32(GICINT133_STATUS, 0x504)
+REG32(GICINT134_EN, 0x600)
+REG32(GICINT134_STATUS, 0x604)
+REG32(GICINT135_EN, 0x700)
+REG32(GICINT135_STATUS, 0x704)
+REG32(GICINT136_EN, 0x800)
+REG32(GICINT136_STATUS, 0x804)
+REG32(GICINT192_201_EN, 0xB00)
+REG32(GICINT192_201_STATUS, 0xB04)
+
+/*
+ * INTCIO Registers
+ *
+ * values below are offset by - 0x100 from datasheet
+ * because its memory region is start at 0x100
+ *
+ */
+REG32(GICINT192_EN, 0x00)
+REG32(GICINT192_STATUS, 0x04)
+REG32(GICINT193_EN, 0x10)
+REG32(GICINT193_STATUS, 0x14)
+REG32(GICINT194_EN, 0x20)
+REG32(GICINT194_STATUS, 0x24)
+REG32(GICINT195_EN, 0x30)
+REG32(GICINT195_STATUS, 0x34)
+REG32(GICINT196_EN, 0x40)
+REG32(GICINT196_STATUS, 0x44)
+REG32(GICINT197_EN, 0x50)
+REG32(GICINT197_STATUS, 0x54)
+
+/*
+ * SSP INTC Registers
+ */
+REG32(SSPINT128_EN, 0x2000)
+REG32(SSPINT128_STATUS, 0x2004)
+REG32(SSPINT129_EN, 0x2100)
+REG32(SSPINT129_STATUS, 0x2104)
+REG32(SSPINT130_EN, 0x2200)
+REG32(SSPINT130_STATUS, 0x2204)
+REG32(SSPINT131_EN, 0x2300)
+REG32(SSPINT131_STATUS, 0x2304)
+REG32(SSPINT132_EN, 0x2400)
+REG32(SSPINT132_STATUS, 0x2404)
+REG32(SSPINT133_EN, 0x2500)
+REG32(SSPINT133_STATUS, 0x2504)
+REG32(SSPINT134_EN, 0x2600)
+REG32(SSPINT134_STATUS, 0x2604)
+REG32(SSPINT135_EN, 0x2700)
+REG32(SSPINT135_STATUS, 0x2704)
+REG32(SSPINT136_EN, 0x2800)
+REG32(SSPINT136_STATUS, 0x2804)
+REG32(SSPINT137_EN, 0x2900)
+REG32(SSPINT137_STATUS, 0x2904)
+REG32(SSPINT138_EN, 0x2A00)
+REG32(SSPINT138_STATUS, 0x2A04)
+REG32(SSPINT160_169_EN, 0x2B00)
+REG32(SSPINT160_169_STATUS, 0x2B04)
+
+/*
+ * SSP INTCIO Registers
+ */
+REG32(SSPINT160_EN, 0x180)
+REG32(SSPINT160_STATUS, 0x184)
+REG32(SSPINT161_EN, 0x190)
+REG32(SSPINT161_STATUS, 0x194)
+REG32(SSPINT162_EN, 0x1A0)
+REG32(SSPINT162_STATUS, 0x1A4)
+REG32(SSPINT163_EN, 0x1B0)
+REG32(SSPINT163_STATUS, 0x1B4)
+REG32(SSPINT164_EN, 0x1C0)
+REG32(SSPINT164_STATUS, 0x1C4)
+REG32(SSPINT165_EN, 0x1D0)
+REG32(SSPINT165_STATUS, 0x1D4)
+
+/*
+ * TSP INTC Registers
+ */
+REG32(TSPINT128_EN, 0x3000)
+REG32(TSPINT128_STATUS, 0x3004)
+REG32(TSPINT129_EN, 0x3100)
+REG32(TSPINT129_STATUS, 0x3104)
+REG32(TSPINT130_EN, 0x3200)
+REG32(TSPINT130_STATUS, 0x3204)
+REG32(TSPINT131_EN, 0x3300)
+REG32(TSPINT131_STATUS, 0x3304)
+REG32(TSPINT132_EN, 0x3400)
+REG32(TSPINT132_STATUS, 0x3404)
+REG32(TSPINT133_EN, 0x3500)
+REG32(TSPINT133_STATUS, 0x3504)
+REG32(TSPINT134_EN, 0x3600)
+REG32(TSPINT134_STATUS, 0x3604)
+REG32(TSPINT135_EN, 0x3700)
+REG32(TSPINT135_STATUS, 0x3704)
+REG32(TSPINT136_EN, 0x3800)
+REG32(TSPINT136_STATUS, 0x3804)
+REG32(TSPINT137_EN, 0x3900)
+REG32(TSPINT137_STATUS, 0x3904)
+REG32(TSPINT138_EN, 0x3A00)
+REG32(TSPINT138_STATUS, 0x3A04)
+REG32(TSPINT160_169_EN, 0x3B00)
+REG32(TSPINT160_169_STATUS, 0x3B04)
+
+/*
+ * TSP INTCIO Registers
+ */
+
+REG32(TSPINT160_EN, 0x200)
+REG32(TSPINT160_STATUS, 0x204)
+REG32(TSPINT161_EN, 0x210)
+REG32(TSPINT161_STATUS, 0x214)
+REG32(TSPINT162_EN, 0x220)
+REG32(TSPINT162_STATUS, 0x224)
+REG32(TSPINT163_EN, 0x230)
+REG32(TSPINT163_STATUS, 0x234)
+REG32(TSPINT164_EN, 0x240)
+REG32(TSPINT164_STATUS, 0x244)
+REG32(TSPINT165_EN, 0x250)
+REG32(TSPINT165_STATUS, 0x254)
+
+static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic,
+ uint32_t reg)
+{
+ int i;
+
+ for (i = 0; i < aic->irq_table_count; i++) {
+ if (aic->irq_table[i].enable_reg == reg ||
+ aic->irq_table[i].status_reg == reg) {
+ return &aic->irq_table[i];
+ }
+ }
+
+ /*
+ * Invalid reg.
+ */
+ g_assert_not_reached();
+}
+
+/*
+ * Update the state of an interrupt controller pin by setting
+ * the specified output pin to the given level.
+ * The input pin index should be between 0 and the number of input pins.
+ * The output pin index should be between 0 and the number of output pins.
+ */
+static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx,
+ int outpin_idx, int level)
{
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
+ const char *name = object_get_typename(OBJECT(s));
- if (irq >= aic->num_ints) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
- __func__, irq);
- return;
+ assert((outpin_idx < aic->num_outpins) && (inpin_idx < aic->num_inpins));
+
+ trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level);
+ qemu_set_irq(s->output_pins[outpin_idx], level);
+}
+
+static void aspeed_intc_set_irq_handler(AspeedINTCState *s,
+ const AspeedINTCIRQ *intc_irq,
+ uint32_t select)
+{
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t status_reg;
+ int outpin_idx;
+ int inpin_idx;
+
+ status_reg = intc_irq->status_reg;
+ outpin_idx = intc_irq->outpin_idx;
+ inpin_idx = intc_irq->inpin_idx;
+
+ if ((s->mask[inpin_idx] & select) || (s->regs[status_reg] & select)) {
+ /*
+ * a. mask is not 0 means in ISR mode
+ * sources interrupt routine are executing.
+ * b. status register value is not 0 means previous
+ * source interrupt does not be executed, yet.
+ *
+ * save source interrupt to pending variable.
+ */
+ s->pending[inpin_idx] |= select;
+ trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]);
+ } else {
+ /*
+ * notify firmware which source interrupt are coming
+ * by setting status register
+ */
+ s->regs[status_reg] = select;
+ trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
+ s->regs[status_reg]);
+ aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
}
+}
+
+static void aspeed_intc_set_irq_handler_multi_outpins(AspeedINTCState *s,
+ const AspeedINTCIRQ *intc_irq, uint32_t select)
+{
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t status_reg;
+ int num_outpins;
+ int outpin_idx;
+ int inpin_idx;
+ int i;
+
+ num_outpins = intc_irq->num_outpins;
+ status_reg = intc_irq->status_reg;
+ outpin_idx = intc_irq->outpin_idx;
+ inpin_idx = intc_irq->inpin_idx;
- trace_aspeed_intc_update_irq(irq, level);
- qemu_set_irq(s->output_pins[irq], level);
+ for (i = 0; i < num_outpins; i++) {
+ if (select & BIT(i)) {
+ if (s->mask[inpin_idx] & BIT(i) ||
+ s->regs[status_reg] & BIT(i)) {
+ /*
+ * a. mask bit is not 0 means in ISR mode sources interrupt
+ * routine are executing.
+ * b. status bit is not 0 means previous source interrupt
+ * does not be executed, yet.
+ *
+ * save source interrupt to pending bit.
+ */
+ s->pending[inpin_idx] |= BIT(i);
+ trace_aspeed_intc_pending_irq(name, inpin_idx,
+ s->pending[inpin_idx]);
+ } else {
+ /*
+ * notify firmware which source interrupt are coming
+ * by setting status bit
+ */
+ s->regs[status_reg] |= BIT(i);
+ trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
+ s->regs[status_reg]);
+ aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
+ }
+ }
+ }
}
/*
- * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
- * Utilize "address & 0x0f00" to get the irq and irq output pin index
- * The value of irq should be 0 to num_ints.
- * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
+ * GICINT192_201 maps 1:10 to input IRQ 0 and output IRQs 0 to 9.
+ * GICINT128 to GICINT136 map 1:1 to input IRQs 1 to 9 and output
+ * IRQs 10 to 18. The value of input IRQ should be between 0 and
+ * the number of input pins.
*/
static void aspeed_intc_set_irq(void *opaque, int irq, int level)
{
AspeedINTCState *s = (AspeedINTCState *)opaque;
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
- uint32_t status_addr = GICINT_STATUS_BASE + ((0x100 * irq) >> 2);
+ const char *name = object_get_typename(OBJECT(s));
+ const AspeedINTCIRQ *intc_irq;
uint32_t select = 0;
uint32_t enable;
+ int num_outpins;
+ int inpin_idx;
int i;
- if (irq >= aic->num_ints) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
- __func__, irq);
- return;
- }
+ assert(irq < aic->num_inpins);
- trace_aspeed_intc_set_irq(irq, level);
- enable = s->enable[irq];
+ intc_irq = &aic->irq_table[irq];
+ num_outpins = intc_irq->num_outpins;
+ inpin_idx = intc_irq->inpin_idx;
+ trace_aspeed_intc_set_irq(name, inpin_idx, level);
+ enable = s->enable[inpin_idx];
if (!level) {
return;
}
for (i = 0; i < aic->num_lines; i++) {
- if (s->orgates[irq].levels[i]) {
+ if (s->orgates[inpin_idx].levels[i]) {
if (enable & BIT(i)) {
select |= BIT(i);
}
@@ -90,45 +309,190 @@ static void aspeed_intc_set_irq(void *opaque, int irq, int level)
return;
}
- trace_aspeed_intc_select(select);
+ trace_aspeed_intc_select(name, select);
+ if (num_outpins > 1) {
+ aspeed_intc_set_irq_handler_multi_outpins(s, intc_irq, select);
+ } else {
+ aspeed_intc_set_irq_handler(s, intc_irq, select);
+ }
+}
- if (s->mask[irq] || s->regs[status_addr]) {
- /*
- * a. mask is not 0 means in ISR mode
- * sources interrupt routine are executing.
- * b. status register value is not 0 means previous
- * source interrupt does not be executed, yet.
- *
- * save source interrupt to pending variable.
- */
- s->pending[irq] |= select;
- trace_aspeed_intc_pending_irq(irq, s->pending[irq]);
+static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
+ uint64_t data)
+{
+ AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
+ const char *name = object_get_typename(OBJECT(s));
+ const AspeedINTCIRQ *intc_irq;
+ uint32_t reg = offset >> 2;
+ uint32_t old_enable;
+ uint32_t change;
+ int inpin_idx;
+
+ intc_irq = aspeed_intc_get_irq(aic, reg);
+ inpin_idx = intc_irq->inpin_idx;
+
+ assert(inpin_idx < aic->num_inpins);
+
+ /*
+ * The enable registers are used to enable source interrupts.
+ * They also handle masking and unmasking of source interrupts
+ * during the execution of the source ISR.
+ */
+
+ /* disable all source interrupt */
+ if (!data && !s->enable[inpin_idx]) {
+ s->regs[reg] = data;
+ return;
+ }
+
+ old_enable = s->enable[inpin_idx];
+ s->enable[inpin_idx] |= data;
+
+ /* enable new source interrupt */
+ if (old_enable != s->enable[inpin_idx]) {
+ trace_aspeed_intc_enable(name, s->enable[inpin_idx]);
+ s->regs[reg] = data;
+ return;
+ }
+
+ /* mask and unmask source interrupt */
+ change = s->regs[reg] ^ data;
+ if (change & data) {
+ s->mask[inpin_idx] &= ~change;
+ trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]);
} else {
- /*
- * notify firmware which source interrupt are coming
- * by setting status register
- */
- s->regs[status_addr] = select;
- trace_aspeed_intc_trigger_irq(irq, s->regs[status_addr]);
- aspeed_intc_update(s, irq, 1);
+ s->mask[inpin_idx] |= change;
+ trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]);
+ }
+
+ s->regs[reg] = data;
+}
+
+static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
+ uint64_t data)
+{
+ AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
+ const char *name = object_get_typename(OBJECT(s));
+ const AspeedINTCIRQ *intc_irq;
+ uint32_t reg = offset >> 2;
+ int outpin_idx;
+ int inpin_idx;
+
+ if (!data) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
+ return;
+ }
+
+ intc_irq = aspeed_intc_get_irq(aic, reg);
+ outpin_idx = intc_irq->outpin_idx;
+ inpin_idx = intc_irq->inpin_idx;
+
+ assert(inpin_idx < aic->num_inpins);
+
+ /* clear status */
+ s->regs[reg] &= ~data;
+
+ /*
+ * These status registers are used for notify sources ISR are executed.
+ * If one source ISR is executed, it will clear one bit.
+ * If it clear all bits, it means to initialize this register status
+ * rather than sources ISR are executed.
+ */
+ if (data == 0xffffffff) {
+ return;
+ }
+
+ /* All source ISR execution are done */
+ if (!s->regs[reg]) {
+ trace_aspeed_intc_all_isr_done(name, inpin_idx);
+ if (s->pending[inpin_idx]) {
+ /*
+ * handle pending source interrupt
+ * notify firmware which source interrupt are pending
+ * by setting status register
+ */
+ s->regs[reg] = s->pending[inpin_idx];
+ s->pending[inpin_idx] = 0;
+ trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
+ s->regs[reg]);
+ aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
+ } else {
+ /* clear irq */
+ trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0);
+ aspeed_intc_update(s, inpin_idx, outpin_idx, 0);
+ }
+ }
+}
+
+static void aspeed_intc_status_handler_multi_outpins(AspeedINTCState *s,
+ hwaddr offset, uint64_t data)
+{
+ const char *name = object_get_typename(OBJECT(s));
+ AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
+ const AspeedINTCIRQ *intc_irq;
+ uint32_t reg = offset >> 2;
+ int num_outpins;
+ int outpin_idx;
+ int inpin_idx;
+ int i;
+
+ if (!data) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
+ return;
+ }
+
+ intc_irq = aspeed_intc_get_irq(aic, reg);
+ num_outpins = intc_irq->num_outpins;
+ outpin_idx = intc_irq->outpin_idx;
+ inpin_idx = intc_irq->inpin_idx;
+ assert(inpin_idx < aic->num_inpins);
+
+ /* clear status */
+ s->regs[reg] &= ~data;
+
+ /*
+ * The status registers are used for notify sources ISR are executed.
+ * If one source ISR is executed, it will clear one bit.
+ * If it clear all bits, it means to initialize this register status
+ * rather than sources ISR are executed.
+ */
+ if (data == 0xffffffff) {
+ return;
+ }
+
+ for (i = 0; i < num_outpins; i++) {
+ /* All source ISR executions are done from a specific bit */
+ if (data & BIT(i)) {
+ trace_aspeed_intc_all_isr_done_bit(name, inpin_idx, i);
+ if (s->pending[inpin_idx] & BIT(i)) {
+ /*
+ * Handle pending source interrupt.
+ * Notify firmware which source interrupt is pending
+ * by setting the status bit.
+ */
+ s->regs[reg] |= BIT(i);
+ s->pending[inpin_idx] &= ~BIT(i);
+ trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
+ s->regs[reg]);
+ aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
+ } else {
+ /* clear irq for the specific bit */
+ trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx + i, 0);
+ aspeed_intc_update(s, inpin_idx, outpin_idx + i, 0);
+ }
+ }
}
}
static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
{
AspeedINTCState *s = ASPEED_INTC(opaque);
- uint32_t addr = offset >> 2;
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
uint32_t value = 0;
- if (addr >= ASPEED_INTC_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
- return 0;
- }
-
- value = s->regs[addr];
- trace_aspeed_intc_read(offset, size, value);
+ value = s->regs[reg];
+ trace_aspeed_intc_read(name, offset, size, value);
return value;
}
@@ -137,22 +501,12 @@ static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
AspeedINTCState *s = ASPEED_INTC(opaque);
- AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
- uint32_t addr = offset >> 2;
- uint32_t old_enable;
- uint32_t change;
- uint32_t irq;
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
- if (addr >= ASPEED_INTC_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
- return;
- }
-
- trace_aspeed_intc_write(offset, size, data);
+ trace_aspeed_intc_write(name, offset, size, data);
- switch (addr) {
+ switch (reg) {
case R_GICINT128_EN:
case R_GICINT129_EN:
case R_GICINT130_EN:
@@ -162,45 +516,8 @@ static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
case R_GICINT134_EN:
case R_GICINT135_EN:
case R_GICINT136_EN:
- irq = (offset & 0x0f00) >> 8;
-
- if (irq >= aic->num_ints) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
- __func__, irq);
- return;
- }
-
- /*
- * These registers are used for enable sources interrupt and
- * mask and unmask source interrupt while executing source ISR.
- */
-
- /* disable all source interrupt */
- if (!data && !s->enable[irq]) {
- s->regs[addr] = data;
- return;
- }
-
- old_enable = s->enable[irq];
- s->enable[irq] |= data;
-
- /* enable new source interrupt */
- if (old_enable != s->enable[irq]) {
- trace_aspeed_intc_enable(s->enable[irq]);
- s->regs[addr] = data;
- return;
- }
-
- /* mask and unmask source interrupt */
- change = s->regs[addr] ^ data;
- if (change & data) {
- s->mask[irq] &= ~change;
- trace_aspeed_intc_unmask(change, s->mask[irq]);
- } else {
- s->mask[irq] |= change;
- trace_aspeed_intc_mask(change, s->mask[irq]);
- }
- s->regs[addr] = data;
+ case R_GICINT192_201_EN:
+ aspeed_intc_enable_handler(s, offset, data);
break;
case R_GICINT128_STATUS:
case R_GICINT129_STATUS:
@@ -211,59 +528,271 @@ static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
case R_GICINT134_STATUS:
case R_GICINT135_STATUS:
case R_GICINT136_STATUS:
- irq = (offset & 0x0f00) >> 8;
+ aspeed_intc_status_handler(s, offset, data);
+ break;
+ case R_GICINT192_201_STATUS:
+ aspeed_intc_status_handler_multi_outpins(s, offset, data);
+ break;
+ default:
+ s->regs[reg] = data;
+ break;
+ }
+}
- if (irq >= aic->num_ints) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
- __func__, irq);
- return;
- }
+static void aspeed_ssp_intc_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ AspeedINTCState *s = ASPEED_INTC(opaque);
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
- /* clear status */
- s->regs[addr] &= ~data;
+ trace_aspeed_intc_write(name, offset, size, data);
- /*
- * These status registers are used for notify sources ISR are executed.
- * If one source ISR is executed, it will clear one bit.
- * If it clear all bits, it means to initialize this register status
- * rather than sources ISR are executed.
- */
- if (data == 0xffffffff) {
- return;
- }
+ switch (reg) {
+ case R_SSPINT128_EN:
+ case R_SSPINT129_EN:
+ case R_SSPINT130_EN:
+ case R_SSPINT131_EN:
+ case R_SSPINT132_EN:
+ case R_SSPINT133_EN:
+ case R_SSPINT134_EN:
+ case R_SSPINT135_EN:
+ case R_SSPINT136_EN:
+ case R_SSPINT160_169_EN:
+ aspeed_intc_enable_handler(s, offset, data);
+ break;
+ case R_SSPINT128_STATUS:
+ case R_SSPINT129_STATUS:
+ case R_SSPINT130_STATUS:
+ case R_SSPINT131_STATUS:
+ case R_SSPINT132_STATUS:
+ case R_SSPINT133_STATUS:
+ case R_SSPINT134_STATUS:
+ case R_SSPINT135_STATUS:
+ case R_SSPINT136_STATUS:
+ aspeed_intc_status_handler(s, offset, data);
+ break;
+ case R_SSPINT160_169_STATUS:
+ aspeed_intc_status_handler_multi_outpins(s, offset, data);
+ break;
+ default:
+ s->regs[reg] = data;
+ break;
+ }
+}
- /* All source ISR execution are done */
- if (!s->regs[addr]) {
- trace_aspeed_intc_all_isr_done(irq);
- if (s->pending[irq]) {
- /*
- * handle pending source interrupt
- * notify firmware which source interrupt are pending
- * by setting status register
- */
- s->regs[addr] = s->pending[irq];
- s->pending[irq] = 0;
- trace_aspeed_intc_trigger_irq(irq, s->regs[addr]);
- aspeed_intc_update(s, irq, 1);
- } else {
- /* clear irq */
- trace_aspeed_intc_clear_irq(irq, 0);
- aspeed_intc_update(s, irq, 0);
- }
- }
+static void aspeed_tsp_intc_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ AspeedINTCState *s = ASPEED_INTC(opaque);
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
+
+ trace_aspeed_intc_write(name, offset, size, data);
+
+ switch (reg) {
+ case R_TSPINT128_EN:
+ case R_TSPINT129_EN:
+ case R_TSPINT130_EN:
+ case R_TSPINT131_EN:
+ case R_TSPINT132_EN:
+ case R_TSPINT133_EN:
+ case R_TSPINT134_EN:
+ case R_TSPINT135_EN:
+ case R_TSPINT136_EN:
+ case R_TSPINT160_169_EN:
+ aspeed_intc_enable_handler(s, offset, data);
+ break;
+ case R_TSPINT128_STATUS:
+ case R_TSPINT129_STATUS:
+ case R_TSPINT130_STATUS:
+ case R_TSPINT131_STATUS:
+ case R_TSPINT132_STATUS:
+ case R_TSPINT133_STATUS:
+ case R_TSPINT134_STATUS:
+ case R_TSPINT135_STATUS:
+ case R_TSPINT136_STATUS:
+ aspeed_intc_status_handler(s, offset, data);
+ break;
+ case R_TSPINT160_169_STATUS:
+ aspeed_intc_status_handler_multi_outpins(s, offset, data);
break;
default:
- s->regs[addr] = data;
+ s->regs[reg] = data;
break;
}
+}
- return;
+static uint64_t aspeed_intcio_read(void *opaque, hwaddr offset,
+ unsigned int size)
+{
+ AspeedINTCState *s = ASPEED_INTC(opaque);
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
+ uint32_t value = 0;
+
+ value = s->regs[reg];
+ trace_aspeed_intc_read(name, offset, size, value);
+
+ return value;
+}
+
+static void aspeed_intcio_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ AspeedINTCState *s = ASPEED_INTC(opaque);
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
+
+ trace_aspeed_intc_write(name, offset, size, data);
+
+ switch (reg) {
+ case R_GICINT192_EN:
+ case R_GICINT193_EN:
+ case R_GICINT194_EN:
+ case R_GICINT195_EN:
+ case R_GICINT196_EN:
+ case R_GICINT197_EN:
+ aspeed_intc_enable_handler(s, offset, data);
+ break;
+ case R_GICINT192_STATUS:
+ case R_GICINT193_STATUS:
+ case R_GICINT194_STATUS:
+ case R_GICINT195_STATUS:
+ case R_GICINT196_STATUS:
+ case R_GICINT197_STATUS:
+ aspeed_intc_status_handler(s, offset, data);
+ break;
+ default:
+ s->regs[reg] = data;
+ break;
+ }
+}
+
+static void aspeed_ssp_intcio_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ AspeedINTCState *s = ASPEED_INTC(opaque);
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
+
+ trace_aspeed_intc_write(name, offset, size, data);
+
+ switch (reg) {
+ case R_SSPINT160_EN:
+ case R_SSPINT161_EN:
+ case R_SSPINT162_EN:
+ case R_SSPINT163_EN:
+ case R_SSPINT164_EN:
+ case R_SSPINT165_EN:
+ aspeed_intc_enable_handler(s, offset, data);
+ break;
+ case R_SSPINT160_STATUS:
+ case R_SSPINT161_STATUS:
+ case R_SSPINT162_STATUS:
+ case R_SSPINT163_STATUS:
+ case R_SSPINT164_STATUS:
+ case R_SSPINT165_STATUS:
+ aspeed_intc_status_handler(s, offset, data);
+ break;
+ default:
+ s->regs[reg] = data;
+ break;
+ }
+}
+
+static void aspeed_tsp_intcio_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ AspeedINTCState *s = ASPEED_INTC(opaque);
+ const char *name = object_get_typename(OBJECT(s));
+ uint32_t reg = offset >> 2;
+
+ trace_aspeed_intc_write(name, offset, size, data);
+
+ switch (reg) {
+ case R_TSPINT160_EN:
+ case R_TSPINT161_EN:
+ case R_TSPINT162_EN:
+ case R_TSPINT163_EN:
+ case R_TSPINT164_EN:
+ case R_TSPINT165_EN:
+ aspeed_intc_enable_handler(s, offset, data);
+ break;
+ case R_TSPINT160_STATUS:
+ case R_TSPINT161_STATUS:
+ case R_TSPINT162_STATUS:
+ case R_TSPINT163_STATUS:
+ case R_TSPINT164_STATUS:
+ case R_TSPINT165_STATUS:
+ aspeed_intc_status_handler(s, offset, data);
+ break;
+ default:
+ s->regs[reg] = data;
+ break;
+ }
}
static const MemoryRegionOps aspeed_intc_ops = {
.read = aspeed_intc_read,
.write = aspeed_intc_write,
.endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ }
+};
+
+static const MemoryRegionOps aspeed_intcio_ops = {
+ .read = aspeed_intcio_read,
+ .write = aspeed_intcio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ }
+};
+
+static const MemoryRegionOps aspeed_ssp_intc_ops = {
+ .read = aspeed_intc_read,
+ .write = aspeed_ssp_intc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ }
+};
+
+static const MemoryRegionOps aspeed_ssp_intcio_ops = {
+ .read = aspeed_intcio_read,
+ .write = aspeed_ssp_intcio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ }
+};
+
+static const MemoryRegionOps aspeed_tsp_intc_ops = {
+ .read = aspeed_intc_read,
+ .write = aspeed_tsp_intc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ }
+};
+
+static const MemoryRegionOps aspeed_tsp_intcio_ops = {
+ .read = aspeed_intcio_read,
+ .write = aspeed_tsp_intcio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -276,8 +805,8 @@ static void aspeed_intc_instance_init(Object *obj)
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
int i;
- assert(aic->num_ints <= ASPEED_INTC_NR_INTS);
- for (i = 0; i < aic->num_ints; i++) {
+ assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS);
+ for (i = 0; i < aic->num_inpins; i++) {
object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
@@ -288,8 +817,9 @@ static void aspeed_intc_instance_init(Object *obj)
static void aspeed_intc_reset(DeviceState *dev)
{
AspeedINTCState *s = ASPEED_INTC(dev);
+ AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
- memset(s->regs, 0, sizeof(s->regs));
+ memset(s->regs, 0, aic->nr_regs << 2);
memset(s->enable, 0, sizeof(s->enable));
memset(s->mask, 0, sizeof(s->mask));
memset(s->pending, 0, sizeof(s->pending));
@@ -302,28 +832,51 @@ static void aspeed_intc_realize(DeviceState *dev, Error **errp)
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
int i;
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
- TYPE_ASPEED_INTC ".regs", ASPEED_INTC_NR_REGS << 2);
+ memory_region_init(&s->iomem_container, OBJECT(s),
+ TYPE_ASPEED_INTC ".container", aic->mem_size);
+
+ sysbus_init_mmio(sbd, &s->iomem_container);
+
+ s->regs = g_new(uint32_t, aic->nr_regs);
+ memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s,
+ TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
- sysbus_init_mmio(sbd, &s->iomem);
- qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints);
+ memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
+ &s->iomem);
- for (i = 0; i < aic->num_ints; i++) {
+ qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins);
+
+ for (i = 0; i < aic->num_inpins; i++) {
if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
return;
}
+ }
+
+ for (i = 0; i < aic->num_outpins; i++) {
sysbus_init_irq(sbd, &s->output_pins[i]);
}
}
-static void aspeed_intc_class_init(ObjectClass *klass, void *data)
+static void aspeed_intc_unrealize(DeviceState *dev)
+{
+ AspeedINTCState *s = ASPEED_INTC(dev);
+
+ g_free(s->regs);
+ s->regs = NULL;
+}
+
+static void aspeed_intc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
dc->desc = "ASPEED INTC Controller";
dc->realize = aspeed_intc_realize;
- dc->reset = aspeed_intc_reset;
+ dc->unrealize = aspeed_intc_unrealize;
+ device_class_set_legacy_reset(dc, aspeed_intc_reset);
dc->vmsd = NULL;
+
+ aic->reg_ops = &aspeed_intc_ops;
}
static const TypeInfo aspeed_intc_info = {
@@ -336,14 +889,33 @@ static const TypeInfo aspeed_intc_info = {
.abstract = true,
};
-static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
+static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
+ {0, 0, 10, R_GICINT192_201_EN, R_GICINT192_201_STATUS},
+ {1, 10, 1, R_GICINT128_EN, R_GICINT128_STATUS},
+ {2, 11, 1, R_GICINT129_EN, R_GICINT129_STATUS},
+ {3, 12, 1, R_GICINT130_EN, R_GICINT130_STATUS},
+ {4, 13, 1, R_GICINT131_EN, R_GICINT131_STATUS},
+ {5, 14, 1, R_GICINT132_EN, R_GICINT132_STATUS},
+ {6, 15, 1, R_GICINT133_EN, R_GICINT133_STATUS},
+ {7, 16, 1, R_GICINT134_EN, R_GICINT134_STATUS},
+ {8, 17, 1, R_GICINT135_EN, R_GICINT135_STATUS},
+ {9, 18, 1, R_GICINT136_EN, R_GICINT136_STATUS},
+};
+
+static void aspeed_2700_intc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
dc->desc = "ASPEED 2700 INTC Controller";
aic->num_lines = 32;
- aic->num_ints = 9;
+ aic->num_inpins = 10;
+ aic->num_outpins = 19;
+ aic->mem_size = 0x4000;
+ aic->nr_regs = 0xB08 >> 2;
+ aic->reg_offset = 0x1000;
+ aic->irq_table = aspeed_2700_intc_irqs;
+ aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intc_irqs);
}
static const TypeInfo aspeed_2700_intc_info = {
@@ -352,10 +924,185 @@ static const TypeInfo aspeed_2700_intc_info = {
.class_init = aspeed_2700_intc_class_init,
};
+static AspeedINTCIRQ aspeed_2700_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
+ {0, 0, 1, R_GICINT192_EN, R_GICINT192_STATUS},
+ {1, 1, 1, R_GICINT193_EN, R_GICINT193_STATUS},
+ {2, 2, 1, R_GICINT194_EN, R_GICINT194_STATUS},
+ {3, 3, 1, R_GICINT195_EN, R_GICINT195_STATUS},
+ {4, 4, 1, R_GICINT196_EN, R_GICINT196_STATUS},
+ {5, 5, 1, R_GICINT197_EN, R_GICINT197_STATUS},
+};
+
+static void aspeed_2700_intcio_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 INTC IO Controller";
+ aic->num_lines = 32;
+ aic->num_inpins = 6;
+ aic->num_outpins = 6;
+ aic->mem_size = 0x400;
+ aic->nr_regs = 0x58 >> 2;
+ aic->reg_offset = 0x100;
+ aic->reg_ops = &aspeed_intcio_ops;
+ aic->irq_table = aspeed_2700_intcio_irqs;
+ aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intcio_irqs);
+}
+
+static const TypeInfo aspeed_2700_intcio_info = {
+ .name = TYPE_ASPEED_2700_INTCIO,
+ .parent = TYPE_ASPEED_INTC,
+ .class_init = aspeed_2700_intcio_class_init,
+};
+
+static AspeedINTCIRQ aspeed_2700ssp_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
+ {0, 0, 10, R_SSPINT160_169_EN, R_SSPINT160_169_STATUS},
+ {1, 10, 1, R_SSPINT128_EN, R_SSPINT128_STATUS},
+ {2, 11, 1, R_SSPINT129_EN, R_SSPINT129_STATUS},
+ {3, 12, 1, R_SSPINT130_EN, R_SSPINT130_STATUS},
+ {4, 13, 1, R_SSPINT131_EN, R_SSPINT131_STATUS},
+ {5, 14, 1, R_SSPINT132_EN, R_SSPINT132_STATUS},
+ {6, 15, 1, R_SSPINT133_EN, R_SSPINT133_STATUS},
+ {7, 16, 1, R_SSPINT134_EN, R_SSPINT134_STATUS},
+ {8, 17, 1, R_SSPINT135_EN, R_SSPINT135_STATUS},
+ {9, 18, 1, R_SSPINT136_EN, R_SSPINT136_STATUS},
+};
+
+static void aspeed_2700ssp_intc_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 SSP INTC Controller";
+ aic->num_lines = 32;
+ aic->num_inpins = 10;
+ aic->num_outpins = 19;
+ aic->mem_size = 0x4000;
+ aic->nr_regs = 0x2B08 >> 2;
+ aic->reg_offset = 0x0;
+ aic->reg_ops = &aspeed_ssp_intc_ops;
+ aic->irq_table = aspeed_2700ssp_intc_irqs;
+ aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intc_irqs);
+}
+
+static const TypeInfo aspeed_2700ssp_intc_info = {
+ .name = TYPE_ASPEED_2700SSP_INTC,
+ .parent = TYPE_ASPEED_INTC,
+ .class_init = aspeed_2700ssp_intc_class_init,
+};
+
+static AspeedINTCIRQ aspeed_2700ssp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
+ {0, 0, 1, R_SSPINT160_EN, R_SSPINT160_STATUS},
+ {1, 1, 1, R_SSPINT161_EN, R_SSPINT161_STATUS},
+ {2, 2, 1, R_SSPINT162_EN, R_SSPINT162_STATUS},
+ {3, 3, 1, R_SSPINT163_EN, R_SSPINT163_STATUS},
+ {4, 4, 1, R_SSPINT164_EN, R_SSPINT164_STATUS},
+ {5, 5, 1, R_SSPINT165_EN, R_SSPINT165_STATUS},
+};
+
+static void aspeed_2700ssp_intcio_class_init(ObjectClass *klass,
+ const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 SSP INTC IO Controller";
+ aic->num_lines = 32;
+ aic->num_inpins = 6;
+ aic->num_outpins = 6;
+ aic->mem_size = 0x400;
+ aic->nr_regs = 0x1d8 >> 2;
+ aic->reg_offset = 0;
+ aic->reg_ops = &aspeed_ssp_intcio_ops;
+ aic->irq_table = aspeed_2700ssp_intcio_irqs;
+ aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intcio_irqs);
+}
+
+static const TypeInfo aspeed_2700ssp_intcio_info = {
+ .name = TYPE_ASPEED_2700SSP_INTCIO,
+ .parent = TYPE_ASPEED_INTC,
+ .class_init = aspeed_2700ssp_intcio_class_init,
+};
+
+static AspeedINTCIRQ aspeed_2700tsp_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
+ {0, 0, 10, R_TSPINT160_169_EN, R_TSPINT160_169_STATUS},
+ {1, 10, 1, R_TSPINT128_EN, R_TSPINT128_STATUS},
+ {2, 11, 1, R_TSPINT129_EN, R_TSPINT129_STATUS},
+ {3, 12, 1, R_TSPINT130_EN, R_TSPINT130_STATUS},
+ {4, 13, 1, R_TSPINT131_EN, R_TSPINT131_STATUS},
+ {5, 14, 1, R_TSPINT132_EN, R_TSPINT132_STATUS},
+ {6, 15, 1, R_TSPINT133_EN, R_TSPINT133_STATUS},
+ {7, 16, 1, R_TSPINT134_EN, R_TSPINT134_STATUS},
+ {8, 17, 1, R_TSPINT135_EN, R_TSPINT135_STATUS},
+ {9, 18, 1, R_TSPINT136_EN, R_TSPINT136_STATUS},
+};
+
+static void aspeed_2700tsp_intc_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 TSP INTC Controller";
+ aic->num_lines = 32;
+ aic->num_inpins = 10;
+ aic->num_outpins = 19;
+ aic->mem_size = 0x4000;
+ aic->nr_regs = 0x3B08 >> 2;
+ aic->reg_offset = 0;
+ aic->reg_ops = &aspeed_tsp_intc_ops;
+ aic->irq_table = aspeed_2700tsp_intc_irqs;
+ aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intc_irqs);
+}
+
+static const TypeInfo aspeed_2700tsp_intc_info = {
+ .name = TYPE_ASPEED_2700TSP_INTC,
+ .parent = TYPE_ASPEED_INTC,
+ .class_init = aspeed_2700tsp_intc_class_init,
+};
+
+static AspeedINTCIRQ aspeed_2700tsp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
+ {0, 0, 1, R_TSPINT160_EN, R_TSPINT160_STATUS},
+ {1, 1, 1, R_TSPINT161_EN, R_TSPINT161_STATUS},
+ {2, 2, 1, R_TSPINT162_EN, R_TSPINT162_STATUS},
+ {3, 3, 1, R_TSPINT163_EN, R_TSPINT163_STATUS},
+ {4, 4, 1, R_TSPINT164_EN, R_TSPINT164_STATUS},
+ {5, 5, 1, R_TSPINT165_EN, R_TSPINT165_STATUS},
+};
+
+static void aspeed_2700tsp_intcio_class_init(ObjectClass *klass,
+ const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 TSP INTC IO Controller";
+ aic->num_lines = 32;
+ aic->num_inpins = 6;
+ aic->num_outpins = 6;
+ aic->mem_size = 0x400;
+ aic->nr_regs = 0x258 >> 2;
+ aic->reg_offset = 0x0;
+ aic->reg_ops = &aspeed_tsp_intcio_ops;
+ aic->irq_table = aspeed_2700tsp_intcio_irqs;
+ aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intcio_irqs);
+}
+
+static const TypeInfo aspeed_2700tsp_intcio_info = {
+ .name = TYPE_ASPEED_2700TSP_INTCIO,
+ .parent = TYPE_ASPEED_INTC,
+ .class_init = aspeed_2700tsp_intcio_class_init,
+};
+
static void aspeed_intc_register_types(void)
{
type_register_static(&aspeed_intc_info);
type_register_static(&aspeed_2700_intc_info);
+ type_register_static(&aspeed_2700_intcio_info);
+ type_register_static(&aspeed_2700ssp_intc_info);
+ type_register_static(&aspeed_2700ssp_intcio_info);
+ type_register_static(&aspeed_2700tsp_intc_info);
+ type_register_static(&aspeed_2700tsp_intcio_info);
}
type_init(aspeed_intc_register_types);
diff --git a/hw/intc/aspeed_vic.c b/hw/intc/aspeed_vic.c
index ba1d953..7120088 100644
--- a/hw/intc/aspeed_vic.c
+++ b/hw/intc/aspeed_vic.c
@@ -339,11 +339,11 @@ static const VMStateDescription vmstate_aspeed_vic = {
}
};
-static void aspeed_vic_class_init(ObjectClass *klass, void *data)
+static void aspeed_vic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_vic_realize;
- dc->reset = aspeed_vic_reset;
+ device_class_set_legacy_reset(dc, aspeed_vic_reset);
dc->desc = "ASPEED Interrupt Controller (New)";
dc->vmsd = &vmstate_aspeed_vic;
}
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
index 2c2e2b1..55e0a5a 100644
--- a/hw/intc/bcm2835_ic.c
+++ b/hw/intc/bcm2835_ic.c
@@ -219,11 +219,11 @@ static const VMStateDescription vmstate_bcm2835_ic = {
}
};
-static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
+static void bcm2835_ic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_ic_reset;
+ device_class_set_legacy_reset(dc, bcm2835_ic_reset);
dc->vmsd = &vmstate_bcm2835_ic;
}
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
index 81faf03..1c02853 100644
--- a/hw/intc/bcm2836_control.c
+++ b/hw/intc/bcm2836_control.c
@@ -384,11 +384,11 @@ static const VMStateDescription vmstate_bcm2836_control = {
}
};
-static void bcm2836_control_class_init(ObjectClass *klass, void *data)
+static void bcm2836_control_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2836_control_reset;
+ device_class_set_legacy_reset(dc, bcm2836_control_reset);
dc->vmsd = &vmstate_bcm2836_control;
}
diff --git a/hw/intc/etraxfs_pic.c b/hw/intc/etraxfs_pic.c
deleted file mode 100644
index bd37d1c..0000000
--- a/hw/intc/etraxfs_pic.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * QEMU ETRAX Interrupt Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qemu/module.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "qom/object.h"
-
-#define D(x)
-
-#define R_RW_MASK 0
-#define R_R_VECT 1
-#define R_R_MASKED_VECT 2
-#define R_R_NMI 3
-#define R_R_GURU 4
-#define R_MAX 5
-
-#define TYPE_ETRAX_FS_PIC "etraxfs-pic"
-DECLARE_INSTANCE_CHECKER(struct etrax_pic, ETRAX_FS_PIC,
- TYPE_ETRAX_FS_PIC)
-
-struct etrax_pic
-{
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq parent_irq;
- qemu_irq parent_nmi;
- uint32_t regs[R_MAX];
-};
-
-static void pic_update(struct etrax_pic *fs)
-{
- uint32_t vector = 0;
- int i;
-
- fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
-
- /* The ETRAX interrupt controller signals interrupts to the core
- through an interrupt request wire and an irq vector bus. If
- multiple interrupts are simultaneously active it chooses vector
- 0x30 and lets the sw choose the priorities. */
- if (fs->regs[R_R_MASKED_VECT]) {
- uint32_t mv = fs->regs[R_R_MASKED_VECT];
- for (i = 0; i < 31; i++) {
- if (mv & 1) {
- vector = 0x31 + i;
- /* Check for multiple interrupts. */
- if (mv > 1)
- vector = 0x30;
- break;
- }
- mv >>= 1;
- }
- }
-
- qemu_set_irq(fs->parent_irq, vector);
-}
-
-static uint64_t
-pic_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct etrax_pic *fs = opaque;
- uint32_t rval;
-
- rval = fs->regs[addr >> 2];
- D(printf("%s %x=%x\n", __func__, addr, rval));
- return rval;
-}
-
-static void pic_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned int size)
-{
- struct etrax_pic *fs = opaque;
- D(printf("%s addr=%x val=%x\n", __func__, addr, value));
-
- if (addr == R_RW_MASK) {
- fs->regs[R_RW_MASK] = value;
- pic_update(fs);
- }
-}
-
-static const MemoryRegionOps pic_ops = {
- .read = pic_read,
- .write = pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void nmi_handler(void *opaque, int irq, int level)
-{
- struct etrax_pic *fs = (void *)opaque;
- uint32_t mask;
-
- mask = 1 << irq;
- if (level)
- fs->regs[R_R_NMI] |= mask;
- else
- fs->regs[R_R_NMI] &= ~mask;
-
- qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{
- struct etrax_pic *fs = (void *)opaque;
-
- if (irq >= 30) {
- nmi_handler(opaque, irq, level);
- return;
- }
-
- irq -= 1;
- fs->regs[R_R_VECT] &= ~(1 << irq);
- fs->regs[R_R_VECT] |= (!!level << irq);
- pic_update(fs);
-}
-
-static void etraxfs_pic_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- struct etrax_pic *s = ETRAX_FS_PIC(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- qdev_init_gpio_in(dev, irq_handler, 32);
- sysbus_init_irq(sbd, &s->parent_irq);
- sysbus_init_irq(sbd, &s->parent_nmi);
-
- memory_region_init_io(&s->mmio, obj, &pic_ops, s,
- "etraxfs-pic", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->mmio);
-}
-
-static const TypeInfo etraxfs_pic_info = {
- .name = TYPE_ETRAX_FS_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct etrax_pic),
- .instance_init = etraxfs_pic_init,
-};
-
-static void etraxfs_pic_register_types(void)
-{
- type_register_static(&etraxfs_pic_info);
-}
-
-type_init(etraxfs_pic_register_types)
diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c
index f0d310a..ebbe234 100644
--- a/hw/intc/exynos4210_combiner.c
+++ b/hw/intc/exynos4210_combiner.c
@@ -325,16 +325,15 @@ static void exynos4210_combiner_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property exynos4210_combiner_properties[] = {
+static const Property exynos4210_combiner_properties[] = {
DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
+static void exynos4210_combiner_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_combiner_reset;
+ device_class_set_legacy_reset(dc, exynos4210_combiner_reset);
device_class_set_props(dc, exynos4210_combiner_properties);
dc->vmsd = &vmstate_exynos4210_combiner;
}
diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c
index fcca85c..7e2d79d 100644
--- a/hw/intc/exynos4210_gic.c
+++ b/hw/intc/exynos4210_gic.c
@@ -111,12 +111,11 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->dist_container);
}
-static Property exynos4210_gic_properties[] = {
+static const Property exynos4210_gic_properties[] = {
DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
+static void exynos4210_gic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/goldfish_pic.c b/hw/intc/goldfish_pic.c
index 6cc1c69..2359861 100644
--- a/hw/intc/goldfish_pic.c
+++ b/hw/intc/goldfish_pic.c
@@ -181,17 +181,16 @@ static void goldfish_pic_instance_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), goldfish_irq_request, GOLDFISH_PIC_IRQ_NB);
}
-static Property goldfish_pic_properties[] = {
+static const Property goldfish_pic_properties[] = {
DEFINE_PROP_UINT8("index", GoldfishPICState, idx, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void goldfish_pic_class_init(ObjectClass *oc, void *data)
+static void goldfish_pic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
- dc->reset = goldfish_pic_reset;
+ device_class_set_legacy_reset(dc, goldfish_pic_reset);
dc->realize = goldfish_pic_realize;
dc->vmsd = &vmstate_goldfish_pic;
ic->get_statistics = goldfish_pic_get_statistics;
@@ -205,7 +204,7 @@ static const TypeInfo goldfish_pic_info = {
.class_init = goldfish_pic_class_init,
.instance_init = goldfish_pic_instance_init,
.instance_size = sizeof(GoldfishPICState),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
index c6c51a3..e0f2646 100644
--- a/hw/intc/grlib_irqmp.c
+++ b/hw/intc/grlib_irqmp.c
@@ -376,17 +376,16 @@ static void grlib_irqmp_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &irqmp->iomem);
}
-static Property grlib_irqmp_properties[] = {
+static const Property grlib_irqmp_properties[] = {
DEFINE_PROP_UINT32("ncpus", IRQMP, ncpus, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
+static void grlib_irqmp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = grlib_irqmp_realize;
- dc->reset = grlib_irqmp_reset;
+ device_class_set_legacy_reset(dc, grlib_irqmp_reset);
device_class_set_props(dc, grlib_irqmp_properties);
}
diff --git a/hw/intc/heathrow_pic.c b/hw/intc/heathrow_pic.c
index c2946ba..447e8c2 100644
--- a/hw/intc/heathrow_pic.c
+++ b/hw/intc/heathrow_pic.c
@@ -184,11 +184,11 @@ static void heathrow_init(Object *obj)
sysbus_init_mmio(sbd, &s->mem);
}
-static void heathrow_class_init(ObjectClass *oc, void *data)
+static void heathrow_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = heathrow_reset;
+ device_class_set_legacy_reset(dc, heathrow_reset);
dc->vmsd = &vmstate_heathrow;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index bbae2d8..b6f96bf 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -32,10 +32,7 @@
#include "trace.h"
#include "qom/object.h"
-/* debug PIC */
-//#define DEBUG_PIC
-
-//#define DEBUG_IRQ_LATENCY
+/*#define DEBUG_IRQ_LATENCY*/
#define TYPE_I8259 "isa-i8259"
typedef struct PICClass PICClass;
@@ -436,13 +433,13 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq_in)
return irq_set;
}
-static void i8259_class_init(ObjectClass *klass, void *data)
+static void i8259_class_init(ObjectClass *klass, const void *data)
{
PICClass *k = PIC_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_parent_realize(dc, pic_realize, &k->parent_realize);
- dc->reset = pic_reset;
+ device_class_set_legacy_reset(dc, pic_reset);
}
static const TypeInfo i8259_info = {
diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c
index d9558e3..602e44c 100644
--- a/hw/intc/i8259_common.c
+++ b/hw/intc/i8259_common.c
@@ -193,15 +193,14 @@ static const VMStateDescription vmstate_pic_common = {
}
};
-static Property pic_properties_common[] = {
+static const Property pic_properties_common[] = {
DEFINE_PROP_UINT32("iobase", PICCommonState, iobase, -1),
DEFINE_PROP_UINT32("elcr_addr", PICCommonState, elcr_addr, -1),
DEFINE_PROP_UINT8("elcr_mask", PICCommonState, elcr_mask, -1),
DEFINE_PROP_BIT("master", PICCommonState, master, 0, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pic_common_class_init(ObjectClass *klass, void *data)
+static void pic_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
@@ -227,7 +226,7 @@ static const TypeInfo pic_common_type = {
.class_size = sizeof(PICCommonClass),
.class_init = pic_common_class_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c
index aedc708..09c3bfa 100644
--- a/hw/intc/imx_avic.c
+++ b/hw/intc/imx_avic.c
@@ -341,12 +341,12 @@ static void imx_avic_init(Object *obj)
}
-static void imx_avic_class_init(ObjectClass *klass, void *data)
+static void imx_avic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_imx_avic;
- dc->reset = imx_avic_reset;
+ device_class_set_legacy_reset(dc, imx_avic_reset);
dc->desc = "i.MX Advanced Vector Interrupt Controller";
}
diff --git a/hw/intc/imx_gpcv2.c b/hw/intc/imx_gpcv2.c
index af45e51..58d286c 100644
--- a/hw/intc/imx_gpcv2.c
+++ b/hw/intc/imx_gpcv2.c
@@ -102,11 +102,11 @@ static const VMStateDescription vmstate_imx_gpcv2 = {
},
};
-static void imx_gpcv2_class_init(ObjectClass *klass, void *data)
+static void imx_gpcv2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx_gpcv2_reset;
+ device_class_set_legacy_reset(dc, imx_gpcv2_reset);
dc->vmsd = &vmstate_imx_gpcv2;
dc->desc = "i.MX GPCv2 Module";
}
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 716ffc8..133bef8 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -30,8 +30,8 @@
#include "hw/intc/ioapic_internal.h"
#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
-#include "sysemu/kvm.h"
-#include "sysemu/sysemu.h"
+#include "system/kvm.h"
+#include "system/system.h"
#include "hw/i386/apic-msidef.h"
#include "hw/i386/x86-iommu.h"
#include "trace.h"
@@ -476,12 +476,11 @@ static void ioapic_unrealize(DeviceState *dev)
timer_free(s->delayed_ioapic_service_timer);
}
-static Property ioapic_properties[] = {
+static const Property ioapic_properties[] = {
DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ioapic_class_init(ObjectClass *klass, void *data)
+static void ioapic_class_init(ObjectClass *klass, const void *data)
{
IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -493,7 +492,7 @@ static void ioapic_class_init(ObjectClass *klass, void *data)
* migration, otherwise first 24 gsi routes will be invalid.
*/
k->post_load = ioapic_update_kvm_routes;
- dc->reset = ioapic_reset_common;
+ device_class_set_legacy_reset(dc, ioapic_reset_common);
device_class_set_props(dc, ioapic_properties);
}
diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c
index 7698963..fce3486 100644
--- a/hw/intc/ioapic_common.c
+++ b/hw/intc/ioapic_common.c
@@ -197,7 +197,7 @@ static const VMStateDescription vmstate_ioapic_common = {
}
};
-static void ioapic_common_class_init(ObjectClass *klass, void *data)
+static void ioapic_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
@@ -215,7 +215,7 @@ static const TypeInfo ioapic_common_type = {
.class_size = sizeof(IOAPICCommonClass),
.class_init = ioapic_common_class_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
diff --git a/hw/intc/ioapic_internal.h b/hw/intc/ioapic_internal.h
index 37b8565..5120576 100644
--- a/hw/intc/ioapic_internal.h
+++ b/hw/intc/ioapic_internal.h
@@ -22,7 +22,7 @@
#ifndef HW_INTC_IOAPIC_INTERNAL_H
#define HW_INTC_IOAPIC_INTERNAL_H
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/intc/ioapic.h"
#include "hw/sysbus.h"
#include "qemu/notify.h"
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 1e8e011..8b8ac6b 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -10,16 +10,31 @@
#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/irq.h"
-#include "hw/sysbus.h"
#include "hw/loongarch/virt.h"
-#include "hw/qdev-properties.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
+#include "system/kvm.h"
#include "hw/intc/loongarch_extioi.h"
-#include "migration/vmstate.h"
#include "trace.h"
+static int extioi_get_index_from_archid(LoongArchExtIOICommonState *s,
+ uint64_t arch_id)
+{
+ int i;
+
+ for (i = 0; i < s->num_cpu; i++) {
+ if (s->cpu[i].arch_id == arch_id) {
+ break;
+ }
+ }
-static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level)
+ if ((i < s->num_cpu) && s->cpu[i].cpu) {
+ return i;
+ }
+
+ return -1;
+}
+
+static void extioi_update_irq(LoongArchExtIOICommonState *s, int irq, int level)
{
int ipnum, cpu, found, irq_index, irq_mask;
@@ -54,17 +69,12 @@ static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level)
static void extioi_setirq(void *opaque, int irq, int level)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
trace_loongarch_extioi_setirq(irq, level);
if (level) {
- /*
- * s->isr should be used in vmstate structure,
- * but it not support 'unsigned long',
- * so we have to switch it.
- */
- set_bit(irq, (unsigned long *)s->isr);
+ set_bit32(irq, s->isr);
} else {
- clear_bit(irq, (unsigned long *)s->isr);
+ clear_bit32(irq, s->isr);
}
extioi_update_irq(s, irq, level);
}
@@ -72,7 +82,7 @@ static void extioi_setirq(void *opaque, int irq, int level)
static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data,
unsigned size, MemTxAttrs attrs)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
unsigned long offset = addr & 0xffff;
uint32_t index, cpu;
@@ -111,7 +121,7 @@ static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data,
return MEMTX_OK;
}
-static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
+static inline void extioi_enable_irq(LoongArchExtIOICommonState *s, int index,\
uint32_t mask, int level)
{
uint32_t val;
@@ -130,10 +140,10 @@ static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
}
}
-static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
- uint64_t val, bool notify)
+static inline void extioi_update_sw_coremap(LoongArchExtIOICommonState *s,
+ int irq, uint64_t val, bool notify)
{
- int i, cpu;
+ int i, cpu, cpuid;
/*
* loongarch only support little endian,
@@ -142,19 +152,24 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
val = cpu_to_le64(val);
for (i = 0; i < 4; i++) {
- cpu = val & 0xff;
+ cpuid = val & 0xff;
val = val >> 8;
if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) {
- cpu = ctz32(cpu);
- cpu = (cpu >= 4) ? 0 : cpu;
+ cpuid = ctz32(cpuid);
+ cpuid = (cpuid >= 4) ? 0 : cpuid;
+ }
+
+ cpu = extioi_get_index_from_archid(s, cpuid);
+ if (cpu < 0) {
+ continue;
}
if (s->sw_coremap[irq + i] == cpu) {
continue;
}
- if (notify && test_bit(irq + i, (unsigned long *)s->isr)) {
+ if (notify && test_bit32(irq + i, s->isr)) {
/*
* lower irq at old cpu and raise irq at new cpu
*/
@@ -167,8 +182,8 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
}
}
-static inline void extioi_update_sw_ipmap(LoongArchExtIOI *s, int index,
- uint64_t val)
+static inline void extioi_update_sw_ipmap(LoongArchExtIOICommonState *s,
+ int index, uint64_t val)
{
int i;
uint8_t ipnum;
@@ -191,7 +206,7 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
uint64_t val, unsigned size,
MemTxAttrs attrs)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
int cpu, index, old_data, irq;
uint32_t offset;
@@ -271,7 +286,7 @@ static const MemoryRegionOps extioi_ops = {
static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data,
unsigned size, MemTxAttrs attrs)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
switch (addr) {
case EXTIOI_VIRT_FEATURES:
@@ -291,7 +306,7 @@ static MemTxResult extioi_virt_writew(void *opaque, hwaddr addr,
uint64_t val, unsigned size,
MemTxAttrs attrs)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
switch (addr) {
case EXTIOI_VIRT_FEATURES:
@@ -325,65 +340,81 @@ static const MemoryRegionOps extioi_virt_ops = {
static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(dev);
+ LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_GET_CLASS(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i, pin;
+ Error *local_err = NULL;
+ int i;
- if (s->num_cpu == 0) {
- error_setg(errp, "num-cpu must be at least 1");
+ lec->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
- for (i = 0; i < EXTIOI_IRQS; i++) {
- sysbus_init_irq(sbd, &s->irq[i]);
- }
-
- qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
- memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
- s, "extioi_system_mem", 0x900);
- sysbus_init_mmio(sbd, &s->extioi_system_mem);
-
if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
- memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
- s, "extioi_virt", EXTIOI_VIRT_SIZE);
- sysbus_init_mmio(sbd, &s->virt_extend);
s->features |= EXTIOI_VIRT_HAS_FEATURES;
} else {
s->status |= BIT(EXTIOI_ENABLE);
}
- s->cpu = g_new0(ExtIOICore, s->num_cpu);
- if (s->cpu == NULL) {
- error_setg(errp, "Memory allocation for ExtIOICore faile");
- return;
- }
+ if (kvm_irqchip_in_kernel()) {
+ kvm_extioi_realize(dev, errp);
+ } else {
+ for (i = 0; i < EXTIOI_IRQS; i++) {
+ sysbus_init_irq(sbd, &s->irq[i]);
+ }
- for (i = 0; i < s->num_cpu; i++) {
- for (pin = 0; pin < LS3A_INTC_IP; pin++) {
- qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1);
+ qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
+ memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
+ s, "extioi_system_mem", 0x900);
+ sysbus_init_mmio(sbd, &s->extioi_system_mem);
+ if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
+ memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
+ s, "extioi_virt", EXTIOI_VIRT_SIZE);
+ sysbus_init_mmio(sbd, &s->virt_extend);
}
}
}
-static void loongarch_extioi_finalize(Object *obj)
+static void loongarch_extioi_unrealize(DeviceState *dev)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(dev);
g_free(s->cpu);
}
-static void loongarch_extioi_reset(DeviceState *d)
+static void loongarch_extioi_reset_hold(Object *obj, ResetType type)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(d);
+ LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_GET_CLASS(obj);
- s->status = 0;
+ if (lec->parent_phases.hold) {
+ lec->parent_phases.hold(obj, type);
+ }
+
+ if (kvm_irqchip_in_kernel()) {
+ kvm_extioi_put(obj, 0);
+ }
+}
+
+static int vmstate_extioi_pre_save(void *opaque)
+{
+ if (kvm_irqchip_in_kernel()) {
+ return kvm_extioi_get(opaque);
+ }
+
+ return 0;
}
static int vmstate_extioi_post_load(void *opaque, int version_id)
{
- LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
int i, start_irq;
+ if (kvm_irqchip_in_kernel()) {
+ return kvm_extioi_put(opaque, version_id);
+ }
+
for (i = 0; i < (EXTIOI_IRQS / 4); i++) {
start_irq = i * 4;
extioi_update_sw_coremap(s, start_irq, s->coremap[i], false);
@@ -396,66 +427,31 @@ static int vmstate_extioi_post_load(void *opaque, int version_id)
return 0;
}
-static const VMStateDescription vmstate_extioi_core = {
- .name = "extioi-core",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_loongarch_extioi = {
- .name = TYPE_LOONGARCH_EXTIOI,
- .version_id = 3,
- .minimum_version_id = 3,
- .post_load = vmstate_extioi_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
- VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
- EXTIOI_IRQS_NODETYPE_COUNT / 2),
- VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32),
- VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32),
- VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4),
- VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4),
-
- VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOI, num_cpu,
- vmstate_extioi_core, ExtIOICore),
- VMSTATE_UINT32(features, LoongArchExtIOI),
- VMSTATE_UINT32(status, LoongArchExtIOI),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property extioi_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", LoongArchExtIOI, num_cpu, 1),
- DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOI, features,
- EXTIOI_HAS_VIRT_EXTENSION, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
+static void loongarch_extioi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = loongarch_extioi_realize;
- dc->reset = loongarch_extioi_reset;
- device_class_set_props(dc, extioi_properties);
- dc->vmsd = &vmstate_loongarch_extioi;
+ LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_CLASS(klass);
+ LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ device_class_set_parent_realize(dc, loongarch_extioi_realize,
+ &lec->parent_realize);
+ device_class_set_parent_unrealize(dc, loongarch_extioi_unrealize,
+ &lec->parent_unrealize);
+ resettable_class_set_parent_phases(rc, NULL, loongarch_extioi_reset_hold,
+ NULL, &lec->parent_phases);
+ lecc->pre_save = vmstate_extioi_pre_save;
+ lecc->post_load = vmstate_extioi_post_load;
}
-static const TypeInfo loongarch_extioi_info = {
- .name = TYPE_LOONGARCH_EXTIOI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct LoongArchExtIOI),
- .class_init = loongarch_extioi_class_init,
- .instance_finalize = loongarch_extioi_finalize,
+static const TypeInfo loongarch_extioi_types[] = {
+ {
+ .name = TYPE_LOONGARCH_EXTIOI,
+ .parent = TYPE_LOONGARCH_EXTIOI_COMMON,
+ .instance_size = sizeof(LoongArchExtIOIState),
+ .class_size = sizeof(LoongArchExtIOIClass),
+ .class_init = loongarch_extioi_class_init,
+ }
};
-static void loongarch_extioi_register_types(void)
-{
- type_register_static(&loongarch_extioi_info);
-}
-
-type_init(loongarch_extioi_register_types)
+DEFINE_TYPES(loongarch_extioi_types)
diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c
new file mode 100644
index 0000000..4a904b3
--- /dev/null
+++ b/hw/intc/loongarch_extioi_common.c
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongson extioi interrupt controller emulation
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/intc/loongarch_extioi_common.h"
+#include "migration/vmstate.h"
+#include "target/loongarch/cpu.h"
+
+static ExtIOICore *loongarch_extioi_get_cpu(LoongArchExtIOICommonState *s,
+ DeviceState *dev)
+{
+ CPUClass *k = CPU_GET_CLASS(dev);
+ uint64_t arch_id = k->get_arch_id(CPU(dev));
+ int i;
+
+ for (i = 0; i < s->num_cpu; i++) {
+ if (s->cpu[i].arch_id == arch_id) {
+ return &s->cpu[i];
+ }
+ }
+
+ return NULL;
+}
+
+static void loongarch_extioi_cpu_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
+ Object *obj = OBJECT(dev);
+ ExtIOICore *core;
+ int pin, index;
+
+ if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
+ warn_report("LoongArch extioi: Invalid %s device type",
+ object_get_typename(obj));
+ return;
+ }
+
+ core = loongarch_extioi_get_cpu(s, dev);
+ if (!core) {
+ return;
+ }
+
+ core->cpu = CPU(dev);
+ index = core - s->cpu;
+
+ /*
+ * connect extioi irq to the cpu irq
+ * cpu_pin[LS3A_INTC_IP + 2 : 2] <= intc_pin[LS3A_INTC_IP : 0]
+ */
+ for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+ qdev_connect_gpio_out(DEVICE(s), index * LS3A_INTC_IP + pin,
+ qdev_get_gpio_in(dev, pin + 2));
+ }
+}
+
+static void loongarch_extioi_cpu_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
+ Object *obj = OBJECT(dev);
+ ExtIOICore *core;
+
+ if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
+ warn_report("LoongArch extioi: Invalid %s device type",
+ object_get_typename(obj));
+ return;
+ }
+
+ core = loongarch_extioi_get_cpu(s, dev);
+ if (!core) {
+ return;
+ }
+
+ core->cpu = NULL;
+}
+
+static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp)
+{
+ LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)dev;
+ MachineState *machine = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ const CPUArchIdList *id_list;
+ int i, pin;
+
+ assert(mc->possible_cpu_arch_ids);
+ id_list = mc->possible_cpu_arch_ids(machine);
+ s->num_cpu = id_list->len;
+ s->cpu = g_new0(ExtIOICore, s->num_cpu);
+ if (s->cpu == NULL) {
+ error_setg(errp, "Memory allocation for ExtIOICore faile");
+ return;
+ }
+
+ for (i = 0; i < s->num_cpu; i++) {
+ s->cpu[i].arch_id = id_list->cpus[i].arch_id;
+ s->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
+
+ for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+ qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1);
+ }
+ }
+}
+
+static void loongarch_extioi_common_reset_hold(Object *obj, ResetType type)
+{
+ LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(obj);
+ LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(obj);
+ ExtIOICore *core;
+ int i;
+
+ if (lecc->parent_phases.hold) {
+ lecc->parent_phases.hold(obj, type);
+ }
+
+ /* Clear HW registers for the board */
+ memset(s->nodetype, 0, sizeof(s->nodetype));
+ memset(s->bounce, 0, sizeof(s->bounce));
+ memset(s->isr, 0, sizeof(s->isr));
+ memset(s->enable, 0, sizeof(s->enable));
+ memset(s->ipmap, 0, sizeof(s->ipmap));
+ memset(s->coremap, 0, sizeof(s->coremap));
+ memset(s->sw_pending, 0, sizeof(s->sw_pending));
+ memset(s->sw_ipmap, 0, sizeof(s->sw_ipmap));
+ memset(s->sw_coremap, 0, sizeof(s->sw_coremap));
+
+ for (i = 0; i < s->num_cpu; i++) {
+ core = s->cpu + i;
+ /* EXTIOI with targeted CPU available however not present */
+ if (!core->cpu) {
+ continue;
+ }
+
+ /* Clear HW registers for CPUs */
+ memset(core->coreisr, 0, sizeof(core->coreisr));
+ memset(core->sw_isr, 0, sizeof(core->sw_isr));
+ }
+
+ s->status = 0;
+}
+
+static int loongarch_extioi_common_pre_save(void *opaque)
+{
+ LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
+ LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
+
+ if (lecc->pre_save) {
+ return lecc->pre_save(s);
+ }
+
+ return 0;
+}
+
+static int loongarch_extioi_common_post_load(void *opaque, int version_id)
+{
+ LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
+ LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
+
+ if (lecc->post_load) {
+ return lecc->post_load(s, version_id);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_extioi_core = {
+ .name = "extioi-core",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_loongarch_extioi = {
+ .name = "loongarch.extioi",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .pre_save = loongarch_extioi_common_pre_save,
+ .post_load = loongarch_extioi_common_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOICommonState,
+ EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOICommonState,
+ EXTIOI_IRQS_NODETYPE_COUNT / 2),
+ VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOICommonState,
+ EXTIOI_IRQS / 32),
+ VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOICommonState,
+ EXTIOI_IRQS / 32),
+ VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOICommonState,
+ EXTIOI_IRQS_IPMAP_SIZE / 4),
+ VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOICommonState,
+ EXTIOI_IRQS / 4),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOICommonState,
+ num_cpu, vmstate_extioi_core, ExtIOICore),
+ VMSTATE_UINT32(features, LoongArchExtIOICommonState),
+ VMSTATE_UINT32(status, LoongArchExtIOICommonState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property extioi_properties[] = {
+ DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState,
+ features, EXTIOI_HAS_VIRT_EXTENSION, 0),
+};
+
+static void loongarch_extioi_common_class_init(ObjectClass *klass,
+ const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ device_class_set_parent_realize(dc, loongarch_extioi_common_realize,
+ &lecc->parent_realize);
+ resettable_class_set_parent_phases(rc, NULL,
+ loongarch_extioi_common_reset_hold,
+ NULL, &lecc->parent_phases);
+ device_class_set_props(dc, extioi_properties);
+ dc->vmsd = &vmstate_loongarch_extioi;
+ hc->plug = loongarch_extioi_cpu_plug;
+ hc->unplug = loongarch_extioi_cpu_unplug;
+}
+
+static const TypeInfo loongarch_extioi_common_types[] = {
+ {
+ .name = TYPE_LOONGARCH_EXTIOI_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LoongArchExtIOICommonState),
+ .class_size = sizeof(LoongArchExtIOICommonClass),
+ .class_init = loongarch_extioi_common_class_init,
+ .interfaces = (const InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { }
+ },
+ .abstract = true,
+ }
+};
+
+DEFINE_TYPES(loongarch_extioi_common_types)
diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c
new file mode 100644
index 0000000..0133540
--- /dev/null
+++ b/hw/intc/loongarch_extioi_kvm.c
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch EXTIOI interrupt kvm support
+ *
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/typedefs.h"
+#include "hw/intc/loongarch_extioi.h"
+#include "linux/kvm.h"
+#include "qapi/error.h"
+#include "system/kvm.h"
+
+static void kvm_extioi_access_reg(int fd, uint64_t addr, void *val, bool write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
+ addr, val, write, &error_abort);
+}
+
+static void kvm_extioi_access_sw_state(int fd, uint64_t addr,
+ void *val, bool write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS,
+ addr, val, write, &error_abort);
+}
+
+static void kvm_extioi_access_sw_status(void *opaque, bool write)
+{
+ LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
+ LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
+ int addr;
+
+ addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE;
+ kvm_extioi_access_sw_state(les->dev_fd, addr, &lecs->status, write);
+}
+
+static void kvm_extioi_access_regs(void *opaque, bool write)
+{
+ LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
+ LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
+ int fd = les->dev_fd;
+ int addr, offset, cpu;
+
+ for (addr = EXTIOI_NODETYPE_START; addr < EXTIOI_NODETYPE_END; addr += 4) {
+ offset = (addr - EXTIOI_NODETYPE_START) / 4;
+ kvm_extioi_access_reg(fd, addr, &lecs->nodetype[offset], write);
+ }
+
+ for (addr = EXTIOI_IPMAP_START; addr < EXTIOI_IPMAP_END; addr += 4) {
+ offset = (addr - EXTIOI_IPMAP_START) / 4;
+ kvm_extioi_access_reg(fd, addr, &lecs->ipmap[offset], write);
+ }
+
+ for (addr = EXTIOI_ENABLE_START; addr < EXTIOI_ENABLE_END; addr += 4) {
+ offset = (addr - EXTIOI_ENABLE_START) / 4;
+ kvm_extioi_access_reg(fd, addr, &lecs->enable[offset], write);
+ }
+
+ for (addr = EXTIOI_BOUNCE_START; addr < EXTIOI_BOUNCE_END; addr += 4) {
+ offset = (addr - EXTIOI_BOUNCE_START) / 4;
+ kvm_extioi_access_reg(fd, addr, &lecs->bounce[offset], write);
+ }
+
+ for (addr = EXTIOI_ISR_START; addr < EXTIOI_ISR_END; addr += 4) {
+ offset = (addr - EXTIOI_ISR_START) / 4;
+ kvm_extioi_access_reg(fd, addr, &lecs->isr[offset], write);
+ }
+
+ for (addr = EXTIOI_COREMAP_START; addr < EXTIOI_COREMAP_END; addr += 4) {
+ offset = (addr - EXTIOI_COREMAP_START) / 4;
+ kvm_extioi_access_reg(fd, addr, &lecs->coremap[offset], write);
+ }
+
+ for (cpu = 0; cpu < lecs->num_cpu; cpu++) {
+ for (addr = EXTIOI_COREISR_START;
+ addr < EXTIOI_COREISR_END; addr += 4) {
+ offset = (addr - EXTIOI_COREISR_START) / 4;
+ kvm_extioi_access_reg(fd, (cpu << 16) | addr,
+ &lecs->cpu[cpu].coreisr[offset], write);
+ }
+ }
+}
+
+int kvm_extioi_get(void *opaque)
+{
+ kvm_extioi_access_regs(opaque, false);
+ kvm_extioi_access_sw_status(opaque, false);
+ return 0;
+}
+
+int kvm_extioi_put(void *opaque, int version_id)
+{
+ LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
+ int fd = les->dev_fd;
+
+ if (fd == 0) {
+ return 0;
+ }
+
+ kvm_extioi_access_regs(opaque, true);
+ kvm_extioi_access_sw_status(opaque, true);
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
+ KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED,
+ NULL, true, &error_abort);
+ return 0;
+}
+
+void kvm_extioi_realize(DeviceState *dev, Error **errp)
+{
+ LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev);
+ LoongArchExtIOIState *les = LOONGARCH_EXTIOI(dev);
+ int ret;
+
+ ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_EIOINTC, false);
+ if (ret < 0) {
+ fprintf(stderr, "create KVM_LOONGARCH_EIOINTC failed: %s\n",
+ strerror(-ret));
+ abort();
+ }
+
+ les->dev_fd = ret;
+ ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
+ KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU,
+ &lecs->num_cpu, true, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_NUM_CPU failed: %s\n",
+ strerror(-ret));
+ abort();
+ }
+
+ ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
+ KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE,
+ &lecs->features, true, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_FEATURE failed: %s\n",
+ strerror(-ret));
+ abort();
+ }
+}
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index 2ae1a42..fc8005c 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -6,8 +6,12 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "hw/boards.h"
+#include "qapi/error.h"
#include "hw/intc/loongarch_ipi.h"
+#include "hw/qdev-properties.h"
+#include "system/kvm.h"
#include "target/loongarch/cpu.h"
static AddressSpace *get_iocsr_as(CPUState *cpu)
@@ -15,53 +19,211 @@ static AddressSpace *get_iocsr_as(CPUState *cpu)
return LOONGARCH_CPU(cpu)->env.address_space_iocsr;
}
-static int archid_cmp(const void *a, const void *b)
+static int loongarch_ipi_cmp(const void *a, const void *b)
{
- CPUArchId *archid_a = (CPUArchId *)a;
- CPUArchId *archid_b = (CPUArchId *)b;
+ IPICore *ipi_a = (IPICore *)a;
+ IPICore *ipi_b = (IPICore *)b;
- return archid_a->arch_id - archid_b->arch_id;
+ return ipi_a->arch_id - ipi_b->arch_id;
}
-static CPUArchId *find_cpu_by_archid(MachineState *ms, uint32_t id)
+static int loongarch_cpu_by_arch_id(LoongsonIPICommonState *lics,
+ int64_t arch_id, int *index, CPUState **pcs)
{
- CPUArchId apic_id, *found_cpu;
+ IPICore ipi, *found;
- apic_id.arch_id = id;
- found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
- ms->possible_cpus->len,
- sizeof(*ms->possible_cpus->cpus),
- archid_cmp);
+ ipi.arch_id = arch_id;
+ found = bsearch(&ipi, lics->cpu, lics->num_cpu, sizeof(IPICore),
+ loongarch_ipi_cmp);
+ if (found && found->cpu) {
+ if (index) {
+ *index = found - lics->cpu;
+ }
- return found_cpu;
+ if (pcs) {
+ *pcs = found->cpu;
+ }
+
+ return MEMTX_OK;
+ }
+
+ return MEMTX_ERROR;
}
-static CPUState *loongarch_cpu_by_arch_id(int64_t arch_id)
+static IPICore *loongarch_ipi_get_cpu(LoongsonIPICommonState *lics,
+ DeviceState *dev)
{
- MachineState *machine = MACHINE(qdev_get_machine());
- CPUArchId *archid;
+ CPUClass *k = CPU_GET_CLASS(dev);
+ uint64_t arch_id = k->get_arch_id(CPU(dev));
+ int i;
- archid = find_cpu_by_archid(machine, arch_id);
- if (archid) {
- return CPU(archid->cpu);
+ for (i = 0; i < lics->num_cpu; i++) {
+ if (lics->cpu[i].arch_id == arch_id) {
+ return &lics->cpu[i];
+ }
}
return NULL;
}
-static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
+static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
+{
+ LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(dev);
+ LoongarchIPIClass *lic = LOONGARCH_IPI_GET_CLASS(dev);
+ MachineState *machine = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ const CPUArchIdList *id_list;
+ Error *local_err = NULL;
+ int i;
+
+ lic->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ assert(mc->possible_cpu_arch_ids);
+ id_list = mc->possible_cpu_arch_ids(machine);
+ lics->num_cpu = id_list->len;
+ lics->cpu = g_new0(IPICore, lics->num_cpu);
+ for (i = 0; i < lics->num_cpu; i++) {
+ lics->cpu[i].arch_id = id_list->cpus[i].arch_id;
+ lics->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
+ lics->cpu[i].ipi = lics;
+ qdev_init_gpio_out(dev, &lics->cpu[i].irq, 1);
+ }
+
+ if (kvm_irqchip_in_kernel()) {
+ kvm_ipi_realize(dev, errp);
+ }
+}
+
+static void loongarch_ipi_reset_hold(Object *obj, ResetType type)
+{
+ int i;
+ LoongarchIPIClass *lic = LOONGARCH_IPI_GET_CLASS(obj);
+ LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(obj);
+ IPICore *core;
+
+ if (lic->parent_phases.hold) {
+ lic->parent_phases.hold(obj, type);
+ }
+
+ for (i = 0; i < lics->num_cpu; i++) {
+ core = lics->cpu + i;
+ /* IPI with targeted CPU available however not present */
+ if (!core->cpu) {
+ continue;
+ }
+
+ core->status = 0;
+ core->en = 0;
+ core->set = 0;
+ core->clear = 0;
+ memset(core->buf, 0, sizeof(core->buf));
+ }
+
+ if (kvm_irqchip_in_kernel()) {
+ kvm_ipi_put(obj, 0);
+ }
+}
+
+static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
+ Object *obj = OBJECT(dev);
+ IPICore *core;
+ int index;
+
+ if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
+ warn_report("LoongArch extioi: Invalid %s device type",
+ object_get_typename(obj));
+ return;
+ }
+
+ core = loongarch_ipi_get_cpu(lics, dev);
+ if (!core) {
+ return;
+ }
+
+ core->cpu = CPU(dev);
+ index = core - lics->cpu;
+
+ /* connect ipi irq to cpu irq */
+ qdev_connect_gpio_out(DEVICE(lics), index, qdev_get_gpio_in(dev, IRQ_IPI));
+}
+
+static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
+ Object *obj = OBJECT(dev);
+ IPICore *core;
+
+ if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
+ warn_report("LoongArch extioi: Invalid %s device type",
+ object_get_typename(obj));
+ return;
+ }
+
+ core = loongarch_ipi_get_cpu(lics, dev);
+ if (!core) {
+ return;
+ }
+
+ core->cpu = NULL;
+}
+
+static int loongarch_ipi_pre_save(void *opaque)
+{
+ if (kvm_irqchip_in_kernel()) {
+ return kvm_ipi_get(opaque);
+ }
+
+ return 0;
+}
+
+static int loongarch_ipi_post_load(void *opaque, int version_id)
+{
+ if (kvm_irqchip_in_kernel()) {
+ return kvm_ipi_put(opaque, version_id);
+ }
+
+ return 0;
+}
+
+static void loongarch_ipi_class_init(ObjectClass *klass, const void *data)
{
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
+ LoongarchIPIClass *lic = LOONGARCH_IPI_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ device_class_set_parent_realize(dc, loongarch_ipi_realize,
+ &lic->parent_realize);
+ resettable_class_set_parent_phases(rc, NULL, loongarch_ipi_reset_hold,
+ NULL, &lic->parent_phases);
licc->get_iocsr_as = get_iocsr_as;
licc->cpu_by_arch_id = loongarch_cpu_by_arch_id;
+ hc->plug = loongarch_ipi_cpu_plug;
+ hc->unplug = loongarch_ipi_cpu_unplug;
+ licc->pre_save = loongarch_ipi_pre_save;
+ licc->post_load = loongarch_ipi_post_load;
}
static const TypeInfo loongarch_ipi_types[] = {
{
.name = TYPE_LOONGARCH_IPI,
.parent = TYPE_LOONGSON_IPI_COMMON,
+ .instance_size = sizeof(LoongarchIPIState),
+ .class_size = sizeof(LoongarchIPIClass),
.class_init = loongarch_ipi_class_init,
+ .interfaces = (const InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { }
+ },
}
};
diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c
new file mode 100644
index 0000000..4cb3acc
--- /dev/null
+++ b/hw/intc/loongarch_ipi_kvm.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch IPI interrupt KVM support
+ *
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "system/kvm.h"
+#include "target/loongarch/cpu.h"
+
+static void kvm_ipi_access_reg(int fd, uint64_t addr, uint32_t *val, bool write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS,
+ addr, val, write, &error_abort);
+}
+
+static void kvm_ipi_access_regs(void *opaque, bool write)
+{
+ LoongsonIPICommonState *ipi = (LoongsonIPICommonState *)opaque;
+ LoongarchIPIState *lis = LOONGARCH_IPI(opaque);
+ IPICore *core;
+ uint64_t attr;
+ int cpu, fd = lis->dev_fd;
+
+ if (fd == 0) {
+ return;
+ }
+
+ for (cpu = 0; cpu < ipi->num_cpu; cpu++) {
+ core = &ipi->cpu[cpu];
+ attr = (cpu << 16) | CORE_STATUS_OFF;
+ kvm_ipi_access_reg(fd, attr, &core->status, write);
+
+ attr = (cpu << 16) | CORE_EN_OFF;
+ kvm_ipi_access_reg(fd, attr, &core->en, write);
+
+ attr = (cpu << 16) | CORE_SET_OFF;
+ kvm_ipi_access_reg(fd, attr, &core->set, write);
+
+ attr = (cpu << 16) | CORE_CLEAR_OFF;
+ kvm_ipi_access_reg(fd, attr, &core->clear, write);
+
+ attr = (cpu << 16) | CORE_BUF_20;
+ kvm_ipi_access_reg(fd, attr, &core->buf[0], write);
+
+ attr = (cpu << 16) | CORE_BUF_28;
+ kvm_ipi_access_reg(fd, attr, &core->buf[2], write);
+
+ attr = (cpu << 16) | CORE_BUF_30;
+ kvm_ipi_access_reg(fd, attr, &core->buf[4], write);
+
+ attr = (cpu << 16) | CORE_BUF_38;
+ kvm_ipi_access_reg(fd, attr, &core->buf[6], write);
+ }
+}
+
+int kvm_ipi_get(void *opaque)
+{
+ kvm_ipi_access_regs(opaque, false);
+ return 0;
+}
+
+int kvm_ipi_put(void *opaque, int version_id)
+{
+ kvm_ipi_access_regs(opaque, true);
+ return 0;
+}
+
+void kvm_ipi_realize(DeviceState *dev, Error **errp)
+{
+ LoongarchIPIState *lis = LOONGARCH_IPI(dev);
+ int ret;
+
+ ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_IPI, false);
+ if (ret < 0) {
+ fprintf(stderr, "IPI KVM_CREATE_DEVICE failed: %s\n",
+ strerror(-ret));
+ abort();
+ }
+
+ lis->dev_fd = ret;
+}
diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
index ecf3ed0..f6d1631 100644
--- a/hw/intc/loongarch_pch_msi.c
+++ b/hw/intc/loongarch_pch_msi.c
@@ -13,6 +13,7 @@
#include "hw/pci/msi.h"
#include "hw/misc/unimp.h"
#include "migration/vmstate.h"
+#include "system/kvm.h"
#include "trace.h"
static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
@@ -26,6 +27,15 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque;
int irq_num;
+ if (kvm_irqchip_in_kernel()) {
+ MSIMessage msg;
+
+ msg.address = addr;
+ msg.data = val;
+ kvm_irqchip_send_msi(kvm_state, msg);
+ return;
+ }
+
/*
* vector number is irq number from upper extioi intc
* need subtract irq base to get msi vector offset
@@ -42,13 +52,6 @@ static const MemoryRegionOps loongarch_pch_msi_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void pch_msi_irq_handler(void *opaque, int irq, int level)
-{
- LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
-
- qemu_set_irq(s->pch_msi_irq[irq], level);
-}
-
static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp)
{
LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(dev);
@@ -59,9 +62,7 @@ static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp)
}
s->pch_msi_irq = g_new(qemu_irq, s->irq_num);
-
qdev_init_gpio_out(dev, s->pch_msi_irq, s->irq_num);
- qdev_init_gpio_in(dev, pch_msi_irq_handler, s->irq_num);
}
static void loongarch_pch_msi_unrealize(DeviceState *dev)
@@ -83,13 +84,12 @@ static void loongarch_pch_msi_init(Object *obj)
}
-static Property loongarch_msi_properties[] = {
+static const Property loongarch_msi_properties[] = {
DEFINE_PROP_UINT32("msi_irq_base", LoongArchPCHMSI, irq_base, 0),
DEFINE_PROP_UINT32("msi_irq_num", LoongArchPCHMSI, irq_num, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void loongarch_pch_msi_class_init(ObjectClass *klass, void *data)
+static void loongarch_pch_msi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
index 2d5e65a..c4b242d 100644
--- a/hw/intc/loongarch_pch_pic.c
+++ b/hw/intc/loongarch_pch_pic.c
@@ -7,17 +7,15 @@
#include "qemu/osdep.h"
#include "qemu/bitops.h"
-#include "hw/sysbus.h"
-#include "hw/loongarch/virt.h"
-#include "hw/pci-host/ls7a.h"
+#include "qemu/log.h"
#include "hw/irq.h"
#include "hw/intc/loongarch_pch_pic.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
+#include "system/kvm.h"
#include "trace.h"
#include "qapi/error.h"
-static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
+static void pch_pic_update_irq(LoongArchPICCommonState *s, uint64_t mask,
+ int level)
{
uint64_t val;
int irq;
@@ -45,12 +43,17 @@ static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
static void pch_pic_irq_handler(void *opaque, int irq, int level)
{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
uint64_t mask = 1ULL << irq;
assert(irq < s->irq_num);
trace_loongarch_pch_pic_irq_handler(irq, level);
+ if (kvm_irqchip_in_kernel()) {
+ kvm_set_irq(kvm_state, irq, !!level);
+ return;
+ }
+
if (s->intedge & mask) {
/* Edge triggered */
if (level) {
@@ -75,389 +78,266 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level)
pch_pic_update_irq(s, mask, level);
}
-static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
- unsigned size)
+static uint64_t pch_pic_read(void *opaque, hwaddr addr, uint64_t field_mask)
{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
uint64_t val = 0;
- uint32_t offset = addr & 0xfff;
+ uint32_t offset;
- switch (offset) {
- case PCH_PIC_INT_ID_LO:
- val = PCH_PIC_INT_ID_VAL;
+ offset = addr & 7;
+ addr -= offset;
+ switch (addr) {
+ case PCH_PIC_INT_ID:
+ val = cpu_to_le64(s->id.data);
break;
- case PCH_PIC_INT_ID_HI:
- /*
- * With 7A1000 manual
- * bit 0-15 pch irqchip version
- * bit 16-31 irq number supported with pch irqchip
- */
- val = deposit32(PCH_PIC_INT_ID_VER, 16, 16, s->irq_num - 1);
+ case PCH_PIC_INT_MASK:
+ val = s->int_mask;
break;
- case PCH_PIC_INT_MASK_LO:
- val = (uint32_t)s->int_mask;
+ case PCH_PIC_INT_EDGE:
+ val = s->intedge;
break;
- case PCH_PIC_INT_MASK_HI:
- val = s->int_mask >> 32;
+ case PCH_PIC_HTMSI_EN:
+ val = s->htmsi_en;
break;
- case PCH_PIC_INT_EDGE_LO:
- val = (uint32_t)s->intedge;
+ case PCH_PIC_AUTO_CTRL0:
+ case PCH_PIC_AUTO_CTRL1:
+ /* PCH PIC connect to EXTIOI always, discard auto_ctrl access */
break;
- case PCH_PIC_INT_EDGE_HI:
- val = s->intedge >> 32;
+ case PCH_PIC_INT_STATUS:
+ val = s->intisr & (~s->int_mask);
break;
- case PCH_PIC_HTMSI_EN_LO:
- val = (uint32_t)s->htmsi_en;
+ case PCH_PIC_INT_POL:
+ val = s->int_polarity;
break;
- case PCH_PIC_HTMSI_EN_HI:
- val = s->htmsi_en >> 32;
+ case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END:
+ val = *(uint64_t *)(s->htmsi_vector + addr - PCH_PIC_HTMSI_VEC);
break;
- case PCH_PIC_AUTO_CTRL0_LO:
- case PCH_PIC_AUTO_CTRL0_HI:
- case PCH_PIC_AUTO_CTRL1_LO:
- case PCH_PIC_AUTO_CTRL1_HI:
+ case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END:
+ val = *(uint64_t *)(s->route_entry + addr - PCH_PIC_ROUTE_ENTRY);
break;
default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pch_pic_read: Bad address 0x%"PRIx64"\n", addr);
break;
}
- trace_loongarch_pch_pic_low_readw(size, addr, val);
- return val;
+ return (val >> (offset * 8)) & field_mask;
}
-static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi)
+static void pch_pic_write(void *opaque, hwaddr addr, uint64_t value,
+ uint64_t field_mask)
{
- uint64_t mask = 0xffffffff00000000;
- uint64_t data = target;
-
- return hi ? (value & ~mask) | (data << 32) : (value & mask) | data;
-}
-
-static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
- uint32_t offset, old_valid, data = (uint32_t)value;
- uint64_t old, int_mask;
- offset = addr & 0xfff;
-
- trace_loongarch_pch_pic_low_writew(size, addr, data);
-
- switch (offset) {
- case PCH_PIC_INT_MASK_LO:
- old = s->int_mask;
- s->int_mask = get_writew_val(old, data, 0);
- old_valid = (uint32_t)old;
- if (old_valid & ~data) {
- pch_pic_update_irq(s, (old_valid & ~data), 1);
- }
- if (~old_valid & data) {
- pch_pic_update_irq(s, (~old_valid & data), 0);
- }
- break;
- case PCH_PIC_INT_MASK_HI:
+ LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
+ uint32_t offset;
+ uint64_t old, mask, data, *ptemp;
+
+ offset = addr & 7;
+ addr -= offset;
+ mask = field_mask << (offset * 8);
+ data = (value & field_mask) << (offset * 8);
+ switch (addr) {
+ case PCH_PIC_INT_MASK:
old = s->int_mask;
- s->int_mask = get_writew_val(old, data, 1);
- old_valid = (uint32_t)(old >> 32);
- int_mask = old_valid & ~data;
- if (int_mask) {
- pch_pic_update_irq(s, int_mask << 32, 1);
+ s->int_mask = (old & ~mask) | data;
+ if (old & ~data) {
+ pch_pic_update_irq(s, old & ~data, 1);
}
- int_mask = ~old_valid & data;
- if (int_mask) {
- pch_pic_update_irq(s, int_mask << 32, 0);
+
+ if (~old & data) {
+ pch_pic_update_irq(s, ~old & data, 0);
}
break;
- case PCH_PIC_INT_EDGE_LO:
- s->intedge = get_writew_val(s->intedge, data, 0);
- break;
- case PCH_PIC_INT_EDGE_HI:
- s->intedge = get_writew_val(s->intedge, data, 1);
+ case PCH_PIC_INT_EDGE:
+ s->intedge = (s->intedge & ~mask) | data;
break;
- case PCH_PIC_INT_CLEAR_LO:
+ case PCH_PIC_INT_CLEAR:
if (s->intedge & data) {
- s->intirr &= (~data);
+ s->intirr &= ~data;
pch_pic_update_irq(s, data, 0);
- s->intisr &= (~data);
+ s->intisr &= ~data;
}
break;
- case PCH_PIC_INT_CLEAR_HI:
- value <<= 32;
- if (s->intedge & value) {
- s->intirr &= (~value);
- pch_pic_update_irq(s, value, 0);
- s->intisr &= (~value);
- }
+ case PCH_PIC_HTMSI_EN:
+ s->htmsi_en = (s->htmsi_en & ~mask) | data;
break;
- case PCH_PIC_HTMSI_EN_LO:
- s->htmsi_en = get_writew_val(s->htmsi_en, data, 0);
+ case PCH_PIC_AUTO_CTRL0:
+ case PCH_PIC_AUTO_CTRL1:
+ /* Discard auto_ctrl access */
break;
- case PCH_PIC_HTMSI_EN_HI:
- s->htmsi_en = get_writew_val(s->htmsi_en, data, 1);
+ case PCH_PIC_INT_POL:
+ s->int_polarity = (s->int_polarity & ~mask) | data;
break;
- case PCH_PIC_AUTO_CTRL0_LO:
- case PCH_PIC_AUTO_CTRL0_HI:
- case PCH_PIC_AUTO_CTRL1_LO:
- case PCH_PIC_AUTO_CTRL1_HI:
+ case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END:
+ ptemp = (uint64_t *)(s->htmsi_vector + addr - PCH_PIC_HTMSI_VEC);
+ *ptemp = (*ptemp & ~mask) | data;
+ break;
+ case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END:
+ ptemp = (uint64_t *)(s->route_entry + addr - PCH_PIC_ROUTE_ENTRY);
+ *ptemp = (*ptemp & ~mask) | data;
break;
default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pch_pic_write: Bad address 0x%"PRIx64"\n", addr);
break;
}
}
-static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
- unsigned size)
+static uint64_t loongarch_pch_pic_read(void *opaque, hwaddr addr,
+ unsigned size)
{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
uint64_t val = 0;
- uint32_t offset = addr & 0xfff;
- switch (offset) {
- case STATUS_LO_START:
- val = (uint32_t)(s->intisr & (~s->int_mask));
+ switch (size) {
+ case 1:
+ val = pch_pic_read(opaque, addr, UCHAR_MAX);
break;
- case STATUS_HI_START:
- val = (s->intisr & (~s->int_mask)) >> 32;
+ case 2:
+ val = pch_pic_read(opaque, addr, USHRT_MAX);
break;
- case POL_LO_START:
- val = (uint32_t)s->int_polarity;
+ case 4:
+ val = pch_pic_read(opaque, addr, UINT_MAX);
break;
- case POL_HI_START:
- val = s->int_polarity >> 32;
+ case 8:
+ val = pch_pic_read(opaque, addr, UINT64_MAX);
break;
default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "loongarch_pch_pic_read: Bad size %d\n", size);
break;
}
- trace_loongarch_pch_pic_high_readw(size, addr, val);
+ trace_loongarch_pch_pic_read(size, addr, val);
return val;
}
-static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
+static void loongarch_pch_pic_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
- uint32_t offset, data = (uint32_t)value;
- offset = addr & 0xfff;
-
- trace_loongarch_pch_pic_high_writew(size, addr, data);
+ trace_loongarch_pch_pic_write(size, addr, value);
- switch (offset) {
- case STATUS_LO_START:
- s->intisr = get_writew_val(s->intisr, data, 0);
+ switch (size) {
+ case 1:
+ pch_pic_write(opaque, addr, value, UCHAR_MAX);
break;
- case STATUS_HI_START:
- s->intisr = get_writew_val(s->intisr, data, 1);
+ case 2:
+ pch_pic_write(opaque, addr, value, USHRT_MAX);
break;
- case POL_LO_START:
- s->int_polarity = get_writew_val(s->int_polarity, data, 0);
break;
- case POL_HI_START:
- s->int_polarity = get_writew_val(s->int_polarity, data, 1);
- break;
- default:
- break;
- }
-}
-
-static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
- uint64_t val = 0;
- uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
- int64_t offset_tmp;
-
- switch (offset) {
- case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
- offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
- if (offset_tmp >= 0 && offset_tmp < 64) {
- val = s->htmsi_vector[offset_tmp];
- }
- break;
- case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
- offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
- if (offset_tmp >= 0 && offset_tmp < 64) {
- val = s->route_entry[offset_tmp];
- }
- break;
- default:
- break;
- }
-
- trace_loongarch_pch_pic_readb(size, addr, val);
- return val;
-}
-
-static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
- int32_t offset_tmp;
- uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
-
- trace_loongarch_pch_pic_writeb(size, addr, data);
-
- switch (offset) {
- case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
- offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
- if (offset_tmp >= 0 && offset_tmp < 64) {
- s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
- }
+ case 4:
+ pch_pic_write(opaque, addr, value, UINT_MAX);
break;
- case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
- offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
- if (offset_tmp >= 0 && offset_tmp < 64) {
- s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
- }
+ case 8:
+ pch_pic_write(opaque, addr, value, UINT64_MAX);
break;
default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "loongarch_pch_pic_write: Bad size %d\n", size);
break;
}
}
-static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
- .read = loongarch_pch_pic_low_readw,
- .write = loongarch_pch_pic_low_writew,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
- .read = loongarch_pch_pic_high_readw,
- .write = loongarch_pch_pic_high_writew,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
- .read = loongarch_pch_pic_readb,
- .write = loongarch_pch_pic_writeb,
+static const MemoryRegionOps loongarch_pch_pic_ops = {
+ .read = loongarch_pch_pic_read,
+ .write = loongarch_pch_pic_write,
.valid = {
.min_access_size = 1,
- .max_access_size = 1,
+ .max_access_size = 8,
+ /*
+ * PCH PIC device would not work correctly if the guest was doing
+ * unaligned access. This might not be a limitation on the real
+ * device but in practice there is no reason for a guest to access
+ * this device unaligned.
+ */
+ .unaligned = false,
},
.impl = {
.min_access_size = 1,
- .max_access_size = 1,
+ .max_access_size = 8,
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void loongarch_pch_pic_reset(DeviceState *d)
+static void loongarch_pic_reset_hold(Object *obj, ResetType type)
{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
- int i;
-
- s->int_mask = -1;
- s->htmsi_en = 0x0;
- s->intedge = 0x0;
- s->intclr = 0x0;
- s->auto_crtl0 = 0x0;
- s->auto_crtl1 = 0x0;
- for (i = 0; i < 64; i++) {
- s->route_entry[i] = 0x1;
- s->htmsi_vector[i] = 0x0;
+ LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(obj);
+
+ if (lpc->parent_phases.hold) {
+ lpc->parent_phases.hold(obj, type);
+ }
+
+ if (kvm_irqchip_in_kernel()) {
+ kvm_pic_put(obj, 0);
}
- s->intirr = 0x0;
- s->intisr = 0x0;
- s->last_intirr = 0x0;
- s->int_polarity = 0x0;
}
-static void loongarch_pch_pic_realize(DeviceState *dev, Error **errp)
+static void loongarch_pic_realize(DeviceState *dev, Error **errp)
{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(dev);
-
- if (!s->irq_num || s->irq_num > VIRT_PCH_PIC_IRQ_NUM) {
- error_setg(errp, "Invalid 'pic_irq_num'");
+ LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(dev);
+ LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ Error *local_err = NULL;
+
+ lpc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
qdev_init_gpio_out(dev, s->parent_irq, s->irq_num);
qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num);
+
+ if (kvm_irqchip_in_kernel()) {
+ kvm_pic_realize(dev, errp);
+ } else {
+ memory_region_init_io(&s->iomem, OBJECT(dev),
+ &loongarch_pch_pic_ops,
+ s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+ }
}
-static void loongarch_pch_pic_init(Object *obj)
+static int loongarch_pic_pre_save(LoongArchPICCommonState *opaque)
{
- LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->iomem32_low, obj,
- &loongarch_pch_pic_reg32_low_ops,
- s, PCH_PIC_NAME(.reg32_part1), 0x100);
- memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
- s, PCH_PIC_NAME(.reg8), 0x2a0);
- memory_region_init_io(&s->iomem32_high, obj,
- &loongarch_pch_pic_reg32_high_ops,
- s, PCH_PIC_NAME(.reg32_part2), 0xc60);
- sysbus_init_mmio(sbd, &s->iomem32_low);
- sysbus_init_mmio(sbd, &s->iomem8);
- sysbus_init_mmio(sbd, &s->iomem32_high);
+ if (kvm_irqchip_in_kernel()) {
+ return kvm_pic_get(opaque);
+ }
+ return 0;
}
-static Property loongarch_pch_pic_properties[] = {
- DEFINE_PROP_UINT32("pch_pic_irq_num", LoongArchPCHPIC, irq_num, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_loongarch_pch_pic = {
- .name = TYPE_LOONGARCH_PCH_PIC,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT64(int_mask, LoongArchPCHPIC),
- VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC),
- VMSTATE_UINT64(intedge, LoongArchPCHPIC),
- VMSTATE_UINT64(intclr, LoongArchPCHPIC),
- VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC),
- VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC),
- VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
- VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
- VMSTATE_UINT64(last_intirr, LoongArchPCHPIC),
- VMSTATE_UINT64(intirr, LoongArchPCHPIC),
- VMSTATE_UINT64(intisr, LoongArchPCHPIC),
- VMSTATE_UINT64(int_polarity, LoongArchPCHPIC),
- VMSTATE_END_OF_LIST()
+static int loongarch_pic_post_load(LoongArchPICCommonState *opaque,
+ int version_id)
+{
+ if (kvm_irqchip_in_kernel()) {
+ return kvm_pic_put(opaque, version_id);
}
-};
-static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
+ return 0;
+}
+
+static void loongarch_pic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = loongarch_pch_pic_realize;
- dc->reset = loongarch_pch_pic_reset;
- dc->vmsd = &vmstate_loongarch_pch_pic;
- device_class_set_props(dc, loongarch_pch_pic_properties);
+ LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass);
+ LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ resettable_class_set_parent_phases(rc, NULL, loongarch_pic_reset_hold,
+ NULL, &lpc->parent_phases);
+ device_class_set_parent_realize(dc, loongarch_pic_realize,
+ &lpc->parent_realize);
+ lpcc->pre_save = loongarch_pic_pre_save;
+ lpcc->post_load = loongarch_pic_post_load;
}
-static const TypeInfo loongarch_pch_pic_info = {
- .name = TYPE_LOONGARCH_PCH_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LoongArchPCHPIC),
- .instance_init = loongarch_pch_pic_init,
- .class_init = loongarch_pch_pic_class_init,
+static const TypeInfo loongarch_pic_types[] = {
+ {
+ .name = TYPE_LOONGARCH_PIC,
+ .parent = TYPE_LOONGARCH_PIC_COMMON,
+ .instance_size = sizeof(LoongarchPICState),
+ .class_size = sizeof(LoongarchPICClass),
+ .class_init = loongarch_pic_class_init,
+ }
};
-static void loongarch_pch_pic_register_types(void)
-{
- type_register_static(&loongarch_pch_pic_info);
-}
-
-type_init(loongarch_pch_pic_register_types)
+DEFINE_TYPES(loongarch_pic_types)
diff --git a/hw/intc/loongarch_pic_common.c b/hw/intc/loongarch_pic_common.c
new file mode 100644
index 0000000..de17050
--- /dev/null
+++ b/hw/intc/loongarch_pic_common.c
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Loongson 7A1000 I/O interrupt controller.
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/intc/loongarch_pic_common.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+static int loongarch_pic_pre_save(void *opaque)
+{
+ LoongArchPICCommonState *s = (LoongArchPICCommonState *)opaque;
+ LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_GET_CLASS(s);
+
+ if (lpcc->pre_save) {
+ return lpcc->pre_save(s);
+ }
+
+ return 0;
+}
+
+static int loongarch_pic_post_load(void *opaque, int version_id)
+{
+ LoongArchPICCommonState *s = (LoongArchPICCommonState *)opaque;
+ LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_GET_CLASS(s);
+
+ if (lpcc->post_load) {
+ return lpcc->post_load(s, version_id);
+ }
+
+ return 0;
+}
+
+static void loongarch_pic_common_realize(DeviceState *dev, Error **errp)
+{
+ LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(dev);
+
+ if (!s->irq_num || s->irq_num > VIRT_PCH_PIC_IRQ_NUM) {
+ error_setg(errp, "Invalid 'pic_irq_num'");
+ return;
+ }
+}
+
+static void loongarch_pic_common_reset_hold(Object *obj, ResetType type)
+{
+ LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(obj);
+ int i;
+
+ /*
+ * With Loongson 7A1000 user manual
+ * Chapter 5.2 "Description of Interrupt-related Registers"
+ *
+ * Interrupt controller identification register 1
+ * Bit 24-31 Interrupt Controller ID
+ * Interrupt controller identification register 2
+ * Bit 0-7 Interrupt Controller version number
+ * Bit 16-23 The number of interrupt sources supported
+ */
+ s->id.desc.id = PCH_PIC_INT_ID_VAL;
+ s->id.desc.version = PCH_PIC_INT_ID_VER;
+ s->id.desc.irq_num = s->irq_num - 1;
+ s->int_mask = UINT64_MAX;
+ s->htmsi_en = 0x0;
+ s->intedge = 0x0;
+ s->intclr = 0x0;
+ s->auto_crtl0 = 0x0;
+ s->auto_crtl1 = 0x0;
+ for (i = 0; i < 64; i++) {
+ s->route_entry[i] = 0x1;
+ s->htmsi_vector[i] = 0x0;
+ }
+ s->intirr = 0x0;
+ s->intisr = 0x0;
+ s->last_intirr = 0x0;
+ s->int_polarity = 0x0;
+}
+
+static const Property loongarch_pic_common_properties[] = {
+ DEFINE_PROP_UINT32("pch_pic_irq_num", LoongArchPICCommonState, irq_num, 0),
+};
+
+static const VMStateDescription vmstate_loongarch_pic_common = {
+ .name = "loongarch_pch_pic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = loongarch_pic_pre_save,
+ .post_load = loongarch_pic_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(int_mask, LoongArchPICCommonState),
+ VMSTATE_UINT64(htmsi_en, LoongArchPICCommonState),
+ VMSTATE_UINT64(intedge, LoongArchPICCommonState),
+ VMSTATE_UINT64(intclr, LoongArchPICCommonState),
+ VMSTATE_UINT64(auto_crtl0, LoongArchPICCommonState),
+ VMSTATE_UINT64(auto_crtl1, LoongArchPICCommonState),
+ VMSTATE_UINT8_ARRAY(route_entry, LoongArchPICCommonState, 64),
+ VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPICCommonState, 64),
+ VMSTATE_UINT64(last_intirr, LoongArchPICCommonState),
+ VMSTATE_UINT64(intirr, LoongArchPICCommonState),
+ VMSTATE_UINT64(intisr, LoongArchPICCommonState),
+ VMSTATE_UINT64(int_polarity, LoongArchPICCommonState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void loongarch_pic_common_class_init(ObjectClass *klass,
+ const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ device_class_set_parent_realize(dc, loongarch_pic_common_realize,
+ &lpcc->parent_realize);
+ resettable_class_set_parent_phases(rc, NULL,
+ loongarch_pic_common_reset_hold,
+ NULL, &lpcc->parent_phases);
+ device_class_set_props(dc, loongarch_pic_common_properties);
+ dc->vmsd = &vmstate_loongarch_pic_common;
+}
+
+static const TypeInfo loongarch_pic_common_types[] = {
+ {
+ .name = TYPE_LOONGARCH_PIC_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LoongArchPICCommonState),
+ .class_size = sizeof(LoongArchPICCommonClass),
+ .class_init = loongarch_pic_common_class_init,
+ .abstract = true,
+ }
+};
+
+DEFINE_TYPES(loongarch_pic_common_types)
diff --git a/hw/intc/loongarch_pic_kvm.c b/hw/intc/loongarch_pic_kvm.c
new file mode 100644
index 0000000..dd504ec
--- /dev/null
+++ b/hw/intc/loongarch_pic_kvm.c
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm pch pic interrupt support
+ *
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "hw/loongarch/virt.h"
+#include "hw/pci-host/ls7a.h"
+#include "system/kvm.h"
+
+static void kvm_pch_pic_access_reg(int fd, uint64_t addr, void *val, bool write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS,
+ addr, val, write, &error_abort);
+}
+
+static void kvm_pch_pic_access(void *opaque, bool write)
+{
+ LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
+ LoongarchPICState *lps = LOONGARCH_PIC(opaque);
+ int fd = lps->dev_fd;
+ int addr, offset;
+
+ if (fd == 0) {
+ return;
+ }
+
+ kvm_pch_pic_access_reg(fd, PCH_PIC_INT_MASK, &s->int_mask, write);
+ kvm_pch_pic_access_reg(fd, PCH_PIC_HTMSI_EN, &s->htmsi_en, write);
+ kvm_pch_pic_access_reg(fd, PCH_PIC_INT_EDGE, &s->intedge, write);
+ kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL0, &s->auto_crtl0, write);
+ kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL1, &s->auto_crtl1, write);
+
+ for (addr = PCH_PIC_ROUTE_ENTRY;
+ addr < PCH_PIC_ROUTE_ENTRY_END; addr++) {
+ offset = addr - PCH_PIC_ROUTE_ENTRY;
+ kvm_pch_pic_access_reg(fd, addr, &s->route_entry[offset], write);
+ }
+
+ for (addr = PCH_PIC_HTMSI_VEC; addr < PCH_PIC_HTMSI_VEC_END; addr++) {
+ offset = addr - PCH_PIC_HTMSI_VEC;
+ kvm_pch_pic_access_reg(fd, addr, &s->htmsi_vector[offset], write);
+ }
+
+ kvm_pch_pic_access_reg(fd, PCH_PIC_INT_REQUEST, &s->intirr, write);
+ kvm_pch_pic_access_reg(fd, PCH_PIC_INT_STATUS, &s->intisr, write);
+ kvm_pch_pic_access_reg(fd, PCH_PIC_INT_POL, &s->int_polarity, write);
+}
+
+int kvm_pic_get(void *opaque)
+{
+ kvm_pch_pic_access(opaque, false);
+ return 0;
+}
+
+int kvm_pic_put(void *opaque, int version_id)
+{
+ kvm_pch_pic_access(opaque, true);
+ return 0;
+}
+
+void kvm_pic_realize(DeviceState *dev, Error **errp)
+{
+ LoongarchPICState *lps = LOONGARCH_PIC(dev);
+ uint64_t pch_pic_base = VIRT_PCH_REG_BASE;
+ int ret;
+
+ ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_PCHPIC, false);
+ if (ret < 0) {
+ fprintf(stderr, "Create KVM_LOONGARCH_PCHPIC failed: %s\n",
+ strerror(-ret));
+ abort();
+ }
+
+ lps->dev_fd = ret;
+ ret = kvm_device_access(lps->dev_fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL,
+ KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT,
+ &pch_pic_base, true, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_LOONGARCH_PCH_PIC_INIT failed: %s\n",
+ strerror(-ret));
+ abort();
+ }
+}
diff --git a/hw/intc/loongson_ipi.c b/hw/intc/loongson_ipi.c
index 8382cec..fbc73e8 100644
--- a/hw/intc/loongson_ipi.c
+++ b/hw/intc/loongson_ipi.c
@@ -6,18 +6,10 @@
*/
#include "qemu/osdep.h"
-#include "hw/boards.h"
-#include "hw/sysbus.h"
#include "hw/intc/loongson_ipi.h"
-#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-#include "migration/vmstate.h"
#include "target/mips/cpu.h"
-#include "trace.h"
static AddressSpace *get_iocsr_as(CPUState *cpu)
{
@@ -28,6 +20,27 @@ static AddressSpace *get_iocsr_as(CPUState *cpu)
return NULL;
}
+static int loongson_cpu_by_arch_id(LoongsonIPICommonState *lics,
+ int64_t arch_id, int *index, CPUState **pcs)
+{
+ CPUState *cs;
+
+ cs = cpu_by_arch_id(arch_id);
+ if (cs == NULL) {
+ return MEMTX_ERROR;
+ }
+
+ if (index) {
+ *index = cs->cpu_index;
+ }
+
+ if (pcs) {
+ *pcs = cs;
+ }
+
+ return MEMTX_OK;
+}
+
static const MemoryRegionOps loongson_ipi_core_ops = {
.read_with_attrs = loongson_ipi_core_readl,
.write_with_attrs = loongson_ipi_core_writel,
@@ -45,6 +58,7 @@ static void loongson_ipi_realize(DeviceState *dev, Error **errp)
LoongsonIPIClass *lic = LOONGSON_IPI_GET_CLASS(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
Error *local_err = NULL;
+ int i;
lic->parent_realize(dev, &local_err);
if (local_err) {
@@ -52,8 +66,19 @@ static void loongson_ipi_realize(DeviceState *dev, Error **errp)
return;
}
+ if (sc->num_cpu == 0) {
+ error_setg(errp, "num-cpu must be at least 1");
+ return;
+ }
+
+ sc->cpu = g_new0(IPICore, sc->num_cpu);
+ for (i = 0; i < sc->num_cpu; i++) {
+ sc->cpu[i].ipi = sc;
+ qdev_init_gpio_out(dev, &sc->cpu[i].irq, 1);
+ }
+
s->ipi_mmio_mem = g_new0(MemoryRegion, sc->num_cpu);
- for (unsigned i = 0; i < sc->num_cpu; i++) {
+ for (i = 0; i < sc->num_cpu; i++) {
g_autofree char *name = g_strdup_printf("loongson_ipi_cpu%d_mmio", i);
memory_region_init_io(&s->ipi_mmio_mem[i], OBJECT(dev),
@@ -72,7 +97,11 @@ static void loongson_ipi_unrealize(DeviceState *dev)
k->parent_unrealize(dev);
}
-static void loongson_ipi_class_init(ObjectClass *klass, void *data)
+static const Property loongson_ipi_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", LoongsonIPICommonState, num_cpu, 1),
+};
+
+static void loongson_ipi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
LoongsonIPIClass *lic = LOONGSON_IPI_CLASS(klass);
@@ -82,8 +111,9 @@ static void loongson_ipi_class_init(ObjectClass *klass, void *data)
&lic->parent_realize);
device_class_set_parent_unrealize(dc, loongson_ipi_unrealize,
&lic->parent_unrealize);
+ device_class_set_props(dc, loongson_ipi_properties);
licc->get_iocsr_as = get_iocsr_as;
- licc->cpu_by_arch_id = cpu_by_arch_id;
+ licc->cpu_by_arch_id = loongson_cpu_by_arch_id;
}
static const TypeInfo loongson_ipi_types[] = {
diff --git a/hw/intc/loongson_ipi_common.c b/hw/intc/loongson_ipi_common.c
index a6ce018..8cd78d4 100644
--- a/hw/intc/loongson_ipi_common.c
+++ b/hw/intc/loongson_ipi_common.c
@@ -9,10 +9,9 @@
#include "hw/sysbus.h"
#include "hw/intc/loongson_ipi_common.h"
#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "qapi/error.h"
#include "qemu/log.h"
#include "migration/vmstate.h"
+#include "system/kvm.h"
#include "trace.h"
MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
@@ -105,16 +104,17 @@ static MemTxResult mail_send(LoongsonIPICommonState *ipi,
uint32_t cpuid;
hwaddr addr;
CPUState *cs;
+ int cpu, ret;
cpuid = extract32(val, 16, 10);
- cs = licc->cpu_by_arch_id(cpuid);
- if (cs == NULL) {
+ ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs);
+ if (ret != MEMTX_OK) {
return MEMTX_DECODE_ERROR;
}
/* override requester_id */
addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
- attrs.requester_id = cs->cpu_index;
+ attrs.requester_id = cpu;
return send_ipi_data(ipi, cs, val, addr, attrs);
}
@@ -125,16 +125,17 @@ static MemTxResult any_send(LoongsonIPICommonState *ipi,
uint32_t cpuid;
hwaddr addr;
CPUState *cs;
+ int cpu, ret;
cpuid = extract32(val, 16, 10);
- cs = licc->cpu_by_arch_id(cpuid);
- if (cs == NULL) {
+ ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs);
+ if (ret != MEMTX_OK) {
return MEMTX_DECODE_ERROR;
}
/* override requester_id */
addr = val & 0xffff;
- attrs.requester_id = cs->cpu_index;
+ attrs.requester_id = cpu;
return send_ipi_data(ipi, cs, val, addr, attrs);
}
@@ -148,6 +149,7 @@ MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, uint64_t val,
uint32_t cpuid;
uint8_t vector;
CPUState *cs;
+ int cpu, ret;
addr &= 0xff;
trace_loongson_ipi_write(size, (uint64_t)addr, val);
@@ -178,11 +180,11 @@ MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, uint64_t val,
cpuid = extract32(val, 16, 10);
/* IPI status vector */
vector = extract8(val, 0, 5);
- cs = licc->cpu_by_arch_id(cpuid);
- if (cs == NULL || cs->cpu_index >= ipi->num_cpu) {
+ ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs);
+ if (ret != MEMTX_OK || cpu >= ipi->num_cpu) {
return MEMTX_DECODE_ERROR;
}
- loongson_ipi_core_writel(&ipi->cpu[cs->cpu_index], CORE_SET_OFF,
+ loongson_ipi_core_writel(&ipi->cpu[cpu], CORE_SET_OFF,
BIT(vector), 4, attrs);
break;
default:
@@ -253,10 +255,8 @@ static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
{
LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i;
- if (s->num_cpu == 0) {
- error_setg(errp, "num-cpu must be at least 1");
+ if (kvm_irqchip_in_kernel()) {
return;
}
@@ -273,13 +273,6 @@ static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
&loongson_ipi64_ops,
s, "loongson_ipi64_iocsr", 0x118);
sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
-
- s->cpu = g_new0(IPICore, s->num_cpu);
- for (i = 0; i < s->num_cpu; i++) {
- s->cpu[i].ipi = s;
-
- qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
- }
}
static void loongson_ipi_common_unrealize(DeviceState *dev)
@@ -289,10 +282,38 @@ static void loongson_ipi_common_unrealize(DeviceState *dev)
g_free(s->cpu);
}
+static int loongson_ipi_common_pre_save(void *opaque)
+{
+ IPICore *ipicore = (IPICore *)opaque;
+ LoongsonIPICommonState *s = ipicore->ipi;
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s);
+
+ if (licc->pre_save) {
+ return licc->pre_save(s);
+ }
+
+ return 0;
+}
+
+static int loongson_ipi_common_post_load(void *opaque, int version_id)
+{
+ IPICore *ipicore = (IPICore *)opaque;
+ LoongsonIPICommonState *s = ipicore->ipi;
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s);
+
+ if (licc->post_load) {
+ return licc->post_load(s, version_id);
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_ipi_core = {
.name = "ipi-single",
.version_id = 2,
.minimum_version_id = 2,
+ .pre_save = loongson_ipi_common_pre_save,
+ .post_load = loongson_ipi_common_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(status, IPICore),
VMSTATE_UINT32(en, IPICore),
@@ -315,12 +336,7 @@ static const VMStateDescription vmstate_loongson_ipi_common = {
}
};
-static Property ipi_common_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", LoongsonIPICommonState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void loongson_ipi_common_class_init(ObjectClass *klass, void *data)
+static void loongson_ipi_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
@@ -329,7 +345,6 @@ static void loongson_ipi_common_class_init(ObjectClass *klass, void *data)
&licc->parent_realize);
device_class_set_parent_unrealize(dc, loongson_ipi_common_unrealize,
&licc->parent_unrealize);
- device_class_set_props(dc, ipi_common_properties);
dc->vmsd = &vmstate_loongson_ipi_common;
}
diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c
index cf3beef..2532322 100644
--- a/hw/intc/m68k_irqc.c
+++ b/hw/intc/m68k_irqc.c
@@ -85,13 +85,12 @@ static const VMStateDescription vmstate_m68k_irqc = {
}
};
-static Property m68k_irqc_properties[] = {
+static const Property m68k_irqc_properties[] = {
DEFINE_PROP_LINK("m68k-cpu", M68KIRQCState, cpu,
TYPE_M68K_CPU, ArchCPU *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void m68k_irqc_class_init(ObjectClass *oc, void *data)
+static void m68k_irqc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
@@ -99,7 +98,7 @@ static void m68k_irqc_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, m68k_irqc_properties);
nc->nmi_monitor_handler = m68k_nmi;
- dc->reset = m68k_irqc_reset;
+ device_class_set_legacy_reset(dc, m68k_irqc_reset);
dc->vmsd = &vmstate_m68k_irqc;
ic->get_statistics = m68k_irqc_get_statistics;
ic->print_info = m68k_irqc_print_info;
@@ -111,7 +110,7 @@ static const TypeInfo m68k_irqc_type_info = {
.instance_size = sizeof(M68KIRQCState),
.instance_init = m68k_irqc_instance_init,
.class_init = m68k_irqc_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NMI },
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index f4d81eb..3137521 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -6,7 +6,7 @@ system_ss.add(when: 'CONFIG_ARM_GIC', if_true: files(
'arm_gicv3_common.c',
'arm_gicv3_its_common.c',
))
-system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
+system_ss.add(when: 'CONFIG_ARM_GICV3', if_true: files(
'arm_gicv3.c',
'arm_gicv3_dist.c',
'arm_gicv3_its.c',
@@ -15,7 +15,6 @@ system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
system_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_intc.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c'))
system_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
system_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
@@ -40,7 +39,7 @@ endif
specific_ss.add(when: 'CONFIG_APIC', if_true: files('apic.c', 'apic_common.c'))
specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c'))
-specific_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files('arm_gicv3_cpuif.c'))
+specific_ss.add(when: 'CONFIG_ARM_GICV3', if_true: files('arm_gicv3_cpuif.c'))
specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
@@ -72,6 +71,12 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c'))
specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
-specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
+specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_IPI'],
+ if_true: files('loongarch_ipi_kvm.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c', 'loongarch_pic_common.c'))
+specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_PCH_PIC'],
+ if_true: files('loongarch_pic_kvm.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
-specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c', 'loongarch_extioi_common.c'))
+specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_EXTIOI'],
+ if_true: files('loongarch_extioi_kvm.c'))
diff --git a/hw/intc/mips_gic.c b/hw/intc/mips_gic.c
index 77ba734..0c50ba4 100644
--- a/hw/intc/mips_gic.c
+++ b/hw/intc/mips_gic.c
@@ -14,9 +14,9 @@
#include "qemu/module.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
-#include "exec/memory.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
+#include "system/memory.h"
+#include "system/kvm.h"
+#include "system/reset.h"
#include "kvm_mips.h"
#include "hw/intc/mips_gic.h"
#include "hw/irq.h"
@@ -255,7 +255,6 @@ static void gic_write_vp(MIPSGICState *gic, uint32_t vp_index, hwaddr addr,
return;
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR, "Wrong GIC offset at 0x%" PRIx64 "\n", addr);
- return;
}
static void gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
@@ -438,13 +437,12 @@ static void mips_gic_realize(DeviceState *dev, Error **errp)
}
}
-static Property mips_gic_properties[] = {
+static const Property mips_gic_properties[] = {
DEFINE_PROP_UINT32("num-vp", MIPSGICState, num_vps, 1),
DEFINE_PROP_UINT32("num-irq", MIPSGICState, num_irq, 256),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mips_gic_class_init(ObjectClass *klass, void *data)
+static void mips_gic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c
index 435c476..c61158b 100644
--- a/hw/intc/omap_intc.c
+++ b/hw/intc/omap_intc.c
@@ -50,8 +50,6 @@ struct OMAPIntcState {
int level_only;
uint32_t size;
- uint8_t revision;
-
/* state */
uint32_t new_agr[2];
int sir_intr[2];
@@ -104,8 +102,8 @@ static inline void omap_inth_update(OMAPIntcState *s, int is_fiq)
}
}
-#define INT_FALLING_EDGE 0
-#define INT_LOW_LEVEL 1
+#define INT_FALLING_EDGE 0
+#define INT_LOW_LEVEL 1
static void omap_set_intr(void *opaque, int irq, int req)
{
@@ -133,26 +131,6 @@ static void omap_set_intr(void *opaque, int irq, int req)
}
}
-/* Simplified version with no edge detection */
-static void omap_set_intr_noedge(void *opaque, int irq, int req)
-{
- OMAPIntcState *ih = opaque;
- uint32_t rise;
-
- struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
- int n = irq & 31;
-
- if (req) {
- rise = ~bank->inputs & (1 << n);
- if (rise) {
- bank->irqs |= bank->inputs |= rise;
- omap_inth_update(ih, 0);
- omap_inth_update(ih, 1);
- }
- } else
- bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
-}
-
static uint64_t omap_inth_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -164,13 +142,13 @@ static uint64_t omap_inth_read(void *opaque, hwaddr addr,
offset &= 0xff;
switch (offset) {
- case 0x00: /* ITR */
+ case 0x00: /* ITR */
return bank->irqs;
- case 0x04: /* MIR */
+ case 0x04: /* MIR */
return bank->mask;
- case 0x10: /* SIR_IRQ_CODE */
+ case 0x10: /* SIR_IRQ_CODE */
case 0x14: /* SIR_FIQ_CODE */
if (bank_no != 0)
break;
@@ -181,49 +159,49 @@ static uint64_t omap_inth_read(void *opaque, hwaddr addr,
bank->irqs &= ~(1 << i);
return line_no;
- case 0x18: /* CONTROL_REG */
+ case 0x18: /* CONTROL_REG */
if (bank_no != 0)
break;
return 0;
- case 0x1c: /* ILR0 */
- case 0x20: /* ILR1 */
- case 0x24: /* ILR2 */
- case 0x28: /* ILR3 */
- case 0x2c: /* ILR4 */
- case 0x30: /* ILR5 */
- case 0x34: /* ILR6 */
- case 0x38: /* ILR7 */
- case 0x3c: /* ILR8 */
- case 0x40: /* ILR9 */
- case 0x44: /* ILR10 */
- case 0x48: /* ILR11 */
- case 0x4c: /* ILR12 */
- case 0x50: /* ILR13 */
- case 0x54: /* ILR14 */
- case 0x58: /* ILR15 */
- case 0x5c: /* ILR16 */
- case 0x60: /* ILR17 */
- case 0x64: /* ILR18 */
- case 0x68: /* ILR19 */
- case 0x6c: /* ILR20 */
- case 0x70: /* ILR21 */
- case 0x74: /* ILR22 */
- case 0x78: /* ILR23 */
- case 0x7c: /* ILR24 */
- case 0x80: /* ILR25 */
- case 0x84: /* ILR26 */
- case 0x88: /* ILR27 */
- case 0x8c: /* ILR28 */
- case 0x90: /* ILR29 */
- case 0x94: /* ILR30 */
- case 0x98: /* ILR31 */
+ case 0x1c: /* ILR0 */
+ case 0x20: /* ILR1 */
+ case 0x24: /* ILR2 */
+ case 0x28: /* ILR3 */
+ case 0x2c: /* ILR4 */
+ case 0x30: /* ILR5 */
+ case 0x34: /* ILR6 */
+ case 0x38: /* ILR7 */
+ case 0x3c: /* ILR8 */
+ case 0x40: /* ILR9 */
+ case 0x44: /* ILR10 */
+ case 0x48: /* ILR11 */
+ case 0x4c: /* ILR12 */
+ case 0x50: /* ILR13 */
+ case 0x54: /* ILR14 */
+ case 0x58: /* ILR15 */
+ case 0x5c: /* ILR16 */
+ case 0x60: /* ILR17 */
+ case 0x64: /* ILR18 */
+ case 0x68: /* ILR19 */
+ case 0x6c: /* ILR20 */
+ case 0x70: /* ILR21 */
+ case 0x74: /* ILR22 */
+ case 0x78: /* ILR23 */
+ case 0x7c: /* ILR24 */
+ case 0x80: /* ILR25 */
+ case 0x84: /* ILR26 */
+ case 0x88: /* ILR27 */
+ case 0x8c: /* ILR28 */
+ case 0x90: /* ILR29 */
+ case 0x94: /* ILR30 */
+ case 0x98: /* ILR31 */
i = (offset - 0x1c) >> 2;
return (bank->priority[i] << 2) |
(((bank->sens_edge >> i) & 1) << 1) |
((bank->fiq >> i) & 1);
- case 0x9c: /* ISR */
+ case 0x9c: /* ISR */
return 0x00000000;
}
@@ -241,24 +219,24 @@ static void omap_inth_write(void *opaque, hwaddr addr,
offset &= 0xff;
switch (offset) {
- case 0x00: /* ITR */
+ case 0x00: /* ITR */
/* Important: ignore the clearing if the IRQ is level-triggered and
the input bit is 1 */
bank->irqs &= value | (bank->inputs & bank->sens_edge);
return;
- case 0x04: /* MIR */
+ case 0x04: /* MIR */
bank->mask = value;
omap_inth_update(s, 0);
omap_inth_update(s, 1);
return;
- case 0x10: /* SIR_IRQ_CODE */
- case 0x14: /* SIR_FIQ_CODE */
+ case 0x10: /* SIR_IRQ_CODE */
+ case 0x14: /* SIR_FIQ_CODE */
OMAP_RO_REG(addr);
break;
- case 0x18: /* CONTROL_REG */
+ case 0x18: /* CONTROL_REG */
if (bank_no != 0)
break;
if (value & 2) {
@@ -273,38 +251,38 @@ static void omap_inth_write(void *opaque, hwaddr addr,
}
return;
- case 0x1c: /* ILR0 */
- case 0x20: /* ILR1 */
- case 0x24: /* ILR2 */
- case 0x28: /* ILR3 */
- case 0x2c: /* ILR4 */
- case 0x30: /* ILR5 */
- case 0x34: /* ILR6 */
- case 0x38: /* ILR7 */
- case 0x3c: /* ILR8 */
- case 0x40: /* ILR9 */
- case 0x44: /* ILR10 */
- case 0x48: /* ILR11 */
- case 0x4c: /* ILR12 */
- case 0x50: /* ILR13 */
- case 0x54: /* ILR14 */
- case 0x58: /* ILR15 */
- case 0x5c: /* ILR16 */
- case 0x60: /* ILR17 */
- case 0x64: /* ILR18 */
- case 0x68: /* ILR19 */
- case 0x6c: /* ILR20 */
- case 0x70: /* ILR21 */
- case 0x74: /* ILR22 */
- case 0x78: /* ILR23 */
- case 0x7c: /* ILR24 */
- case 0x80: /* ILR25 */
- case 0x84: /* ILR26 */
- case 0x88: /* ILR27 */
- case 0x8c: /* ILR28 */
- case 0x90: /* ILR29 */
- case 0x94: /* ILR30 */
- case 0x98: /* ILR31 */
+ case 0x1c: /* ILR0 */
+ case 0x20: /* ILR1 */
+ case 0x24: /* ILR2 */
+ case 0x28: /* ILR3 */
+ case 0x2c: /* ILR4 */
+ case 0x30: /* ILR5 */
+ case 0x34: /* ILR6 */
+ case 0x38: /* ILR7 */
+ case 0x3c: /* ILR8 */
+ case 0x40: /* ILR9 */
+ case 0x44: /* ILR10 */
+ case 0x48: /* ILR11 */
+ case 0x4c: /* ILR12 */
+ case 0x50: /* ILR13 */
+ case 0x54: /* ILR14 */
+ case 0x58: /* ILR15 */
+ case 0x5c: /* ILR16 */
+ case 0x60: /* ILR17 */
+ case 0x64: /* ILR18 */
+ case 0x68: /* ILR19 */
+ case 0x6c: /* ILR20 */
+ case 0x70: /* ILR21 */
+ case 0x74: /* ILR22 */
+ case 0x78: /* ILR23 */
+ case 0x7c: /* ILR24 */
+ case 0x80: /* ILR25 */
+ case 0x84: /* ILR26 */
+ case 0x88: /* ILR27 */
+ case 0x8c: /* ILR28 */
+ case 0x90: /* ILR29 */
+ case 0x94: /* ILR30 */
+ case 0x98: /* ILR31 */
i = (offset - 0x1c) >> 2;
bank->priority[i] = (value >> 2) & 0x1f;
bank->sens_edge &= ~(1 << i);
@@ -313,7 +291,7 @@ static void omap_inth_write(void *opaque, hwaddr addr,
bank->fiq |= (value & 1) << i;
return;
- case 0x9c: /* ISR */
+ case 0x9c: /* ISR */
for (i = 0; i < 32; i ++)
if (value & (1 << i)) {
omap_set_intr(s, 32 * bank_no + i, 1);
@@ -397,16 +375,15 @@ void omap_intc_set_fclk(OMAPIntcState *intc, omap_clk clk)
intc->fclk = clk;
}
-static Property omap_intc_properties[] = {
+static const Property omap_intc_properties[] = {
DEFINE_PROP_UINT32("size", OMAPIntcState, size, 0x100),
- DEFINE_PROP_END_OF_LIST(),
};
-static void omap_intc_class_init(ObjectClass *klass, void *data)
+static void omap_intc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = omap_inth_reset;
+ device_class_set_legacy_reset(dc, omap_inth_reset);
device_class_set_props(dc, omap_intc_properties);
/* Reason: pointer property "clk" */
dc->user_creatable = false;
@@ -414,277 +391,16 @@ static void omap_intc_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo omap_intc_info = {
- .name = "omap-intc",
- .parent = TYPE_OMAP_INTC,
- .instance_init = omap_intc_init,
- .class_init = omap_intc_class_init,
-};
-
-static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- OMAPIntcState *s = opaque;
- int offset = addr;
- int bank_no, line_no;
- struct omap_intr_handler_bank_s *bank = NULL;
-
- if ((offset & 0xf80) == 0x80) {
- bank_no = (offset & 0x60) >> 5;
- if (bank_no < s->nbanks) {
- offset &= ~0x60;
- bank = &s->bank[bank_no];
- } else {
- OMAP_BAD_REG(addr);
- return 0;
- }
- }
-
- switch (offset) {
- case 0x00: /* INTC_REVISION */
- return s->revision;
-
- case 0x10: /* INTC_SYSCONFIG */
- return (s->autoidle >> 2) & 1;
-
- case 0x14: /* INTC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* INTC_SIR_IRQ */
- return s->sir_intr[0];
-
- case 0x44: /* INTC_SIR_FIQ */
- return s->sir_intr[1];
-
- case 0x48: /* INTC_CONTROL */
- return (!s->mask) << 2; /* GLOBALMASK */
-
- case 0x4c: /* INTC_PROTECTION */
- return 0;
-
- case 0x50: /* INTC_IDLE */
- return s->autoidle & 3;
-
- /* Per-bank registers */
- case 0x80: /* INTC_ITR */
- return bank->inputs;
-
- case 0x84: /* INTC_MIR */
- return bank->mask;
-
- case 0x88: /* INTC_MIR_CLEAR */
- case 0x8c: /* INTC_MIR_SET */
- return 0;
-
- case 0x90: /* INTC_ISR_SET */
- return bank->swi;
-
- case 0x94: /* INTC_ISR_CLEAR */
- return 0;
-
- case 0x98: /* INTC_PENDING_IRQ */
- return bank->irqs & ~bank->mask & ~bank->fiq;
-
- case 0x9c: /* INTC_PENDING_FIQ */
- return bank->irqs & ~bank->mask & bank->fiq;
-
- /* Per-line registers */
- case 0x100 ... 0x300: /* INTC_ILR */
- bank_no = (offset - 0x100) >> 7;
- if (bank_no > s->nbanks)
- break;
- bank = &s->bank[bank_no];
- line_no = (offset & 0x7f) >> 2;
- return (bank->priority[line_no] << 2) |
- ((bank->fiq >> line_no) & 1);
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_inth_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- OMAPIntcState *s = opaque;
- int offset = addr;
- int bank_no, line_no;
- struct omap_intr_handler_bank_s *bank = NULL;
-
- if ((offset & 0xf80) == 0x80) {
- bank_no = (offset & 0x60) >> 5;
- if (bank_no < s->nbanks) {
- offset &= ~0x60;
- bank = &s->bank[bank_no];
- } else {
- OMAP_BAD_REG(addr);
- return;
- }
- }
-
- switch (offset) {
- case 0x10: /* INTC_SYSCONFIG */
- s->autoidle &= 4;
- s->autoidle |= (value & 1) << 2;
- if (value & 2) { /* SOFTRESET */
- omap_inth_reset(DEVICE(s));
- }
- return;
-
- case 0x48: /* INTC_CONTROL */
- s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */
- if (value & 2) { /* NEWFIQAGR */
- qemu_set_irq(s->parent_intr[1], 0);
- s->new_agr[1] = ~0;
- omap_inth_update(s, 1);
- }
- if (value & 1) { /* NEWIRQAGR */
- qemu_set_irq(s->parent_intr[0], 0);
- s->new_agr[0] = ~0;
- omap_inth_update(s, 0);
- }
- return;
-
- case 0x4c: /* INTC_PROTECTION */
- /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
- * for every register, see Chapter 3 and 4 for privileged mode. */
- if (value & 1)
- fprintf(stderr, "%s: protection mode enable attempt\n",
- __func__);
- return;
-
- case 0x50: /* INTC_IDLE */
- s->autoidle &= ~3;
- s->autoidle |= value & 3;
- return;
-
- /* Per-bank registers */
- case 0x84: /* INTC_MIR */
- bank->mask = value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x88: /* INTC_MIR_CLEAR */
- bank->mask &= ~value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x8c: /* INTC_MIR_SET */
- bank->mask |= value;
- return;
-
- case 0x90: /* INTC_ISR_SET */
- bank->irqs |= bank->swi |= value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x94: /* INTC_ISR_CLEAR */
- bank->swi &= ~value;
- bank->irqs = bank->swi & bank->inputs;
- return;
-
- /* Per-line registers */
- case 0x100 ... 0x300: /* INTC_ILR */
- bank_no = (offset - 0x100) >> 7;
- if (bank_no > s->nbanks)
- break;
- bank = &s->bank[bank_no];
- line_no = (offset & 0x7f) >> 2;
- bank->priority[line_no] = (value >> 2) & 0x3f;
- bank->fiq &= ~(1 << line_no);
- bank->fiq |= (value & 1) << line_no;
- return;
-
- case 0x00: /* INTC_REVISION */
- case 0x14: /* INTC_SYSSTATUS */
- case 0x40: /* INTC_SIR_IRQ */
- case 0x44: /* INTC_SIR_FIQ */
- case 0x80: /* INTC_ITR */
- case 0x98: /* INTC_PENDING_IRQ */
- case 0x9c: /* INTC_PENDING_FIQ */
- OMAP_RO_REG(addr);
- return;
- }
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap2_inth_mem_ops = {
- .read = omap2_inth_read,
- .write = omap2_inth_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void omap2_intc_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- OMAPIntcState *s = OMAP_INTC(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- s->level_only = 1;
- s->nbanks = 3;
- sysbus_init_irq(sbd, &s->parent_intr[0]);
- sysbus_init_irq(sbd, &s->parent_intr[1]);
- qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
- memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s,
- "omap2-intc", 0x1000);
- sysbus_init_mmio(sbd, &s->mmio);
-}
-
-static void omap2_intc_realize(DeviceState *dev, Error **errp)
-{
- OMAPIntcState *s = OMAP_INTC(dev);
-
- if (!s->iclk) {
- error_setg(errp, "omap2-intc: iclk not connected");
- return;
- }
- if (!s->fclk) {
- error_setg(errp, "omap2-intc: fclk not connected");
- return;
- }
-}
-
-static Property omap2_intc_properties[] = {
- DEFINE_PROP_UINT8("revision", OMAPIntcState,
- revision, 0x21),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_intc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = omap_inth_reset;
- device_class_set_props(dc, omap2_intc_properties);
- /* Reason: pointer property "iclk", "fclk" */
- dc->user_creatable = false;
- dc->realize = omap2_intc_realize;
-}
-
-static const TypeInfo omap2_intc_info = {
- .name = "omap2-intc",
- .parent = TYPE_OMAP_INTC,
- .instance_init = omap2_intc_init,
- .class_init = omap2_intc_class_init,
-};
-
-static const TypeInfo omap_intc_type_info = {
.name = TYPE_OMAP_INTC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(OMAPIntcState),
- .abstract = true,
+ .instance_init = omap_intc_init,
+ .class_init = omap_intc_class_init,
};
static void omap_intc_register_types(void)
{
- type_register_static(&omap_intc_type_info);
type_register_static(&omap_intc_info);
- type_register_static(&omap2_intc_info);
}
type_init(omap_intc_register_types)
diff --git a/hw/intc/ompic.c b/hw/intc/ompic.c
index 99032ea..047c367 100644
--- a/hw/intc/ompic.c
+++ b/hw/intc/ompic.c
@@ -13,7 +13,7 @@
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qom/object.h"
#define TYPE_OR1K_OMPIC "or1k-ompic"
@@ -128,9 +128,8 @@ static void or1k_ompic_realize(DeviceState *dev, Error **errp)
}
}
-static Property or1k_ompic_properties[] = {
+static const Property or1k_ompic_properties[] = {
DEFINE_PROP_UINT32("num-cpus", OR1KOMPICState, num_cpus, 1),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_or1k_ompic_cpu = {
@@ -156,7 +155,7 @@ static const VMStateDescription vmstate_or1k_ompic = {
}
};
-static void or1k_ompic_class_init(ObjectClass *klass, void *data)
+static void or1k_ompic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 9792a11..87733eb 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -41,7 +41,6 @@
#include "hw/pci/msi.h"
#include "qapi/error.h"
#include "qemu/bitops.h"
-#include "qapi/qmp/qerror.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
@@ -1032,13 +1031,14 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
s_IRQ = IRQ_get_next(opp, &dst->servicing);
/* Check queued interrupts. */
n_IRQ = IRQ_get_next(opp, &dst->raised);
- src = &opp->src[n_IRQ];
- if (n_IRQ != -1 &&
- (s_IRQ == -1 ||
- IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
- DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
- idx, n_IRQ);
- qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
+ if (n_IRQ != -1) {
+ src = &opp->src[n_IRQ];
+ if (s_IRQ == -1 ||
+ IVPR_PRIORITY(src->ivpr) > dst->servicing.priority) {
+ DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
+ idx, n_IRQ);
+ qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
+ }
}
break;
default:
@@ -1535,9 +1535,7 @@ static void openpic_realize(DeviceState *dev, Error **errp)
};
if (opp->nb_cpus > MAX_CPU) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
- TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus,
- (uint64_t)0, (uint64_t)MAX_CPU);
+ error_setg(errp, "property 'nb_cpus' can be at most %d", MAX_CPU);
return;
}
@@ -1608,19 +1606,18 @@ static void openpic_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq);
}
-static Property openpic_properties[] = {
+static const Property openpic_properties[] = {
DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void openpic_class_init(ObjectClass *oc, void *data)
+static void openpic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = openpic_realize;
device_class_set_props(dc, openpic_properties);
- dc->reset = openpic_reset;
+ device_class_set_legacy_reset(dc, openpic_reset);
dc->vmsd = &vmstate_openpic;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index 557dd0c..673ea9c 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -30,7 +30,7 @@
#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qom/object.h"
@@ -262,19 +262,18 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
kvm_arch_vcpu_id(cs));
}
-static Property kvm_openpic_properties[] = {
+static const Property kvm_openpic_properties[] = {
DEFINE_PROP_UINT32("model", KVMOpenPICState, model,
OPENPIC_MODEL_FSL_MPIC_20),
- DEFINE_PROP_END_OF_LIST(),
};
-static void kvm_openpic_class_init(ObjectClass *oc, void *data)
+static void kvm_openpic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = kvm_openpic_realize;
device_class_set_props(dc, kvm_openpic_properties);
- dc->reset = kvm_openpic_reset;
+ device_class_set_legacy_reset(dc, kvm_openpic_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
diff --git a/hw/intc/pl190.c b/hw/intc/pl190.c
index d79e5d8..838c21c 100644
--- a/hw/intc/pl190.c
+++ b/hw/intc/pl190.c
@@ -273,11 +273,11 @@ static const VMStateDescription vmstate_pl190 = {
}
};
-static void pl190_class_init(ObjectClass *klass, void *data)
+static void pl190_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pl190_reset;
+ device_class_set_legacy_reset(dc, pl190_reset);
dc->vmsd = &vmstate_pl190;
}
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index 5bacbce..935c0e4 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -1,10 +1,9 @@
/*
* QEMU PowerPC XIVE interrupt controller model
*
- * Copyright (c) 2017-2019, IBM Corporation.
+ * Copyright (c) 2017-2024, IBM Corporation.
*
- * This code is licensed under the GPL version 2 or later. See the
- * COPYING file in the top-level directory.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
@@ -12,9 +11,9 @@
#include "qemu/module.h"
#include "qapi/error.h"
#include "target/ppc/cpu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/dma.h"
-#include "sysemu/reset.h"
+#include "system/cpus.h"
+#include "system/dma.h"
+#include "system/reset.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_chip.h"
@@ -473,7 +472,7 @@ static bool pnv_xive_is_cpu_enabled(PnvXive *xive, PowerPCCPU *cpu)
static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
PnvXive *xive = PNV_XIVE(xptr);
@@ -500,7 +499,8 @@ static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
* Check the thread context CAM lines and record matches.
*/
ring = xive_presenter_tctx_match(xptr, tctx, format, nvt_blk,
- nvt_idx, cam_ignore, logic_serv);
+ nvt_idx, cam_ignore,
+ logic_serv);
/*
* Save the context and follow on to catch duplicates, that we
* don't support yet.
@@ -2059,17 +2059,16 @@ static int pnv_xive_dt_xscom(PnvXScomInterface *dev, void *fdt,
return 0;
}
-static Property pnv_xive_properties[] = {
+static const Property pnv_xive_properties[] = {
DEFINE_PROP_UINT64("ic-bar", PnvXive, ic_base, 0),
DEFINE_PROP_UINT64("vc-bar", PnvXive, vc_base, 0),
DEFINE_PROP_UINT64("pc-bar", PnvXive, pc_base, 0),
DEFINE_PROP_UINT64("tm-bar", PnvXive, tm_base, 0),
/* The PnvChip id identifies the XIVE interrupt controller. */
DEFINE_PROP_LINK("chip", PnvXive, chip, TYPE_PNV_CHIP, PnvChip *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_xive_class_init(ObjectClass *klass, void *data)
+static void pnv_xive_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -2107,7 +2106,7 @@ static const TypeInfo pnv_xive_info = {
.instance_size = sizeof(PnvXive),
.class_init = pnv_xive_class_init,
.class_size = sizeof(PnvXiveClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c
index 7860910..ec8b0c6 100644
--- a/hw/intc/pnv_xive2.c
+++ b/hw/intc/pnv_xive2.c
@@ -1,18 +1,17 @@
/*
* QEMU PowerPC XIVE2 interrupt controller model (POWER10)
*
- * Copyright (c) 2019-2022, IBM Corporation.
+ * Copyright (c) 2019-2024, IBM Corporation.
*
- * This code is licensed under the GPL version 2 or later. See the
- * COPYING file in the top-level directory.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "target/ppc/cpu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/dma.h"
+#include "system/cpus.h"
+#include "system/dma.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_chip.h"
@@ -24,8 +23,8 @@
#include "hw/ppc/xive2_regs.h"
#include "hw/ppc/ppc.h"
#include "hw/qdev-properties.h"
-#include "sysemu/reset.h"
-#include "sysemu/qtest.h"
+#include "system/reset.h"
+#include "system/qtest.h"
#include <libfdt.h>
@@ -490,6 +489,23 @@ static int pnv_xive2_write_nvp(Xive2Router *xrtr, uint8_t blk, uint32_t idx,
word_number);
}
+static int pnv_xive2_get_nvgc(Xive2Router *xrtr, bool crowd,
+ uint8_t blk, uint32_t idx,
+ Xive2Nvgc *nvgc)
+{
+ return pnv_xive2_vst_read(PNV_XIVE2(xrtr), crowd ? VST_NVC : VST_NVG,
+ blk, idx, nvgc);
+}
+
+static int pnv_xive2_write_nvgc(Xive2Router *xrtr, bool crowd,
+ uint8_t blk, uint32_t idx,
+ Xive2Nvgc *nvgc)
+{
+ return pnv_xive2_vst_write(PNV_XIVE2(xrtr), crowd ? VST_NVC : VST_NVG,
+ blk, idx, nvgc,
+ XIVE_VST_WORD_ALL);
+}
+
static int pnv_xive2_nxc_to_table_type(uint8_t nxc_type, uint32_t *table_type)
{
switch (nxc_type) {
@@ -608,7 +624,7 @@ static bool pnv_xive2_is_cpu_enabled(PnvXive2 *xive, PowerPCCPU *cpu)
static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
PnvXive2 *xive = PNV_XIVE2(xptr);
@@ -639,25 +655,38 @@ static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
logic_serv);
} else {
ring = xive2_presenter_tctx_match(xptr, tctx, format, nvt_blk,
- nvt_idx, cam_ignore,
- logic_serv);
+ nvt_idx, crowd, cam_ignore,
+ logic_serv);
}
- /*
- * Save the context and follow on to catch duplicates,
- * that we don't support yet.
- */
if (ring != -1) {
- if (match->tctx) {
+ /*
+ * For VP-specific match, finding more than one is a
+ * problem. For group notification, it's possible.
+ */
+ if (!cam_ignore && match->tctx) {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: already found a "
"thread context NVT %x/%x\n",
nvt_blk, nvt_idx);
- return false;
+ /* Should set a FIR if we ever model it */
+ return -1;
+ }
+ /*
+ * For a group notification, we need to know if the
+ * match is precluded first by checking the current
+ * thread priority. If the interrupt can be delivered,
+ * we always notify the first match (for now).
+ */
+ if (cam_ignore &&
+ xive2_tm_irq_precluded(tctx, ring, priority)) {
+ match->precluded = true;
+ } else {
+ if (!match->tctx) {
+ match->ring = ring;
+ match->tctx = tctx;
+ }
+ count++;
}
-
- match->ring = ring;
- match->tctx = tctx;
- count++;
}
}
}
@@ -676,6 +705,47 @@ static uint32_t pnv_xive2_presenter_get_config(XivePresenter *xptr)
return cfg;
}
+static int pnv_xive2_broadcast(XivePresenter *xptr,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool crowd, bool ignore, uint8_t priority)
+{
+ PnvXive2 *xive = PNV_XIVE2(xptr);
+ PnvChip *chip = xive->chip;
+ int i, j;
+ bool gen1_tima_os =
+ xive->cq_regs[CQ_XIVE_CFG >> 3] & CQ_XIVE_CFG_GEN1_TIMA_OS;
+
+ for (i = 0; i < chip->nr_cores; i++) {
+ PnvCore *pc = chip->cores[i];
+ CPUCore *cc = CPU_CORE(pc);
+
+ for (j = 0; j < cc->nr_threads; j++) {
+ PowerPCCPU *cpu = pc->threads[j];
+ XiveTCTX *tctx;
+ int ring;
+
+ if (!pnv_xive2_is_cpu_enabled(xive, cpu)) {
+ continue;
+ }
+
+ tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc);
+
+ if (gen1_tima_os) {
+ ring = xive_presenter_tctx_match(xptr, tctx, 0, nvt_blk,
+ nvt_idx, ignore, 0);
+ } else {
+ ring = xive2_presenter_tctx_match(xptr, tctx, 0, nvt_blk,
+ nvt_idx, crowd, ignore, 0);
+ }
+
+ if (ring != -1) {
+ xive2_tm_set_lsmfb(tctx, ring, priority);
+ }
+ }
+ }
+ return 0;
+}
+
static uint8_t pnv_xive2_get_block_id(Xive2Router *xrtr)
{
return pnv_xive2_block_id(PNV_XIVE2(xrtr));
@@ -2132,21 +2202,40 @@ static const MemoryRegionOps pnv_xive2_tm_ops = {
},
};
-static uint64_t pnv_xive2_nvc_read(void *opaque, hwaddr offset,
+static uint64_t pnv_xive2_nvc_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
+ XivePresenter *xptr = XIVE_PRESENTER(xive);
+ uint32_t page = addr >> xive->nvpg_shift;
+ uint16_t op = addr & 0xFFF;
+ uint8_t blk = pnv_xive2_block_id(xive);
- xive2_error(xive, "NVC: invalid read @%"HWADDR_PRIx, offset);
- return -1;
+ if (size != 2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid nvc load size %d\n",
+ size);
+ return -1;
+ }
+
+ return xive2_presenter_nvgc_backlog_op(xptr, true, blk, page, op, 1);
}
-static void pnv_xive2_nvc_write(void *opaque, hwaddr offset,
+static void pnv_xive2_nvc_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
+ XivePresenter *xptr = XIVE_PRESENTER(xive);
+ uint32_t page = addr >> xive->nvc_shift;
+ uint16_t op = addr & 0xFFF;
+ uint8_t blk = pnv_xive2_block_id(xive);
+
+ if (size != 1) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid nvc write size %d\n",
+ size);
+ return;
+ }
- xive2_error(xive, "NVC: invalid write @%"HWADDR_PRIx, offset);
+ (void)xive2_presenter_nvgc_backlog_op(xptr, true, blk, page, op, val);
}
static const MemoryRegionOps pnv_xive2_nvc_ops = {
@@ -2154,30 +2243,63 @@ static const MemoryRegionOps pnv_xive2_nvc_ops = {
.write = pnv_xive2_nvc_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
.impl = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
};
-static uint64_t pnv_xive2_nvpg_read(void *opaque, hwaddr offset,
+static uint64_t pnv_xive2_nvpg_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
+ XivePresenter *xptr = XIVE_PRESENTER(xive);
+ uint32_t page = addr >> xive->nvpg_shift;
+ uint16_t op = addr & 0xFFF;
+ uint32_t index = page >> 1;
+ uint8_t blk = pnv_xive2_block_id(xive);
- xive2_error(xive, "NVPG: invalid read @%"HWADDR_PRIx, offset);
- return -1;
+ if (size != 2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid nvpg load size %d\n",
+ size);
+ return -1;
+ }
+
+ if (page % 2) {
+ /* odd page - NVG */
+ return xive2_presenter_nvgc_backlog_op(xptr, false, blk, index, op, 1);
+ } else {
+ /* even page - NVP */
+ return xive2_presenter_nvp_backlog_op(xptr, blk, index, op);
+ }
}
-static void pnv_xive2_nvpg_write(void *opaque, hwaddr offset,
+static void pnv_xive2_nvpg_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
+ XivePresenter *xptr = XIVE_PRESENTER(xive);
+ uint32_t page = addr >> xive->nvpg_shift;
+ uint16_t op = addr & 0xFFF;
+ uint32_t index = page >> 1;
+ uint8_t blk = pnv_xive2_block_id(xive);
+
+ if (size != 1) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid nvpg write size %d\n",
+ size);
+ return;
+ }
- xive2_error(xive, "NVPG: invalid write @%"HWADDR_PRIx, offset);
+ if (page % 2) {
+ /* odd page - NVG */
+ (void)xive2_presenter_nvgc_backlog_op(xptr, false, blk, index, op, val);
+ } else {
+ /* even page - NVP */
+ (void)xive2_presenter_nvp_backlog_op(xptr, blk, index, op);
+ }
}
static const MemoryRegionOps pnv_xive2_nvpg_ops = {
@@ -2185,11 +2307,11 @@ static const MemoryRegionOps pnv_xive2_nvpg_ops = {
.write = pnv_xive2_nvpg_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
.impl = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
};
@@ -2337,7 +2459,7 @@ static void pnv_xive2_realize(DeviceState *dev, Error **errp)
qemu_register_reset(pnv_xive2_reset, dev);
}
-static Property pnv_xive2_properties[] = {
+static const Property pnv_xive2_properties[] = {
DEFINE_PROP_UINT64("ic-bar", PnvXive2, ic_base, 0),
DEFINE_PROP_UINT64("esb-bar", PnvXive2, esb_base, 0),
DEFINE_PROP_UINT64("end-bar", PnvXive2, end_base, 0),
@@ -2349,7 +2471,6 @@ static Property pnv_xive2_properties[] = {
DEFINE_PROP_UINT64("config", PnvXive2, config,
PNV_XIVE2_CONFIGURATION),
DEFINE_PROP_LINK("chip", PnvXive2, chip, TYPE_PNV_CHIP, PnvChip *),
- DEFINE_PROP_END_OF_LIST(),
};
static void pnv_xive2_instance_init(Object *obj)
@@ -2384,7 +2505,7 @@ static int pnv_xive2_dt_xscom(PnvXScomInterface *dev, void *fdt,
return 0;
}
-static void pnv_xive2_class_init(ObjectClass *klass, void *data)
+static void pnv_xive2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -2407,6 +2528,8 @@ static void pnv_xive2_class_init(ObjectClass *klass, void *data)
xrc->write_end = pnv_xive2_write_end;
xrc->get_nvp = pnv_xive2_get_nvp;
xrc->write_nvp = pnv_xive2_write_nvp;
+ xrc->get_nvgc = pnv_xive2_get_nvgc;
+ xrc->write_nvgc = pnv_xive2_write_nvgc;
xrc->get_config = pnv_xive2_get_config;
xrc->get_block_id = pnv_xive2_get_block_id;
@@ -2414,6 +2537,7 @@ static void pnv_xive2_class_init(ObjectClass *klass, void *data)
xpc->match_nvt = pnv_xive2_match_nvt;
xpc->get_config = pnv_xive2_presenter_get_config;
+ xpc->broadcast = pnv_xive2_broadcast;
};
static const TypeInfo pnv_xive2_info = {
@@ -2423,7 +2547,7 @@ static const TypeInfo pnv_xive2_info = {
.instance_size = sizeof(PnvXive2),
.class_init = pnv_xive2_class_init,
.class_size = sizeof(PnvXive2Class),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
@@ -2497,8 +2621,9 @@ void pnv_xive2_pic_print_info(PnvXive2 *xive, GString *buf)
Xive2Eas eas;
Xive2End end;
Xive2Nvp nvp;
+ Xive2Nvgc nvgc;
int i;
- uint64_t xive_nvp_per_subpage;
+ uint64_t entries_per_subpage;
g_string_append_printf(buf, "XIVE[%x] Source %08x .. %08x\n",
blk, srcno0, srcno0 + nr_esbs - 1);
@@ -2530,10 +2655,28 @@ void pnv_xive2_pic_print_info(PnvXive2 *xive, GString *buf)
g_string_append_printf(buf, "XIVE[%x] #%d NVPT %08x .. %08x\n",
chip_id, blk, 0, XIVE2_NVP_COUNT - 1);
- xive_nvp_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVP);
- for (i = 0; i < XIVE2_NVP_COUNT; i += xive_nvp_per_subpage) {
+ entries_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVP);
+ for (i = 0; i < XIVE2_NVP_COUNT; i += entries_per_subpage) {
while (!xive2_router_get_nvp(xrtr, blk, i, &nvp)) {
xive2_nvp_pic_print_info(&nvp, i++, buf);
}
}
+
+ g_string_append_printf(buf, "XIVE[%x] #%d NVGT %08x .. %08x\n",
+ chip_id, blk, 0, XIVE2_NVP_COUNT - 1);
+ entries_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVG);
+ for (i = 0; i < XIVE2_NVP_COUNT; i += entries_per_subpage) {
+ while (!xive2_router_get_nvgc(xrtr, false, blk, i, &nvgc)) {
+ xive2_nvgc_pic_print_info(&nvgc, i++, buf);
+ }
+ }
+
+ g_string_append_printf(buf, "XIVE[%x] #%d NVCT %08x .. %08x\n",
+ chip_id, blk, 0, XIVE2_NVP_COUNT - 1);
+ entries_per_subpage = pnv_xive2_vst_per_subpage(xive, VST_NVC);
+ for (i = 0; i < XIVE2_NVP_COUNT; i += entries_per_subpage) {
+ while (!xive2_router_get_nvgc(xrtr, true, blk, i, &nvgc)) {
+ xive2_nvgc_pic_print_info(&nvgc, i++, buf);
+ }
+ }
}
diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
index 9a67f7f..bc4dc90 100644
--- a/hw/intc/ppc-uic.c
+++ b/hw/intc/ppc-uic.c
@@ -259,10 +259,9 @@ static void ppc_uic_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
}
-static Property ppc_uic_properties[] = {
+static const Property ppc_uic_properties[] = {
DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0xc0),
DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
- DEFINE_PROP_END_OF_LIST()
};
static const VMStateDescription ppc_uic_vmstate = {
@@ -282,11 +281,11 @@ static const VMStateDescription ppc_uic_vmstate = {
},
};
-static void ppc_uic_class_init(ObjectClass *klass, void *data)
+static void ppc_uic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ppc_uic_reset;
+ device_class_set_legacy_reset(dc, ppc_uic_reset);
dc->realize = ppc_uic_realize;
dc->vmsd = &ppc_uic_vmstate;
device_class_set_props(dc, ppc_uic_properties);
diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c
index 9b12116..63e25c2 100644
--- a/hw/intc/realview_gic.c
+++ b/hw/intc/realview_gic.c
@@ -63,7 +63,7 @@ static void realview_gic_init(Object *obj)
qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", 1);
}
-static void realview_gic_class_init(ObjectClass *oc, void *data)
+static void realview_gic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index e9f0536..b0139f0 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -262,7 +262,7 @@ static const MemoryRegionOps riscv_aclint_mtimer_ops = {
}
};
-static Property riscv_aclint_mtimer_properties[] = {
+static const Property riscv_aclint_mtimer_properties[] = {
DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
hartid_base, 0),
DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 1),
@@ -274,7 +274,6 @@ static Property riscv_aclint_mtimer_properties[] = {
aperture_size, RISCV_ACLINT_DEFAULT_MTIMER_SIZE),
DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
timebase_freq, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
@@ -329,7 +328,7 @@ static const VMStateDescription vmstate_riscv_mtimer = {
}
};
-static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
+static void riscv_aclint_mtimer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = riscv_aclint_mtimer_realize;
@@ -462,11 +461,10 @@ static const MemoryRegionOps riscv_aclint_swi_ops = {
}
};
-static Property riscv_aclint_swi_properties[] = {
+static const Property riscv_aclint_swi_properties[] = {
DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 1),
DEFINE_PROP_UINT32("sswi", RISCVAclintSwiState, sswi, false),
- DEFINE_PROP_END_OF_LIST(),
};
static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
@@ -511,7 +509,7 @@ static void riscv_aclint_swi_reset_enter(Object *obj, ResetType type)
}
}
-static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
+static void riscv_aclint_swi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = riscv_aclint_swi_realize;
diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
index 32edd6d..8bcd9f4 100644
--- a/hw/intc/riscv_aplic.c
+++ b/hw/intc/riscv_aplic.c
@@ -22,7 +22,7 @@
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "qemu/bswap.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/sysbus.h"
#include "hw/pci/msi.h"
#include "hw/boards.h"
@@ -30,8 +30,9 @@
#include "hw/intc/riscv_aplic.h"
#include "hw/irq.h"
#include "target/riscv/cpu.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
+#include "system/system.h"
+#include "system/kvm.h"
+#include "system/tcg.h"
#include "kvm/kvm_riscv.h"
#include "migration/vmstate.h"
@@ -154,36 +155,76 @@
* KVM AIA only supports APLIC MSI, fallback to QEMU emulation if we want to use
* APLIC Wired.
*/
-static bool is_kvm_aia(bool msimode)
+bool riscv_is_kvm_aia_aplic_imsic(bool msimode)
{
return kvm_irqchip_in_kernel() && msimode;
}
+bool riscv_use_emulated_aplic(bool msimode)
+{
+#ifdef CONFIG_KVM
+ if (tcg_enabled()) {
+ return true;
+ }
+
+ if (!riscv_is_kvm_aia_aplic_imsic(msimode)) {
+ return true;
+ }
+
+ return kvm_kernel_irqchip_split();
+#else
+ return true;
+#endif
+}
+
+void riscv_aplic_set_kvm_msicfgaddr(RISCVAPLICState *aplic, hwaddr addr)
+{
+#ifdef CONFIG_KVM
+ if (riscv_use_emulated_aplic(aplic->msimode)) {
+ addr >>= APLIC_xMSICFGADDR_PPN_SHIFT;
+ aplic->kvm_msicfgaddr = extract64(addr, 0, 32);
+ aplic->kvm_msicfgaddrH = extract64(addr, 32, 32) &
+ APLIC_xMSICFGADDRH_VALID_MASK;
+ }
+#endif
+}
+
+static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic,
+ uint32_t irq)
+{
+ uint32_t sourcecfg, sm, raw_input, irq_inverted;
+
+ if (!irq || aplic->num_irqs <= irq) {
+ return false;
+ }
+
+ sourcecfg = aplic->sourcecfg[irq];
+ if (sourcecfg & APLIC_SOURCECFG_D) {
+ return false;
+ }
+
+ sm = sourcecfg & APLIC_SOURCECFG_SM_MASK;
+ if (sm == APLIC_SOURCECFG_SM_INACTIVE) {
+ return false;
+ }
+
+ raw_input = (aplic->state[irq] & APLIC_ISTATE_INPUT) ? 1 : 0;
+ irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW ||
+ sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0;
+
+ return !!(raw_input ^ irq_inverted);
+}
+
static uint32_t riscv_aplic_read_input_word(RISCVAPLICState *aplic,
uint32_t word)
{
- uint32_t i, irq, sourcecfg, sm, raw_input, irq_inverted, ret = 0;
+ uint32_t i, irq, rectified_val, ret = 0;
for (i = 0; i < 32; i++) {
irq = word * 32 + i;
- if (!irq || aplic->num_irqs <= irq) {
- continue;
- }
- sourcecfg = aplic->sourcecfg[irq];
- if (sourcecfg & APLIC_SOURCECFG_D) {
- continue;
- }
-
- sm = sourcecfg & APLIC_SOURCECFG_SM_MASK;
- if (sm == APLIC_SOURCECFG_SM_INACTIVE) {
- continue;
- }
-
- raw_input = (aplic->state[irq] & APLIC_ISTATE_INPUT) ? 1 : 0;
- irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW ||
- sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0;
- ret |= (raw_input ^ irq_inverted) << i;
+ rectified_val = riscv_aplic_irq_rectified_val(aplic, irq);
+ ret |= rectified_val << i;
}
return ret;
@@ -237,9 +278,12 @@ static void riscv_aplic_set_pending(RISCVAPLICState *aplic,
if ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) ||
(sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) {
- if (!aplic->msimode || (aplic->msimode && !pending)) {
+ if (!aplic->msimode) {
return;
}
+ if (aplic->msimode && !pending) {
+ goto noskip_write_pending;
+ }
if ((aplic->state[irq] & APLIC_ISTATE_INPUT) &&
(sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) {
return;
@@ -250,6 +294,7 @@ static void riscv_aplic_set_pending(RISCVAPLICState *aplic,
}
}
+noskip_write_pending:
riscv_aplic_set_pending_raw(aplic, irq, pending);
}
@@ -348,21 +393,29 @@ static void riscv_aplic_msi_send(RISCVAPLICState *aplic,
uint32_t lhxs, lhxw, hhxs, hhxw, group_idx, msicfgaddr, msicfgaddrH;
aplic_m = aplic;
- while (aplic_m && !aplic_m->mmode) {
- aplic_m = aplic_m->parent;
- }
- if (!aplic_m) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: m-level APLIC not found\n",
- __func__);
- return;
+
+ if (!aplic->kvm_splitmode) {
+ while (aplic_m && !aplic_m->mmode) {
+ aplic_m = aplic_m->parent;
+ }
+ if (!aplic_m) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: m-level APLIC not found\n",
+ __func__);
+ return;
+ }
}
- if (aplic->mmode) {
- msicfgaddr = aplic_m->mmsicfgaddr;
- msicfgaddrH = aplic_m->mmsicfgaddrH;
+ if (aplic->kvm_splitmode) {
+ msicfgaddr = aplic->kvm_msicfgaddr;
+ msicfgaddrH = ((uint64_t)aplic->kvm_msicfgaddrH << 32);
} else {
- msicfgaddr = aplic_m->smsicfgaddr;
- msicfgaddrH = aplic_m->smsicfgaddrH;
+ if (aplic->mmode) {
+ msicfgaddr = aplic_m->mmsicfgaddr;
+ msicfgaddrH = aplic_m->mmsicfgaddrH;
+ } else {
+ msicfgaddr = aplic_m->smsicfgaddr;
+ msicfgaddrH = aplic_m->smsicfgaddrH;
+ }
}
lhxs = (msicfgaddrH >> APLIC_xMSICFGADDRH_LHXS_SHIFT) &
@@ -375,7 +428,6 @@ static void riscv_aplic_msi_send(RISCVAPLICState *aplic,
APLIC_xMSICFGADDRH_HHXW_MASK;
group_idx = hart_idx >> lhxw;
- hart_idx &= APLIC_xMSICFGADDR_PPN_LHX_MASK(lhxw);
addr = msicfgaddr;
addr |= ((uint64_t)(msicfgaddrH & APLIC_xMSICFGADDRH_BAPPN_MASK)) << 32;
@@ -702,6 +754,10 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
(aplic->sourcecfg[irq] == 0)) {
riscv_aplic_set_pending_raw(aplic, irq, false);
riscv_aplic_set_enabled_raw(aplic, irq, false);
+ } else {
+ if (riscv_aplic_irq_rectified_val(aplic, irq)) {
+ riscv_aplic_set_pending_raw(aplic, irq, true);
+ }
}
} else if (aplic->mmode && aplic->msimode &&
(addr == APLIC_MMSICFGADDR)) {
@@ -838,7 +894,27 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
uint32_t i;
RISCVAPLICState *aplic = RISCV_APLIC(dev);
- if (!is_kvm_aia(aplic->msimode)) {
+ if (riscv_use_emulated_aplic(aplic->msimode)) {
+ /* Create output IRQ lines for non-MSI mode */
+ if (!aplic->msimode) {
+ /* Claim the CPU interrupt to be triggered by this APLIC */
+ for (i = 0; i < aplic->num_harts; i++) {
+ RISCVCPU *cpu;
+
+ cpu = RISCV_CPU(cpu_by_arch_id(aplic->hartid_base + i));
+ if (riscv_cpu_claim_interrupts(cpu,
+ (aplic->mmode) ? MIP_MEIP : MIP_SEIP) < 0) {
+ error_report("%s already claimed",
+ (aplic->mmode) ? "MEIP" : "SEIP");
+ exit(1);
+ }
+ }
+
+ aplic->external_irqs = g_malloc(sizeof(qemu_irq) *
+ aplic->num_harts);
+ qdev_init_gpio_out(dev, aplic->external_irqs, aplic->num_harts);
+ }
+
aplic->bitfield_words = (aplic->num_irqs + 31) >> 5;
aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
aplic->state = g_new0(uint32_t, aplic->num_irqs);
@@ -855,6 +931,10 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&aplic->mmio, OBJECT(dev), &riscv_aplic_ops,
aplic, TYPE_RISCV_APLIC, aplic->aperture_size);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &aplic->mmio);
+
+ if (kvm_enabled()) {
+ aplic->kvm_splitmode = true;
+ }
}
/*
@@ -862,34 +942,17 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
* have IRQ lines delegated by their parent APLIC.
*/
if (!aplic->parent) {
- if (kvm_enabled() && is_kvm_aia(aplic->msimode)) {
+ if (kvm_enabled() && !riscv_use_emulated_aplic(aplic->msimode)) {
qdev_init_gpio_in(dev, riscv_kvm_aplic_request, aplic->num_irqs);
} else {
qdev_init_gpio_in(dev, riscv_aplic_request, aplic->num_irqs);
}
}
- /* Create output IRQ lines for non-MSI mode */
- if (!aplic->msimode) {
- aplic->external_irqs = g_malloc(sizeof(qemu_irq) * aplic->num_harts);
- qdev_init_gpio_out(dev, aplic->external_irqs, aplic->num_harts);
-
- /* Claim the CPU interrupt to be triggered by this APLIC */
- for (i = 0; i < aplic->num_harts; i++) {
- RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(aplic->hartid_base + i));
- if (riscv_cpu_claim_interrupts(cpu,
- (aplic->mmode) ? MIP_MEIP : MIP_SEIP) < 0) {
- error_report("%s already claimed",
- (aplic->mmode) ? "MEIP" : "SEIP");
- exit(1);
- }
- }
- }
-
msi_nonbroken = true;
}
-static Property riscv_aplic_properties[] = {
+static const Property riscv_aplic_properties[] = {
DEFINE_PROP_UINT32("aperture-size", RISCVAPLICState, aperture_size, 0),
DEFINE_PROP_UINT32("hartid-base", RISCVAPLICState, hartid_base, 0),
DEFINE_PROP_UINT32("num-harts", RISCVAPLICState, num_harts, 0),
@@ -897,13 +960,12 @@ static Property riscv_aplic_properties[] = {
DEFINE_PROP_UINT32("num-irqs", RISCVAPLICState, num_irqs, 0),
DEFINE_PROP_BOOL("msimode", RISCVAPLICState, msimode, 0),
DEFINE_PROP_BOOL("mmode", RISCVAPLICState, mmode, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_riscv_aplic = {
.name = "riscv_aplic",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(domaincfg, RISCVAPLICState),
VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState),
@@ -911,6 +973,8 @@ static const VMStateDescription vmstate_riscv_aplic = {
VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState),
VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState),
VMSTATE_UINT32(genmsi, RISCVAPLICState),
+ VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState),
+ VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState),
VMSTATE_VARRAY_UINT32(sourcecfg, RISCVAPLICState,
num_irqs, 0,
vmstate_info_uint32, uint32_t),
@@ -933,7 +997,7 @@ static const VMStateDescription vmstate_riscv_aplic = {
}
};
-static void riscv_aplic_class_init(ObjectClass *klass, void *data)
+static void riscv_aplic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1006,17 +1070,17 @@ DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size,
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- if (!is_kvm_aia(msimode)) {
+ if (riscv_use_emulated_aplic(msimode)) {
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
- }
- if (!msimode) {
- for (i = 0; i < num_harts; i++) {
- CPUState *cpu = cpu_by_arch_id(hartid_base + i);
+ if (!msimode) {
+ for (i = 0; i < num_harts; i++) {
+ CPUState *cpu = cpu_by_arch_id(hartid_base + i);
- qdev_connect_gpio_out_named(dev, NULL, i,
- qdev_get_gpio_in(DEVICE(cpu),
+ qdev_connect_gpio_out_named(dev, NULL, i,
+ qdev_get_gpio_in(DEVICE(cpu),
(mmode) ? IRQ_M_EXT : IRQ_S_EXT));
+ }
}
}
diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
index b90f0d7..2169988 100644
--- a/hw/intc/riscv_imsic.c
+++ b/hw/intc/riscv_imsic.c
@@ -22,7 +22,7 @@
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "qemu/bswap.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/sysbus.h"
#include "hw/pci/msi.h"
#include "hw/boards.h"
@@ -31,8 +31,8 @@
#include "hw/irq.h"
#include "target/riscv/cpu.h"
#include "target/riscv/cpu_bits.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
+#include "system/system.h"
+#include "system/kvm.h"
#include "migration/vmstate.h"
#define IMSIC_MMIO_PAGE_LE 0x00
@@ -55,7 +55,7 @@ static uint32_t riscv_imsic_topei(RISCVIMSICState *imsic, uint32_t page)
(imsic->eithreshold[page] <= imsic->num_irqs)) ?
imsic->eithreshold[page] : imsic->num_irqs;
for (i = 1; i < max_irq; i++) {
- if ((imsic->eistate[base + i] & IMSIC_EISTATE_ENPEND) ==
+ if ((qatomic_read(&imsic->eistate[base + i]) & IMSIC_EISTATE_ENPEND) ==
IMSIC_EISTATE_ENPEND) {
return (i << IMSIC_TOPEI_IID_SHIFT) | i;
}
@@ -66,10 +66,24 @@ static uint32_t riscv_imsic_topei(RISCVIMSICState *imsic, uint32_t page)
static void riscv_imsic_update(RISCVIMSICState *imsic, uint32_t page)
{
+ uint32_t base = page * imsic->num_irqs;
+
+ /*
+ * Lower the interrupt line if necessary, then evaluate the current
+ * IMSIC state.
+ * This sequence ensures that any race between evaluating the eistate and
+ * updating the interrupt line will not result in an incorrectly
+ * deactivated connected CPU IRQ line.
+ * If multiple interrupts are pending, this sequence functions identically
+ * to qemu_irq_pulse.
+ */
+
+ if (qatomic_fetch_and(&imsic->eistate[base], ~IMSIC_EISTATE_ENPEND)) {
+ qemu_irq_lower(imsic->external_irqs[page]);
+ }
if (imsic->eidelivery[page] && riscv_imsic_topei(imsic, page)) {
qemu_irq_raise(imsic->external_irqs[page]);
- } else {
- qemu_irq_lower(imsic->external_irqs[page]);
+ qatomic_or(&imsic->eistate[base], IMSIC_EISTATE_ENPEND);
}
}
@@ -125,12 +139,11 @@ static int riscv_imsic_topei_rmw(RISCVIMSICState *imsic, uint32_t page,
topei >>= IMSIC_TOPEI_IID_SHIFT;
base = page * imsic->num_irqs;
if (topei) {
- imsic->eistate[base + topei] &= ~IMSIC_EISTATE_PENDING;
+ qatomic_and(&imsic->eistate[base + topei], ~IMSIC_EISTATE_PENDING);
}
-
- riscv_imsic_update(imsic, page);
}
+ riscv_imsic_update(imsic, page);
return 0;
}
@@ -139,7 +152,7 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
uint32_t num, bool pend, target_ulong *val,
target_ulong new_val, target_ulong wr_mask)
{
- uint32_t i, base;
+ uint32_t i, base, prev;
target_ulong mask;
uint32_t state = (pend) ? IMSIC_EISTATE_PENDING : IMSIC_EISTATE_ENABLED;
@@ -157,10 +170,6 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
if (val) {
*val = 0;
- for (i = 0; i < xlen; i++) {
- mask = (target_ulong)1 << i;
- *val |= (imsic->eistate[base + i] & state) ? mask : 0;
- }
}
for (i = 0; i < xlen; i++) {
@@ -172,10 +181,15 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
mask = (target_ulong)1 << i;
if (wr_mask & mask) {
if (new_val & mask) {
- imsic->eistate[base + i] |= state;
+ prev = qatomic_fetch_or(&imsic->eistate[base + i], state);
} else {
- imsic->eistate[base + i] &= ~state;
+ prev = qatomic_fetch_and(&imsic->eistate[base + i], ~state);
}
+ } else {
+ prev = qatomic_read(&imsic->eistate[base + i]);
+ }
+ if (val && (prev & state)) {
+ *val |= mask;
}
}
@@ -302,14 +316,14 @@ static void riscv_imsic_write(void *opaque, hwaddr addr, uint64_t value,
page = addr >> IMSIC_MMIO_PAGE_SHIFT;
if ((addr & (IMSIC_MMIO_PAGE_SZ - 1)) == IMSIC_MMIO_PAGE_LE) {
if (value && (value < imsic->num_irqs)) {
- imsic->eistate[(page * imsic->num_irqs) + value] |=
- IMSIC_EISTATE_PENDING;
+ qatomic_or(&imsic->eistate[(page * imsic->num_irqs) + value],
+ IMSIC_EISTATE_PENDING);
+
+ /* Update CPU external interrupt status */
+ riscv_imsic_update(imsic, page);
}
}
- /* Update CPU external interrupt status */
- riscv_imsic_update(imsic, page);
-
return;
err:
@@ -335,7 +349,19 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp)
CPUState *cpu = cpu_by_arch_id(imsic->hartid);
CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
+ /* Claim the CPU interrupt to be triggered by this IMSIC */
+ if (riscv_cpu_claim_interrupts(rcpu,
+ (imsic->mmode) ? MIP_MEIP : MIP_SEIP) < 0) {
+ error_setg(errp, "%s already claimed",
+ (imsic->mmode) ? "MEIP" : "SEIP");
+ return;
+ }
+
if (!kvm_irqchip_in_kernel()) {
+ /* Create output IRQ lines */
+ imsic->external_irqs = g_malloc(sizeof(qemu_irq) * imsic->num_pages);
+ qdev_init_gpio_out(dev, imsic->external_irqs, imsic->num_pages);
+
imsic->num_eistate = imsic->num_pages * imsic->num_irqs;
imsic->eidelivery = g_new0(uint32_t, imsic->num_pages);
imsic->eithreshold = g_new0(uint32_t, imsic->num_pages);
@@ -347,18 +373,6 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp)
IMSIC_MMIO_SIZE(imsic->num_pages));
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &imsic->mmio);
- /* Claim the CPU interrupt to be triggered by this IMSIC */
- if (riscv_cpu_claim_interrupts(rcpu,
- (imsic->mmode) ? MIP_MEIP : MIP_SEIP) < 0) {
- error_setg(errp, "%s already claimed",
- (imsic->mmode) ? "MEIP" : "SEIP");
- return;
- }
-
- /* Create output IRQ lines */
- imsic->external_irqs = g_malloc(sizeof(qemu_irq) * imsic->num_pages);
- qdev_init_gpio_out(dev, imsic->external_irqs, imsic->num_pages);
-
/* Force select AIA feature and setup CSR read-modify-write callback */
if (env) {
if (!imsic->mmode) {
@@ -367,19 +381,21 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp)
} else {
rcpu->cfg.ext_smaia = true;
}
- riscv_cpu_set_aia_ireg_rmw_fn(env, (imsic->mmode) ? PRV_M : PRV_S,
- riscv_imsic_rmw, imsic);
+
+ if (!kvm_irqchip_in_kernel()) {
+ riscv_cpu_set_aia_ireg_rmw_fn(env, (imsic->mmode) ? PRV_M : PRV_S,
+ riscv_imsic_rmw, imsic);
+ }
}
msi_nonbroken = true;
}
-static Property riscv_imsic_properties[] = {
+static const Property riscv_imsic_properties[] = {
DEFINE_PROP_BOOL("mmode", RISCVIMSICState, mmode, 0),
DEFINE_PROP_UINT32("hartid", RISCVIMSICState, hartid, 0),
DEFINE_PROP_UINT32("num-pages", RISCVIMSICState, num_pages, 0),
DEFINE_PROP_UINT32("num-irqs", RISCVIMSICState, num_irqs, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_riscv_imsic = {
@@ -400,7 +416,7 @@ static const VMStateDescription vmstate_riscv_imsic = {
}
};
-static void riscv_imsic_class_init(ObjectClass *klass, void *data)
+static void riscv_imsic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -451,15 +467,17 @@ DeviceState *riscv_imsic_create(hwaddr addr, uint32_t hartid, bool mmode,
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
- for (i = 0; i < num_pages; i++) {
- if (!i) {
- qdev_connect_gpio_out_named(dev, NULL, i,
- qdev_get_gpio_in(DEVICE(cpu),
+ if (!kvm_irqchip_in_kernel()) {
+ for (i = 0; i < num_pages; i++) {
+ if (!i) {
+ qdev_connect_gpio_out_named(dev, NULL, i,
+ qdev_get_gpio_in(DEVICE(cpu),
(mmode) ? IRQ_M_EXT : IRQ_S_EXT));
- } else {
- qdev_connect_gpio_out_named(dev, NULL, i,
- qdev_get_gpio_in(DEVICE(cpu),
+ } else {
+ qdev_connect_gpio_out_named(dev, NULL, i,
+ qdev_get_gpio_in(DEVICE(cpu),
IRQ_LOCAL_MAX + i - 1));
+ }
}
}
diff --git a/hw/intc/rx_icu.c b/hw/intc/rx_icu.c
index b2d4338..f861552 100644
--- a/hw/intc/rx_icu.c
+++ b/hw/intc/rx_icu.c
@@ -361,15 +361,14 @@ static const VMStateDescription vmstate_rxicu = {
}
};
-static Property rxicu_properties[] = {
+static const Property rxicu_properties[] = {
DEFINE_PROP_ARRAY("ipr-map", RXICUState, nr_irqs, map,
qdev_prop_uint8, uint8_t),
DEFINE_PROP_ARRAY("trigger-level", RXICUState, nr_sense, init_sense,
qdev_prop_uint8, uint8_t),
- DEFINE_PROP_END_OF_LIST(),
};
-static void rxicu_class_init(ObjectClass *klass, void *data)
+static void rxicu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index a91a4a4..8f4c9fd 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -445,19 +445,18 @@ static void qemu_s390_flic_instance_init(Object *obj)
}
}
-static Property qemu_s390_flic_properties[] = {
+static const Property qemu_s390_flic_properties[] = {
DEFINE_PROP_BOOL("migrate-all-state", QEMUS390FLICState,
migrate_all_state, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
+static void qemu_s390_flic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
device_class_set_props(dc, qemu_s390_flic_properties);
- dc->reset = qemu_s390_flic_reset;
+ device_class_set_legacy_reset(dc, qemu_s390_flic_reset);
dc->vmsd = &qemu_s390_flic_vmstate;
fsc->register_io_adapter = qemu_s390_register_io_adapter;
fsc->io_adapter_map = qemu_s390_io_adapter_map;
@@ -471,33 +470,17 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
fsc->inject_crw_mchk = qemu_s390_inject_crw_mchk;
}
-static Property s390_flic_common_properties[] = {
- DEFINE_PROP_UINT32("adapter_routes_max_batch", S390FLICState,
- adapter_routes_max_batch, ADAPTER_ROUTES_MAX_GSI),
- DEFINE_PROP_BOOL("migration-enabled", S390FLICState,
- migration_enabled, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void s390_flic_common_realize(DeviceState *dev, Error **errp)
{
S390FLICState *fs = S390_FLIC_COMMON(dev);
- uint32_t max_batch = fs->adapter_routes_max_batch;
-
- if (max_batch > ADAPTER_ROUTES_MAX_GSI) {
- error_setg(errp, "flic property adapter_routes_max_batch too big"
- " (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI);
- return;
- }
fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION);
}
-static void s390_flic_class_init(ObjectClass *oc, void *data)
+static void s390_flic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- device_class_set_props(dc, s390_flic_common_properties);
dc->realize = s390_flic_common_realize;
}
@@ -526,18 +509,10 @@ static void qemu_s390_flic_register_types(void)
type_init(qemu_s390_flic_register_types)
-static bool adapter_info_so_needed(void *opaque)
-{
- S390FLICState *fs = s390_get_flic();
-
- return fs->migration_enabled;
-}
-
const VMStateDescription vmstate_adapter_info_so = {
.name = "s390_adapter_info/summary_offset",
.version_id = 1,
.minimum_version_id = 1,
- .needed = adapter_info_so_needed,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(summary_offset, AdapterInfo),
VMSTATE_END_OF_LIST()
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
index 330f08d..f833a39 100644
--- a/hw/intc/s390_flic_kvm.c
+++ b/hw/intc/s390_flic_kvm.c
@@ -16,7 +16,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qapi/error.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/adapter.h"
#include "hw/s390x/css.h"
@@ -670,7 +670,7 @@ static void kvm_s390_flic_reset(DeviceState *dev)
flic_enable_pfault(flic);
}
-static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
+static void kvm_s390_flic_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
@@ -679,7 +679,7 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
device_class_set_parent_realize(dc, kvm_s390_flic_realize,
&kfsc->parent_realize);
dc->vmsd = &kvm_s390_flic_vmstate;
- dc->reset = kvm_s390_flic_reset;
+ device_class_set_legacy_reset(dc, kvm_s390_flic_reset);
fsc->register_io_adapter = kvm_s390_register_io_adapter;
fsc->io_adapter_map = kvm_s390_io_adapter_map;
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c
index e559f11..3160b21 100644
--- a/hw/intc/sifive_plic.c
+++ b/hw/intc/sifive_plic.c
@@ -30,7 +30,7 @@
#include "target/riscv/cpu.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
static bool addr_between(uint32_t addr, uint32_t base, uint32_t num)
{
@@ -189,8 +189,13 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
uint32_t irq = (addr - plic->priority_base) >> 2;
-
- if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
+ if (irq == 0) {
+ /* IRQ 0 source prioority is reserved */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid source priority write 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return;
+ } else if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
/*
* if "num_priorities + 1" is power-of-2, make each register bit of
* interrupt priority WARL (Write-Any-Read-Legal). Just filter
@@ -349,8 +354,10 @@ static void sifive_plic_irq_request(void *opaque, int irq, int level)
{
SiFivePLICState *s = opaque;
- sifive_plic_set_pending(s, irq, level > 0);
- sifive_plic_update(s);
+ if (level > 0) {
+ sifive_plic_set_pending(s, irq, true);
+ sifive_plic_update(s);
+ }
}
static void sifive_plic_realize(DeviceState *dev, Error **errp)
@@ -423,7 +430,7 @@ static const VMStateDescription vmstate_sifive_plic = {
}
};
-static Property sifive_plic_properties[] = {
+static const Property sifive_plic_properties[] = {
DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config),
DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0),
/* number of interrupt sources including interrupt source 0 */
@@ -437,14 +444,13 @@ static Property sifive_plic_properties[] = {
DEFINE_PROP_UINT32("context-base", SiFivePLICState, context_base, 0),
DEFINE_PROP_UINT32("context-stride", SiFivePLICState, context_stride, 0),
DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sifive_plic_class_init(ObjectClass *klass, void *data)
+static void sifive_plic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = sifive_plic_reset;
+ device_class_set_legacy_reset(dc, sifive_plic_reset);
device_class_set_props(dc, sifive_plic_properties);
dc->realize = sifive_plic_realize;
dc->vmsd = &vmstate_sifive_plic;
diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c
index d6e49d2..00b80bb 100644
--- a/hw/intc/slavio_intctl.c
+++ b/hw/intc/slavio_intctl.c
@@ -441,12 +441,12 @@ static void slavio_intctl_init(Object *obj)
}
}
-static void slavio_intctl_class_init(ObjectClass *klass, void *data)
+static void slavio_intctl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
- dc->reset = slavio_intctl_reset;
+ device_class_set_legacy_reset(dc, slavio_intctl_reset);
dc->vmsd = &vmstate_intctl;
#ifdef DEBUG_IRQ_COUNT
ic->get_statistics = slavio_intctl_get_statistics;
@@ -460,7 +460,7 @@ static const TypeInfo slavio_intctl_info = {
.instance_size = sizeof(SLAVIO_INTCTLState),
.instance_init = slavio_intctl_init,
.class_init = slavio_intctl_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index 283a6b8..440edb9 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -1,10 +1,9 @@
/*
* QEMU PowerPC sPAPR XIVE interrupt controller model
*
- * Copyright (c) 2017-2018, IBM Corporation.
+ * Copyright (c) 2017-2024, IBM Corporation.
*
- * This code is licensed under the GPL version 2 or later. See the
- * COPYING file in the top-level directory.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
@@ -13,8 +12,8 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "target/ppc/cpu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/reset.h"
+#include "system/cpus.h"
+#include "system/reset.h"
#include "migration/vmstate.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/spapr.h"
@@ -431,7 +430,8 @@ static int spapr_xive_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk,
static int spapr_xive_match_nvt(XivePresenter *xptr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore,
+ uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
CPUState *cs;
@@ -627,13 +627,12 @@ static void spapr_xive_free_irq(SpaprInterruptController *intc, int lisn)
xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID);
}
-static Property spapr_xive_properties[] = {
+static const Property spapr_xive_properties[] = {
DEFINE_PROP_UINT32("nr-irqs", SpaprXive, nr_irqs, 0),
DEFINE_PROP_UINT32("nr-ends", SpaprXive, nr_ends, 0),
DEFINE_PROP_UINT64("vc-base", SpaprXive, vc_base, SPAPR_XIVE_VC_BASE),
DEFINE_PROP_UINT64("tm-base", SpaprXive, tm_base, SPAPR_XIVE_TM_BASE),
DEFINE_PROP_UINT8("hv-prio", SpaprXive, hv_prio, 7),
- DEFINE_PROP_END_OF_LIST(),
};
static int spapr_xive_cpu_intc_create(SpaprInterruptController *intc,
@@ -810,7 +809,7 @@ static bool spapr_xive_in_kernel_xptr(const XivePresenter *xptr)
return spapr_xive_in_kernel(SPAPR_XIVE(xptr));
}
-static void spapr_xive_class_init(ObjectClass *klass, void *data)
+static void spapr_xive_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
@@ -857,7 +856,7 @@ static const TypeInfo spapr_xive_info = {
.instance_size = sizeof(SpaprXive),
.class_init = spapr_xive_class_init,
.class_size = sizeof(SpaprXiveClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_SPAPR_INTC },
{ }
},
diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c
index 5789062..26d30b4 100644
--- a/hw/intc/spapr_xive_kvm.c
+++ b/hw/intc/spapr_xive_kvm.c
@@ -12,9 +12,9 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "target/ppc/cpu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
-#include "sysemu/runstate.h"
+#include "system/cpus.h"
+#include "system/kvm.h"
+#include "system/runstate.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_cpu_core.h"
#include "hw/ppc/spapr_xive.h"
@@ -720,7 +720,7 @@ int kvmppc_xive_connect(SpaprInterruptController *intc, uint32_t nr_servers,
{
SpaprXive *xive = SPAPR_XIVE(intc);
XiveSource *xsrc = &xive->source;
- size_t esb_len = xive_source_esb_len(xsrc);
+ uint64_t esb_len = xive_source_esb_len(xsrc);
size_t tima_len = 4ull << TM_SHIFT;
CPUState *cs;
int fd;
@@ -824,7 +824,7 @@ void kvmppc_xive_disconnect(SpaprInterruptController *intc)
{
SpaprXive *xive = SPAPR_XIVE(intc);
XiveSource *xsrc;
- size_t esb_len;
+ uint64_t esb_len;
assert(xive->fd != -1);
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 3dcf147..334aa6a 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -80,18 +80,19 @@ aspeed_vic_update_irq(int flags) "Raising IRQ: %d"
aspeed_vic_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_vic_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
# aspeed_intc.c
-aspeed_intc_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
-aspeed_intc_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
-aspeed_intc_set_irq(int irq, int level) "Set IRQ %d: %d"
-aspeed_intc_clear_irq(int irq, int level) "Clear IRQ %d: %d"
-aspeed_intc_update_irq(int irq, int level) "Update IRQ: %d: %d"
-aspeed_intc_pending_irq(int irq, uint32_t value) "Pending IRQ: %d: 0x%x"
-aspeed_intc_trigger_irq(int irq, uint32_t value) "Trigger IRQ: %d: 0x%x"
-aspeed_intc_all_isr_done(int irq) "All source ISR execution are done: %d"
-aspeed_intc_enable(uint32_t value) "Enable: 0x%x"
-aspeed_intc_select(uint32_t value) "Select: 0x%x"
-aspeed_intc_mask(uint32_t change, uint32_t value) "Mask: 0x%x: 0x%x"
-aspeed_intc_unmask(uint32_t change, uint32_t value) "UnMask: 0x%x: 0x%x"
+aspeed_intc_read(const char *s, uint64_t offset, unsigned size, uint32_t value) "%s: From 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_intc_write(const char *s, uint64_t offset, unsigned size, uint32_t data) "%s: To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_intc_set_irq(const char *s, int inpin_idx, int level) "%s: Set IRQ %d: %d"
+aspeed_intc_clear_irq(const char *s, int inpin_idx, int outpin_idx, int level) "%s: Clear IRQ %d-%d: %d"
+aspeed_intc_update_irq(const char *s, int inpin_idx, int outpin_idx, int level) "%s: Update IRQ: %d-%d: %d"
+aspeed_intc_pending_irq(const char *s, int inpin_idx, uint32_t value) "%s: Pending IRQ: %d: 0x%x"
+aspeed_intc_trigger_irq(const char *s, int inpin_idx, int outpin_idx, uint32_t value) "%s: Trigger IRQ: %d-%d: 0x%x"
+aspeed_intc_all_isr_done(const char *s, int inpin_idx) "%s: All source ISR execution are done: %d"
+aspeed_intc_enable(const char *s, uint32_t value) "%s: Enable: 0x%x"
+aspeed_intc_select(const char *s, uint32_t value) "%s: Select: 0x%x"
+aspeed_intc_mask(const char *s, uint32_t change, uint32_t value) "%s: Mask: 0x%x: 0x%x"
+aspeed_intc_unmask(const char *s, uint32_t change, uint32_t value) "%s: UnMask: 0x%x: 0x%x"
+aspeed_intc_all_isr_done_bit(const char *s, int inpin_idx, int bit) "%s: All source ISR execution are done from specific bit: %d-%d"
# arm_gic.c
gic_enable_irq(int irq) "irq %d enabled"
@@ -282,9 +283,13 @@ xive_router_end_notify(uint8_t end_blk, uint32_t end_idx, uint32_t end_data) "EN
xive_router_end_escalate(uint8_t end_blk, uint32_t end_idx, uint8_t esc_blk, uint32_t esc_idx, uint32_t end_data) "END 0x%02x/0x%04x -> escalate END 0x%02x/0x%04x data 0x%08x"
xive_tctx_tm_write(uint32_t index, uint64_t offset, unsigned int size, uint64_t value) "target=%d @0x%"PRIx64" sz=%d val=0x%" PRIx64
xive_tctx_tm_read(uint32_t index, uint64_t offset, unsigned int size, uint64_t value) "target=%d @0x%"PRIx64" sz=%d val=0x%" PRIx64
-xive_presenter_notify(uint8_t nvt_blk, uint32_t nvt_idx, uint8_t ring) "found NVT 0x%x/0x%x ring=0x%x"
+xive_presenter_notify(uint8_t nvt_blk, uint32_t nvt_idx, uint8_t ring, uint8_t group_level) "found NVT 0x%x/0x%x ring=0x%x group_level=%d"
xive_end_source_read(uint8_t end_blk, uint32_t end_idx, uint64_t addr) "END 0x%x/0x%x @0x%"PRIx64
+# xive2.c
+xive_nvp_backlog_op(uint8_t blk, uint32_t idx, uint8_t op, uint8_t priority, uint8_t rc) "NVP 0x%x/0x%x operation=%d priority=%d rc=%d"
+xive_nvgc_backlog_op(bool c, uint8_t blk, uint32_t idx, uint8_t op, uint8_t priority, uint32_t rc) "NVGC crowd=%d 0x%x/0x%x operation=%d priority=%d rc=%d"
+
# pnv_xive.c
pnv_xive_ic_hw_trigger(uint64_t addr, uint64_t val) "@0x%"PRIx64" val=0x%"PRIx64
@@ -309,12 +314,8 @@ loongson_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x
loongson_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
# loongarch_pch_pic.c
loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d"
-loongarch_pch_pic_low_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
-loongarch_pch_pic_low_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
-loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
-loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
-loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
-loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
+loongarch_pch_pic_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
+loongarch_pch_pic_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
# loongarch_pch_msi.c
loongarch_msi_set_irq(int irq_num) "set msi irq %d"
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 6f4d527..d9a199e 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -37,8 +37,8 @@
#include "migration/vmstate.h"
#include "hw/intc/intc.h"
#include "hw/irq.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
+#include "system/kvm.h"
+#include "system/reset.h"
#include "target/ppc/cpu.h"
void icp_pic_print_info(ICPState *icp, GString *buf)
@@ -335,22 +335,6 @@ static void icp_realize(DeviceState *dev, Error **errp)
return;
}
}
- /*
- * The way that pre_2_10_icp is handling is really, really hacky.
- * We used to have here this call:
- *
- * vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp);
- *
- * But we were doing:
- * pre_2_10_vmstate_register_dummy_icp()
- * this vmstate_register()
- * pre_2_10_vmstate_unregister_dummy_icp()
- *
- * So for a short amount of time we had to vmstate entries with
- * the same name. This fixes it.
- */
- vmstate_replace_hack_for_ppc(NULL, icp->cs->cpu_index,
- &vmstate_icp_server, icp);
}
static void icp_unrealize(DeviceState *dev)
@@ -360,14 +344,13 @@ static void icp_unrealize(DeviceState *dev)
vmstate_unregister(NULL, &vmstate_icp_server, icp);
}
-static Property icp_properties[] = {
+static const Property icp_properties[] = {
DEFINE_PROP_LINK(ICP_PROP_XICS, ICPState, xics, TYPE_XICS_FABRIC,
XICSFabric *),
DEFINE_PROP_LINK(ICP_PROP_CPU, ICPState, cs, TYPE_CPU, CPUState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void icp_class_init(ObjectClass *klass, void *data)
+static void icp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -692,14 +675,13 @@ static const VMStateDescription vmstate_ics = {
},
};
-static Property ics_properties[] = {
+static const Property ics_properties[] = {
DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0),
DEFINE_PROP_LINK(ICS_PROP_XICS, ICSState, xics, TYPE_XICS_FABRIC,
XICSFabric *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ics_class_init(ObjectClass *klass, void *data)
+static void ics_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 9719d98..ee72969 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -28,7 +28,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "trace.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_cpu_core.h"
#include "hw/ppc/xics.h"
diff --git a/hw/intc/xics_pnv.c b/hw/intc/xics_pnv.c
index 753c067..ff602d9 100644
--- a/hw/intc/xics_pnv.c
+++ b/hw/intc/xics_pnv.c
@@ -176,7 +176,7 @@ static void pnv_icp_realize(DeviceState *dev, Error **errp)
icp, "icp-thread", 0x1000);
}
-static void pnv_icp_class_init(ObjectClass *klass, void *data)
+static void pnv_icp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICPStateClass *icpc = ICP_CLASS(klass);
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index a0d97bd..7663596 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -436,7 +436,7 @@ static void xics_spapr_deactivate(SpaprInterruptController *intc)
}
}
-static void ics_spapr_class_init(ObjectClass *klass, void *data)
+static void ics_spapr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_CLASS(klass);
@@ -461,7 +461,7 @@ static const TypeInfo ics_spapr_info = {
.name = TYPE_ICS_SPAPR,
.parent = TYPE_ICS,
.class_init = ics_spapr_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_SPAPR_INTC },
{ }
},
diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c
index 6e5012e..5257ad5 100644
--- a/hw/intc/xilinx_intc.c
+++ b/hw/intc/xilinx_intc.c
@@ -3,6 +3,9 @@
*
* Copyright (c) 2009 Edgar E. Iglesias.
*
+ * https://docs.amd.com/v/u/en-US/xps_intc
+ * DS572: LogiCORE IP XPS Interrupt Controller (v2.01a)
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -23,10 +26,12 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/sysbus.h"
#include "qemu/module.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "qom/object.h"
#define D(x)
@@ -49,6 +54,7 @@ struct XpsIntc
{
SysBusDevice parent_obj;
+ EndianMode model_endianness;
MemoryRegion mmio;
qemu_irq parent_irq;
@@ -140,14 +146,28 @@ static void pic_write(void *opaque, hwaddr addr,
update_irq(p);
}
-static const MemoryRegionOps pic_ops = {
- .read = pic_read,
- .write = pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
+static const MemoryRegionOps pic_ops[2] = {
+ [0 ... 1] = {
+ .read = pic_read,
+ .write = pic_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .valid = {
+ /*
+ * All XPS INTC registers are accessed through the PLB interface.
+ * The base address for these registers is provided by the
+ * configuration parameter, C_BASEADDR. Each register is 32 bits
+ * although some bits may be unused and is accessed on a 4-byte
+ * boundary offset from the base address.
+ */
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ },
+ [0].endianness = DEVICE_LITTLE_ENDIAN,
+ [1].endianness = DEVICE_BIG_ENDIAN,
};
static void irq_handler(void *opaque, int irq, int level)
@@ -170,21 +190,35 @@ static void xilinx_intc_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
+}
- memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
+static void xilinx_intc_realize(DeviceState *dev, Error **errp)
+{
+ XpsIntc *p = XILINX_INTC(dev);
+
+ if (p->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
+ error_setg(errp, TYPE_XILINX_INTC " property 'endianness'"
+ " must be set to 'big' or 'little'");
+ return;
+ }
+
+ memory_region_init_io(&p->mmio, OBJECT(dev),
+ &pic_ops[p->model_endianness == ENDIAN_MODE_BIG],
+ p, "xlnx.xps-intc",
R_MAX * 4);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
}
-static Property xilinx_intc_properties[] = {
+static const Property xilinx_intc_properties[] = {
+ DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XpsIntc, model_endianness),
DEFINE_PROP_UINT32("kind-of-intr", XpsIntc, c_kind_of_intr, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xilinx_intc_class_init(ObjectClass *klass, void *data)
+static void xilinx_intc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = xilinx_intc_realize;
device_class_set_props(dc, xilinx_intc_properties);
}
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 5a02dd8..27b473e 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -3,8 +3,7 @@
*
* Copyright (c) 2017-2018, IBM Corporation.
*
- * This code is licensed under the GPL version 2 or later. See the
- * COPYING file in the top-level directory.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
@@ -12,9 +11,9 @@
#include "qemu/module.h"
#include "qapi/error.h"
#include "target/ppc/cpu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/dma.h"
-#include "sysemu/reset.h"
+#include "system/cpus.h"
+#include "system/dma.h"
+#include "system/reset.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
@@ -27,28 +26,6 @@
* XIVE Thread Interrupt Management context
*/
-/*
- * Convert an Interrupt Pending Buffer (IPB) register to a Pending
- * Interrupt Priority Register (PIPR), which contains the priority of
- * the most favored pending notification.
- */
-static uint8_t ipb_to_pipr(uint8_t ibp)
-{
- return ibp ? clz32((uint32_t)ibp << 24) : 0xff;
-}
-
-static uint8_t exception_mask(uint8_t ring)
-{
- switch (ring) {
- case TM_QW1_OS:
- return TM_QW1_NSR_EO;
- case TM_QW3_HV_PHYS:
- return TM_QW3_NSR_HE;
- default:
- g_assert_not_reached();
- }
-}
-
static qemu_irq xive_tctx_output(XiveTCTX *tctx, uint8_t ring)
{
switch (ring) {
@@ -68,66 +45,88 @@ static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
{
uint8_t *regs = &tctx->regs[ring];
uint8_t nsr = regs[TM_NSR];
- uint8_t mask = exception_mask(ring);
qemu_irq_lower(xive_tctx_output(tctx, ring));
- if (regs[TM_NSR] & mask) {
+ if (regs[TM_NSR] != 0) {
uint8_t cppr = regs[TM_PIPR];
+ uint8_t alt_ring;
+ uint8_t *alt_regs;
+
+ /* POOL interrupt uses IPB in QW2, POOL ring */
+ if ((ring == TM_QW3_HV_PHYS) && (nsr & (TM_QW3_NSR_HE_POOL << 6))) {
+ alt_ring = TM_QW2_HV_POOL;
+ } else {
+ alt_ring = ring;
+ }
+ alt_regs = &tctx->regs[alt_ring];
regs[TM_CPPR] = cppr;
- /* Reset the pending buffer bit */
- regs[TM_IPB] &= ~xive_priority_to_ipb(cppr);
- regs[TM_PIPR] = ipb_to_pipr(regs[TM_IPB]);
+ /*
+ * If the interrupt was for a specific VP, reset the pending
+ * buffer bit, otherwise clear the logical server indicator
+ */
+ if (regs[TM_NSR] & TM_NSR_GRP_LVL) {
+ regs[TM_NSR] &= ~TM_NSR_GRP_LVL;
+ } else {
+ alt_regs[TM_IPB] &= ~xive_priority_to_ipb(cppr);
+ }
- /* Drop Exception bit */
- regs[TM_NSR] &= ~mask;
+ /* Drop the exception bit and any group/crowd */
+ regs[TM_NSR] = 0;
- trace_xive_tctx_accept(tctx->cs->cpu_index, ring,
- regs[TM_IPB], regs[TM_PIPR],
+ trace_xive_tctx_accept(tctx->cs->cpu_index, alt_ring,
+ alt_regs[TM_IPB], regs[TM_PIPR],
regs[TM_CPPR], regs[TM_NSR]);
}
- return (nsr << 8) | regs[TM_CPPR];
+ return ((uint64_t)nsr << 8) | regs[TM_CPPR];
}
-static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
+void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring, uint8_t group_level)
{
+ /* HV_POOL ring uses HV_PHYS NSR, CPPR and PIPR registers */
+ uint8_t alt_ring = (ring == TM_QW2_HV_POOL) ? TM_QW3_HV_PHYS : ring;
+ uint8_t *alt_regs = &tctx->regs[alt_ring];
uint8_t *regs = &tctx->regs[ring];
- if (regs[TM_PIPR] < regs[TM_CPPR]) {
+ if (alt_regs[TM_PIPR] < alt_regs[TM_CPPR]) {
switch (ring) {
case TM_QW1_OS:
- regs[TM_NSR] |= TM_QW1_NSR_EO;
+ regs[TM_NSR] = TM_QW1_NSR_EO | (group_level & 0x3F);
+ break;
+ case TM_QW2_HV_POOL:
+ alt_regs[TM_NSR] = (TM_QW3_NSR_HE_POOL << 6) | (group_level & 0x3F);
break;
case TM_QW3_HV_PHYS:
- regs[TM_NSR] |= (TM_QW3_NSR_HE_PHYS << 6);
+ regs[TM_NSR] = (TM_QW3_NSR_HE_PHYS << 6) | (group_level & 0x3F);
break;
default:
g_assert_not_reached();
}
trace_xive_tctx_notify(tctx->cs->cpu_index, ring,
- regs[TM_IPB], regs[TM_PIPR],
- regs[TM_CPPR], regs[TM_NSR]);
+ regs[TM_IPB], alt_regs[TM_PIPR],
+ alt_regs[TM_CPPR], alt_regs[TM_NSR]);
qemu_irq_raise(xive_tctx_output(tctx, ring));
}
}
-void xive_tctx_reset_os_signal(XiveTCTX *tctx)
+void xive_tctx_reset_signal(XiveTCTX *tctx, uint8_t ring)
{
/*
- * Lower the External interrupt. Used when pulling an OS
- * context. It is necessary to avoid catching it in the hypervisor
- * context. It should be raised again when re-pushing the OS
- * context.
+ * Lower the External interrupt. Used when pulling a context. It is
+ * necessary to avoid catching it in the higher privilege context. It
+ * should be raised again when re-pushing the lower privilege context.
*/
- qemu_irq_lower(xive_tctx_output(tctx, TM_QW1_OS));
+ qemu_irq_lower(xive_tctx_output(tctx, ring));
}
static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
{
uint8_t *regs = &tctx->regs[ring];
+ uint8_t pipr_min;
+ uint8_t ring_min;
trace_xive_tctx_set_cppr(tctx->cs->cpu_index, ring,
regs[TM_IPB], regs[TM_PIPR],
@@ -139,18 +138,57 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
tctx->regs[ring + TM_CPPR] = cppr;
+ /*
+ * Recompute the PIPR based on local pending interrupts. The PHYS
+ * ring must take the minimum of both the PHYS and POOL PIPR values.
+ */
+ pipr_min = xive_ipb_to_pipr(regs[TM_IPB]);
+ ring_min = ring;
+
+ /* PHYS updates also depend on POOL values */
+ if (ring == TM_QW3_HV_PHYS) {
+ uint8_t *pool_regs = &tctx->regs[TM_QW2_HV_POOL];
+
+ /* POOL values only matter if POOL ctx is valid */
+ if (pool_regs[TM_WORD2] & 0x80) {
+
+ uint8_t pool_pipr = xive_ipb_to_pipr(pool_regs[TM_IPB]);
+
+ /*
+ * Determine highest priority interrupt and
+ * remember which ring has it.
+ */
+ if (pool_pipr < pipr_min) {
+ pipr_min = pool_pipr;
+ ring_min = TM_QW2_HV_POOL;
+ }
+ }
+ }
+
+ regs[TM_PIPR] = pipr_min;
+
/* CPPR has changed, check if we need to raise a pending exception */
- xive_tctx_notify(tctx, ring);
+ xive_tctx_notify(tctx, ring_min, 0);
}
-void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb)
-{
+void xive_tctx_pipr_update(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
+ uint8_t group_level)
+ {
+ /* HV_POOL ring uses HV_PHYS NSR, CPPR and PIPR registers */
+ uint8_t alt_ring = (ring == TM_QW2_HV_POOL) ? TM_QW3_HV_PHYS : ring;
+ uint8_t *alt_regs = &tctx->regs[alt_ring];
uint8_t *regs = &tctx->regs[ring];
- regs[TM_IPB] |= ipb;
- regs[TM_PIPR] = ipb_to_pipr(regs[TM_IPB]);
- xive_tctx_notify(tctx, ring);
-}
+ if (group_level == 0) {
+ /* VP-specific */
+ regs[TM_IPB] |= xive_priority_to_ipb(priority);
+ alt_regs[TM_PIPR] = xive_ipb_to_pipr(regs[TM_IPB]);
+ } else {
+ /* VP-group */
+ alt_regs[TM_PIPR] = xive_priority_to_pipr(priority);
+ }
+ xive_tctx_notify(tctx, ring, group_level);
+ }
/*
* XIVE Thread Interrupt Management Area (TIMA)
@@ -179,6 +217,17 @@ static uint64_t xive_tm_pull_pool_ctx(XivePresenter *xptr, XiveTCTX *tctx,
return qw2w2;
}
+static uint64_t xive_tm_pull_phys_ctx(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, unsigned size)
+{
+ uint8_t qw3b8_prev = tctx->regs[TM_QW3_HV_PHYS + TM_WORD2];
+ uint8_t qw3b8;
+
+ qw3b8 = qw3b8_prev & ~TM_QW3B8_VT;
+ tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] = qw3b8;
+ return qw3b8;
+}
+
static void xive_tm_vt_push(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
uint64_t value, unsigned size)
{
@@ -207,14 +256,14 @@ static uint64_t xive_tm_vt_poll(XivePresenter *xptr, XiveTCTX *tctx,
static const uint8_t xive_tm_hw_view[] = {
3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
- 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
+ 0, 0, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 3, 3, 3, 0, /* QW-3 PHYS */
};
static const uint8_t xive_tm_hv_view[] = {
3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
- 0, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
+ 0, 0, 3, 3, 0, 3, 3, 0, 0, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 0, 0, 0, 0, /* QW-3 PHYS */
};
@@ -341,14 +390,27 @@ static void xive_tm_set_os_cppr(XivePresenter *xptr, XiveTCTX *tctx,
xive_tctx_set_cppr(tctx, TM_QW1_OS, value & 0xff);
}
+static void xive_tctx_set_lgs(XiveTCTX *tctx, uint8_t ring, uint8_t lgs)
+{
+ uint8_t *regs = &tctx->regs[ring];
+
+ regs[TM_LGS] = lgs;
+}
+
+static void xive_tm_set_os_lgs(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, uint64_t value, unsigned size)
+{
+ xive_tctx_set_lgs(tctx, TM_QW1_OS, value & 0xff);
+}
+
/*
- * Adjust the IPB to allow a CPU to process event queues of other
+ * Adjust the PIPR to allow a CPU to process event queues of other
* priorities during one physical interrupt cycle.
*/
static void xive_tm_set_os_pending(XivePresenter *xptr, XiveTCTX *tctx,
hwaddr offset, uint64_t value, unsigned size)
{
- xive_tctx_ipb_update(tctx, TM_QW1_OS, xive_priority_to_ipb(value & 0xff));
+ xive_tctx_pipr_update(tctx, TM_QW1_OS, value & 0xff, 0);
}
static void xive_os_cam_decode(uint32_t cam, uint8_t *nvt_blk,
@@ -400,7 +462,7 @@ static uint64_t xive_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
qw1w2_new = xive_set_field32(TM_QW1W2_VO, qw1w2, 0);
xive_tctx_set_os_cam(tctx, qw1w2_new);
- xive_tctx_reset_os_signal(tctx);
+ xive_tctx_reset_signal(tctx, TM_QW1_OS);
return qw1w2;
}
@@ -426,16 +488,20 @@ static void xive_tctx_need_resend(XiveRouter *xrtr, XiveTCTX *tctx,
/* Reset the NVT value */
nvt.w4 = xive_set_field32(NVT_W4_IPB, nvt.w4, 0);
xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
+
+ uint8_t *regs = &tctx->regs[TM_QW1_OS];
+ regs[TM_IPB] |= ipb;
}
+
/*
- * Always call xive_tctx_ipb_update(). Even if there were no
+ * Always call xive_tctx_pipr_update(). Even if there were no
* escalation triggered, there could be a pending interrupt which
* was saved when the context was pulled and that we need to take
* into account by recalculating the PIPR (which is not
* saved/restored).
* It will also raise the External interrupt signal if needed.
*/
- xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb);
+ xive_tctx_pipr_update(tctx, TM_QW1_OS, 0xFF, 0); /* fxb */
}
/*
@@ -488,20 +554,34 @@ static const XiveTmOp xive_tm_operations[] = {
* MMIOs below 2K : raw values and special operations without side
* effects
*/
- { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL },
- { XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive_tm_push_os_ctx, NULL },
- { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, NULL },
- { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL },
- { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll },
+ { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive_tm_push_os_ctx,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
+ xive_tm_vt_poll },
/* MMIOs above 2K : special operations with side effects */
- { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg },
- { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive_tm_pull_os_ctx },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive_tm_pull_os_ctx },
- { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx },
+ { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
+ xive_tm_ack_os_reg },
+ { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
+ xive_tm_pull_os_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
+ xive_tm_pull_os_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
+ xive_tm_ack_hv_reg },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
+ xive_tm_pull_pool_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
+ xive_tm_pull_pool_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
+ xive_tm_pull_phys_ctx },
};
static const XiveTmOp xive2_tm_operations[] = {
@@ -509,20 +589,50 @@ static const XiveTmOp xive2_tm_operations[] = {
* MMIOs below 2K : raw values and special operations without side
* effects
*/
- { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL },
- { XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive2_tm_push_os_ctx, NULL },
- { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, NULL },
- { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL },
- { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll },
+ { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive2_tm_set_os_cppr,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive2_tm_push_os_ctx,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 8, xive2_tm_push_os_ctx,
+ NULL },
+ { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_LGS, 1, xive_tm_set_os_lgs,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive2_tm_set_hv_cppr,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
+ xive_tm_vt_poll },
+ { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_T, 1, xive2_tm_set_hv_target,
+ NULL },
/* MMIOs above 2K : special operations with side effects */
- { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg },
- { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive2_tm_pull_os_ctx },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive2_tm_pull_os_ctx },
- { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx },
- { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx },
+ { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
+ xive_tm_ack_os_reg },
+ { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_G2, 4, NULL,
+ xive2_tm_pull_os_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
+ xive2_tm_pull_os_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
+ xive2_tm_pull_os_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
+ xive_tm_ack_hv_reg },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX_G2, 4, NULL,
+ xive_tm_pull_pool_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
+ xive_tm_pull_pool_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
+ xive_tm_pull_pool_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_OL, 1, xive2_tm_pull_os_ctx_ol,
+ NULL },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_G2, 4, NULL,
+ xive_tm_pull_phys_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
+ xive_tm_pull_phys_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_OL, 1, xive2_tm_pull_phys_ctx_ol,
+ NULL },
};
static const XiveTmOp *xive_tm_find_op(XivePresenter *xptr, hwaddr offset,
@@ -718,15 +828,19 @@ void xive_tctx_reset(XiveTCTX *tctx)
tctx->regs[TM_QW1_OS + TM_LSMFB] = 0xFF;
tctx->regs[TM_QW1_OS + TM_ACK_CNT] = 0xFF;
tctx->regs[TM_QW1_OS + TM_AGE] = 0xFF;
+ if (!(xive_presenter_get_config(tctx->xptr) &
+ XIVE_PRESENTER_GEN1_TIMA_OS)) {
+ tctx->regs[TM_QW1_OS + TM_OGEN] = 2;
+ }
/*
* Initialize PIPR to 0xFF to avoid phantom interrupts when the
* CPPR is first set.
*/
tctx->regs[TM_QW1_OS + TM_PIPR] =
- ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]);
+ xive_ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]);
tctx->regs[TM_QW3_HV_PHYS + TM_PIPR] =
- ipb_to_pipr(tctx->regs[TM_QW3_HV_PHYS + TM_IPB]);
+ xive_ipb_to_pipr(tctx->regs[TM_QW3_HV_PHYS + TM_IPB]);
}
static void xive_tctx_realize(DeviceState *dev, Error **errp)
@@ -810,14 +924,13 @@ static const VMStateDescription vmstate_xive_tctx = {
},
};
-static Property xive_tctx_properties[] = {
+static const Property xive_tctx_properties[] = {
DEFINE_PROP_LINK("cpu", XiveTCTX, cs, TYPE_CPU, CPUState *),
DEFINE_PROP_LINK("presenter", XiveTCTX, xptr, TYPE_XIVE_PRESENTER,
XivePresenter *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xive_tctx_class_init(ObjectClass *klass, void *data)
+static void xive_tctx_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1242,7 +1355,7 @@ static void xive_source_reset(void *dev)
static void xive_source_realize(DeviceState *dev, Error **errp)
{
XiveSource *xsrc = XIVE_SOURCE(dev);
- size_t esb_len = xive_source_esb_len(xsrc);
+ uint64_t esb_len = xive_source_esb_len(xsrc);
assert(xsrc->xive);
@@ -1286,7 +1399,7 @@ static const VMStateDescription vmstate_xive_source = {
* The default XIVE interrupt source setting for the ESB MMIOs is two
* 64k pages without Store EOI, to be in sync with KVM.
*/
-static Property xive_source_properties[] = {
+static const Property xive_source_properties[] = {
DEFINE_PROP_UINT64("flags", XiveSource, esb_flags, 0),
DEFINE_PROP_UINT32("nr-irqs", XiveSource, nr_irqs, 0),
DEFINE_PROP_UINT32("shift", XiveSource, esb_shift, XIVE_ESB_64K_2PAGE),
@@ -1297,10 +1410,9 @@ static Property xive_source_properties[] = {
DEFINE_PROP_UINT8("reset-pq", XiveSource, reset_pq, XIVE_ESB_OFF),
DEFINE_PROP_LINK("xive", XiveSource, xive, TYPE_XIVE_NOTIFIER,
XiveNotifier *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xive_source_class_init(ObjectClass *klass, void *data)
+static void xive_source_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1543,6 +1655,75 @@ static uint32_t xive_tctx_hw_cam_line(XivePresenter *xptr, XiveTCTX *tctx)
return xive_nvt_cam_line(blk, 1 << 7 | (pir & 0x7f));
}
+uint32_t xive_get_vpgroup_size(uint32_t nvp_index)
+{
+ /*
+ * Group size is a power of 2. The position of the first 0
+ * (starting with the least significant bits) in the NVP index
+ * gives the size of the group.
+ */
+ int first_zero = cto32(nvp_index);
+ if (first_zero >= 31) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid group index 0x%08x",
+ nvp_index);
+ return 0;
+ }
+
+ return 1U << (first_zero + 1);
+}
+
+static uint8_t xive_get_group_level(bool crowd, bool ignore,
+ uint32_t nvp_blk, uint32_t nvp_index)
+{
+ int first_zero;
+ uint8_t level;
+
+ if (!ignore) {
+ g_assert(!crowd);
+ return 0;
+ }
+
+ first_zero = cto32(nvp_index);
+ if (first_zero >= 31) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid group index 0x%08x",
+ nvp_index);
+ return 0;
+ }
+
+ level = (first_zero + 1) & 0b1111;
+ if (crowd) {
+ uint32_t blk;
+
+ /* crowd level is bit position of first 0 from the right in nvp_blk */
+ first_zero = cto32(nvp_blk);
+ if (first_zero >= 31) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid crowd block 0x%08x",
+ nvp_blk);
+ return 0;
+ }
+ blk = first_zero + 1;
+
+ /*
+ * Supported crowd sizes are 2^1, 2^2, and 2^4. 2^3 is not supported.
+ * HW will encode level 4 as the value 3. See xive2_pgofnext().
+ */
+ switch (blk) {
+ case 1:
+ case 2:
+ break;
+ case 4:
+ blk = 3;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* Crowd level bits reside in upper 2 bits of the 6 bit group level */
+ level |= blk << 4;
+ }
+ return level;
+}
+
/*
* The thread context register words are in big-endian format.
*/
@@ -1609,31 +1790,41 @@ int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
/*
* This is our simple Xive Presenter Engine model. It is merged in the
* Router as it does not require an extra object.
- *
- * It receives notification requests sent by the IVRE to find one
- * matching NVT (or more) dispatched on the processor threads. In case
- * of a single NVT notification, the process is abbreviated and the
- * thread is signaled if a match is found. In case of a logical server
- * notification (bits ignored at the end of the NVT identifier), the
- * IVPE and IVRE select a winning thread using different filters. This
- * involves 2 or 3 exchanges on the PowerBus that the model does not
- * support.
- *
- * The parameters represent what is sent on the PowerBus
*/
bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
- uint32_t logic_serv)
+ bool crowd, bool cam_ignore, uint8_t priority,
+ uint32_t logic_serv, bool *precluded)
{
XiveFabricClass *xfc = XIVE_FABRIC_GET_CLASS(xfb);
- XiveTCTXMatch match = { .tctx = NULL, .ring = 0 };
+ XiveTCTXMatch match = { .tctx = NULL, .ring = 0, .precluded = false };
+ uint8_t group_level;
int count;
/*
- * Ask the machine to scan the interrupt controllers for a match
+ * Ask the machine to scan the interrupt controllers for a match.
+ *
+ * For VP-specific notification, we expect at most one match and
+ * one call to the presenters is all we need (abbreviated notify
+ * sequence documented by the architecture).
+ *
+ * For VP-group notification, match_nvt() is the equivalent of the
+ * "histogram" and "poll" commands sent to the power bus to the
+ * presenters. 'count' could be more than one, but we always
+ * select the first match for now. 'precluded' tells if (at least)
+ * one thread matches but can't take the interrupt now because
+ * it's running at a more favored priority. We return the
+ * information to the router so that it can take appropriate
+ * actions (backlog, escalation, broadcast, etc...)
+ *
+ * If we were to implement a better way of dispatching the
+ * interrupt in case of multiple matches (instead of the first
+ * match), we would need a heuristic to elect a thread (for
+ * example, the hardware keeps track of an 'age' in the TIMA) and
+ * a new command to the presenters (the equivalent of the "assign"
+ * power bus command in the documented full notify sequence.
*/
- count = xfc->match_nvt(xfb, format, nvt_blk, nvt_idx, cam_ignore,
+ count = xfc->match_nvt(xfb, format, nvt_blk, nvt_idx, crowd, cam_ignore,
priority, logic_serv, &match);
if (count < 0) {
return false;
@@ -1641,9 +1832,11 @@ bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
/* handle CPU exception delivery */
if (count) {
- trace_xive_presenter_notify(nvt_blk, nvt_idx, match.ring);
- xive_tctx_ipb_update(match.tctx, match.ring,
- xive_priority_to_ipb(priority));
+ group_level = xive_get_group_level(crowd, cam_ignore, nvt_blk, nvt_idx);
+ trace_xive_presenter_notify(nvt_blk, nvt_idx, match.ring, group_level);
+ xive_tctx_pipr_update(match.tctx, match.ring, priority, group_level);
+ } else {
+ *precluded = match.precluded;
}
return !!count;
@@ -1683,7 +1876,7 @@ void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas)
uint8_t nvt_blk;
uint32_t nvt_idx;
XiveNVT nvt;
- bool found;
+ bool found, precluded;
uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w);
uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
@@ -1764,10 +1957,12 @@ void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas)
}
found = xive_presenter_notify(xrtr->xfb, format, nvt_blk, nvt_idx,
+ false /* crowd */,
xive_get_field32(END_W7_F0_IGNORE, end.w7),
priority,
- xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7));
-
+ xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7),
+ &precluded);
+ /* we don't support VP-group notification on P9, so precluded is not used */
/* TODO: Auto EOI. */
if (found) {
@@ -1885,13 +2080,12 @@ void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked)
xive_router_end_notify_handler(xrtr, &eas);
}
-static Property xive_router_properties[] = {
+static const Property xive_router_properties[] = {
DEFINE_PROP_LINK("xive-fabric", XiveRouter, xfb,
TYPE_XIVE_FABRIC, XiveFabric *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xive_router_class_init(ObjectClass *klass, void *data)
+static void xive_router_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
@@ -1914,7 +2108,7 @@ static const TypeInfo xive_router_info = {
.instance_size = sizeof(XiveRouter),
.class_size = sizeof(XiveRouterClass),
.class_init = xive_router_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_NOTIFIER },
{ TYPE_XIVE_PRESENTER },
{ }
@@ -2053,15 +2247,14 @@ static void xive_end_source_realize(DeviceState *dev, Error **errp)
(1ull << (xsrc->esb_shift + 1)) * xsrc->nr_ends);
}
-static Property xive_end_source_properties[] = {
+static const Property xive_end_source_properties[] = {
DEFINE_PROP_UINT32("nr-ends", XiveENDSource, nr_ends, 0),
DEFINE_PROP_UINT32("shift", XiveENDSource, esb_shift, XIVE_ESB_64K),
DEFINE_PROP_LINK("xive", XiveENDSource, xrtr, TYPE_XIVE_ROUTER,
XiveRouter *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xive_end_source_class_init(ObjectClass *klass, void *data)
+static void xive_end_source_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c
index 1f15068..a08cf90 100644
--- a/hw/intc/xive2.c
+++ b/hw/intc/xive2.c
@@ -1,10 +1,9 @@
/*
* QEMU PowerPC XIVE2 interrupt controller model (POWER10)
*
- * Copyright (c) 2019-2022, IBM Corporation..
+ * Copyright (c) 2019-2024, IBM Corporation..
*
- * This code is licensed under the GPL version 2 or later. See the
- * COPYING file in the top-level directory.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
@@ -12,12 +11,13 @@
#include "qemu/module.h"
#include "qapi/error.h"
#include "target/ppc/cpu.h"
-#include "sysemu/cpus.h"
-#include "sysemu/dma.h"
+#include "system/cpus.h"
+#include "system/dma.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/xive.h"
#include "hw/ppc/xive2.h"
#include "hw/ppc/xive2_regs.h"
+#include "trace.h"
uint32_t xive2_router_get_config(Xive2Router *xrtr)
{
@@ -26,6 +26,155 @@ uint32_t xive2_router_get_config(Xive2Router *xrtr)
return xrc->get_config(xrtr);
}
+static int xive2_router_get_block_id(Xive2Router *xrtr)
+{
+ Xive2RouterClass *xrc = XIVE2_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->get_block_id(xrtr);
+}
+
+static uint64_t xive2_nvp_reporting_addr(Xive2Nvp *nvp)
+{
+ uint64_t cache_addr;
+
+ cache_addr = xive_get_field32(NVP2_W6_REPORTING_LINE, nvp->w6) << 24 |
+ xive_get_field32(NVP2_W7_REPORTING_LINE, nvp->w7);
+ cache_addr <<= 8; /* aligned on a cache line pair */
+ return cache_addr;
+}
+
+static uint32_t xive2_nvgc_get_backlog(Xive2Nvgc *nvgc, uint8_t priority)
+{
+ uint32_t val = 0;
+ uint8_t *ptr, i;
+
+ if (priority > 7) {
+ return 0;
+ }
+
+ /*
+ * The per-priority backlog counters are 24-bit and the structure
+ * is stored in big endian. NVGC is 32-bytes long, so 24-bytes from
+ * w2, which fits 8 priorities * 24-bits per priority.
+ */
+ ptr = (uint8_t *)&nvgc->w2 + priority * 3;
+ for (i = 0; i < 3; i++, ptr++) {
+ val = (val << 8) + *ptr;
+ }
+ return val;
+}
+
+static void xive2_nvgc_set_backlog(Xive2Nvgc *nvgc, uint8_t priority,
+ uint32_t val)
+{
+ uint8_t *ptr, i;
+ uint32_t shift;
+
+ if (priority > 7) {
+ return;
+ }
+
+ if (val > 0xFFFFFF) {
+ val = 0xFFFFFF;
+ }
+ /*
+ * The per-priority backlog counters are 24-bit and the structure
+ * is stored in big endian
+ */
+ ptr = (uint8_t *)&nvgc->w2 + priority * 3;
+ for (i = 0; i < 3; i++, ptr++) {
+ shift = 8 * (2 - i);
+ *ptr = (val >> shift) & 0xFF;
+ }
+}
+
+uint64_t xive2_presenter_nvgc_backlog_op(XivePresenter *xptr,
+ bool crowd,
+ uint8_t blk, uint32_t idx,
+ uint16_t offset, uint16_t val)
+{
+ Xive2Router *xrtr = XIVE2_ROUTER(xptr);
+ uint8_t priority = GETFIELD(NVx_BACKLOG_PRIO, offset);
+ uint8_t op = GETFIELD(NVx_BACKLOG_OP, offset);
+ Xive2Nvgc nvgc;
+ uint32_t count, old_count;
+
+ if (xive2_router_get_nvgc(xrtr, crowd, blk, idx, &nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No %s %x/%x\n",
+ crowd ? "NVC" : "NVG", blk, idx);
+ return -1;
+ }
+ if (!xive2_nvgc_is_valid(&nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid NVG %x/%x\n", blk, idx);
+ return -1;
+ }
+
+ old_count = xive2_nvgc_get_backlog(&nvgc, priority);
+ count = old_count;
+ /*
+ * op:
+ * 0b00 => increment
+ * 0b01 => decrement
+ * 0b1- => read
+ */
+ if (op == 0b00 || op == 0b01) {
+ if (op == 0b00) {
+ count += val;
+ } else {
+ if (count > val) {
+ count -= val;
+ } else {
+ count = 0;
+ }
+ }
+ xive2_nvgc_set_backlog(&nvgc, priority, count);
+ xive2_router_write_nvgc(xrtr, crowd, blk, idx, &nvgc);
+ }
+ trace_xive_nvgc_backlog_op(crowd, blk, idx, op, priority, old_count);
+ return old_count;
+}
+
+uint64_t xive2_presenter_nvp_backlog_op(XivePresenter *xptr,
+ uint8_t blk, uint32_t idx,
+ uint16_t offset)
+{
+ Xive2Router *xrtr = XIVE2_ROUTER(xptr);
+ uint8_t priority = GETFIELD(NVx_BACKLOG_PRIO, offset);
+ uint8_t op = GETFIELD(NVx_BACKLOG_OP, offset);
+ Xive2Nvp nvp;
+ uint8_t ipb, old_ipb, rc;
+
+ if (xive2_router_get_nvp(xrtr, blk, idx, &nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n", blk, idx);
+ return -1;
+ }
+ if (!xive2_nvp_is_valid(&nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid NVP %x/%x\n", blk, idx);
+ return -1;
+ }
+
+ old_ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2);
+ ipb = old_ipb;
+ /*
+ * op:
+ * 0b00 => set priority bit
+ * 0b01 => reset priority bit
+ * 0b1- => read
+ */
+ if (op == 0b00 || op == 0b01) {
+ if (op == 0b00) {
+ ipb |= xive_priority_to_ipb(priority);
+ } else {
+ ipb &= ~xive_priority_to_ipb(priority);
+ }
+ nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, ipb);
+ xive2_router_write_nvp(xrtr, blk, idx, &nvp, 2);
+ }
+ rc = !!(old_ipb & xive_priority_to_ipb(priority));
+ trace_xive_nvp_backlog_op(blk, idx, op, priority, rc);
+ return rc;
+}
+
void xive2_eas_pic_print_info(Xive2Eas *eas, uint32_t lisn, GString *buf)
{
if (!xive2_eas_is_valid(eas)) {
@@ -77,8 +226,8 @@ void xive2_end_pic_print_info(Xive2End *end, uint32_t end_idx, GString *buf)
uint32_t qsize = xive_get_field32(END2_W3_QSIZE, end->w3);
uint32_t qentries = 1 << (qsize + 10);
- uint32_t nvp_blk = xive_get_field32(END2_W6_VP_BLOCK, end->w6);
- uint32_t nvp_idx = xive_get_field32(END2_W6_VP_OFFSET, end->w6);
+ uint32_t nvx_blk = xive_get_field32(END2_W6_VP_BLOCK, end->w6);
+ uint32_t nvx_idx = xive_get_field32(END2_W6_VP_OFFSET, end->w6);
uint8_t priority = xive_get_field32(END2_W7_F0_PRIORITY, end->w7);
uint8_t pq;
@@ -107,7 +256,7 @@ void xive2_end_pic_print_info(Xive2End *end, uint32_t end_idx, GString *buf)
xive2_end_is_firmware2(end) ? 'F' : '-',
xive2_end_is_ignore(end) ? 'i' : '-',
xive2_end_is_crowd(end) ? 'c' : '-',
- priority, nvp_blk, nvp_idx);
+ priority, nvx_blk, nvx_idx);
if (qaddr_base) {
g_string_append_printf(buf, " eq:@%08"PRIx64"% 6d/%5d ^%d",
@@ -144,14 +293,20 @@ void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx, GString *buf)
{
uint8_t eq_blk = xive_get_field32(NVP2_W5_VP_END_BLOCK, nvp->w5);
uint32_t eq_idx = xive_get_field32(NVP2_W5_VP_END_INDEX, nvp->w5);
+ uint64_t cache_line = xive2_nvp_reporting_addr(nvp);
if (!xive2_nvp_is_valid(nvp)) {
return;
}
- g_string_append_printf(buf, " %08x end:%02x/%04x IPB:%02x",
+ g_string_append_printf(buf, " %08x end:%02x/%04x IPB:%02x PGoFirst:%02x",
nvp_idx, eq_blk, eq_idx,
- xive_get_field32(NVP2_W2_IPB, nvp->w2));
+ xive_get_field32(NVP2_W2_IPB, nvp->w2),
+ xive_get_field32(NVP2_W0_PGOFIRST, nvp->w0));
+ if (cache_line) {
+ g_string_append_printf(buf, " reporting CL:%016"PRIx64, cache_line);
+ }
+
/*
* When the NVP is HW controlled, more fields are updated
*/
@@ -166,6 +321,23 @@ void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx, GString *buf)
g_string_append_c(buf, '\n');
}
+void xive2_nvgc_pic_print_info(Xive2Nvgc *nvgc, uint32_t nvgc_idx, GString *buf)
+{
+ uint8_t i;
+
+ if (!xive2_nvgc_is_valid(nvgc)) {
+ return;
+ }
+
+ g_string_append_printf(buf, " %08x PGoNext:%02x bklog: ", nvgc_idx,
+ xive_get_field32(NVGC2_W0_PGONEXT, nvgc->w0));
+ for (i = 0; i <= XIVE_PRIORITY_MAX; i++) {
+ g_string_append_printf(buf, "[%d]=0x%x ",
+ i, xive2_nvgc_get_backlog(nvgc, i));
+ }
+ g_string_append_printf(buf, "\n");
+}
+
static void xive2_end_enqueue(Xive2End *end, uint32_t data)
{
uint64_t qaddr_base = xive2_end_qaddr(end);
@@ -195,6 +367,115 @@ static void xive2_end_enqueue(Xive2End *end, uint32_t data)
end->w1 = xive_set_field32(END2_W1_PAGE_OFF, end->w1, qindex);
}
+static void xive2_pgofnext(uint8_t *nvgc_blk, uint32_t *nvgc_idx,
+ uint8_t next_level)
+{
+ uint32_t mask, next_idx;
+ uint8_t next_blk;
+
+ /*
+ * Adjust the block and index of a VP for the next group/crowd
+ * size (PGofFirst/PGofNext field in the NVP and NVGC structures).
+ *
+ * The 6-bit group level is split into a 2-bit crowd and 4-bit
+ * group levels. Encoding is similar. However, we don't support
+ * crowd size of 8. So a crowd level of 0b11 is bumped to a crowd
+ * size of 16.
+ */
+ next_blk = NVx_CROWD_LVL(next_level);
+ if (next_blk == 3) {
+ next_blk = 4;
+ }
+ mask = (1 << next_blk) - 1;
+ *nvgc_blk &= ~mask;
+ *nvgc_blk |= mask >> 1;
+
+ next_idx = NVx_GROUP_LVL(next_level);
+ mask = (1 << next_idx) - 1;
+ *nvgc_idx &= ~mask;
+ *nvgc_idx |= mask >> 1;
+}
+
+/*
+ * Scan the group chain and return the highest priority and group
+ * level of pending group interrupts.
+ */
+static uint8_t xive2_presenter_backlog_scan(XivePresenter *xptr,
+ uint8_t nvx_blk, uint32_t nvx_idx,
+ uint8_t first_group,
+ uint8_t *out_level)
+{
+ Xive2Router *xrtr = XIVE2_ROUTER(xptr);
+ uint32_t nvgc_idx;
+ uint32_t current_level, count;
+ uint8_t nvgc_blk, prio;
+ Xive2Nvgc nvgc;
+
+ for (prio = 0; prio <= XIVE_PRIORITY_MAX; prio++) {
+ current_level = first_group & 0x3F;
+ nvgc_blk = nvx_blk;
+ nvgc_idx = nvx_idx;
+
+ while (current_level) {
+ xive2_pgofnext(&nvgc_blk, &nvgc_idx, current_level);
+
+ if (xive2_router_get_nvgc(xrtr, NVx_CROWD_LVL(current_level),
+ nvgc_blk, nvgc_idx, &nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVGC %x/%x\n",
+ nvgc_blk, nvgc_idx);
+ return 0xFF;
+ }
+ if (!xive2_nvgc_is_valid(&nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid NVGC %x/%x\n",
+ nvgc_blk, nvgc_idx);
+ return 0xFF;
+ }
+
+ count = xive2_nvgc_get_backlog(&nvgc, prio);
+ if (count) {
+ *out_level = current_level;
+ return prio;
+ }
+ current_level = xive_get_field32(NVGC2_W0_PGONEXT, nvgc.w0) & 0x3F;
+ }
+ }
+ return 0xFF;
+}
+
+static void xive2_presenter_backlog_decr(XivePresenter *xptr,
+ uint8_t nvx_blk, uint32_t nvx_idx,
+ uint8_t group_prio,
+ uint8_t group_level)
+{
+ Xive2Router *xrtr = XIVE2_ROUTER(xptr);
+ uint32_t nvgc_idx, count;
+ uint8_t nvgc_blk;
+ Xive2Nvgc nvgc;
+
+ nvgc_blk = nvx_blk;
+ nvgc_idx = nvx_idx;
+ xive2_pgofnext(&nvgc_blk, &nvgc_idx, group_level);
+
+ if (xive2_router_get_nvgc(xrtr, NVx_CROWD_LVL(group_level),
+ nvgc_blk, nvgc_idx, &nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVGC %x/%x\n",
+ nvgc_blk, nvgc_idx);
+ return;
+ }
+ if (!xive2_nvgc_is_valid(&nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid NVGC %x/%x\n",
+ nvgc_blk, nvgc_idx);
+ return;
+ }
+ count = xive2_nvgc_get_backlog(&nvgc, group_prio);
+ if (!count) {
+ return;
+ }
+ xive2_nvgc_set_backlog(&nvgc, group_prio, count - 1);
+ xive2_router_write_nvgc(xrtr, NVx_CROWD_LVL(group_level),
+ nvgc_blk, nvgc_idx, &nvgc);
+}
+
/*
* XIVE Thread Interrupt Management Area (TIMA) - Gen2 mode
*
@@ -210,13 +491,14 @@ static void xive2_end_enqueue(Xive2End *end, uint32_t data)
* the NVP by changing the H bit while the context is enabled
*/
-static void xive2_tctx_save_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
- uint8_t nvp_blk, uint32_t nvp_idx)
+static void xive2_tctx_save_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
+ uint8_t nvp_blk, uint32_t nvp_idx,
+ uint8_t ring)
{
CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
uint32_t pir = env->spr_cb[SPR_PIR].default_value;
Xive2Nvp nvp;
- uint8_t *regs = &tctx->regs[TM_QW1_OS];
+ uint8_t *regs = &tctx->regs[ring];
if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n",
@@ -252,7 +534,19 @@ static void xive2_tctx_save_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, regs[TM_IPB]);
nvp.w2 = xive_set_field32(NVP2_W2_CPPR, nvp.w2, regs[TM_CPPR]);
- nvp.w2 = xive_set_field32(NVP2_W2_LSMFB, nvp.w2, regs[TM_LSMFB]);
+ if (nvp.w0 & NVP2_W0_L) {
+ /*
+ * Typically not used. If LSMFB is restored with 0, it will
+ * force a backlog rescan
+ */
+ nvp.w2 = xive_set_field32(NVP2_W2_LSMFB, nvp.w2, regs[TM_LSMFB]);
+ }
+ if (nvp.w0 & NVP2_W0_G) {
+ nvp.w2 = xive_set_field32(NVP2_W2_LGS, nvp.w2, regs[TM_LGS]);
+ }
+ if (nvp.w0 & NVP2_W0_T) {
+ nvp.w2 = xive_set_field32(NVP2_W2_T, nvp.w2, regs[TM_T]);
+ }
xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2);
nvp.w1 = xive_set_field32(NVP2_W1_CO, nvp.w1, 0);
@@ -261,44 +555,190 @@ static void xive2_tctx_save_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 1);
}
-static void xive2_os_cam_decode(uint32_t cam, uint8_t *nvp_blk,
- uint32_t *nvp_idx, bool *vo, bool *ho)
+static void xive2_cam_decode(uint32_t cam, uint8_t *nvp_blk,
+ uint32_t *nvp_idx, bool *valid, bool *hw)
{
*nvp_blk = xive2_nvp_blk(cam);
*nvp_idx = xive2_nvp_idx(cam);
- *vo = !!(cam & TM2_QW1W2_VO);
- *ho = !!(cam & TM2_QW1W2_HO);
+ *valid = !!(cam & TM2_W2_VALID);
+ *hw = !!(cam & TM2_W2_HW);
}
-uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
- hwaddr offset, unsigned size)
+/*
+ * Encode the HW CAM line with 7bit or 8bit thread id. The thread id
+ * width and block id width is configurable at the IC level.
+ *
+ * chipid << 24 | 0000 0000 0000 0000 1 threadid (7Bit)
+ * chipid << 24 | 0000 0000 0000 0001 threadid (8Bit)
+ */
+static uint32_t xive2_tctx_hw_cam_line(XivePresenter *xptr, XiveTCTX *tctx)
{
Xive2Router *xrtr = XIVE2_ROUTER(xptr);
- uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
- uint32_t qw1w2_new;
- uint32_t cam = be32_to_cpu(qw1w2);
+ CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
+ uint32_t pir = env->spr_cb[SPR_PIR].default_value;
+ uint8_t blk = xive2_router_get_block_id(xrtr);
+ uint8_t tid_shift =
+ xive2_router_get_config(xrtr) & XIVE2_THREADID_8BITS ? 8 : 7;
+ uint8_t tid_mask = (1 << tid_shift) - 1;
+
+ return xive2_nvp_cam_line(blk, 1 << tid_shift | (pir & tid_mask));
+}
+
+static uint64_t xive2_tm_pull_ctx(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, unsigned size, uint8_t ring)
+{
+ Xive2Router *xrtr = XIVE2_ROUTER(xptr);
+ uint32_t target_ringw2 = xive_tctx_word2(&tctx->regs[ring]);
+ uint32_t cam = be32_to_cpu(target_ringw2);
uint8_t nvp_blk;
uint32_t nvp_idx;
- bool vo;
+ uint8_t cur_ring;
+ bool valid;
bool do_save;
- xive2_os_cam_decode(cam, &nvp_blk, &nvp_idx, &vo, &do_save);
+ xive2_cam_decode(cam, &nvp_blk, &nvp_idx, &valid, &do_save);
- if (!vo) {
+ if (!valid) {
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pulling invalid NVP %x/%x !?\n",
nvp_blk, nvp_idx);
}
- /* Invalidate CAM line */
- qw1w2_new = xive_set_field32(TM2_QW1W2_VO, qw1w2, 0);
- memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2_new, 4);
+ /* Invalidate CAM line of requested ring and all lower rings */
+ for (cur_ring = TM_QW0_USER; cur_ring <= ring;
+ cur_ring += XIVE_TM_RING_SIZE) {
+ uint32_t ringw2 = xive_tctx_word2(&tctx->regs[cur_ring]);
+ uint32_t ringw2_new = xive_set_field32(TM2_QW1W2_VO, ringw2, 0);
+ memcpy(&tctx->regs[cur_ring + TM_WORD2], &ringw2_new, 4);
+ }
if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE && do_save) {
- xive2_tctx_save_os_ctx(xrtr, tctx, nvp_blk, nvp_idx);
+ xive2_tctx_save_ctx(xrtr, tctx, nvp_blk, nvp_idx, ring);
+ }
+
+ /*
+ * Lower external interrupt line of requested ring and below except for
+ * USER, which doesn't exist.
+ */
+ for (cur_ring = TM_QW1_OS; cur_ring <= ring;
+ cur_ring += XIVE_TM_RING_SIZE) {
+ xive_tctx_reset_signal(tctx, cur_ring);
+ }
+ return target_ringw2;
+}
+
+uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, unsigned size)
+{
+ return xive2_tm_pull_ctx(xptr, tctx, offset, size, TM_QW1_OS);
+}
+
+#define REPORT_LINE_GEN1_SIZE 16
+
+static void xive2_tm_report_line_gen1(XiveTCTX *tctx, uint8_t *data,
+ uint8_t size)
+{
+ uint8_t *regs = tctx->regs;
+
+ g_assert(size == REPORT_LINE_GEN1_SIZE);
+ memset(data, 0, size);
+ /*
+ * See xive architecture for description of what is saved. It is
+ * hand-picked information to fit in 16 bytes.
+ */
+ data[0x0] = regs[TM_QW3_HV_PHYS + TM_NSR];
+ data[0x1] = regs[TM_QW3_HV_PHYS + TM_CPPR];
+ data[0x2] = regs[TM_QW3_HV_PHYS + TM_IPB];
+ data[0x3] = regs[TM_QW2_HV_POOL + TM_IPB];
+ data[0x4] = regs[TM_QW1_OS + TM_ACK_CNT];
+ data[0x5] = regs[TM_QW3_HV_PHYS + TM_LGS];
+ data[0x6] = 0xFF;
+ data[0x7] = regs[TM_QW3_HV_PHYS + TM_WORD2] & 0x80;
+ data[0x7] |= (regs[TM_QW2_HV_POOL + TM_WORD2] & 0x80) >> 1;
+ data[0x7] |= (regs[TM_QW1_OS + TM_WORD2] & 0x80) >> 2;
+ data[0x7] |= (regs[TM_QW3_HV_PHYS + TM_WORD2] & 0x3);
+ data[0x8] = regs[TM_QW1_OS + TM_NSR];
+ data[0x9] = regs[TM_QW1_OS + TM_CPPR];
+ data[0xA] = regs[TM_QW1_OS + TM_IPB];
+ data[0xB] = regs[TM_QW1_OS + TM_LGS];
+ if (regs[TM_QW0_USER + TM_WORD2] & 0x80) {
+ /*
+ * Logical server extension, except VU bit replaced by EB bit
+ * from NSR
+ */
+ data[0xC] = regs[TM_QW0_USER + TM_WORD2];
+ data[0xC] &= ~0x80;
+ data[0xC] |= regs[TM_QW0_USER + TM_NSR] & 0x80;
+ data[0xD] = regs[TM_QW0_USER + TM_WORD2 + 1];
+ data[0xE] = regs[TM_QW0_USER + TM_WORD2 + 2];
+ data[0xF] = regs[TM_QW0_USER + TM_WORD2 + 3];
}
+}
- xive_tctx_reset_os_signal(tctx);
- return qw1w2;
+static void xive2_tm_pull_ctx_ol(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, uint64_t value,
+ unsigned size, uint8_t ring)
+{
+ Xive2Router *xrtr = XIVE2_ROUTER(xptr);
+ uint32_t hw_cam, nvp_idx, xive2_cfg, reserved;
+ uint8_t nvp_blk;
+ Xive2Nvp nvp;
+ uint64_t phys_addr;
+ MemTxResult result;
+
+ hw_cam = xive2_tctx_hw_cam_line(xptr, tctx);
+ nvp_blk = xive2_nvp_blk(hw_cam);
+ nvp_idx = xive2_nvp_idx(hw_cam);
+
+ if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n",
+ nvp_blk, nvp_idx);
+ return;
+ }
+
+ if (!xive2_nvp_is_valid(&nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid NVP %x/%x\n",
+ nvp_blk, nvp_idx);
+ return;
+ }
+
+ xive2_cfg = xive2_router_get_config(xrtr);
+
+ phys_addr = xive2_nvp_reporting_addr(&nvp) + 0x80; /* odd line */
+ if (xive2_cfg & XIVE2_GEN1_TIMA_OS) {
+ uint8_t pull_ctxt[REPORT_LINE_GEN1_SIZE];
+
+ xive2_tm_report_line_gen1(tctx, pull_ctxt, REPORT_LINE_GEN1_SIZE);
+ result = dma_memory_write(&address_space_memory, phys_addr,
+ pull_ctxt, REPORT_LINE_GEN1_SIZE,
+ MEMTXATTRS_UNSPECIFIED);
+ assert(result == MEMTX_OK);
+ } else {
+ result = dma_memory_write(&address_space_memory, phys_addr,
+ &tctx->regs, sizeof(tctx->regs),
+ MEMTXATTRS_UNSPECIFIED);
+ assert(result == MEMTX_OK);
+ reserved = 0xFFFFFFFF;
+ result = dma_memory_write(&address_space_memory, phys_addr + 12,
+ &reserved, sizeof(reserved),
+ MEMTXATTRS_UNSPECIFIED);
+ assert(result == MEMTX_OK);
+ }
+
+ /* the rest is similar to pull context to registers */
+ xive2_tm_pull_ctx(xptr, tctx, offset, size, ring);
+}
+
+void xive2_tm_pull_os_ctx_ol(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, uint64_t value, unsigned size)
+{
+ xive2_tm_pull_ctx_ol(xptr, tctx, offset, value, size, TM_QW1_OS);
+}
+
+
+void xive2_tm_pull_phys_ctx_ol(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, uint64_t value, unsigned size)
+{
+ xive2_tm_pull_ctx_ol(xptr, tctx, offset, value, size, TM_QW3_HV_PHYS);
}
static uint8_t xive2_tctx_restore_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
@@ -320,7 +760,9 @@ static uint8_t xive2_tctx_restore_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, nvp, 2);
tctx->regs[TM_QW1_OS + TM_CPPR] = cppr;
- /* we don't model LSMFB */
+ tctx->regs[TM_QW1_OS + TM_LSMFB] = xive_get_field32(NVP2_W2_LSMFB, nvp->w2);
+ tctx->regs[TM_QW1_OS + TM_LGS] = xive_get_field32(NVP2_W2_LGS, nvp->w2);
+ tctx->regs[TM_QW1_OS + TM_T] = xive_get_field32(NVP2_W2_T, nvp->w2);
nvp->w1 = xive_set_field32(NVP2_W1_CO, nvp->w1, 1);
nvp->w1 = xive_set_field32(NVP2_W1_CO_THRID_VALID, nvp->w1, 1);
@@ -343,8 +785,15 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx,
uint8_t nvp_blk, uint32_t nvp_idx,
bool do_restore)
{
- Xive2Nvp nvp;
+ XivePresenter *xptr = XIVE_PRESENTER(xrtr);
uint8_t ipb;
+ uint8_t backlog_level;
+ uint8_t group_level;
+ uint8_t first_group;
+ uint8_t backlog_prio;
+ uint8_t group_prio;
+ uint8_t *regs = &tctx->regs[TM_QW1_OS];
+ Xive2Nvp nvp;
/*
* Grab the associated thread interrupt context registers in the
@@ -373,15 +822,29 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx,
nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, 0);
xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2);
}
+ regs[TM_IPB] |= ipb;
+ backlog_prio = xive_ipb_to_pipr(ipb);
+ backlog_level = 0;
+
+ first_group = xive_get_field32(NVP2_W0_PGOFIRST, nvp.w0);
+ if (first_group && regs[TM_LSMFB] < backlog_prio) {
+ group_prio = xive2_presenter_backlog_scan(xptr, nvp_blk, nvp_idx,
+ first_group, &group_level);
+ regs[TM_LSMFB] = group_prio;
+ if (regs[TM_LGS] && group_prio < backlog_prio) {
+ /* VP can take a group interrupt */
+ xive2_presenter_backlog_decr(xptr, nvp_blk, nvp_idx,
+ group_prio, group_level);
+ backlog_prio = group_prio;
+ backlog_level = group_level;
+ }
+ }
+
/*
- * Always call xive_tctx_ipb_update(). Even if there were no
- * escalation triggered, there could be a pending interrupt which
- * was saved when the context was pulled and that we need to take
- * into account by recalculating the PIPR (which is not
- * saved/restored).
- * It will also raise the External interrupt signal if needed.
+ * Compute the PIPR based on the restored state.
+ * It will raise the External interrupt signal if needed.
*/
- xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb);
+ xive_tctx_pipr_update(tctx, TM_QW1_OS, backlog_prio, backlog_level);
}
/*
@@ -390,17 +853,31 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx,
void xive2_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
hwaddr offset, uint64_t value, unsigned size)
{
- uint32_t cam = value;
- uint32_t qw1w2 = cpu_to_be32(cam);
+ uint32_t cam;
+ uint32_t qw1w2;
+ uint64_t qw1dw1;
uint8_t nvp_blk;
uint32_t nvp_idx;
bool vo;
bool do_restore;
- xive2_os_cam_decode(cam, &nvp_blk, &nvp_idx, &vo, &do_restore);
-
/* First update the thead context */
- memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4);
+ switch (size) {
+ case 4:
+ cam = value;
+ qw1w2 = cpu_to_be32(cam);
+ memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4);
+ break;
+ case 8:
+ cam = value >> 32;
+ qw1dw1 = cpu_to_be64(value);
+ memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1dw1, 8);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ xive2_cam_decode(cam, &nvp_blk, &nvp_idx, &vo, &do_restore);
/* Check the interrupt pending bits */
if (vo) {
@@ -409,6 +886,185 @@ void xive2_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
}
}
+static int xive2_tctx_get_nvp_indexes(XiveTCTX *tctx, uint8_t ring,
+ uint32_t *nvp_blk, uint32_t *nvp_idx)
+{
+ uint32_t w2, cam;
+
+ w2 = xive_tctx_word2(&tctx->regs[ring]);
+ switch (ring) {
+ case TM_QW1_OS:
+ if (!(be32_to_cpu(w2) & TM2_QW1W2_VO)) {
+ return -1;
+ }
+ cam = xive_get_field32(TM2_QW1W2_OS_CAM, w2);
+ break;
+ case TM_QW2_HV_POOL:
+ if (!(be32_to_cpu(w2) & TM2_QW2W2_VP)) {
+ return -1;
+ }
+ cam = xive_get_field32(TM2_QW2W2_POOL_CAM, w2);
+ break;
+ case TM_QW3_HV_PHYS:
+ if (!(be32_to_cpu(w2) & TM2_QW3W2_VT)) {
+ return -1;
+ }
+ cam = xive2_tctx_hw_cam_line(tctx->xptr, tctx);
+ break;
+ default:
+ return -1;
+ }
+ *nvp_blk = xive2_nvp_blk(cam);
+ *nvp_idx = xive2_nvp_idx(cam);
+ return 0;
+}
+
+static void xive2_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
+{
+ uint8_t *regs = &tctx->regs[ring];
+ Xive2Router *xrtr = XIVE2_ROUTER(tctx->xptr);
+ uint8_t old_cppr, backlog_prio, first_group, group_level = 0;
+ uint8_t pipr_min, lsmfb_min, ring_min;
+ bool group_enabled;
+ uint32_t nvp_blk, nvp_idx;
+ Xive2Nvp nvp;
+ int rc;
+
+ trace_xive_tctx_set_cppr(tctx->cs->cpu_index, ring,
+ regs[TM_IPB], regs[TM_PIPR],
+ cppr, regs[TM_NSR]);
+
+ if (cppr > XIVE_PRIORITY_MAX) {
+ cppr = 0xff;
+ }
+
+ old_cppr = regs[TM_CPPR];
+ regs[TM_CPPR] = cppr;
+
+ /*
+ * Recompute the PIPR based on local pending interrupts. It will
+ * be adjusted below if needed in case of pending group interrupts.
+ */
+ pipr_min = xive_ipb_to_pipr(regs[TM_IPB]);
+ group_enabled = !!regs[TM_LGS];
+ lsmfb_min = (group_enabled) ? regs[TM_LSMFB] : 0xff;
+ ring_min = ring;
+
+ /* PHYS updates also depend on POOL values */
+ if (ring == TM_QW3_HV_PHYS) {
+ uint8_t *pregs = &tctx->regs[TM_QW2_HV_POOL];
+
+ /* POOL values only matter if POOL ctx is valid */
+ if (pregs[TM_WORD2] & 0x80) {
+
+ uint8_t pool_pipr = xive_ipb_to_pipr(pregs[TM_IPB]);
+ uint8_t pool_lsmfb = pregs[TM_LSMFB];
+
+ /*
+ * Determine highest priority interrupt and
+ * remember which ring has it.
+ */
+ if (pool_pipr < pipr_min) {
+ pipr_min = pool_pipr;
+ if (pool_pipr < lsmfb_min) {
+ ring_min = TM_QW2_HV_POOL;
+ }
+ }
+
+ /* Values needed for group priority calculation */
+ if (pregs[TM_LGS] && (pool_lsmfb < lsmfb_min)) {
+ group_enabled = true;
+ lsmfb_min = pool_lsmfb;
+ if (lsmfb_min < pipr_min) {
+ ring_min = TM_QW2_HV_POOL;
+ }
+ }
+ }
+ }
+ regs[TM_PIPR] = pipr_min;
+
+ rc = xive2_tctx_get_nvp_indexes(tctx, ring_min, &nvp_blk, &nvp_idx);
+ if (rc) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: set CPPR on invalid context\n");
+ return;
+ }
+
+ if (cppr < old_cppr) {
+ /*
+ * FIXME: check if there's a group interrupt being presented
+ * and if the new cppr prevents it. If so, then the group
+ * interrupt needs to be re-added to the backlog and
+ * re-triggered (see re-trigger END info in the NVGC
+ * structure)
+ */
+ }
+
+ if (group_enabled &&
+ lsmfb_min < cppr &&
+ lsmfb_min < regs[TM_PIPR]) {
+ /*
+ * Thread has seen a group interrupt with a higher priority
+ * than the new cppr or pending local interrupt. Check the
+ * backlog
+ */
+ if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n",
+ nvp_blk, nvp_idx);
+ return;
+ }
+
+ if (!xive2_nvp_is_valid(&nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid NVP %x/%x\n",
+ nvp_blk, nvp_idx);
+ return;
+ }
+
+ first_group = xive_get_field32(NVP2_W0_PGOFIRST, nvp.w0);
+ if (!first_group) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid NVP %x/%x\n",
+ nvp_blk, nvp_idx);
+ return;
+ }
+
+ backlog_prio = xive2_presenter_backlog_scan(tctx->xptr,
+ nvp_blk, nvp_idx,
+ first_group, &group_level);
+ tctx->regs[ring_min + TM_LSMFB] = backlog_prio;
+ if (backlog_prio != 0xFF) {
+ xive2_presenter_backlog_decr(tctx->xptr, nvp_blk, nvp_idx,
+ backlog_prio, group_level);
+ regs[TM_PIPR] = backlog_prio;
+ }
+ }
+ /* CPPR has changed, check if we need to raise a pending exception */
+ xive_tctx_notify(tctx, ring_min, group_level);
+}
+
+void xive2_tm_set_hv_cppr(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, uint64_t value, unsigned size)
+{
+ xive2_tctx_set_cppr(tctx, TM_QW3_HV_PHYS, value & 0xff);
+}
+
+void xive2_tm_set_os_cppr(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, uint64_t value, unsigned size)
+{
+ xive2_tctx_set_cppr(tctx, TM_QW1_OS, value & 0xff);
+}
+
+static void xive2_tctx_set_target(XiveTCTX *tctx, uint8_t ring, uint8_t target)
+{
+ uint8_t *regs = &tctx->regs[ring];
+
+ regs[TM_T] = target;
+}
+
+void xive2_tm_set_hv_target(XivePresenter *xptr, XiveTCTX *tctx,
+ hwaddr offset, uint64_t value, unsigned size)
+{
+ xive2_tctx_set_target(tctx, TM_QW3_HV_PHYS, value & 0xff);
+}
+
/*
* XIVE Router (aka. Virtualization Controller or IVRE)
*/
@@ -471,31 +1127,63 @@ int xive2_router_write_nvp(Xive2Router *xrtr, uint8_t nvp_blk, uint32_t nvp_idx,
return xrc->write_nvp(xrtr, nvp_blk, nvp_idx, nvp, word_number);
}
-static int xive2_router_get_block_id(Xive2Router *xrtr)
+int xive2_router_get_nvgc(Xive2Router *xrtr, bool crowd,
+ uint8_t nvgc_blk, uint32_t nvgc_idx,
+ Xive2Nvgc *nvgc)
{
Xive2RouterClass *xrc = XIVE2_ROUTER_GET_CLASS(xrtr);
- return xrc->get_block_id(xrtr);
+ return xrc->get_nvgc(xrtr, crowd, nvgc_blk, nvgc_idx, nvgc);
}
-/*
- * Encode the HW CAM line with 7bit or 8bit thread id. The thread id
- * width and block id width is configurable at the IC level.
- *
- * chipid << 24 | 0000 0000 0000 0000 1 threadid (7Bit)
- * chipid << 24 | 0000 0000 0000 0001 threadid (8Bit)
- */
-static uint32_t xive2_tctx_hw_cam_line(XivePresenter *xptr, XiveTCTX *tctx)
+int xive2_router_write_nvgc(Xive2Router *xrtr, bool crowd,
+ uint8_t nvgc_blk, uint32_t nvgc_idx,
+ Xive2Nvgc *nvgc)
{
- Xive2Router *xrtr = XIVE2_ROUTER(xptr);
- CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
- uint32_t pir = env->spr_cb[SPR_PIR].default_value;
- uint8_t blk = xive2_router_get_block_id(xrtr);
- uint8_t tid_shift =
- xive2_router_get_config(xrtr) & XIVE2_THREADID_8BITS ? 8 : 7;
- uint8_t tid_mask = (1 << tid_shift) - 1;
+ Xive2RouterClass *xrc = XIVE2_ROUTER_GET_CLASS(xrtr);
- return xive2_nvp_cam_line(blk, 1 << tid_shift | (pir & tid_mask));
+ return xrc->write_nvgc(xrtr, crowd, nvgc_blk, nvgc_idx, nvgc);
+}
+
+static bool xive2_vp_match_mask(uint32_t cam1, uint32_t cam2,
+ uint32_t vp_mask)
+{
+ return (cam1 & vp_mask) == (cam2 & vp_mask);
+}
+
+static uint8_t xive2_get_vp_block_mask(uint32_t nvt_blk, bool crowd)
+{
+ uint8_t block_mask = 0b1111;
+
+ /* 3 supported crowd sizes: 2, 4, 16 */
+ if (crowd) {
+ uint32_t size = xive_get_vpgroup_size(nvt_blk);
+
+ if (size != 2 && size != 4 && size != 16) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid crowd size of %d",
+ size);
+ return block_mask;
+ }
+ block_mask &= ~(size - 1);
+ }
+ return block_mask;
+}
+
+static uint32_t xive2_get_vp_index_mask(uint32_t nvt_index, bool cam_ignore)
+{
+ uint32_t index_mask = 0xFFFFFF; /* 24 bits */
+
+ if (cam_ignore) {
+ uint32_t size = xive_get_vpgroup_size(nvt_index);
+
+ if (size < 2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid group size of %d",
+ size);
+ return index_mask;
+ }
+ index_mask &= ~(size - 1);
+ }
+ return index_mask;
}
/*
@@ -504,7 +1192,8 @@ static uint32_t xive2_tctx_hw_cam_line(XivePresenter *xptr, XiveTCTX *tctx)
int xive2_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint32_t logic_serv)
+ bool crowd, bool cam_ignore,
+ uint32_t logic_serv)
{
uint32_t cam = xive2_nvp_cam_line(nvt_blk, nvt_idx);
uint32_t qw3w2 = xive_tctx_word2(&tctx->regs[TM_QW3_HV_PHYS]);
@@ -512,44 +1201,51 @@ int xive2_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
uint32_t qw0w2 = xive_tctx_word2(&tctx->regs[TM_QW0_USER]);
- /*
- * TODO (PowerNV): ignore mode. The low order bits of the NVT
- * identifier are ignored in the "CAM" match.
- */
+ uint32_t index_mask, vp_mask;
+ uint8_t block_mask;
if (format == 0) {
- if (cam_ignore == true) {
- /*
- * F=0 & i=1: Logical server notification (bits ignored at
- * the end of the NVT identifier)
- */
- qemu_log_mask(LOG_UNIMP, "XIVE: no support for LS NVT %x/%x\n",
- nvt_blk, nvt_idx);
- return -1;
- }
+ /*
+ * i=0: Specific NVT notification
+ * i=1: VP-group notification (bits ignored at the end of the
+ * NVT identifier)
+ */
+ block_mask = xive2_get_vp_block_mask(nvt_blk, crowd);
+ index_mask = xive2_get_vp_index_mask(nvt_idx, cam_ignore);
+ vp_mask = xive2_nvp_cam_line(block_mask, index_mask);
- /* F=0 & i=0: Specific NVT notification */
+ /* For VP-group notifications, threads with LGS=0 are excluded */
/* PHYS ring */
if ((be32_to_cpu(qw3w2) & TM2_QW3W2_VT) &&
- cam == xive2_tctx_hw_cam_line(xptr, tctx)) {
+ !(cam_ignore && tctx->regs[TM_QW3_HV_PHYS + TM_LGS] == 0) &&
+ xive2_vp_match_mask(cam,
+ xive2_tctx_hw_cam_line(xptr, tctx),
+ vp_mask)) {
return TM_QW3_HV_PHYS;
}
/* HV POOL ring */
if ((be32_to_cpu(qw2w2) & TM2_QW2W2_VP) &&
- cam == xive_get_field32(TM2_QW2W2_POOL_CAM, qw2w2)) {
+ !(cam_ignore && tctx->regs[TM_QW2_HV_POOL + TM_LGS] == 0) &&
+ xive2_vp_match_mask(cam,
+ xive_get_field32(TM2_QW2W2_POOL_CAM, qw2w2),
+ vp_mask)) {
return TM_QW2_HV_POOL;
}
/* OS ring */
if ((be32_to_cpu(qw1w2) & TM2_QW1W2_VO) &&
- cam == xive_get_field32(TM2_QW1W2_OS_CAM, qw1w2)) {
+ !(cam_ignore && tctx->regs[TM_QW1_OS + TM_LGS] == 0) &&
+ xive2_vp_match_mask(cam,
+ xive_get_field32(TM2_QW1W2_OS_CAM, qw1w2),
+ vp_mask)) {
return TM_QW1_OS;
}
} else {
/* F=1 : User level Event-Based Branch (EBB) notification */
+ /* FIXME: what if cam_ignore and LGS = 0 ? */
/* USER ring */
if ((be32_to_cpu(qw1w2) & TM2_QW1W2_VO) &&
(cam == xive_get_field32(TM2_QW1W2_OS_CAM, qw1w2)) &&
@@ -561,6 +1257,37 @@ int xive2_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
return -1;
}
+bool xive2_tm_irq_precluded(XiveTCTX *tctx, int ring, uint8_t priority)
+{
+ /* HV_POOL ring uses HV_PHYS NSR, CPPR and PIPR registers */
+ uint8_t alt_ring = (ring == TM_QW2_HV_POOL) ? TM_QW3_HV_PHYS : ring;
+ uint8_t *alt_regs = &tctx->regs[alt_ring];
+
+ /*
+ * The xive2_presenter_tctx_match() above tells if there's a match
+ * but for VP-group notification, we still need to look at the
+ * priority to know if the thread can take the interrupt now or if
+ * it is precluded.
+ */
+ if (priority < alt_regs[TM_CPPR]) {
+ return false;
+ }
+ return true;
+}
+
+void xive2_tm_set_lsmfb(XiveTCTX *tctx, int ring, uint8_t priority)
+{
+ uint8_t *regs = &tctx->regs[ring];
+
+ /*
+ * Called by the router during a VP-group notification when the
+ * thread matches but can't take the interrupt because it's
+ * already running at a more favored priority. It then stores the
+ * new interrupt priority in the LSMFB field.
+ */
+ regs[TM_LSMFB] = priority;
+}
+
static void xive2_router_realize(DeviceState *dev, Error **errp)
{
Xive2Router *xrtr = XIVE2_ROUTER(dev);
@@ -600,10 +1327,9 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
Xive2End end;
uint8_t priority;
uint8_t format;
- bool found;
- Xive2Nvp nvp;
- uint8_t nvp_blk;
- uint32_t nvp_idx;
+ bool found, precluded;
+ uint8_t nvx_blk;
+ uint32_t nvx_idx;
/* END cache lookup */
if (xive2_router_get_end(xrtr, end_blk, end_idx, &end)) {
@@ -618,6 +1344,12 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
return;
}
+ if (xive2_end_is_crowd(&end) && !xive2_end_is_ignore(&end)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: invalid END, 'crowd' bit requires 'ignore' bit\n");
+ return;
+ }
+
if (xive2_end_is_enqueue(&end)) {
xive2_end_enqueue(&end, end_data);
/* Enqueuing event data modifies the EQ toggle and index */
@@ -662,26 +1394,14 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
/*
* Follows IVPE notification
*/
- nvp_blk = xive_get_field32(END2_W6_VP_BLOCK, end.w6);
- nvp_idx = xive_get_field32(END2_W6_VP_OFFSET, end.w6);
-
- /* NVP cache lookup */
- if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVP %x/%x\n",
- nvp_blk, nvp_idx);
- return;
- }
-
- if (!xive2_nvp_is_valid(&nvp)) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVP %x/%x is invalid\n",
- nvp_blk, nvp_idx);
- return;
- }
+ nvx_blk = xive_get_field32(END2_W6_VP_BLOCK, end.w6);
+ nvx_idx = xive_get_field32(END2_W6_VP_OFFSET, end.w6);
- found = xive_presenter_notify(xrtr->xfb, format, nvp_blk, nvp_idx,
- xive2_end_is_ignore(&end),
+ found = xive_presenter_notify(xrtr->xfb, format, nvx_blk, nvx_idx,
+ xive2_end_is_crowd(&end), xive2_end_is_ignore(&end),
priority,
- xive_get_field32(END2_W7_F1_LOG_SERVER_ID, end.w7));
+ xive_get_field32(END2_W7_F1_LOG_SERVER_ID, end.w7),
+ &precluded);
/* TODO: Auto EOI. */
@@ -692,10 +1412,9 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
/*
* If no matching NVP is dispatched on a HW thread :
* - specific VP: update the NVP structure if backlog is activated
- * - logical server : forward request to IVPE (not supported)
+ * - VP-group: update the backlog counter for that priority in the NVG
*/
if (xive2_end_is_backlog(&end)) {
- uint8_t ipb;
if (format == 1) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -704,19 +1423,82 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
return;
}
- /*
- * Record the IPB in the associated NVP structure for later
- * use. The presenter will resend the interrupt when the vCPU
- * is dispatched again on a HW thread.
- */
- ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2) |
- xive_priority_to_ipb(priority);
- nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, ipb);
- xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2);
+ if (!xive2_end_is_ignore(&end)) {
+ uint8_t ipb;
+ Xive2Nvp nvp;
- /*
- * On HW, follows a "Broadcast Backlog" to IVPEs
- */
+ /* NVP cache lookup */
+ if (xive2_router_get_nvp(xrtr, nvx_blk, nvx_idx, &nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVP %x/%x\n",
+ nvx_blk, nvx_idx);
+ return;
+ }
+
+ if (!xive2_nvp_is_valid(&nvp)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVP %x/%x is invalid\n",
+ nvx_blk, nvx_idx);
+ return;
+ }
+
+ /*
+ * Record the IPB in the associated NVP structure for later
+ * use. The presenter will resend the interrupt when the vCPU
+ * is dispatched again on a HW thread.
+ */
+ ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2) |
+ xive_priority_to_ipb(priority);
+ nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, ipb);
+ xive2_router_write_nvp(xrtr, nvx_blk, nvx_idx, &nvp, 2);
+ } else {
+ Xive2Nvgc nvgc;
+ uint32_t backlog;
+ bool crowd;
+
+ crowd = xive2_end_is_crowd(&end);
+
+ /*
+ * For groups and crowds, the per-priority backlog
+ * counters are stored in the NVG/NVC structures
+ */
+ if (xive2_router_get_nvgc(xrtr, crowd,
+ nvx_blk, nvx_idx, &nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no %s %x/%x\n",
+ crowd ? "NVC" : "NVG", nvx_blk, nvx_idx);
+ return;
+ }
+
+ if (!xive2_nvgc_is_valid(&nvgc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVG %x/%x is invalid\n",
+ nvx_blk, nvx_idx);
+ return;
+ }
+
+ /*
+ * Increment the backlog counter for that priority.
+ * We only call broadcast the first time the counter is
+ * incremented. broadcast will set the LSMFB field of the TIMA of
+ * relevant threads so that they know an interrupt is pending.
+ */
+ backlog = xive2_nvgc_get_backlog(&nvgc, priority) + 1;
+ xive2_nvgc_set_backlog(&nvgc, priority, backlog);
+ xive2_router_write_nvgc(xrtr, crowd, nvx_blk, nvx_idx, &nvgc);
+
+ if (backlog == 1) {
+ XiveFabricClass *xfc = XIVE_FABRIC_GET_CLASS(xrtr->xfb);
+ xfc->broadcast(xrtr->xfb, nvx_blk, nvx_idx,
+ xive2_end_is_crowd(&end),
+ xive2_end_is_ignore(&end),
+ priority);
+
+ if (!xive2_end_is_precluded_escalation(&end)) {
+ /*
+ * The interrupt will be picked up when the
+ * matching thread lowers its priority level
+ */
+ return;
+ }
+ }
+ }
}
do_escalation:
@@ -803,13 +1585,12 @@ void xive2_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked)
xive_get_field64(EAS2_END_DATA, eas.w));
}
-static Property xive2_router_properties[] = {
+static const Property xive2_router_properties[] = {
DEFINE_PROP_LINK("xive-fabric", Xive2Router, xfb,
TYPE_XIVE_FABRIC, XiveFabric *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xive2_router_class_init(ObjectClass *klass, void *data)
+static void xive2_router_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
@@ -828,7 +1609,7 @@ static const TypeInfo xive2_router_info = {
.instance_size = sizeof(Xive2Router),
.class_size = sizeof(Xive2RouterClass),
.class_init = xive2_router_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_NOTIFIER },
{ TYPE_XIVE_PRESENTER },
{ }
@@ -1017,15 +1798,14 @@ static void xive2_end_source_realize(DeviceState *dev, Error **errp)
(1ull << (xsrc->esb_shift + 1)) * xsrc->nr_ends);
}
-static Property xive2_end_source_properties[] = {
+static const Property xive2_end_source_properties[] = {
DEFINE_PROP_UINT32("nr-ends", Xive2EndSource, nr_ends, 0),
DEFINE_PROP_UINT32("shift", Xive2EndSource, esb_shift, XIVE_ESB_64K),
DEFINE_PROP_LINK("xive", Xive2EndSource, xrtr, TYPE_XIVE2_ROUTER,
Xive2Router *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xive2_end_source_class_init(ObjectClass *klass, void *data)
+static void xive2_end_source_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/intc/xlnx-pmu-iomod-intc.c b/hw/intc/xlnx-pmu-iomod-intc.c
index 12bd1a3..9200585 100644
--- a/hw/intc/xlnx-pmu-iomod-intc.c
+++ b/hw/intc/xlnx-pmu-iomod-intc.c
@@ -474,11 +474,10 @@ static const MemoryRegionOps xlnx_pmu_io_intc_ops = {
},
};
-static Property xlnx_pmu_io_intc_properties[] = {
+static const Property xlnx_pmu_io_intc_properties[] = {
DEFINE_PROP_UINT32("intc-intr-size", XlnxPMUIOIntc, cfg.intr_size, 0),
DEFINE_PROP_UINT32("intc-level-edge", XlnxPMUIOIntc, cfg.level_edge, 0),
DEFINE_PROP_UINT32("intc-positive", XlnxPMUIOIntc, cfg.positive, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static void xlnx_pmu_io_intc_realize(DeviceState *dev, Error **errp)
@@ -532,11 +531,11 @@ static const VMStateDescription vmstate_xlnx_pmu_io_intc = {
}
};
-static void xlnx_pmu_io_intc_class_init(ObjectClass *klass, void *data)
+static void xlnx_pmu_io_intc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_pmu_io_intc_reset;
+ device_class_set_legacy_reset(dc, xlnx_pmu_io_intc_reset);
dc->realize = xlnx_pmu_io_intc_realize;
dc->vmsd = &vmstate_xlnx_pmu_io_intc;
device_class_set_props(dc, xlnx_pmu_io_intc_properties);
diff --git a/hw/intc/xlnx-zynqmp-ipi.c b/hw/intc/xlnx-zynqmp-ipi.c
index 509ee79..610cd0e 100644
--- a/hw/intc/xlnx-zynqmp-ipi.c
+++ b/hw/intc/xlnx-zynqmp-ipi.c
@@ -355,11 +355,11 @@ static const VMStateDescription vmstate_zynqmp_pmu_ipi = {
}
};
-static void xlnx_zynqmp_ipi_class_init(ObjectClass *klass, void *data)
+static void xlnx_zynqmp_ipi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_zynqmp_ipi_reset;
+ device_class_set_legacy_reset(dc, xlnx_zynqmp_ipi_reset);
dc->realize = xlnx_zynqmp_ipi_realize;
dc->vmsd = &vmstate_zynqmp_pmu_ipi;
}
diff --git a/hw/ipack/Kconfig b/hw/ipack/Kconfig
index f8da24a..28d6687 100644
--- a/hw/ipack/Kconfig
+++ b/hw/ipack/Kconfig
@@ -1,4 +1,8 @@
config IPACK
bool
+
+config TPCI200
+ bool
+ select IPACK
default y if PCI_DEVICES
depends on PCI
diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c
index c39dbb4..ab602bf 100644
--- a/hw/ipack/ipack.c
+++ b/hw/ipack/ipack.c
@@ -55,30 +55,26 @@ static void ipack_device_realize(DeviceState *dev, Error **errp)
}
bus->free_slot = idev->slot + 1;
- idev->irq = qemu_allocate_irqs(bus->set_irq, idev, 2);
+ qemu_init_irqs(idev->irq, ARRAY_SIZE(idev->irq), bus->set_irq, idev);
k->realize(dev, errp);
}
static void ipack_device_unrealize(DeviceState *dev)
{
- IPackDevice *idev = IPACK_DEVICE(dev);
IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev);
if (k->unrealize) {
k->unrealize(dev);
return;
}
-
- qemu_free_irqs(idev->irq, 2);
}
-static Property ipack_device_props[] = {
+static const Property ipack_device_props[] = {
DEFINE_PROP_INT32("slot", IPackDevice, slot, -1),
- DEFINE_PROP_END_OF_LIST()
};
-static void ipack_device_class_init(ObjectClass *klass, void *data)
+static void ipack_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
diff --git a/hw/ipack/meson.build b/hw/ipack/meson.build
index 26567f1..e480522 100644
--- a/hw/ipack/meson.build
+++ b/hw/ipack/meson.build
@@ -1 +1,2 @@
-system_ss.add(when: 'CONFIG_IPACK', if_true: files('ipack.c', 'tpci200.c'))
+system_ss.add(when: 'CONFIG_IPACK', if_true: files('ipack.c'))
+system_ss.add(when: 'CONFIG_TPCI200', if_true: files('tpci200.c'))
diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c
index 88eef4b..40b3051 100644
--- a/hw/ipack/tpci200.c
+++ b/hw/ipack/tpci200.c
@@ -275,11 +275,11 @@ static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val,
if (ip != NULL) {
if (val & STATUS_INT(i, 0)) {
DPRINTF("Clear IP %c INT0# status\n", 'A' + i);
- qemu_irq_lower(ip->irq[0]);
+ qemu_irq_lower(&ip->irq[0]);
}
if (val & STATUS_INT(i, 1)) {
DPRINTF("Clear IP %c INT1# status\n", 'A' + i);
- qemu_irq_lower(ip->irq[1]);
+ qemu_irq_lower(&ip->irq[1]);
}
}
@@ -344,7 +344,7 @@ static uint64_t tpci200_read_las1(void *opaque, hwaddr addr, unsigned size)
bool int_set = s->status & STATUS_INT(ip_n, intno);
bool int_edge_sensitive = s->ctrl[ip_n] & CTRL_INT_EDGE(intno);
if (int_set && !int_edge_sensitive) {
- qemu_irq_lower(ip->irq[intno]);
+ qemu_irq_lower(&ip->irq[intno]);
}
}
@@ -629,7 +629,7 @@ static const VMStateDescription vmstate_tpci200 = {
}
};
-static void tpci200_class_init(ObjectClass *klass, void *data)
+static void tpci200_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -650,7 +650,7 @@ static const TypeInfo tpci200_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(TPCI200State),
.class_init = tpci200_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c
index bbb07b1..b91e487 100644
--- a/hw/ipmi/ipmi.c
+++ b/hw/ipmi/ipmi.c
@@ -26,7 +26,7 @@
#include "hw/ipmi/ipmi.h"
#include "hw/qdev-properties.h"
#include "qom/object_interfaces.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "hw/nmi.h"
@@ -78,7 +78,7 @@ static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly)
}
}
-static void ipmi_interface_class_init(ObjectClass *class, void *data)
+static void ipmi_interface_class_init(ObjectClass *class, const void *data)
{
IPMIInterfaceClass *ik = IPMI_INTERFACE_CLASS(class);
@@ -108,12 +108,11 @@ void ipmi_bmc_find_and_link(Object *obj, Object **bmc)
OBJ_PROP_LINK_STRONG);
}
-static Property ipmi_bmc_properties[] = {
+static const Property ipmi_bmc_properties[] = {
DEFINE_PROP_UINT8("slave_addr", IPMIBmc, slave_addr, 0x20),
- DEFINE_PROP_END_OF_LIST(),
};
-static void bmc_class_init(ObjectClass *oc, void *data)
+static void bmc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index 29c5af3..9f1ba7b 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -142,7 +142,6 @@ static void continue_send(IPMIBmcExtern *ibe)
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 4000000000ULL);
}
}
- return;
}
static void extern_timeout(void *opaque)
@@ -214,7 +213,7 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
rsp[2] = err;
ibe->waiting_rsp = false;
k->handle_rsp(s, msg_id, rsp, 3);
- goto out;
+ return;
}
addchar(ibe, msg_id);
@@ -229,9 +228,6 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b,
/* Start the transmit */
continue_send(ibe);
-
- out:
- return;
}
static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op)
@@ -497,8 +493,6 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive,
chr_event, NULL, ibe, NULL, true);
-
- vmstate_register(NULL, 0, &vmstate_ipmi_bmc_extern, ibe);
}
static void ipmi_bmc_extern_init(Object *obj)
@@ -515,12 +509,11 @@ static void ipmi_bmc_extern_finalize(Object *obj)
timer_free(ibe->extern_timer);
}
-static Property ipmi_bmc_extern_properties[] = {
+static const Property ipmi_bmc_extern_properties[] = {
DEFINE_PROP_CHR("chardev", IPMIBmcExtern, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ipmi_bmc_extern_class_init(ObjectClass *oc, void *data)
+static void ipmi_bmc_extern_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
@@ -529,6 +522,7 @@ static void ipmi_bmc_extern_class_init(ObjectClass *oc, void *data)
bk->handle_reset = ipmi_bmc_extern_handle_reset;
dc->hotpluggable = false;
dc->realize = ipmi_bmc_extern_realize;
+ dc->vmsd = &vmstate_ipmi_bmc_extern;
device_class_set_props(dc, ipmi_bmc_extern_properties);
}
diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index 33c839c..04e1dcd 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -23,7 +23,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/timer.h"
#include "hw/ipmi/ipmi.h"
#include "qemu/error-report.h"
@@ -70,6 +70,7 @@
#define IPMI_CMD_GET_MSG 0x33
#define IPMI_CMD_SEND_MSG 0x34
#define IPMI_CMD_READ_EVT_MSG_BUF 0x35
+#define IPMI_CMD_GET_CHANNEL_INFO 0x42
#define IPMI_NETFN_STORAGE 0x0a
@@ -234,6 +235,7 @@ struct IPMIBmcSim {
#define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
(IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
+#define IPMI_BMC_GLOBAL_ENABLES_SUPPORTED 0x0f
#define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
#define IPMI_BMC_EVBUF_FULL_INT_BIT 1
#define IPMI_BMC_EVENT_MSG_BUF_BIT 2
@@ -463,14 +465,12 @@ void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
}
if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
- goto out;
+ return;
}
memcpy(ibs->evtbuf, evt, 16);
ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
k->set_atn(s, 1, attn_irq_enabled(ibs));
- out:
- return;
}
static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
uint8_t evd1, uint8_t evd2, uint8_t evd3)
@@ -513,7 +513,8 @@ static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
unsigned int bit, unsigned int val,
- uint8_t evd1, uint8_t evd2, uint8_t evd3)
+ uint8_t evd1, uint8_t evd2, uint8_t evd3,
+ bool do_log)
{
IPMISensor *sens;
uint16_t mask;
@@ -533,7 +534,7 @@ static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
return; /* Already asserted */
}
sens->assert_states |= mask & sens->assert_suppt;
- if (sens->assert_enable & mask & sens->assert_states) {
+ if (do_log && (sens->assert_enable & mask & sens->assert_states)) {
/* Send an event on assert */
gen_event(ibs, sensor, 0, evd1, evd2, evd3);
}
@@ -543,7 +544,7 @@ static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
return; /* Already deasserted */
}
sens->deassert_states |= mask & sens->deassert_suppt;
- if (sens->deassert_enable & mask & sens->deassert_states) {
+ if (do_log && (sens->deassert_enable & mask & sens->deassert_states)) {
/* Send an event on deassert */
gen_event(ibs, sensor, 1, evd1, evd2, evd3);
}
@@ -699,6 +700,7 @@ static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
{
IPMIInterface *s = ibs->parent.intf;
IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
+ bool do_log = !IPMI_BMC_WATCHDOG_GET_DONT_LOG(ibs);
if (!ibs->watchdog_running) {
goto out;
@@ -710,14 +712,16 @@ static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
k->do_hw_op(s, IPMI_SEND_NMI, 0);
sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
- 0xc8, (2 << 4) | 0xf, 0xff);
+ 0xc8, (2 << 4) | 0xf, 0xff,
+ do_log);
break;
case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
k->set_atn(s, 1, attn_irq_enabled(ibs));
sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
- 0xc8, (3 << 4) | 0xf, 0xff);
+ 0xc8, (3 << 4) | 0xf, 0xff,
+ do_log);
break;
default:
@@ -737,24 +741,28 @@ static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
case IPMI_BMC_WATCHDOG_ACTION_NONE:
sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
- 0xc0, ibs->watchdog_use & 0xf, 0xff);
+ 0xc0, ibs->watchdog_use & 0xf, 0xff,
+ do_log);
break;
case IPMI_BMC_WATCHDOG_ACTION_RESET:
sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
- 0xc1, ibs->watchdog_use & 0xf, 0xff);
+ 0xc1, ibs->watchdog_use & 0xf, 0xff,
+ do_log);
k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
break;
case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
- 0xc2, ibs->watchdog_use & 0xf, 0xff);
+ 0xc2, ibs->watchdog_use & 0xf, 0xff,
+ do_log);
k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
break;
case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
- 0xc3, ibs->watchdog_use & 0xf, 0xff);
+ 0xc3, ibs->watchdog_use & 0xf, 0xff,
+ do_log);
k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
break;
}
@@ -925,7 +933,14 @@ static void set_bmc_global_enables(IPMIBmcSim *ibs,
uint8_t *cmd, unsigned int cmd_len,
RspBuffer *rsp)
{
- set_global_enables(ibs, cmd[2]);
+ uint8_t val = cmd[2];
+
+ if (val & ~IPMI_BMC_GLOBAL_ENABLES_SUPPORTED) {
+ rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+ return;
+ }
+
+ set_global_enables(ibs, val);
}
static void get_bmc_global_enables(IPMIBmcSim *ibs,
@@ -980,7 +995,7 @@ static void get_msg(IPMIBmcSim *ibs,
if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
- goto out;
+ return;
}
rsp_buffer_push(rsp, 0); /* Channel 0 */
msg = QTAILQ_FIRST(&ibs->rcvbufs);
@@ -995,9 +1010,6 @@ static void get_msg(IPMIBmcSim *ibs,
ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
}
-
-out:
- return;
}
static unsigned char
@@ -1020,8 +1032,8 @@ static void send_msg(IPMIBmcSim *ibs,
uint8_t *buf;
uint8_t netfn, rqLun, rsLun, rqSeq;
- if (cmd[2] != 0) {
- /* We only handle channel 0 with no options */
+ if (cmd[2] != IPMI_CHANNEL_IPMB) {
+ /* We only handle channel 0h (IPMB) with no options */
rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
return;
}
@@ -1219,6 +1231,68 @@ static void get_watchdog_timer(IPMIBmcSim *ibs,
}
}
+static void get_channel_info(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ RspBuffer *rsp)
+{
+ IPMIInterface *s = ibs->parent.intf;
+ IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
+ IPMIFwInfo info = {};
+ uint8_t ch = cmd[2] & 0x0f;
+
+ /* Only define channel 0h (IPMB) and Fh (system interface) */
+
+ if (ch == 0x0e) { /* "This channel" */
+ ch = IPMI_CHANNEL_SYSTEM;
+ }
+ rsp_buffer_push(rsp, ch);
+
+ if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) {
+ /* Not a supported channel */
+ rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+ return;
+ }
+
+ if (k->get_fwinfo) {
+ k->get_fwinfo(s, &info);
+ }
+
+ if (ch == IPMI_CHANNEL_IPMB) {
+ rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB);
+ rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB);
+ } else { /* IPMI_CHANNEL_SYSTEM */
+ rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM);
+ rsp_buffer_push(rsp, info.ipmi_channel_protocol);
+ }
+
+ rsp_buffer_push(rsp, 0x00); /* Session-less */
+
+ /* IPMI Enterprise Number for Vendor ID */
+ rsp_buffer_push(rsp, 0xf2);
+ rsp_buffer_push(rsp, 0x1b);
+ rsp_buffer_push(rsp, 0x00);
+
+ if (ch == IPMI_CHANNEL_SYSTEM) {
+ uint8_t irq;
+
+ if (info.irq_source == IPMI_ISA_IRQ) {
+ irq = info.interrupt_number;
+ } else if (info.irq_source == IPMI_PCI_IRQ) {
+ irq = 0x10 + info.interrupt_number;
+ } else {
+ irq = 0xff; /* no interrupt / unspecified */
+ }
+
+ /* Both interrupts use the same irq number */
+ rsp_buffer_push(rsp, irq);
+ rsp_buffer_push(rsp, irq);
+ } else {
+ /* Reserved */
+ rsp_buffer_push(rsp, 0x00);
+ rsp_buffer_push(rsp, 0x00);
+ }
+}
+
static void get_sdr_rep_info(IPMIBmcSim *ibs,
uint8_t *cmd, unsigned int cmd_len,
RspBuffer *rsp)
@@ -2015,6 +2089,7 @@ static const IPMICmdHandler app_cmds[] = {
[IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
[IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
[IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
+ [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 },
};
static const IPMINetfn app_netfn = {
.cmd_nums = ARRAY_SIZE(app_cmds),
@@ -2187,11 +2262,9 @@ static void ipmi_sim_realize(DeviceState *dev, Error **errp)
register_cmds(ibs);
ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
-
- vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
}
-static Property ipmi_sim_properties[] = {
+static const Property ipmi_sim_properties[] = {
DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
@@ -2203,16 +2276,16 @@ static Property ipmi_sim_properties[] = {
DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ipmi_sim_class_init(ObjectClass *oc, void *data)
+static void ipmi_sim_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
dc->hotpluggable = false;
dc->realize = ipmi_sim_realize;
+ dc->vmsd = &vmstate_ipmi_sim;
device_class_set_props(dc, ipmi_sim_properties);
bk->handle_command = ipmi_sim_handle_command;
}
diff --git a/hw/ipmi/ipmi_bt.c b/hw/ipmi/ipmi_bt.c
index 583fc64..e01d02f 100644
--- a/hw/ipmi/ipmi_bt.c
+++ b/hw/ipmi/ipmi_bt.c
@@ -98,14 +98,14 @@ static void ipmi_bt_handle_event(IPMIInterface *ii)
IPMIBT *ib = iic->get_backend_data(ii);
if (ib->inlen < 4) {
- goto out;
+ return;
}
/* Note that overruns are handled by handle_command */
if (ib->inmsg[0] != (ib->inlen - 1)) {
/* Length mismatch, just ignore. */
IPMI_BT_SET_BBUSY(ib->control_reg, 1);
ib->inlen = 0;
- goto out;
+ return;
}
if ((ib->inmsg[1] == (IPMI_NETFN_APP << 2)) &&
(ib->inmsg[3] == IPMI_CMD_GET_BT_INTF_CAP)) {
@@ -136,7 +136,7 @@ static void ipmi_bt_handle_event(IPMIInterface *ii)
IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
ipmi_bt_raise_irq(ib);
}
- goto out;
+ return;
}
ib->waiting_seq = ib->inmsg[2];
ib->inmsg[2] = ib->inmsg[1];
@@ -145,8 +145,6 @@ static void ipmi_bt_handle_event(IPMIInterface *ii)
bk->handle_command(ib->bmc, ib->inmsg + 2, ib->inlen - 2,
sizeof(ib->inmsg), ib->waiting_rsp);
}
- out:
- return;
}
static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
@@ -419,6 +417,8 @@ void ipmi_bt_get_fwinfo(struct IPMIBT *ib, IPMIFwInfo *info)
info->interface_type = IPMI_SMBIOS_BT;
info->ipmi_spec_major_revision = 2;
info->ipmi_spec_minor_revision = 0;
+ /* BT System Interface Format, IPMI v1.5 */
+ info->ipmi_channel_protocol = IPMI_CHANNEL_PROTOCOL_BT_15;
info->base_address = ib->io_base;
info->register_length = ib->io_length;
info->register_spacing = 1;
diff --git a/hw/ipmi/ipmi_kcs.c b/hw/ipmi/ipmi_kcs.c
index c15977c..d5cfe6c 100644
--- a/hw/ipmi/ipmi_kcs.c
+++ b/hw/ipmi/ipmi_kcs.c
@@ -168,7 +168,7 @@ static void ipmi_kcs_handle_event(IPMIInterface *ii)
ik->outpos = 0;
bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg),
ik->waiting_rsp);
- goto out_noibf;
+ return;
} else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) {
ik->cmd_reg = -1;
ik->write_end = 1;
@@ -197,8 +197,6 @@ static void ipmi_kcs_handle_event(IPMIInterface *ii)
ik->cmd_reg = -1;
ik->data_in_reg = -1;
IPMI_KCS_SET_IBF(ik->status_reg, 0);
- out_noibf:
- return;
}
static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
@@ -405,6 +403,7 @@ void ipmi_kcs_get_fwinfo(IPMIKCS *ik, IPMIFwInfo *info)
info->interface_type = IPMI_SMBIOS_KCS;
info->ipmi_spec_major_revision = 2;
info->ipmi_spec_minor_revision = 0;
+ info->ipmi_channel_protocol = IPMI_CHANNEL_PROTOCOL_KCS;
info->base_address = ik->io_base;
info->i2c_slave_address = ik->bmc->slave_addr;
info->register_length = ik->io_length;
diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c
index 7b36d51..0ad91cc 100644
--- a/hw/ipmi/isa_ipmi_bt.c
+++ b/hw/ipmi/isa_ipmi_bt.c
@@ -49,6 +49,7 @@ static void isa_ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
ipmi_bt_get_fwinfo(&iib->bt, info);
+ info->irq_source = IPMI_ISA_IRQ;
info->interrupt_number = iib->isairq;
info->i2c_slave_address = iib->bt.bmc->slave_addr;
info->uuid = iib->uuid;
@@ -117,8 +118,6 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length);
isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base);
-
- vmstate_register(NULL, 0, &vmstate_ISAIPMIBTDevice, dev);
}
static void isa_ipmi_bt_init(Object *obj)
@@ -135,19 +134,19 @@ static void *isa_ipmi_bt_get_backend_data(IPMIInterface *ii)
return &iib->bt;
}
-static Property ipmi_isa_properties[] = {
+static const Property ipmi_isa_properties[] = {
DEFINE_PROP_UINT32("ioport", ISAIPMIBTDevice, bt.io_base, 0xe4),
DEFINE_PROP_INT32("irq", ISAIPMIBTDevice, isairq, 5),
- DEFINE_PROP_END_OF_LIST(),
};
-static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
+static void isa_ipmi_bt_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc);
dc->realize = isa_ipmi_bt_realize;
+ dc->vmsd = &vmstate_ISAIPMIBTDevice;
device_class_set_props(dc, ipmi_isa_properties);
iic->get_backend_data = isa_ipmi_bt_get_backend_data;
@@ -162,7 +161,7 @@ static const TypeInfo isa_ipmi_bt_info = {
.instance_size = sizeof(ISAIPMIBTDevice),
.instance_init = isa_ipmi_bt_init,
.class_init = isa_ipmi_bt_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ TYPE_ACPI_DEV_AML_IF },
{ }
diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
index f52b32e..418d234 100644
--- a/hw/ipmi/isa_ipmi_kcs.c
+++ b/hw/ipmi/isa_ipmi_kcs.c
@@ -49,6 +49,7 @@ static void isa_ipmi_kcs_get_fwinfo(IPMIInterface *ii, IPMIFwInfo *info)
ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii);
ipmi_kcs_get_fwinfo(&iik->kcs, info);
+ info->irq_source = IPMI_ISA_IRQ;
info->interrupt_number = iik->isairq;
info->uuid = iik->uuid;
}
@@ -72,6 +73,10 @@ static bool vmstate_kcs_before_version2(void *opaque, int version)
return version <= 1;
}
+/*
+ * Version 1 had an incorrect name, it clashed with the BT IPMI
+ * device, so receive it, but transmit a different version.
+ */
static const VMStateDescription vmstate_ISAIPMIKCSDevice = {
.name = TYPE_IPMI_INTERFACE,
.version_id = 2,
@@ -119,13 +124,6 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp)
qdev_set_legacy_instance_id(dev, iik->kcs.io_base, iik->kcs.io_length);
isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base);
-
- /*
- * Version 1 had an incorrect name, it clashed with the BT
- * IPMI device, so receive it, but transmit a different
- * version.
- */
- vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik);
}
static void isa_ipmi_kcs_init(Object *obj)
@@ -142,19 +140,19 @@ static void *isa_ipmi_kcs_get_backend_data(IPMIInterface *ii)
return &iik->kcs;
}
-static Property ipmi_isa_properties[] = {
+static const Property ipmi_isa_properties[] = {
DEFINE_PROP_UINT32("ioport", ISAIPMIKCSDevice, kcs.io_base, 0xca2),
DEFINE_PROP_INT32("irq", ISAIPMIKCSDevice, isairq, 5),
- DEFINE_PROP_END_OF_LIST(),
};
-static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data)
+static void isa_ipmi_kcs_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc);
dc->realize = ipmi_isa_realize;
+ dc->vmsd = &vmstate_ISAIPMIKCSDevice;
device_class_set_props(dc, ipmi_isa_properties);
iic->get_backend_data = isa_ipmi_kcs_get_backend_data;
@@ -169,7 +167,7 @@ static const TypeInfo isa_ipmi_kcs_info = {
.instance_size = sizeof(ISAIPMIKCSDevice),
.instance_init = isa_ipmi_kcs_init,
.class_init = isa_ipmi_kcs_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ TYPE_ACPI_DEV_AML_IF },
{ }
diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c
index afeea6f..905101d 100644
--- a/hw/ipmi/pci_ipmi_bt.c
+++ b/hw/ipmi/pci_ipmi_bt.c
@@ -38,49 +38,60 @@ struct PCIIPMIBTDevice {
uint32_t uuid;
};
-static void pci_ipmi_raise_irq(IPMIBT *ik)
+static void pci_ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
{
- PCIIPMIBTDevice *pik = ik->opaque;
+ PCIIPMIBTDevice *pib = PCI_IPMI_BT(ii);
- pci_set_irq(&pik->dev, true);
+ ipmi_bt_get_fwinfo(&pib->bt, info);
+ info->irq_source = IPMI_PCI_IRQ;
+ info->interrupt_number = pci_intx(&pib->dev);
+ info->i2c_slave_address = pib->bt.bmc->slave_addr;
+ info->uuid = pib->uuid;
}
-static void pci_ipmi_lower_irq(IPMIBT *ik)
+static void pci_ipmi_raise_irq(IPMIBT *ib)
{
- PCIIPMIBTDevice *pik = ik->opaque;
+ PCIIPMIBTDevice *pib = ib->opaque;
- pci_set_irq(&pik->dev, false);
+ pci_set_irq(&pib->dev, true);
+}
+
+static void pci_ipmi_lower_irq(IPMIBT *ib)
+{
+ PCIIPMIBTDevice *pib = ib->opaque;
+
+ pci_set_irq(&pib->dev, false);
}
static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp)
{
Error *err = NULL;
- PCIIPMIBTDevice *pik = PCI_IPMI_BT(pd);
+ PCIIPMIBTDevice *pib = PCI_IPMI_BT(pd);
IPMIInterface *ii = IPMI_INTERFACE(pd);
IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
- if (!pik->bt.bmc) {
+ if (!pib->bt.bmc) {
error_setg(errp, "IPMI device requires a bmc attribute to be set");
return;
}
- pik->uuid = ipmi_next_uuid();
+ pib->uuid = ipmi_next_uuid();
- pik->bt.bmc->intf = ii;
- pik->bt.opaque = pik;
+ pib->bt.bmc->intf = ii;
+ pib->bt.opaque = pib;
pci_config_set_prog_interface(pd->config, 0x02); /* BT */
pci_config_set_interrupt_pin(pd->config, 0x01);
- pik->bt.use_irq = 1;
- pik->bt.raise_irq = pci_ipmi_raise_irq;
- pik->bt.lower_irq = pci_ipmi_lower_irq;
+ pib->bt.use_irq = 1;
+ pib->bt.raise_irq = pci_ipmi_raise_irq;
+ pib->bt.lower_irq = pci_ipmi_lower_irq;
iic->init(ii, 8, &err);
if (err) {
error_propagate(errp, err);
return;
}
- pci_register_bar(pd, 0, PCI_BASE_ADDRESS_SPACE_IO, &pik->bt.io);
+ pci_register_bar(pd, 0, PCI_BASE_ADDRESS_SPACE_IO, &pib->bt.io);
}
const VMStateDescription vmstate_PCIIPMIBTDevice = {
@@ -96,19 +107,19 @@ const VMStateDescription vmstate_PCIIPMIBTDevice = {
static void pci_ipmi_bt_instance_init(Object *obj)
{
- PCIIPMIBTDevice *pik = PCI_IPMI_BT(obj);
+ PCIIPMIBTDevice *pib = PCI_IPMI_BT(obj);
- ipmi_bmc_find_and_link(obj, (Object **) &pik->bt.bmc);
+ ipmi_bmc_find_and_link(obj, (Object **) &pib->bt.bmc);
}
static void *pci_ipmi_bt_get_backend_data(IPMIInterface *ii)
{
- PCIIPMIBTDevice *pik = PCI_IPMI_BT(ii);
+ PCIIPMIBTDevice *pib = PCI_IPMI_BT(ii);
- return &pik->bt;
+ return &pib->bt;
}
-static void pci_ipmi_bt_class_init(ObjectClass *oc, void *data)
+static void pci_ipmi_bt_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
@@ -125,6 +136,7 @@ static void pci_ipmi_bt_class_init(ObjectClass *oc, void *data)
iic->get_backend_data = pci_ipmi_bt_get_backend_data;
ipmi_bt_class_init(iic);
+ iic->get_fwinfo = pci_ipmi_bt_get_fwinfo;
}
static const TypeInfo pci_ipmi_bt_info = {
@@ -133,7 +145,7 @@ static const TypeInfo pci_ipmi_bt_info = {
.instance_size = sizeof(PCIIPMIBTDevice),
.instance_init = pci_ipmi_bt_instance_init,
.class_init = pci_ipmi_bt_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
diff --git a/hw/ipmi/pci_ipmi_kcs.c b/hw/ipmi/pci_ipmi_kcs.c
index 05ba97e..4d6cde8 100644
--- a/hw/ipmi/pci_ipmi_kcs.c
+++ b/hw/ipmi/pci_ipmi_kcs.c
@@ -38,6 +38,16 @@ struct PCIIPMIKCSDevice {
uint32_t uuid;
};
+static void pci_ipmi_kcs_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
+{
+ PCIIPMIKCSDevice *pik = PCI_IPMI_KCS(ii);
+
+ ipmi_kcs_get_fwinfo(&pik->kcs, info);
+ info->irq_source = IPMI_PCI_IRQ;
+ info->interrupt_number = pci_intx(&pik->dev);
+ info->uuid = pik->uuid;
+}
+
static void pci_ipmi_raise_irq(IPMIKCS *ik)
{
PCIIPMIKCSDevice *pik = ik->opaque;
@@ -108,7 +118,7 @@ static void *pci_ipmi_kcs_get_backend_data(IPMIInterface *ii)
return &pik->kcs;
}
-static void pci_ipmi_kcs_class_init(ObjectClass *oc, void *data)
+static void pci_ipmi_kcs_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
@@ -125,6 +135,7 @@ static void pci_ipmi_kcs_class_init(ObjectClass *oc, void *data)
iic->get_backend_data = pci_ipmi_kcs_get_backend_data;
ipmi_kcs_class_init(iic);
+ iic->get_fwinfo = pci_ipmi_kcs_get_fwinfo;
}
static const TypeInfo pci_ipmi_kcs_info = {
@@ -133,7 +144,7 @@ static const TypeInfo pci_ipmi_kcs_info = {
.instance_size = sizeof(PCIIPMIKCSDevice),
.instance_init = pci_ipmi_kcs_instance_init,
.class_init = pci_ipmi_kcs_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c
index 56865df..78c332d 100644
--- a/hw/ipmi/smbus_ipmi.c
+++ b/hw/ipmi/smbus_ipmi.c
@@ -351,7 +351,7 @@ static void smbus_ipmi_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
info->uuid = sid->uuid;
}
-static void smbus_ipmi_class_init(ObjectClass *oc, void *data)
+static void smbus_ipmi_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
@@ -376,7 +376,7 @@ static const TypeInfo smbus_ipmi_info = {
.instance_size = sizeof(SMBusIPMIDevice),
.instance_init = smbus_ipmi_init,
.class_init = smbus_ipmi_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_IPMI_INTERFACE },
{ TYPE_ACPI_DEV_AML_IF },
{ }
diff --git a/hw/isa/fdc37m81x-superio.c b/hw/isa/fdc37m81x-superio.c
index 55e91fb..c2a38f0 100644
--- a/hw/isa/fdc37m81x-superio.c
+++ b/hw/isa/fdc37m81x-superio.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "hw/isa/superio.h"
-static void fdc37m81x_class_init(ObjectClass *klass, void *data)
+static void fdc37m81x_class_init(ObjectClass *klass, const void *data)
{
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c
index cbaa152..06e8f0c 100644
--- a/hw/isa/i82378.c
+++ b/hw/isa/i82378.c
@@ -122,7 +122,7 @@ static void i82378_init(Object *obj)
qdev_init_gpio_in(dev, i82378_request_pic_irq, 16);
}
-static void i82378_class_init(ObjectClass *klass, void *data)
+static void i82378_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -142,7 +142,7 @@ static const TypeInfo i82378_type_info = {
.instance_size = sizeof(I82378State),
.instance_init = i82378_init,
.class_init = i82378_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index f1e0f14..6c9802e 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -22,14 +22,14 @@
#include "qemu/module.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/isa/isa.h"
static ISABus *isabus;
static char *isabus_get_fw_dev_path(DeviceState *dev);
-static void isa_bus_class_init(ObjectClass *klass, void *data)
+static void isa_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
@@ -205,7 +205,7 @@ ISADevice *isa_vga_init(ISABus *bus)
}
}
-static void isabus_bridge_class_init(ObjectClass *klass, void *data)
+static void isabus_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -220,7 +220,7 @@ static const TypeInfo isabus_bridge_info = {
.class_init = isabus_bridge_class_init,
};
-static void isa_device_class_init(ObjectClass *klass, void *data)
+static void isa_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->bus_type = TYPE_ISA_BUS;
diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c
index a8c8c58..2853485 100644
--- a/hw/isa/isa-superio.c
+++ b/hw/isa/isa-superio.c
@@ -14,7 +14,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qapi/error.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "chardev/char.h"
#include "hw/char/parallel.h"
#include "hw/block/fdc.h"
@@ -22,7 +22,7 @@
#include "hw/qdev-properties.h"
#include "hw/input/i8042.h"
#include "hw/char/parallel-isa.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "trace.h"
static void isa_superio_realize(DeviceState *dev, Error **errp)
@@ -172,7 +172,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp)
}
}
-static void isa_superio_class_init(ObjectClass *oc, void *data)
+static void isa_superio_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index bd727b2..304dffa 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -43,10 +43,11 @@
#include "hw/southbridge/ich9.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/ich9.h"
+#include "hw/acpi/ich9_timer.h"
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "hw/core/cpu.h"
#include "hw/nvram/fw_cfg.h"
#include "qemu/cutils.h"
@@ -181,7 +182,6 @@ static uint64_t ich9_cc_read(void *opaque, hwaddr addr,
}
/* IRQ routing */
-/* */
static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
{
*pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK;
@@ -531,6 +531,15 @@ ich9_lpc_pmcon_update(ICH9LPCState *lpc)
uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1);
uint16_t wmask;
+ if (lpc->pm.swsmi_timer_enabled) {
+ ich9_pm_update_swsmi_timer(
+ &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN);
+ }
+ if (lpc->pm.periodic_timer_enabled) {
+ ich9_pm_update_periodic_timer(
+ &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN);
+ }
+
if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) {
wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1);
wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK;
@@ -816,7 +825,7 @@ static const VMStateDescription vmstate_ich9_lpc = {
}
};
-static Property ich9_lpc_properties[] = {
+static const Property ich9_lpc_properties[] = {
DEFINE_PROP_BOOL("noreboot", ICH9LPCState, pin_strap.spkr_hi, false),
DEFINE_PROP_BOOL("smm-compat", ICH9LPCState, pm.smm_compat, false),
DEFINE_PROP_BOOL("smm-enabled", ICH9LPCState, pm.smm_enabled, false),
@@ -826,7 +835,10 @@ static Property ich9_lpc_properties[] = {
ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT, true),
DEFINE_PROP_BIT64("x-smi-cpu-hotunplug", ICH9LPCState, smi_host_features,
ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT, true),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("x-smi-swsmi-timer", ICH9LPCState,
+ pm.swsmi_timer_enabled, true),
+ DEFINE_PROP_BOOL("x-smi-periodic-timer", ICH9LPCState,
+ pm.periodic_timer_enabled, true),
};
static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
@@ -862,7 +874,7 @@ static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
qbus_build_aml(bus, scope);
}
-static void ich9_lpc_class_init(ObjectClass *klass, void *data)
+static void ich9_lpc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -871,7 +883,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
AcpiDevAmlIfClass *amldevc = ACPI_DEV_AML_IF_CLASS(klass);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = ich9_lpc_reset;
+ device_class_set_legacy_reset(dc, ich9_lpc_reset);
k->realize = ich9_lpc_realize;
dc->vmsd = &vmstate_ich9_lpc;
device_class_set_props(dc, ich9_lpc_properties);
@@ -902,7 +914,7 @@ static const TypeInfo ich9_lpc_info = {
.instance_size = sizeof(ICH9LPCState),
.instance_init = ich9_lpc_initfn,
.class_init = ich9_lpc_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c
index 64dd17b..388da8f 100644
--- a/hw/isa/pc87312.c
+++ b/hw/isa/pc87312.c
@@ -327,18 +327,17 @@ static const VMStateDescription vmstate_pc87312 = {
}
};
-static Property pc87312_properties[] = {
+static const Property pc87312_properties[] = {
DEFINE_PROP_UINT16("iobase", PC87312State, iobase, 0x398),
DEFINE_PROP_UINT8("config", PC87312State, config, 1),
- DEFINE_PROP_END_OF_LIST()
};
-static void pc87312_class_init(ObjectClass *klass, void *data)
+static void pc87312_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
- dc->reset = pc87312_reset;
+ device_class_set_legacy_reset(dc, pc87312_reset);
dc->vmsd = &vmstate_pc87312;
device_class_set_parent_realize(dc, pc87312_realize,
&sc->parent_realize);
diff --git a/hw/isa/piix.c b/hw/isa/piix.c
index 2d30711..52c14d3 100644
--- a/hw/isa/piix.c
+++ b/hw/isa/piix.c
@@ -34,7 +34,7 @@
#include "hw/ide/piix.h"
#include "hw/intc/i8259.h"
#include "hw/isa/isa.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "migration/vmstate.h"
#include "hw/acpi/acpi_aml_interface.h"
@@ -408,24 +408,23 @@ static void pci_piix_init(Object *obj)
object_initialize_child(obj, "rtc", &d->rtc, TYPE_MC146818_RTC);
}
-static Property pci_piix_props[] = {
+static const Property pci_piix_props[] = {
DEFINE_PROP_UINT32("smb_io_base", PIIXState, smb_io_base, 0),
DEFINE_PROP_BOOL("has-acpi", PIIXState, has_acpi, true),
DEFINE_PROP_BOOL("has-pic", PIIXState, has_pic, true),
DEFINE_PROP_BOOL("has-pit", PIIXState, has_pit, true),
DEFINE_PROP_BOOL("has-usb", PIIXState, has_usb, true),
DEFINE_PROP_BOOL("smm-enabled", PIIXState, smm_enabled, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pci_piix_class_init(ObjectClass *klass, void *data)
+static void pci_piix_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
k->config_write = piix_write_config;
- dc->reset = piix_reset;
+ device_class_set_legacy_reset(dc, piix_reset);
dc->desc = "ISA bridge";
dc->hotpluggable = false;
k->vendor_id = PCI_VENDOR_ID_INTEL;
@@ -446,7 +445,7 @@ static const TypeInfo piix_pci_type_info = {
.instance_init = pci_piix_init,
.abstract = true,
.class_init = pci_piix_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ TYPE_ACPI_DEV_AML_IF },
{ },
@@ -465,7 +464,7 @@ static void piix3_init(Object *obj)
object_initialize_child(obj, "ide", &d->ide, TYPE_PIIX3_IDE);
}
-static void piix3_class_init(ObjectClass *klass, void *data)
+static void piix3_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -495,7 +494,7 @@ static void piix4_init(Object *obj)
object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE);
}
-static void piix4_class_init(ObjectClass *klass, void *data)
+static void piix4_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/isa/smc37c669-superio.c b/hw/isa/smc37c669-superio.c
index d2e58c9..0ec63f5 100644
--- a/hw/isa/smc37c669-superio.c
+++ b/hw/isa/smc37c669-superio.c
@@ -58,7 +58,7 @@ static unsigned int get_fdc_dma(ISASuperIODevice *sio, uint8_t index)
return 2;
}
-static void smc37c669_class_init(ObjectClass *klass, void *data)
+static void smc37c669_class_init(ObjectClass *klass, const void *data)
{
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 505b44c..3379586 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -17,7 +17,7 @@
#include "hw/isa/vt82c686.h"
#include "hw/block/fdc.h"
#include "hw/char/parallel-isa.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "hw/ide/pci.h"
@@ -220,11 +220,11 @@ typedef struct via_pm_init_info {
uint16_t device_id;
} ViaPMInitInfo;
-static void via_pm_class_init(ObjectClass *klass, void *data)
+static void via_pm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- ViaPMInitInfo *info = data;
+ const ViaPMInitInfo *info = data;
k->realize = via_pm_realize;
k->config_write = pm_write_config;
@@ -232,7 +232,7 @@ static void via_pm_class_init(ObjectClass *klass, void *data)
k->device_id = info->device_id;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
k->revision = 0x40;
- dc->reset = via_pm_reset;
+ device_class_set_legacy_reset(dc, via_pm_reset);
/* Reason: part of VIA south bridge, does not exist stand alone */
dc->user_creatable = false;
dc->vmsd = &vmstate_acpi;
@@ -243,7 +243,7 @@ static const TypeInfo via_pm_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(ViaPMState),
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -259,7 +259,7 @@ static const TypeInfo vt82c686b_pm_info = {
.name = TYPE_VT82C686B_PM,
.parent = TYPE_VIA_PM,
.class_init = via_pm_class_init,
- .class_data = (void *)&vt82c686b_pm_init_info,
+ .class_data = &vt82c686b_pm_init_info,
};
static const ViaPMInitInfo vt8231_pm_init_info = {
@@ -272,7 +272,7 @@ static const TypeInfo vt8231_pm_info = {
.name = TYPE_VT8231_PM,
.parent = TYPE_VIA_PM,
.class_init = via_pm_class_init,
- .class_data = (void *)&vt8231_pm_init_info,
+ .class_data = &vt8231_pm_init_info,
};
@@ -337,7 +337,7 @@ static void via_superio_devices_enable(ViaSuperIOState *s, uint8_t data)
isa_fdc_set_enabled(s->superio.floppy, data & BIT(4));
}
-static void via_superio_class_init(ObjectClass *klass, void *data)
+static void via_superio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
@@ -456,12 +456,12 @@ static void vt82c686b_superio_init(Object *obj)
VIA_SUPERIO(obj)->io_ops = &vt82c686b_superio_cfg_ops;
}
-static void vt82c686b_superio_class_init(ObjectClass *klass, void *data)
+static void vt82c686b_superio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
- dc->reset = vt82c686b_superio_reset;
+ device_class_set_legacy_reset(dc, vt82c686b_superio_reset);
sc->serial.count = 2;
sc->parallel.count = 1;
sc->ide.count = 0; /* emulated by via-ide */
@@ -565,12 +565,12 @@ static void vt8231_superio_init(Object *obj)
VIA_SUPERIO(obj)->io_ops = &vt8231_superio_cfg_ops;
}
-static void vt8231_superio_class_init(ObjectClass *klass, void *data)
+static void vt8231_superio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
- dc->reset = vt8231_superio_reset;
+ device_class_set_legacy_reset(dc, vt8231_superio_reset);
sc->serial.count = 1;
sc->parallel.count = 1;
sc->ide.count = 0; /* emulated by via-ide */
@@ -592,6 +592,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ViaISAState, VIA_ISA)
struct ViaISAState {
PCIDevice dev;
+
+ IRQState i8259_irq;
qemu_irq cpu_intr;
qemu_irq *isa_irqs_in;
uint16_t irq_state[ISA_NUM_IRQS];
@@ -632,7 +634,7 @@ static const TypeInfo via_isa_info = {
.instance_size = sizeof(ViaISAState),
.instance_init = via_isa_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -715,13 +717,12 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
ViaISAState *s = VIA_ISA(d);
DeviceState *dev = DEVICE(d);
PCIBus *pci_bus = pci_get_bus(d);
- qemu_irq *isa_irq;
ISABus *isa_bus;
int i;
qdev_init_gpio_out_named(dev, &s->cpu_intr, "intr", 1);
qdev_init_gpio_in_named(dev, via_isa_pirq, "pirq", PCI_NUM_PINS);
- isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1);
+ qemu_init_irq(&s->i8259_irq, via_isa_request_i8259_irq, s, 0);
isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d),
errp);
@@ -729,7 +730,7 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
return;
}
- s->isa_irqs_in = i8259_init(isa_bus, *isa_irq);
+ s->isa_irqs_in = i8259_init(isa_bus, &s->i8259_irq);
isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in);
i8254_pit_init(isa_bus, 0x40, 0, NULL);
i8257_dma_init(OBJECT(d), isa_bus, 0);
@@ -832,7 +833,7 @@ static void vt82c686b_init(Object *obj)
object_initialize_child(obj, "pm", &s->pm, TYPE_VT82C686B_PM);
}
-static void vt82c686b_class_init(ObjectClass *klass, void *data)
+static void vt82c686b_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -843,7 +844,7 @@ static void vt82c686b_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_VIA_82C686B_ISA;
k->class_id = PCI_CLASS_BRIDGE_ISA;
k->revision = 0x40;
- dc->reset = vt82c686b_isa_reset;
+ device_class_set_legacy_reset(dc, vt82c686b_isa_reset);
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_via;
/* Reason: part of VIA VT82C686 southbridge, needs to be wired up */
@@ -897,7 +898,7 @@ static void vt8231_init(Object *obj)
object_initialize_child(obj, "pm", &s->pm, TYPE_VT8231_PM);
}
-static void vt8231_class_init(ObjectClass *klass, void *data)
+static void vt8231_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -908,7 +909,7 @@ static void vt8231_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_VIA_8231_ISA;
k->class_id = PCI_CLASS_BRIDGE_ISA;
k->revision = 0x10;
- dc->reset = vt8231_isa_reset;
+ device_class_set_legacy_reset(dc, vt8231_isa_reset);
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_via;
/* Reason: part of VIA VT8231 southbridge, needs to be wired up */
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 0de713a..bb2838b 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -5,11 +5,10 @@ config LOONGARCH_VIRT
select DEVICE_TREE
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
- imply VIRTIO_VGA
imply PCI_DEVICES
imply NVDIMM
imply TPM_TIS_SYSBUS
- select SERIAL
+ select SERIAL_MM
select VIRTIO_PCI
select PLATFORM_BUS
select LOONGARCH_IPI
@@ -18,6 +17,7 @@ config LOONGARCH_VIRT
select LOONGARCH_EXTIOI
select LS7A_RTC
select SMBIOS
+ select ACPI_CPU_HOTPLUG
select ACPI_PCI
select ACPI_HW_REDUCED
select FW_CFG_DMA
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index cb66870..14d6c52 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -12,14 +12,28 @@
#include "hw/loader.h"
#include "elf.h"
#include "qemu/error-report.h"
-#include "sysemu/reset.h"
-#include "sysemu/qtest.h"
+#include "system/reset.h"
+#include "system/qtest.h"
-struct memmap_entry *memmap_table;
-unsigned memmap_entries;
-
-ram_addr_t initrd_offset;
-uint64_t initrd_size;
+/*
+ * Linux Image Format
+ * https://docs.kernel.org/arch/loongarch/booting.html
+ */
+#define LINUX_PE_MAGIC 0x818223cd
+#define MZ_MAGIC 0x5a4d /* "MZ" */
+
+struct loongarch_linux_hdr {
+ uint32_t mz_magic;
+ uint32_t res0;
+ uint64_t kernel_entry;
+ uint64_t kernel_size;
+ uint64_t load_offset;
+ uint64_t res1;
+ uint64_t res2;
+ uint64_t res3;
+ uint32_t linux_pe_magic;
+ uint32_t pe_header_offset;
+} QEMU_PACKED;
static const unsigned int slave_boot_code[] = {
/* Configure reset ebase. */
@@ -74,12 +88,16 @@ static inline void *guidcpy(void *dst, const void *src)
return memcpy(dst, src, sizeof(efi_guid_t));
}
-static void init_efi_boot_memmap(struct efi_system_table *systab,
+static void init_efi_boot_memmap(MachineState *ms,
+ struct efi_system_table *systab,
void *p, void *start)
{
unsigned i;
struct efi_boot_memmap *boot_memmap = p;
efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms);
+ struct memmap_entry *memmap_table;
+ unsigned int memmap_entries;
/* efi_configuration_table 1 */
guidcpy(&systab->tables[0].guid, &tbl_guid);
@@ -91,6 +109,8 @@ static void init_efi_boot_memmap(struct efi_system_table *systab,
boot_memmap->map_size = 0;
efi_memory_desc_t *map = p + sizeof(struct efi_boot_memmap);
+ memmap_table = lvms->memmap_table;
+ memmap_entries = lvms->memmap_entries;
for (i = 0; i < memmap_entries; i++) {
map = (void *)boot_memmap + sizeof(*map);
map[i].type = memmap_table[i].type;
@@ -101,7 +121,8 @@ static void init_efi_boot_memmap(struct efi_system_table *systab,
}
}
-static void init_efi_initrd_table(struct efi_system_table *systab,
+static void init_efi_initrd_table(struct loongarch_boot_info *info,
+ struct efi_system_table *systab,
void *p, void *start)
{
efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
@@ -112,8 +133,8 @@ static void init_efi_initrd_table(struct efi_system_table *systab,
systab->tables[1].table = (struct efi_configuration_table *)(p - start);
systab->nr_tables = 2;
- initrd_table->base = initrd_offset;
- initrd_table->size = initrd_size;
+ initrd_table->base = info->initrd_addr;
+ initrd_table->size = info->initrd_size;
}
static void init_efi_fdt_table(struct efi_system_table *systab)
@@ -126,10 +147,12 @@ static void init_efi_fdt_table(struct efi_system_table *systab)
systab->nr_tables = 3;
}
-static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
+static void init_systab(MachineState *ms,
+ struct loongarch_boot_info *info, void *p, void *start)
{
void *bp_tables_start;
struct efi_system_table *systab = p;
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms);
info->a2 = p - start;
@@ -146,10 +169,10 @@ static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
systab->tables = p;
bp_tables_start = p;
- init_efi_boot_memmap(systab, p, start);
+ init_efi_boot_memmap(ms, systab, p, start);
p += ROUND_UP(sizeof(struct efi_boot_memmap) +
- sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
- init_efi_initrd_table(systab, p, start);
+ sizeof(efi_memory_desc_t) * lvms->memmap_entries, 64 * KiB);
+ init_efi_initrd_table(info, systab, p, start);
p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
init_efi_fdt_table(systab);
@@ -171,16 +194,105 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
}
+static int64_t load_loongarch_linux_image(const char *filename,
+ uint64_t *kernel_entry,
+ uint64_t *kernel_low,
+ uint64_t *kernel_high)
+{
+ gsize len;
+ ssize_t size;
+ uint8_t *buffer;
+ struct loongarch_linux_hdr *hdr;
+
+ /* Load as raw file otherwise */
+ if (!g_file_get_contents(filename, (char **)&buffer, &len, NULL)) {
+ return -1;
+ }
+ size = len;
+
+ /* Unpack the image if it is a EFI zboot image */
+ if (unpack_efi_zboot_image(&buffer, &size) < 0) {
+ g_free(buffer);
+ return -1;
+ }
+
+ hdr = (struct loongarch_linux_hdr *)buffer;
+
+ if (extract32(le32_to_cpu(hdr->mz_magic), 0, 16) != MZ_MAGIC ||
+ le32_to_cpu(hdr->linux_pe_magic) != LINUX_PE_MAGIC) {
+ g_free(buffer);
+ return -1;
+ }
+
+ /* Early kernel versions may have those fields in virtual address */
+ *kernel_entry = extract64(le64_to_cpu(hdr->kernel_entry),
+ 0, TARGET_PHYS_ADDR_SPACE_BITS);
+ *kernel_low = extract64(le64_to_cpu(hdr->load_offset),
+ 0, TARGET_PHYS_ADDR_SPACE_BITS);
+ *kernel_high = *kernel_low + size;
+
+ rom_add_blob_fixed(filename, buffer, size, *kernel_low);
+
+ g_free(buffer);
+
+ return size;
+}
+
+static ram_addr_t alloc_initrd_memory(struct loongarch_boot_info *info,
+ uint64_t advice_start, ssize_t rd_size)
+{
+ hwaddr base, ram_size, gap, low_end;
+ ram_addr_t initrd_end, initrd_start;
+
+ base = VIRT_LOWMEM_BASE;
+ gap = VIRT_LOWMEM_SIZE;
+ initrd_start = advice_start;
+ initrd_end = initrd_start + rd_size;
+
+ ram_size = info->ram_size;
+ low_end = base + MIN(ram_size, gap);
+ if (initrd_end <= low_end) {
+ return initrd_start;
+ }
+
+ if (ram_size <= gap) {
+ error_report("The low memory too small for initial ram disk '%s',"
+ "You need to expand the ram",
+ info->initrd_filename);
+ exit(1);
+ }
+
+ /*
+ * Try to load initrd in the high memory
+ */
+ ram_size -= gap;
+ initrd_start = VIRT_HIGHMEM_BASE;
+ if (rd_size <= ram_size) {
+ return initrd_start;
+ }
+
+ error_report("The high memory too small for initial ram disk '%s',"
+ "You need to expand the ram",
+ info->initrd_filename);
+ exit(1);
+}
+
static int64_t load_kernel_info(struct loongarch_boot_info *info)
{
- uint64_t kernel_entry, kernel_low, kernel_high;
- ssize_t kernel_size;
+ uint64_t kernel_entry, kernel_low, kernel_high, initrd_offset = 0;
+ ssize_t kernel_size, initrd_size;
kernel_size = load_elf(info->kernel_filename, NULL,
cpu_loongarch_virt_to_phys, NULL,
&kernel_entry, &kernel_low,
- &kernel_high, NULL, 0,
+ &kernel_high, NULL, ELFDATA2LSB,
EM_LOONGARCH, 1, 0);
+ kernel_entry = cpu_loongarch_virt_to_phys(NULL, kernel_entry);
+ if (kernel_size < 0) {
+ kernel_size = load_loongarch_linux_image(info->kernel_filename,
+ &kernel_entry, &kernel_low,
+ &kernel_high);
+ }
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
@@ -193,15 +305,10 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info)
initrd_size = get_image_size(info->initrd_filename);
if (initrd_size > 0) {
initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
-
- if (initrd_offset + initrd_size > info->ram_size) {
- error_report("memory too small for initial ram disk '%s'",
- info->initrd_filename);
- exit(1);
- }
-
- initrd_size = load_image_targphys(info->initrd_filename, initrd_offset,
- info->ram_size - initrd_offset);
+ initrd_offset = alloc_initrd_memory(info, initrd_offset,
+ initrd_size);
+ initrd_size = load_image_targphys(info->initrd_filename,
+ initrd_offset, initrd_size);
}
if (initrd_size == (target_ulong)-1) {
@@ -209,8 +316,9 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info)
info->initrd_filename);
exit(1);
}
- } else {
- initrd_size = 0;
+
+ info->initrd_addr = initrd_offset;
+ info->initrd_size = initrd_size;
}
return kernel_entry;
@@ -223,7 +331,7 @@ static void reset_load_elf(void *opaque)
cpu_reset(CPU(cpu));
if (env->load_elf) {
- if (cpu == LOONGARCH_CPU(first_cpu)) {
+ if (cpu == LOONGARCH_CPU(first_cpu)) {
env->gpr[4] = env->boot_info->a0;
env->gpr[5] = env->boot_info->a1;
env->gpr[6] = env->boot_info->a2;
@@ -265,36 +373,37 @@ static void loongarch_firmware_boot(LoongArchVirtMachineState *lvms,
fw_cfg_add_kernel_info(info, lvms->fw_cfg);
}
-static void init_boot_rom(struct loongarch_boot_info *info, void *p)
+static void init_boot_rom(MachineState *ms,
+ struct loongarch_boot_info *info, void *p)
{
void *start = p;
init_cmdline(info, p, start);
p += COMMAND_LINE_SIZE;
- init_systab(info, p, start);
+ init_systab(ms, info, p, start);
}
-static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
+static void loongarch_direct_kernel_boot(MachineState *ms,
+ struct loongarch_boot_info *info)
{
void *p, *bp;
- int64_t kernel_addr = 0;
+ int64_t kernel_addr = VIRT_FLASH0_BASE;
LoongArchCPU *lacpu;
CPUState *cs;
if (info->kernel_filename) {
kernel_addr = load_kernel_info(info);
} else {
- if(!qtest_enabled()) {
- error_report("Need kernel filename\n");
- exit(1);
+ if (!qtest_enabled()) {
+ warn_report("No kernel provided, booting from flash drive.");
}
}
/* Load cmdline and system tables at [0 - 1 MiB] */
p = g_malloc0(1 * MiB);
bp = p;
- init_boot_rom(info, p);
+ init_boot_rom(ms, info, p);
rom_add_blob_fixed_as("boot_info", bp, 1 * MiB, 0, &address_space_memory);
/* Load slave boot code at pflash0 . */
@@ -334,6 +443,6 @@ void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
if (lvms->bios_loaded) {
loongarch_firmware_boot(lvms, info);
} else {
- loongarch_direct_kernel_boot(info);
+ loongarch_direct_kernel_boot(ms, info);
}
}
diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c
index 35aeb2d..4935636 100644
--- a/hw/loongarch/fw_cfg.c
+++ b/hw/loongarch/fw_cfg.c
@@ -9,7 +9,7 @@
#include "hw/loongarch/fw_cfg.h"
#include "hw/loongarch/virt.h"
#include "hw/nvram/fw_cfg.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index bce7eba..d494d1e 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,9 +1,11 @@
loongarch_ss = ss.source_set()
loongarch_ss.add(files(
- 'fw_cfg.c',
'boot.c',
))
-loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('virt.c'))
-loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'))
+common_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('fw_cfg.c'))
+loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files(
+ 'virt-fdt-build.c',
+ 'virt.c'))
+loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
hw_arch += {'loongarch': loongarch_ss}
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/virt-acpi-build.c
index 2638f87..2cd2d9d 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/virt-acpi-build.c
@@ -18,7 +18,7 @@
#include "hw/acpi/bios-linker-loader.h"
#include "migration/vmstate.h"
#include "hw/mem/memory-device.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
/* Supported chipsets: */
#include "hw/pci-host/ls7a.h"
@@ -31,7 +31,8 @@
#include "hw/acpi/generic_event_device.h"
#include "hw/pci-host/gpex.h"
-#include "sysemu/tpm.h"
+#include "system/system.h"
+#include "system/tpm.h"
#include "hw/platform-bus.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/hmat.h"
@@ -46,6 +47,22 @@
#define ACPI_BUILD_DPRINTF(fmt, ...)
#endif
+static void virt_madt_cpu_entry(int uid,
+ const CPUArchIdList *apic_ids,
+ GArray *entry, bool force_enabled)
+{
+ uint32_t flags, apic_id = apic_ids->cpus[uid].arch_id;
+
+ flags = apic_ids->cpus[uid].cpu || force_enabled ? 1 /* Enabled */ : 0;
+
+ /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */
+ build_append_int_noprefix(entry, 0, 1); /* Type */
+ build_append_int_noprefix(entry, 8, 1); /* Length */
+ build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */
+ build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */
+ build_append_int_noprefix(entry, flags, 4); /* Flags */
+}
+
/* build FADT */
static void init_common_fadt_data(AcpiFadtData *data)
{
@@ -111,7 +128,7 @@ build_madt(GArray *table_data, BIOSLinker *linker,
MachineState *ms = MACHINE(lvms);
MachineClass *mc = MACHINE_GET_CLASS(ms);
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
- int i, arch_id;
+ int i, arch_id, flags;
AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id,
.oem_table_id = lvms->oem_table_id };
@@ -124,13 +141,13 @@ build_madt(GArray *table_data, BIOSLinker *linker,
for (i = 0; i < arch_ids->len; i++) {
/* Processor Core Interrupt Controller Structure */
arch_id = arch_ids->cpus[i].arch_id;
-
+ flags = arch_ids->cpus[i].cpu ? 1 : 0;
build_append_int_noprefix(table_data, 17, 1); /* Type */
build_append_int_noprefix(table_data, 15, 1); /* Length */
build_append_int_noprefix(table_data, 1, 1); /* Version */
build_append_int_noprefix(table_data, i, 4); /* ACPI Processor ID */
build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */
- build_append_int_noprefix(table_data, 1, 4); /* Flags */
+ build_append_int_noprefix(table_data, flags, 4); /* Flags */
}
/* Extend I/O Interrupt Controller Structure */
@@ -241,6 +258,48 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
acpi_table_end(linker, &table);
}
+/*
+ * Serial Port Console Redirection Table (SPCR)
+ * https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
+ */
+static void
+spcr_setup(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+ LoongArchVirtMachineState *lvms;
+ AcpiSpcrData serial = {
+ .interface_type = 0, /* 16550 compatible */
+ .base_addr.id = AML_AS_SYSTEM_MEMORY,
+ .base_addr.width = 32,
+ .base_addr.offset = 0,
+ .base_addr.size = 1,
+ .base_addr.addr = VIRT_UART_BASE,
+ .interrupt_type = 0, /* Interrupt not supported */
+ .pc_interrupt = 0,
+ .interrupt = VIRT_UART_IRQ,
+ .baud_rate = 7, /* 115200 */
+ .parity = 0,
+ .stop_bits = 1,
+ .flow_control = 0,
+ .terminal_type = 3, /* ANSI */
+ .language = 0, /* Language */
+ .pci_device_id = 0xffff, /* not a PCI device*/
+ .pci_vendor_id = 0xffff, /* not a PCI device*/
+ .pci_bus = 0,
+ .pci_device = 0,
+ .pci_function = 0,
+ .pci_flags = 0,
+ .pci_segment = 0,
+ };
+
+ lvms = LOONGARCH_VIRT_MACHINE(machine);
+ /*
+ * Passing NULL as the SPCR Table for Revision 2 doesn't support
+ * NameSpaceString.
+ */
+ build_spcr(table_data, linker, &serial, 2, lvms->oem_id,
+ lvms->oem_table_id, NULL);
+}
+
typedef
struct AcpiBuildState {
/* Copy of table in RAM (for patching). */
@@ -252,23 +311,27 @@ struct AcpiBuildState {
MemoryRegion *linker_mr;
} AcpiBuildState;
-static void build_uart_device_aml(Aml *table)
+static void build_uart_device_aml(Aml *table, int index)
{
Aml *dev;
Aml *crs;
Aml *pkg0, *pkg1, *pkg2;
- uint32_t uart_irq = VIRT_UART_IRQ;
-
- Aml *scope = aml_scope("_SB");
- dev = aml_device("COMA");
+ Aml *scope;
+ uint32_t uart_irq;
+ uint64_t base;
+
+ uart_irq = VIRT_UART_IRQ + index;
+ base = VIRT_UART_BASE + index * VIRT_UART_SIZE;
+ scope = aml_scope("_SB");
+ dev = aml_device("COM%d", index);
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(index)));
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
crs = aml_resource_template();
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
AML_NON_CACHEABLE, AML_READ_WRITE,
- 0, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1,
+ 0, base, base + VIRT_UART_SIZE - 1,
0, VIRT_UART_SIZE));
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_SHARED, &uart_irq, 1));
@@ -291,6 +354,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
{
uint32_t event;
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
+ CPUHotplugFeatures opts;
build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
HOTPLUG_HANDLER(lvms->acpi_ged),
@@ -303,6 +367,18 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
AML_SYSTEM_MEMORY,
VIRT_GED_MEM_ADDR);
}
+
+ if (event & ACPI_GED_CPU_HOTPLUG_EVT) {
+ opts.acpi_1_compatible = false;
+ opts.has_legacy_cphp = false;
+ opts.fw_unplugs_cpu = false;
+ opts.smi_path = NULL;
+
+ build_cpus_aml(dsdt, machine, opts, virt_madt_cpu_entry,
+ VIRT_GED_CPUHP_ADDR, "\\_SB",
+ AML_GED_EVT_CPU_SCAN_METHOD, AML_SYSTEM_MEMORY);
+ }
+
acpi_dsdt_add_power_button(dsdt);
}
@@ -401,6 +477,7 @@ static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms)
static void
build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
+ int i;
Aml *dsdt, *scope, *pkg;
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id,
@@ -408,7 +485,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
acpi_table_begin(&table, table_data);
dsdt = init_aml_allocator();
- build_uart_device_aml(dsdt);
+ for (i = 0; i < VIRT_UART_COUNT; i++) {
+ build_uart_device_aml(dsdt, i);
+ }
build_pci_device_aml(dsdt, lvms);
build_la_ged_aml(dsdt, machine);
build_flash_aml(dsdt, lvms);
@@ -435,7 +514,7 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
GArray *table_offsets;
AcpiFadtData fadt_data;
- unsigned facs, rsdt, dsdt;
+ unsigned facs, xsdt, dsdt;
uint8_t *u;
GArray *tables_blob = tables->table_data;
@@ -477,6 +556,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
+ acpi_add_table(table_offsets, tables_blob);
+ spcr_setup(tables_blob, tables->linker, machine);
if (machine->numa_state->num_nodes) {
if (machine->numa_state->have_numa_distance) {
@@ -494,8 +575,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
{
AcpiMcfgInfo mcfg = {
- .base = cpu_to_le64(VIRT_PCI_CFG_BASE),
- .size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
+ .base = VIRT_PCI_CFG_BASE,
+ .size = VIRT_PCI_CFG_SIZE,
};
build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id,
lvms->oem_table_id);
@@ -519,17 +600,17 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
}
/* RSDT is pointed to by RSDP */
- rsdt = tables_blob->len;
- build_rsdt(tables_blob, tables->linker, table_offsets,
+ xsdt = tables_blob->len;
+ build_xsdt(tables_blob, tables->linker, table_offsets,
lvms->oem_id, lvms->oem_table_id);
/* RSDP is in FSEG memory, so allocate it separately */
{
AcpiRsdpData rsdp_data = {
- .revision = 0,
+ .revision = 2,
.oem_id = lvms->oem_id,
- .xsdt_tbl_offset = NULL,
- .rsdt_tbl_offset = &rsdt,
+ .xsdt_tbl_offset = &xsdt,
+ .rsdt_tbl_offset = NULL,
};
build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
}
@@ -604,7 +685,7 @@ static const VMStateDescription vmstate_acpi_build = {
},
};
-static bool loongarch_is_acpi_enabled(LoongArchVirtMachineState *lvms)
+static bool virt_is_acpi_enabled(LoongArchVirtMachineState *lvms)
{
if (lvms->acpi == ON_OFF_AUTO_OFF) {
return false;
@@ -612,7 +693,7 @@ static bool loongarch_is_acpi_enabled(LoongArchVirtMachineState *lvms)
return true;
}
-void loongarch_acpi_setup(LoongArchVirtMachineState *lvms)
+void virt_acpi_setup(LoongArchVirtMachineState *lvms)
{
AcpiBuildTables tables;
AcpiBuildState *build_state;
@@ -622,7 +703,7 @@ void loongarch_acpi_setup(LoongArchVirtMachineState *lvms)
return;
}
- if (!loongarch_is_acpi_enabled(lvms)) {
+ if (!virt_is_acpi_enabled(lvms)) {
ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
return;
}
diff --git a/hw/loongarch/virt-fdt-build.c b/hw/loongarch/virt-fdt-build.c
new file mode 100644
index 0000000..728ce46
--- /dev/null
+++ b/hw/loongarch/virt-fdt-build.c
@@ -0,0 +1,534 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Loongson Technology Corporation Limited
+ */
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include <libfdt.h>
+#include "hw/acpi/generic_event_device.h"
+#include "hw/core/sysbus-fdt.h"
+#include "hw/intc/loongarch_extioi.h"
+#include "hw/loader.h"
+#include "hw/loongarch/virt.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/pci-host/ls7a.h"
+#include "system/device_tree.h"
+#include "system/reset.h"
+#include "target/loongarch/cpu.h"
+
+static void create_fdt(LoongArchVirtMachineState *lvms)
+{
+ MachineState *ms = MACHINE(lvms);
+ uint8_t rng_seed[32];
+
+ ms->fdt = create_device_tree(&lvms->fdt_size);
+ if (!ms->fdt) {
+ error_report("create_device_tree() failed");
+ exit(1);
+ }
+
+ /* Header */
+ qemu_fdt_setprop_string(ms->fdt, "/", "compatible",
+ "linux,dummy-loongson3");
+ qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
+ qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
+ qemu_fdt_add_subnode(ms->fdt, "/chosen");
+
+ /* Pass seed to RNG */
+ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
+ qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
+}
+
+static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms)
+{
+ int num;
+ MachineState *ms = MACHINE(lvms);
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const CPUArchIdList *possible_cpus;
+ LoongArchCPU *cpu;
+ CPUState *cs;
+ char *nodename, *map_path;
+
+ qemu_fdt_add_subnode(ms->fdt, "/cpus");
+ qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
+ qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
+
+ /* cpu nodes */
+ possible_cpus = mc->possible_cpu_arch_ids(ms);
+ for (num = 0; num < possible_cpus->len; num++) {
+ cs = possible_cpus->cpus[num].cpu;
+ if (cs == NULL) {
+ continue;
+ }
+
+ nodename = g_strdup_printf("/cpus/cpu@%d", num);
+ cpu = LOONGARCH_CPU(cs);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+ cpu->dtb_compatible);
+ if (possible_cpus->cpus[num].props.has_node_id) {
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id",
+ possible_cpus->cpus[num].props.node_id);
+ }
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
+ qemu_fdt_alloc_phandle(ms->fdt));
+ g_free(nodename);
+ }
+
+ /*cpu map */
+ qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
+ for (num = 0; num < possible_cpus->len; num++) {
+ cs = possible_cpus->cpus[num].cpu;
+ if (cs == NULL) {
+ continue;
+ }
+
+ nodename = g_strdup_printf("/cpus/cpu@%d", num);
+ if (ms->smp.threads > 1) {
+ map_path = g_strdup_printf(
+ "/cpus/cpu-map/socket%d/core%d/thread%d",
+ num / (ms->smp.cores * ms->smp.threads),
+ (num / ms->smp.threads) % ms->smp.cores,
+ num % ms->smp.threads);
+ } else {
+ map_path = g_strdup_printf(
+ "/cpus/cpu-map/socket%d/core%d",
+ num / ms->smp.cores,
+ num % ms->smp.cores);
+ }
+ qemu_fdt_add_path(ms->fdt, map_path);
+ qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", nodename);
+
+ g_free(map_path);
+ g_free(nodename);
+ }
+}
+
+static void fdt_add_memory_node(MachineState *ms,
+ uint64_t base, uint64_t size, int node_id)
+{
+ char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base,
+ size >> 32, size);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
+
+ if (ms->numa_state && ms->numa_state->num_nodes) {
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", node_id);
+ }
+
+ g_free(nodename);
+}
+
+static void fdt_add_memory_nodes(MachineState *ms)
+{
+ hwaddr base, size, ram_size, gap;
+ int i, nb_numa_nodes, nodes;
+ NodeInfo *numa_info;
+
+ ram_size = ms->ram_size;
+ base = VIRT_LOWMEM_BASE;
+ gap = VIRT_LOWMEM_SIZE;
+ nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+ numa_info = ms->numa_state->nodes;
+ if (!nodes) {
+ nodes = 1;
+ }
+
+ for (i = 0; i < nodes; i++) {
+ if (nb_numa_nodes) {
+ size = numa_info[i].node_mem;
+ } else {
+ size = ram_size;
+ }
+
+ /*
+ * memory for the node splited into two part
+ * lowram: [base, +gap)
+ * highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+ if (size >= gap) {
+ fdt_add_memory_node(ms, base, gap, i);
+ size -= gap;
+ base = VIRT_HIGHMEM_BASE;
+ gap = ram_size - VIRT_LOWMEM_SIZE;
+ }
+
+ if (size) {
+ fdt_add_memory_node(ms, base, size, i);
+ base += size;
+ gap -= size;
+ }
+ }
+}
+
+static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState *lvms)
+{
+ char *nodename;
+ hwaddr base = VIRT_FWCFG_BASE;
+ const MachineState *ms = MACHINE(lvms);
+
+ nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename,
+ "compatible", "qemu,fw-cfg-mmio");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
+ 2, base, 2, 0x18);
+ qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
+ g_free(nodename);
+}
+
+static void fdt_add_flash_node(LoongArchVirtMachineState *lvms)
+{
+ MachineState *ms = MACHINE(lvms);
+ char *nodename;
+ MemoryRegion *flash_mem;
+
+ hwaddr flash0_base;
+ hwaddr flash0_size;
+
+ hwaddr flash1_base;
+ hwaddr flash1_size;
+
+ flash_mem = pflash_cfi01_get_memory(lvms->flash[0]);
+ flash0_base = flash_mem->addr;
+ flash0_size = memory_region_size(flash_mem);
+
+ flash_mem = pflash_cfi01_get_memory(lvms->flash[1]);
+ flash1_base = flash_mem->addr;
+ flash1_size = memory_region_size(flash_mem);
+
+ nodename = g_strdup_printf("/flash@%" PRIx64, flash0_base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
+ 2, flash0_base, 2, flash0_size,
+ 2, flash1_base, 2, flash1_size);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4);
+ g_free(nodename);
+}
+
+static void fdt_add_cpuic_node(LoongArchVirtMachineState *lvms,
+ uint32_t *cpuintc_phandle)
+{
+ MachineState *ms = MACHINE(lvms);
+ char *nodename;
+
+ *cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+ nodename = g_strdup_printf("/cpuic");
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+ "loongson,cpu-interrupt-controller");
+ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+ g_free(nodename);
+}
+
+static void fdt_add_eiointc_node(LoongArchVirtMachineState *lvms,
+ uint32_t *cpuintc_phandle,
+ uint32_t *eiointc_phandle)
+{
+ MachineState *ms = MACHINE(lvms);
+ char *nodename;
+ hwaddr extioi_base = APIC_BASE;
+ hwaddr extioi_size = EXTIOI_SIZE;
+
+ *eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+ nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+ "loongson,ls2k2000-eiointc");
+ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+ *cpuintc_phandle);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
+ extioi_base, 0x0, extioi_size);
+ g_free(nodename);
+}
+
+static void fdt_add_pch_pic_node(LoongArchVirtMachineState *lvms,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_pic_phandle)
+{
+ MachineState *ms = MACHINE(lvms);
+ char *nodename;
+ hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
+ hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
+
+ *pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+ nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_pic_phandle);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+ "loongson,pch-pic-1.0");
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
+ pch_pic_base, 0, pch_pic_size);
+ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+ *eiointc_phandle);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
+ g_free(nodename);
+}
+
+static void fdt_add_pch_msi_node(LoongArchVirtMachineState *lvms,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_msi_phandle)
+{
+ MachineState *ms = MACHINE(lvms);
+ char *nodename;
+ hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
+ hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
+
+ *pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+ nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+ "loongson,pch-msi-1.0");
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
+ 0, pch_msi_base,
+ 0, pch_msi_size);
+ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+ *eiointc_phandle);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
+ VIRT_PCH_PIC_IRQ_NUM);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
+ EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
+ g_free(nodename);
+}
+
+static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms,
+ char *nodename,
+ uint32_t *pch_pic_phandle)
+{
+ int pin, dev;
+ uint32_t irq_map_stride = 0;
+ uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 10] = {};
+ uint32_t *irq_map = full_irq_map;
+ const MachineState *ms = MACHINE(lvms);
+
+ /*
+ * This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+
+ for (dev = 0; dev < PCI_NUM_PINS; dev++) {
+ int devfn = dev * 0x8;
+
+ for (pin = 0; pin < PCI_NUM_PINS; pin++) {
+ int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
+ int i = 0;
+
+ /* Fill PCI address cells */
+ irq_map[i] = cpu_to_be32(devfn << 8);
+ i += 3;
+
+ /* Fill PCI Interrupt cells */
+ irq_map[i] = cpu_to_be32(pin + 1);
+ i += 1;
+
+ /* Fill interrupt controller phandle and cells */
+ irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
+ irq_map[i++] = cpu_to_be32(irq_nr);
+
+ if (!irq_map_stride) {
+ irq_map_stride = i;
+ }
+ irq_map += irq_map_stride;
+ }
+ }
+
+
+ qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
+ PCI_NUM_PINS * PCI_NUM_PINS *
+ irq_map_stride * sizeof(uint32_t));
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
+static void fdt_add_pcie_node(const LoongArchVirtMachineState *lvms,
+ uint32_t *pch_pic_phandle,
+ uint32_t *pch_msi_phandle)
+{
+ char *nodename;
+ hwaddr base_mmio = VIRT_PCI_MEM_BASE;
+ hwaddr size_mmio = VIRT_PCI_MEM_SIZE;
+ hwaddr base_pio = VIRT_PCI_IO_BASE;
+ hwaddr size_pio = VIRT_PCI_IO_SIZE;
+ hwaddr base_pcie = VIRT_PCI_CFG_BASE;
+ hwaddr size_pcie = VIRT_PCI_CFG_SIZE;
+ hwaddr base = base_pcie;
+ const MachineState *ms = MACHINE(lvms);
+
+ nodename = g_strdup_printf("/pcie@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename,
+ "compatible", "pci-host-ecam-generic");
+ qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
+ PCIE_MMCFG_BUS(VIRT_PCI_CFG_SIZE - 1));
+ qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
+ 2, base_pcie, 2, size_pcie);
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
+ 1, FDT_PCI_RANGE_IOPORT, 2, VIRT_PCI_IO_OFFSET,
+ 2, base_pio, 2, size_pio,
+ 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
+ 2, base_mmio, 2, size_mmio);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
+ 0, *pch_msi_phandle, 0, 0x10000);
+ fdt_add_pcie_irq_map_node(lvms, nodename, pch_pic_phandle);
+ g_free(nodename);
+}
+
+static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
+ uint32_t *pch_pic_phandle, hwaddr base,
+ int irq, bool chosen)
+{
+ char *nodename;
+ hwaddr size = VIRT_UART_SIZE;
+ MachineState *ms = MACHINE(lvms);
+
+ nodename = g_strdup_printf("/serial@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a");
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000);
+ if (chosen) {
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+ }
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+ *pch_pic_phandle);
+ g_free(nodename);
+}
+
+static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms,
+ uint32_t *pch_pic_phandle)
+{
+ char *nodename;
+ hwaddr base = VIRT_RTC_REG_BASE;
+ hwaddr size = VIRT_RTC_LEN;
+ MachineState *ms = MACHINE(lvms);
+
+ nodename = g_strdup_printf("/rtc@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+ "loongson,ls7a-rtc");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+ VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+ *pch_pic_phandle);
+ g_free(nodename);
+}
+
+static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms)
+{
+ char *name;
+ uint32_t ged_handle;
+ MachineState *ms = MACHINE(lvms);
+ hwaddr base = VIRT_GED_REG_ADDR;
+ hwaddr size = ACPI_GED_REG_COUNT;
+
+ ged_handle = qemu_fdt_alloc_phandle(ms->fdt);
+ name = g_strdup_printf("/ged@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon");
+ qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size);
+ /* 8 bit registers */
+ qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0);
+ qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1);
+ qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle);
+ ged_handle = qemu_fdt_get_phandle(ms->fdt, name);
+ g_free(name);
+
+ name = g_strdup_printf("/reboot");
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot");
+ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
+ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET);
+ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE);
+ g_free(name);
+
+ name = g_strdup_printf("/poweroff");
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff");
+ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
+ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL);
+ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN |
+ (ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS));
+ g_free(name);
+}
+
+void virt_fdt_setup(LoongArchVirtMachineState *lvms)
+{
+ MachineState *machine = MACHINE(lvms);
+ uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, pch_msi_phandle;
+ int i;
+
+ create_fdt(lvms);
+ fdt_add_cpu_nodes(lvms);
+ fdt_add_memory_nodes(machine);
+ fdt_add_fw_cfg_node(lvms);
+ fdt_add_flash_node(lvms);
+
+ /* Add cpu interrupt-controller */
+ fdt_add_cpuic_node(lvms, &cpuintc_phandle);
+ /* Add Extend I/O Interrupt Controller node */
+ fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle);
+ /* Add PCH PIC node */
+ fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
+ /* Add PCH MSI node */
+ fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle);
+ /* Add pcie node */
+ fdt_add_pcie_node(lvms, &pch_pic_phandle, &pch_msi_phandle);
+
+ /*
+ * Create uart fdt node in reverse order so that they appear
+ * in the finished device tree lowest address first
+ */
+ for (i = VIRT_UART_COUNT; i-- > 0;) {
+ hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE;
+ int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE;
+ fdt_add_uart_node(lvms, &pch_pic_phandle, base, irq, i == 0);
+ }
+
+ fdt_add_rtc_node(lvms, &pch_pic_phandle);
+ fdt_add_ged_reset(lvms);
+ platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
+ VIRT_PLATFORM_BUS_BASEADDRESS,
+ VIRT_PLATFORM_BUS_SIZE,
+ VIRT_PLATFORM_BUS_IRQ);
+
+ /*
+ * Since lowmem region starts from 0 and Linux kernel legacy start address
+ * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
+ * access. FDT size limit with 1 MiB.
+ * Put the FDT into the memory map as a ROM image: this will ensure
+ * the FDT is copied again upon reset, even if addr points into RAM.
+ */
+ rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE,
+ &address_space_memory);
+ qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
+ rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size));
+}
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 2904042..b15ada2 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -8,17 +8,18 @@
#include "qemu/units.h"
#include "qemu/datadir.h"
#include "qapi/error.h"
+#include "exec/target_page.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
-#include "sysemu/kvm.h"
-#include "sysemu/tcg.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/runstate.h"
-#include "sysemu/reset.h"
-#include "sysemu/rtc.h"
+#include "hw/char/serial-mm.h"
+#include "system/kvm.h"
+#include "system/tcg.h"
+#include "system/system.h"
+#include "system/qtest.h"
+#include "system/runstate.h"
+#include "system/reset.h"
+#include "system/rtc.h"
#include "hw/loongarch/virt.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/irq.h"
#include "net/net.h"
#include "hw/loader.h"
@@ -33,30 +34,19 @@
#include "hw/loongarch/fw_cfg.h"
#include "target/loongarch/cpu.h"
#include "hw/firmware/smbios.h"
-#include "hw/acpi/aml-build.h"
#include "qapi/qapi-visit-common.h"
#include "hw/acpi/generic_event_device.h"
#include "hw/mem/nvdimm.h"
-#include "sysemu/device_tree.h"
-#include <libfdt.h>
-#include "hw/core/sysbus-fdt.h"
#include "hw/platform-bus.h"
#include "hw/display/ramfb.h"
+#include "hw/uefi/var-service-api.h"
#include "hw/mem/pc-dimm.h"
-#include "sysemu/tpm.h"
-#include "sysemu/block-backend.h"
+#include "system/tpm.h"
+#include "system/block-backend.h"
#include "hw/block/flash.h"
#include "hw/virtio/virtio-iommu.h"
#include "qemu/error-report.h"
-static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
-{
- if (lvms->veiointc == ON_OFF_AUTO_OFF) {
- return false;
- }
- return true;
-}
-
static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -134,416 +124,6 @@ static void virt_flash_map(LoongArchVirtMachineState *lvms,
virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem);
}
-static void fdt_add_cpuic_node(LoongArchVirtMachineState *lvms,
- uint32_t *cpuintc_phandle)
-{
- MachineState *ms = MACHINE(lvms);
- char *nodename;
-
- *cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
- nodename = g_strdup_printf("/cpuic");
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
- "loongson,cpu-interrupt-controller");
- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
- g_free(nodename);
-}
-
-static void fdt_add_eiointc_node(LoongArchVirtMachineState *lvms,
- uint32_t *cpuintc_phandle,
- uint32_t *eiointc_phandle)
-{
- MachineState *ms = MACHINE(lvms);
- char *nodename;
- hwaddr extioi_base = APIC_BASE;
- hwaddr extioi_size = EXTIOI_SIZE;
-
- *eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
- nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
- "loongson,ls2k2000-eiointc");
- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
- *cpuintc_phandle);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
- extioi_base, 0x0, extioi_size);
- g_free(nodename);
-}
-
-static void fdt_add_pch_pic_node(LoongArchVirtMachineState *lvms,
- uint32_t *eiointc_phandle,
- uint32_t *pch_pic_phandle)
-{
- MachineState *ms = MACHINE(lvms);
- char *nodename;
- hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
- hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
-
- *pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
- nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_pic_phandle);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
- "loongson,pch-pic-1.0");
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
- pch_pic_base, 0, pch_pic_size);
- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
- *eiointc_phandle);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
- g_free(nodename);
-}
-
-static void fdt_add_pch_msi_node(LoongArchVirtMachineState *lvms,
- uint32_t *eiointc_phandle,
- uint32_t *pch_msi_phandle)
-{
- MachineState *ms = MACHINE(lvms);
- char *nodename;
- hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
- hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
-
- *pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
- nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
- "loongson,pch-msi-1.0");
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
- 0, pch_msi_base,
- 0, pch_msi_size);
- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
- *eiointc_phandle);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
- VIRT_PCH_PIC_IRQ_NUM);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
- EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
- g_free(nodename);
-}
-
-static void fdt_add_flash_node(LoongArchVirtMachineState *lvms)
-{
- MachineState *ms = MACHINE(lvms);
- char *nodename;
- MemoryRegion *flash_mem;
-
- hwaddr flash0_base;
- hwaddr flash0_size;
-
- hwaddr flash1_base;
- hwaddr flash1_size;
-
- flash_mem = pflash_cfi01_get_memory(lvms->flash[0]);
- flash0_base = flash_mem->addr;
- flash0_size = memory_region_size(flash_mem);
-
- flash_mem = pflash_cfi01_get_memory(lvms->flash[1]);
- flash1_base = flash_mem->addr;
- flash1_size = memory_region_size(flash_mem);
-
- nodename = g_strdup_printf("/flash@%" PRIx64, flash0_base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash");
- qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, flash0_base, 2, flash0_size,
- 2, flash1_base, 2, flash1_size);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4);
- g_free(nodename);
-}
-
-static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms,
- uint32_t *pch_pic_phandle)
-{
- char *nodename;
- hwaddr base = VIRT_RTC_REG_BASE;
- hwaddr size = VIRT_RTC_LEN;
- MachineState *ms = MACHINE(lvms);
-
- nodename = g_strdup_printf("/rtc@%" PRIx64, base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
- "loongson,ls7a-rtc");
- qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
- VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
- *pch_pic_phandle);
- g_free(nodename);
-}
-
-static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
- uint32_t *pch_pic_phandle)
-{
- char *nodename;
- hwaddr base = VIRT_UART_BASE;
- hwaddr size = VIRT_UART_SIZE;
- MachineState *ms = MACHINE(lvms);
-
- nodename = g_strdup_printf("/serial@%" PRIx64, base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a");
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000);
- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
- VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
- *pch_pic_phandle);
- g_free(nodename);
-}
-
-static void create_fdt(LoongArchVirtMachineState *lvms)
-{
- MachineState *ms = MACHINE(lvms);
-
- ms->fdt = create_device_tree(&lvms->fdt_size);
- if (!ms->fdt) {
- error_report("create_device_tree() failed");
- exit(1);
- }
-
- /* Header */
- qemu_fdt_setprop_string(ms->fdt, "/", "compatible",
- "linux,dummy-loongson3");
- qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
- qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
- qemu_fdt_add_subnode(ms->fdt, "/chosen");
-}
-
-static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms)
-{
- int num;
- const MachineState *ms = MACHINE(lvms);
- int smp_cpus = ms->smp.cpus;
-
- qemu_fdt_add_subnode(ms->fdt, "/cpus");
- qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
- qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
-
- /* cpu nodes */
- for (num = smp_cpus - 1; num >= 0; num--) {
- char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
- LoongArchCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num));
- CPUState *cs = CPU(cpu);
-
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
- qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
- cpu->dtb_compatible);
- if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
- qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id",
- ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
- }
- qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
- qemu_fdt_alloc_phandle(ms->fdt));
- g_free(nodename);
- }
-
- /*cpu map */
- qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
-
- for (num = smp_cpus - 1; num >= 0; num--) {
- char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num);
- char *map_path;
-
- if (ms->smp.threads > 1) {
- map_path = g_strdup_printf(
- "/cpus/cpu-map/socket%d/core%d/thread%d",
- num / (ms->smp.cores * ms->smp.threads),
- (num / ms->smp.threads) % ms->smp.cores,
- num % ms->smp.threads);
- } else {
- map_path = g_strdup_printf(
- "/cpus/cpu-map/socket%d/core%d",
- num / ms->smp.cores,
- num % ms->smp.cores);
- }
- qemu_fdt_add_path(ms->fdt, map_path);
- qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", cpu_path);
-
- g_free(map_path);
- g_free(cpu_path);
- }
-}
-
-static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState *lvms)
-{
- char *nodename;
- hwaddr base = VIRT_FWCFG_BASE;
- const MachineState *ms = MACHINE(lvms);
-
- nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename,
- "compatible", "qemu,fw-cfg-mmio");
- qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, base, 2, 0x18);
- qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
- g_free(nodename);
-}
-
-static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms,
- char *nodename,
- uint32_t *pch_pic_phandle)
-{
- int pin, dev;
- uint32_t irq_map_stride = 0;
- uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {};
- uint32_t *irq_map = full_irq_map;
- const MachineState *ms = MACHINE(lvms);
-
- /* This code creates a standard swizzle of interrupts such that
- * each device's first interrupt is based on it's PCI_SLOT number.
- * (See pci_swizzle_map_irq_fn())
- *
- * We only need one entry per interrupt in the table (not one per
- * possible slot) seeing the interrupt-map-mask will allow the table
- * to wrap to any number of devices.
- */
-
- for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
- int devfn = dev * 0x8;
-
- for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
- int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
- int i = 0;
-
- /* Fill PCI address cells */
- irq_map[i] = cpu_to_be32(devfn << 8);
- i += 3;
-
- /* Fill PCI Interrupt cells */
- irq_map[i] = cpu_to_be32(pin + 1);
- i += 1;
-
- /* Fill interrupt controller phandle and cells */
- irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
- irq_map[i++] = cpu_to_be32(irq_nr);
-
- if (!irq_map_stride) {
- irq_map_stride = i;
- }
- irq_map += irq_map_stride;
- }
- }
-
-
- qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
- GPEX_NUM_IRQS * GPEX_NUM_IRQS *
- irq_map_stride * sizeof(uint32_t));
- qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
- 0x1800, 0, 0, 0x7);
-}
-
-static void fdt_add_pcie_node(const LoongArchVirtMachineState *lvms,
- uint32_t *pch_pic_phandle,
- uint32_t *pch_msi_phandle)
-{
- char *nodename;
- hwaddr base_mmio = VIRT_PCI_MEM_BASE;
- hwaddr size_mmio = VIRT_PCI_MEM_SIZE;
- hwaddr base_pio = VIRT_PCI_IO_BASE;
- hwaddr size_pio = VIRT_PCI_IO_SIZE;
- hwaddr base_pcie = VIRT_PCI_CFG_BASE;
- hwaddr size_pcie = VIRT_PCI_CFG_SIZE;
- hwaddr base = base_pcie;
-
- const MachineState *ms = MACHINE(lvms);
-
- nodename = g_strdup_printf("/pcie@%" PRIx64, base);
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_string(ms->fdt, nodename,
- "compatible", "pci-host-ecam-generic");
- qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
- qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
- PCIE_MMCFG_BUS(VIRT_PCI_CFG_SIZE - 1));
- qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
- qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, base_pcie, 2, size_pcie);
- qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
- 1, FDT_PCI_RANGE_IOPORT, 2, VIRT_PCI_IO_OFFSET,
- 2, base_pio, 2, size_pio,
- 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
- 2, base_mmio, 2, size_mmio);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
- 0, *pch_msi_phandle, 0, 0x10000);
-
- fdt_add_pcie_irq_map_node(lvms, nodename, pch_pic_phandle);
-
- g_free(nodename);
-}
-
-static void fdt_add_memory_node(MachineState *ms,
- uint64_t base, uint64_t size, int node_id)
-{
- char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
-
- qemu_fdt_add_subnode(ms->fdt, nodename);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base,
- size >> 32, size);
- qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
-
- if (ms->numa_state && ms->numa_state->num_nodes) {
- qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", node_id);
- }
-
- g_free(nodename);
-}
-
-static void fdt_add_memory_nodes(MachineState *ms)
-{
- hwaddr base, size, ram_size, gap;
- int i, nb_numa_nodes, nodes;
- NodeInfo *numa_info;
-
- ram_size = ms->ram_size;
- base = VIRT_LOWMEM_BASE;
- gap = VIRT_LOWMEM_SIZE;
- nodes = nb_numa_nodes = ms->numa_state->num_nodes;
- numa_info = ms->numa_state->nodes;
- if (!nodes) {
- nodes = 1;
- }
-
- for (i = 0; i < nodes; i++) {
- if (nb_numa_nodes) {
- size = numa_info[i].node_mem;
- } else {
- size = ram_size;
- }
-
- /*
- * memory for the node splited into two part
- * lowram: [base, +gap)
- * highram: [VIRT_HIGHMEM_BASE, +(len - gap))
- */
- if (size >= gap) {
- fdt_add_memory_node(ms, base, gap, i);
- size -= gap;
- base = VIRT_HIGHMEM_BASE;
- gap = ram_size - VIRT_LOWMEM_SIZE;
- }
-
- if (size) {
- fdt_add_memory_node(ms, base, size, i);
- base += size;
- gap -= size;
- }
- }
-}
-
static void virt_build_smbios(LoongArchVirtMachineState *lvms)
{
MachineState *ms = MACHINE(lvms);
@@ -556,6 +136,10 @@ static void virt_build_smbios(LoongArchVirtMachineState *lvms)
return;
}
+ if (kvm_enabled()) {
+ product = "KVM Virtual Machine";
+ }
+
smbios_set_defaults("QEMU", product, mc->name);
smbios_get_tables(ms, SMBIOS_ENTRY_POINT_TYPE_64,
@@ -576,7 +160,8 @@ static void virt_done(Notifier *notifier, void *data)
LoongArchVirtMachineState *lvms = container_of(notifier,
LoongArchVirtMachineState, machine_done);
virt_build_smbios(lvms);
- loongarch_acpi_setup(lvms);
+ virt_acpi_setup(lvms);
+ virt_fdt_setup(lvms);
}
static void virt_powerdown_req(Notifier *notifier, void *opaque)
@@ -587,8 +172,15 @@ static void virt_powerdown_req(Notifier *notifier, void *opaque)
acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
}
-static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
+static void memmap_add_entry(MachineState *ms, uint64_t address,
+ uint64_t length, uint32_t type)
{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms);
+ struct memmap_entry *memmap_table;
+ unsigned int memmap_entries;
+
+ memmap_table = lvms->memmap_table;
+ memmap_entries = lvms->memmap_entries;
/* Ensure there are no duplicate entries. */
for (unsigned i = 0; i < memmap_entries; i++) {
assert(memmap_table[i].address != address);
@@ -601,6 +193,8 @@ static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
memmap_table[memmap_entries].type = cpu_to_le32(type);
memmap_table[memmap_entries].reserved = 0;
memmap_entries++;
+ lvms->memmap_table = memmap_table;
+ lvms->memmap_entries = memmap_entries;
}
static DeviceState *create_acpi_ged(DeviceState *pch_pic,
@@ -608,11 +202,17 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic,
{
DeviceState *dev;
MachineState *ms = MACHINE(lvms);
+ MachineClass *mc = MACHINE_GET_CLASS(lvms);
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
if (ms->ram_slots) {
event |= ACPI_GED_MEM_HOTPLUG_EVT;
}
+
+ if (mc->has_hotpluggable_cpus) {
+ event |= ACPI_GED_CPU_HOTPLUG_EVT;
+ }
+
dev = qdev_new(TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -624,6 +224,10 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic,
/* ged regs used for reset and power down */
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_GED_REG_ADDR);
+ if (mc->has_hotpluggable_cpus) {
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 3, VIRT_GED_CPUHP_ADDR);
+ }
+
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - VIRT_GSI_BASE));
return dev;
@@ -655,9 +259,7 @@ static DeviceState *create_platform_bus(DeviceState *pch_pic)
}
static void virt_devices_init(DeviceState *pch_pic,
- LoongArchVirtMachineState *lvms,
- uint32_t *pch_pic_phandle,
- uint32_t *pch_msi_phandle)
+ LoongArchVirtMachineState *lvms)
{
MachineClass *mc = MACHINE_GET_CLASS(lvms);
DeviceState *gpex_dev;
@@ -697,20 +299,23 @@ static void virt_devices_init(DeviceState *pch_pic,
memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE,
pio_alias);
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
sysbus_connect_irq(d, i,
qdev_get_gpio_in(pch_pic, 16 + i));
gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
}
- /* Add pcie node */
- fdt_add_pcie_node(lvms, pch_pic_phandle, pch_msi_phandle);
-
- serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
- qdev_get_gpio_in(pch_pic,
- VIRT_UART_IRQ - VIRT_GSI_BASE),
- 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
- fdt_add_uart_node(lvms, pch_pic_phandle);
+ /*
+ * Create uart fdt node in reverse order so that they appear
+ * in the finished device tree lowest address first
+ */
+ for (i = VIRT_UART_COUNT; i-- > 0;) {
+ hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE;
+ int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE;
+ serial_mm_init(get_system_memory(), base, 0,
+ qdev_get_gpio_in(pch_pic, irq),
+ 115200, serial_hd(i), DEVICE_LITTLE_ENDIAN);
+ }
/* Network init */
pci_init_nic_devices(pci_bus, mc->default_nic);
@@ -723,7 +328,6 @@ static void virt_devices_init(DeviceState *pch_pic,
sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE,
qdev_get_gpio_in(pch_pic,
VIRT_RTC_IRQ - VIRT_GSI_BASE));
- fdt_add_rtc_node(lvms, pch_pic_phandle);
/* acpi ged */
lvms->acpi_ged = create_acpi_ged(pch_pic, lvms);
@@ -731,17 +335,35 @@ static void virt_devices_init(DeviceState *pch_pic,
lvms->platform_bus_dev = create_platform_bus(pch_pic);
}
-static void virt_irq_init(LoongArchVirtMachineState *lvms)
+static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
{
+ int num;
MachineState *ms = MACHINE(lvms);
- DeviceState *pch_pic, *pch_msi, *cpudev;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const CPUArchIdList *possible_cpus;
+ CPUState *cs;
+
+ /* cpu nodes */
+ possible_cpus = mc->possible_cpu_arch_ids(ms);
+ for (num = 0; num < possible_cpus->len; num++) {
+ cs = possible_cpus->cpus[num].cpu;
+ if (cs == NULL) {
+ continue;
+ }
+
+ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), DEVICE(cs),
+ &error_abort);
+ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), DEVICE(cs),
+ &error_abort);
+ }
+}
+
+static void virt_irq_init(LoongArchVirtMachineState *lvms)
+{
+ DeviceState *pch_pic, *pch_msi;
DeviceState *ipi, *extioi;
SysBusDevice *d;
- LoongArchCPU *lacpu;
- CPULoongArchState *env;
- CPUState *cpu_state;
- int cpu, pin, i, start, num;
- uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, pch_msi_phandle;
+ int i, start, num;
/*
* Extended IRQ model.
@@ -789,80 +411,23 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
/* Create IPI device */
ipi = qdev_new(TYPE_LOONGARCH_IPI);
- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.cpus);
+ lvms->ipi = ipi;
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
- /* IPI iocsr memory region */
- memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
- memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
-
- /* Add cpu interrupt-controller */
- fdt_add_cpuic_node(lvms, &cpuintc_phandle);
-
- for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
- cpu_state = qemu_get_cpu(cpu);
- cpudev = DEVICE(cpu_state);
- lacpu = LOONGARCH_CPU(cpu_state);
- env = &(lacpu->env);
- env->address_space_iocsr = &lvms->as_iocsr;
-
- /* connect ipi irq to cpu irq */
- qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
- env->ipistate = ipi;
- }
-
/* Create EXTIOI device */
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
- qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
+ lvms->extioi = extioi;
if (virt_is_veiointc_enabled(lvms)) {
qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
}
sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
- memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
- if (virt_is_veiointc_enabled(lvms)) {
- memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
- }
- /*
- * connect ext irq to the cpu irq
- * cpu_pin[9:2] <= intc_pin[7:0]
- */
- for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
- cpudev = DEVICE(qemu_get_cpu(cpu));
- for (pin = 0; pin < LS3A_INTC_IP; pin++) {
- qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
- qdev_get_gpio_in(cpudev, pin + 2));
- }
- }
-
- /* Add Extend I/O Interrupt Controller node */
- fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle);
-
- pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
+ virt_cpu_irq_init(lvms);
+ pch_pic = qdev_new(TYPE_LOONGARCH_PIC);
num = VIRT_PCH_PIC_IRQ_NUM;
qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
d = SYS_BUS_DEVICE(pch_pic);
sysbus_realize_and_unref(d, &error_fatal);
- memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
- sysbus_mmio_get_region(d, 0));
- memory_region_add_subregion(get_system_memory(),
- VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
- sysbus_mmio_get_region(d, 1));
- memory_region_add_subregion(get_system_memory(),
- VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
- sysbus_mmio_get_region(d, 2));
-
- /* Connect pch_pic irqs to extioi */
- for (i = 0; i < num; i++) {
- qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
- }
-
- /* Add PCH PIC node */
- fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
start = num;
@@ -872,16 +437,41 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
d = SYS_BUS_DEVICE(pch_msi);
sysbus_realize_and_unref(d, &error_fatal);
sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
- for (i = 0; i < num; i++) {
- /* Connect pch_msi irqs to extioi */
- qdev_connect_gpio_out(DEVICE(d), i,
- qdev_get_gpio_in(extioi, i + start));
- }
- /* Add PCH MSI node */
- fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle);
+ if (kvm_irqchip_in_kernel()) {
+ kvm_loongarch_init_irq_routing();
+ } else {
+ /* IPI iocsr memory region */
+ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
+ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+
+ /* EXTIOI iocsr memory region */
+ memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+ if (virt_is_veiointc_enabled(lvms)) {
+ memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
+ }
+
+ /* PCH_PIC memory region */
+ memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(pch_pic), 0));
+
+ /* Connect pch_pic irqs to extioi */
+ for (i = 0; i < VIRT_PCH_PIC_IRQ_NUM; i++) {
+ qdev_connect_gpio_out(DEVICE(pch_pic), i,
+ qdev_get_gpio_in(extioi, i));
+ }
- virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle);
+ for (i = VIRT_PCH_PIC_IRQ_NUM; i < EXTIOI_IRQS; i++) {
+ /* Connect pch_msi irqs to extioi */
+ qdev_connect_gpio_out(DEVICE(pch_msi), i - VIRT_PCH_PIC_IRQ_NUM,
+ qdev_get_gpio_in(extioi, i));
+ }
+ }
+ virt_devices_init(pch_pic, lvms);
}
static void virt_firmware_init(LoongArchVirtMachineState *lvms)
@@ -941,6 +531,10 @@ static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
switch (addr) {
case MISC_FUNC_REG:
+ if (kvm_irqchip_in_kernel()) {
+ return MEMTX_OK;
+ }
+
if (!virt_is_veiointc_enabled(lvms)) {
return MEMTX_OK;
}
@@ -991,6 +585,10 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
ret = 0x303030354133ULL; /* "3A5000" */
break;
case MISC_FUNC_REG:
+ if (kvm_irqchip_in_kernel()) {
+ return MEMTX_OK;
+ }
+
if (!virt_is_veiointc_enabled(lvms)) {
ret |= BIT_ULL(IOCSRM_EXTIOI_EN);
break;
@@ -1051,13 +649,13 @@ static void fw_cfg_add_memory(MachineState *ms)
}
if (size >= gap) {
- memmap_add_entry(base, gap, 1);
+ memmap_add_entry(ms, base, gap, 1);
size -= gap;
base = VIRT_HIGHMEM_BASE;
}
if (size) {
- memmap_add_entry(base, size, 1);
+ memmap_add_entry(ms, base, size, 1);
base += size;
}
@@ -1072,35 +670,32 @@ static void fw_cfg_add_memory(MachineState *ms)
* lowram: [base, +(gap - numa_info[0].node_mem))
* highram: [VIRT_HIGHMEM_BASE, +(ram_size - gap))
*/
- memmap_add_entry(base, gap - numa_info[0].node_mem, 1);
+ memmap_add_entry(ms, base, gap - numa_info[0].node_mem, 1);
size = ram_size - gap;
base = VIRT_HIGHMEM_BASE;
} else {
size = ram_size - numa_info[0].node_mem;
}
- if (size)
- memmap_add_entry(base, size, 1);
+ if (size) {
+ memmap_add_entry(ms, base, size, 1);
+ }
}
static void virt_init(MachineState *machine)
{
- LoongArchCPU *lacpu;
const char *cpu_model = machine->cpu_type;
MemoryRegion *address_space_mem = get_system_memory();
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
int i;
hwaddr base, size, ram_size = machine->ram_size;
- const CPUArchIdList *possible_cpus;
MachineClass *mc = MACHINE_GET_CLASS(machine);
- CPUState *cpu;
+ Object *cpuobj;
if (!cpu_model) {
cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
}
- create_fdt(lvms);
-
/* Create IOCSR space */
memory_region_init_io(&lvms->system_iocsr, OBJECT(machine), NULL,
machine, "iocsr", UINT64_MAX);
@@ -1111,16 +706,16 @@ static void virt_init(MachineState *machine)
memory_region_add_subregion(&lvms->system_iocsr, 0, &lvms->iocsr_mem);
/* Init CPUs */
- possible_cpus = mc->possible_cpu_arch_ids(machine);
- for (i = 0; i < possible_cpus->len; i++) {
- cpu = cpu_create(machine->cpu_type);
- cpu->cpu_index = i;
- machine->possible_cpus->cpus[i].cpu = cpu;
- lacpu = LOONGARCH_CPU(cpu);
- lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
+ mc->possible_cpu_arch_ids(machine);
+ for (i = 0; i < machine->smp.cpus; i++) {
+ cpuobj = object_new(machine->cpu_type);
+ if (cpuobj == NULL) {
+ error_report("Fail to create object with type %s ",
+ machine->cpu_type);
+ exit(EXIT_FAILURE);
+ }
+ qdev_realize_and_unref(DEVICE(cpuobj), NULL, &error_fatal);
}
- fdt_add_cpu_nodes(lvms);
- fdt_add_memory_nodes(machine);
fw_cfg_add_memory(machine);
/* Node0 memory */
@@ -1169,37 +764,18 @@ static void virt_init(MachineState *machine)
rom_set_fw(lvms->fw_cfg);
if (lvms->fw_cfg != NULL) {
fw_cfg_add_file(lvms->fw_cfg, "etc/memmap",
- memmap_table,
- sizeof(struct memmap_entry) * (memmap_entries));
+ lvms->memmap_table,
+ sizeof(struct memmap_entry) * lvms->memmap_entries);
}
- fdt_add_fw_cfg_node(lvms);
- fdt_add_flash_node(lvms);
/* Initialize the IO interrupt subsystem */
virt_irq_init(lvms);
- platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
- VIRT_PLATFORM_BUS_BASEADDRESS,
- VIRT_PLATFORM_BUS_SIZE,
- VIRT_PLATFORM_BUS_IRQ);
lvms->machine_done.notify = virt_done;
qemu_add_machine_init_done_notifier(&lvms->machine_done);
/* connect powerdown request */
lvms->powerdown_notifier.notify = virt_powerdown_req;
qemu_register_powerdown_notifier(&lvms->powerdown_notifier);
- /*
- * Since lowmem region starts from 0 and Linux kernel legacy start address
- * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
- * access. FDT size limit with 1 MiB.
- * Put the FDT into the memory map as a ROM image: this will ensure
- * the FDT is copied again upon reset, even if addr points into RAM.
- */
- qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size);
- rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE,
- &address_space_memory);
- qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
- rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size));
-
lvms->bootinfo.ram_size = ram_size;
loongarch_load_kernel(machine, &lvms->bootinfo);
}
@@ -1221,6 +797,48 @@ static void virt_set_acpi(Object *obj, Visitor *v, const char *name,
visit_type_OnOffAuto(v, name, &lvms->acpi, errp);
}
+static char *virt_get_oem_id(Object *obj, Error **errp)
+{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+
+ return g_strdup(lvms->oem_id);
+}
+
+static void virt_set_oem_id(Object *obj, const char *value, Error **errp)
+{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+ size_t len = strlen(value);
+
+ if (len > 6) {
+ error_setg(errp,
+ "User specified oem-id value is bigger than 6 bytes in size");
+ return;
+ }
+
+ strncpy(lvms->oem_id, value, 6);
+}
+
+static char *virt_get_oem_table_id(Object *obj, Error **errp)
+{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+
+ return g_strdup(lvms->oem_table_id);
+}
+
+static void virt_set_oem_table_id(Object *obj, const char *value,
+ Error **errp)
+{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+ size_t len = strlen(value);
+
+ if (len > 8) {
+ error_setg(errp,
+ "User specified oem-table-id value is bigger than 8 bytes in size");
+ return;
+ }
+ strncpy(lvms->oem_table_id, value, 8);
+}
+
static void virt_initfn(Object *obj)
{
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
@@ -1234,6 +852,195 @@ static void virt_initfn(Object *obj)
virt_flash_create(lvms);
}
+static void virt_get_topo_from_index(MachineState *ms,
+ LoongArchCPUTopo *topo, int index)
+{
+ topo->socket_id = index / (ms->smp.cores * ms->smp.threads);
+ topo->core_id = index / ms->smp.threads % ms->smp.cores;
+ topo->thread_id = index % ms->smp.threads;
+}
+
+static unsigned int topo_align_up(unsigned int count)
+{
+ g_assert(count >= 1);
+ count -= 1;
+ return BIT(count ? 32 - clz32(count) : 0);
+}
+
+/*
+ * LoongArch Reference Manual Vol1, Chapter 7.4.12 CPU Identity
+ * For CPU architecture, bit0 .. bit8 is valid for CPU id, max cpuid is 512
+ * However for IPI/Eiointc interrupt controller, max supported cpu id for
+ * irq routingis 256
+ *
+ * Here max cpu id is 256 for virt machine
+ */
+static int virt_get_arch_id_from_topo(MachineState *ms, LoongArchCPUTopo *topo)
+{
+ int arch_id, threads, cores, sockets;
+
+ threads = topo_align_up(ms->smp.threads);
+ cores = topo_align_up(ms->smp.cores);
+ sockets = topo_align_up(ms->smp.sockets);
+ if ((threads * cores * sockets) > 256) {
+ error_report("Exceeding max cpuid 256 with sockets[%d] cores[%d]"
+ " threads[%d]", ms->smp.sockets, ms->smp.cores,
+ ms->smp.threads);
+ exit(1);
+ }
+
+ arch_id = topo->thread_id + topo->core_id * threads;
+ arch_id += topo->socket_id * threads * cores;
+ return arch_id;
+}
+
+/* Find cpu slot in machine->possible_cpus by arch_id */
+static CPUArchId *virt_find_cpu_slot(MachineState *ms, int arch_id)
+{
+ int n;
+ for (n = 0; n < ms->possible_cpus->len; n++) {
+ if (ms->possible_cpus->cpus[n].arch_id == arch_id) {
+ return &ms->possible_cpus->cpus[n];
+ }
+ }
+
+ return NULL;
+}
+
+/* Find cpu slot for cold-plut CPU object where cpu is NULL */
+static CPUArchId *virt_find_empty_cpu_slot(MachineState *ms)
+{
+ int n;
+ for (n = 0; n < ms->possible_cpus->len; n++) {
+ if (ms->possible_cpus->cpus[n].cpu == NULL) {
+ return &ms->possible_cpus->cpus[n];
+ }
+ }
+
+ return NULL;
+}
+
+static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
+ MachineState *ms = MACHINE(OBJECT(hotplug_dev));
+ LoongArchCPU *cpu = LOONGARCH_CPU(dev);
+ CPUState *cs = CPU(dev);
+ CPUArchId *cpu_slot;
+ LoongArchCPUTopo topo;
+ int arch_id;
+
+ if (lvms->acpi_ged) {
+ if ((cpu->thread_id < 0) || (cpu->thread_id >= ms->smp.threads)) {
+ error_setg(errp,
+ "Invalid thread-id %u specified, must be in range 1:%u",
+ cpu->thread_id, ms->smp.threads - 1);
+ return;
+ }
+
+ if ((cpu->core_id < 0) || (cpu->core_id >= ms->smp.cores)) {
+ error_setg(errp,
+ "Invalid core-id %u specified, must be in range 1:%u",
+ cpu->core_id, ms->smp.cores - 1);
+ return;
+ }
+
+ if ((cpu->socket_id < 0) || (cpu->socket_id >= ms->smp.sockets)) {
+ error_setg(errp,
+ "Invalid socket-id %u specified, must be in range 1:%u",
+ cpu->socket_id, ms->smp.sockets - 1);
+ return;
+ }
+
+ topo.socket_id = cpu->socket_id;
+ topo.core_id = cpu->core_id;
+ topo.thread_id = cpu->thread_id;
+ arch_id = virt_get_arch_id_from_topo(ms, &topo);
+ cpu_slot = virt_find_cpu_slot(ms, arch_id);
+ if (CPU(cpu_slot->cpu)) {
+ error_setg(errp,
+ "cpu(id%d=%d:%d:%d) with arch-id %" PRIu64 " exists",
+ cs->cpu_index, cpu->socket_id, cpu->core_id,
+ cpu->thread_id, cpu_slot->arch_id);
+ return;
+ }
+ } else {
+ /* For cold-add cpu, find empty cpu slot */
+ cpu_slot = virt_find_empty_cpu_slot(ms);
+ topo.socket_id = cpu_slot->props.socket_id;
+ topo.core_id = cpu_slot->props.core_id;
+ topo.thread_id = cpu_slot->props.thread_id;
+ object_property_set_int(OBJECT(dev), "socket-id", topo.socket_id, NULL);
+ object_property_set_int(OBJECT(dev), "core-id", topo.core_id, NULL);
+ object_property_set_int(OBJECT(dev), "thread-id", topo.thread_id, NULL);
+ }
+
+ cpu->env.address_space_iocsr = &lvms->as_iocsr;
+ cpu->phy_id = cpu_slot->arch_id;
+ cs->cpu_index = cpu_slot - ms->possible_cpus->cpus;
+ numa_cpu_pre_plug(cpu_slot, dev, errp);
+}
+
+static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
+ LoongArchCPU *cpu = LOONGARCH_CPU(dev);
+ CPUState *cs = CPU(dev);
+
+ if (cs->cpu_index == 0) {
+ error_setg(errp, "hot-unplug of boot cpu(id%d=%d:%d:%d) not supported",
+ cs->cpu_index, cpu->socket_id,
+ cpu->core_id, cpu->thread_id);
+ return;
+ }
+
+ hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev, errp);
+}
+
+static void virt_cpu_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ CPUArchId *cpu_slot;
+ LoongArchCPU *cpu = LOONGARCH_CPU(dev);
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
+
+ /* Notify ipi and extioi irqchip to remove interrupt routing to CPU */
+ hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->ipi), dev, &error_abort);
+ hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort);
+
+ /* Notify acpi ged CPU removed */
+ hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &error_abort);
+
+ cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id);
+ cpu_slot->cpu = NULL;
+}
+
+static void virt_cpu_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ CPUArchId *cpu_slot;
+ LoongArchCPU *cpu = LOONGARCH_CPU(dev);
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
+
+ if (lvms->ipi) {
+ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), dev, &error_abort);
+ }
+
+ if (lvms->extioi) {
+ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort);
+ }
+
+ if (lvms->acpi_ged) {
+ hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev,
+ &error_abort);
+ }
+
+ cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id);
+ cpu_slot->cpu = CPU(dev);
+}
+
static bool memhp_type_supported(DeviceState *dev)
{
/* we only support pc dimm now */
@@ -1252,6 +1059,8 @@ static void virt_device_pre_plug(HotplugHandler *hotplug_dev,
{
if (memhp_type_supported(dev)) {
virt_mem_pre_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
+ virt_cpu_pre_plug(hotplug_dev, dev, errp);
}
}
@@ -1270,6 +1079,8 @@ static void virt_device_unplug_request(HotplugHandler *hotplug_dev,
{
if (memhp_type_supported(dev)) {
virt_mem_unplug_request(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
+ virt_cpu_unplug_request(hotplug_dev, dev, errp);
}
}
@@ -1288,6 +1099,8 @@ static void virt_device_unplug(HotplugHandler *hotplug_dev,
{
if (memhp_type_supported(dev)) {
virt_mem_unplug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
+ virt_cpu_unplug(hotplug_dev, dev, errp);
}
}
@@ -1315,6 +1128,8 @@ static void virt_device_plug_cb(HotplugHandler *hotplug_dev,
}
} else if (memhp_type_supported(dev)) {
virt_mem_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU)) {
+ virt_cpu_plug(hotplug_dev, dev, errp);
}
}
@@ -1324,6 +1139,7 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine,
MachineClass *mc = MACHINE_GET_CLASS(machine);
if (device_is_dynamic_sysbus(mc, dev) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_LOONGARCH_CPU) ||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
memhp_type_supported(dev)) {
return HOTPLUG_HANDLER(machine);
@@ -1333,8 +1149,9 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine,
static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
{
- int n;
+ int n, arch_id;
unsigned int max_cpus = ms->smp.max_cpus;
+ LoongArchCPUTopo topo;
if (ms->possible_cpus) {
assert(ms->possible_cpus->len == max_cpus);
@@ -1345,17 +1162,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
sizeof(CPUArchId) * max_cpus);
ms->possible_cpus->len = max_cpus;
for (n = 0; n < ms->possible_cpus->len; n++) {
+ virt_get_topo_from_index(ms, &topo, n);
+ arch_id = virt_get_arch_id_from_topo(ms, &topo);
ms->possible_cpus->cpus[n].type = ms->cpu_type;
- ms->possible_cpus->cpus[n].arch_id = n;
-
+ ms->possible_cpus->cpus[n].arch_id = arch_id;
+ ms->possible_cpus->cpus[n].vcpus_count = 1;
ms->possible_cpus->cpus[n].props.has_socket_id = true;
- ms->possible_cpus->cpus[n].props.socket_id =
- n / (ms->smp.cores * ms->smp.threads);
+ ms->possible_cpus->cpus[n].props.socket_id = topo.socket_id;
ms->possible_cpus->cpus[n].props.has_core_id = true;
- ms->possible_cpus->cpus[n].props.core_id =
- n / ms->smp.threads % ms->smp.cores;
+ ms->possible_cpus->cpus[n].props.core_id = topo.core_id;
ms->possible_cpus->cpus[n].props.has_thread_id = true;
- ms->possible_cpus->cpus[n].props.thread_id = n % ms->smp.threads;
+ ms->possible_cpus->cpus[n].props.thread_id = topo.thread_id;
}
return ms->possible_cpus;
}
@@ -1382,7 +1199,7 @@ static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx)
}
}
-static void virt_class_init(ObjectClass *oc, void *data)
+static void virt_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -1390,6 +1207,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
mc->init = virt_init;
mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
mc->default_ram_id = "loongarch.ram";
+ mc->desc = "QEMU LoongArch Virtual Machine";
mc->max_cpus = LOONGARCH_MAX_CPUS;
mc->is_default = 1;
mc->default_kernel_irqchip_split = false;
@@ -1402,6 +1220,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
mc->numa_mem_supported = true;
mc->auto_enable_numa_with_memhp = true;
mc->auto_enable_numa_with_memdev = true;
+ mc->has_hotpluggable_cpus = true;
mc->get_hotplug_handler = virt_get_hotplug_handler;
mc->default_nic = "virtio-net-pci";
hc->plug = virt_device_plug_cb;
@@ -1420,9 +1239,26 @@ static void virt_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "v-eiointc",
"Enable Virt Extend I/O Interrupt Controller.");
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
+ object_class_property_add_str(oc, "x-oem-id",
+ virt_get_oem_id,
+ virt_set_oem_id);
+ object_class_property_set_description(oc, "x-oem-id",
+ "Override the default value of field OEMID "
+ "in ACPI table header."
+ "The string may be up to 6 bytes in size");
+
+
+ object_class_property_add_str(oc, "x-oem-table-id",
+ virt_get_oem_table_id,
+ virt_set_oem_table_id);
+ object_class_property_set_description(oc, "x-oem-table-id",
+ "Override the default value of field OEM Table ID "
+ "in ACPI table header."
+ "The string may be up to 8 bytes in size");
}
static const TypeInfo virt_machine_types[] = {
@@ -1432,7 +1268,7 @@ static const TypeInfo virt_machine_types[] = {
.instance_size = sizeof(LoongArchVirtMachineState),
.class_init = virt_class_init,
.instance_init = virt_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
},
diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig
index 0092cda..aff769b 100644
--- a/hw/m68k/Kconfig
+++ b/hw/m68k/Kconfig
@@ -18,6 +18,7 @@ config NEXTCUBE
depends on M68K
select FRAMEBUFFER
select ESCC
+ select EMPTY_SLOT
config Q800
bool
diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c
index 1e8e64f..d97399b 100644
--- a/hw/m68k/an5206.c
+++ b/hw/m68k/an5206.c
@@ -14,7 +14,7 @@
#include "hw/loader.h"
#include "elf.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#define KERNEL_LOAD_ADDR 0x10000
#define AN5206_MBAR_ADDR 0x10000000
@@ -74,7 +74,7 @@ static void an5206_init(MachineState *machine)
}
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
- NULL, NULL, NULL, 1, EM_68K, 0, 0);
+ NULL, NULL, NULL, ELFDATA2MSB, EM_68K, 0, 0);
entry = elf_entry;
if (kernel_size < 0) {
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h
index 0e6e3ee..0b3e7c4 100644
--- a/hw/m68k/bootinfo.h
+++ b/hw/m68k/bootinfo.h
@@ -1,5 +1,5 @@
/*
- * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ * SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
*
* Bootinfo tags from linux bootinfo.h and bootinfo-mac.h:
* This is an easily parsable and extendable structure containing all
@@ -14,39 +14,39 @@
#define BOOTINFO0(base, id) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, sizeof(struct bi_record)); \
+ stw_be_p(base, sizeof(struct bi_record)); \
base += 2; \
} while (0)
#define BOOTINFO1(base, id, value) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, sizeof(struct bi_record) + 4); \
+ stw_be_p(base, sizeof(struct bi_record) + 4); \
base += 2; \
- stl_p(base, value); \
+ stl_be_p(base, value); \
base += 4; \
} while (0)
#define BOOTINFO2(base, id, value1, value2) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, sizeof(struct bi_record) + 8); \
+ stw_be_p(base, sizeof(struct bi_record) + 8); \
base += 2; \
- stl_p(base, value1); \
+ stl_be_p(base, value1); \
base += 4; \
- stl_p(base, value2); \
+ stl_be_p(base, value2); \
base += 4; \
} while (0)
#define BOOTINFOSTR(base, id, string) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, \
+ stw_be_p(base, \
(sizeof(struct bi_record) + strlen(string) + \
1 /* null termination */ + 3 /* padding */) & ~3); \
base += 2; \
@@ -59,13 +59,13 @@
#define BOOTINFODATA(base, id, data, len) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, \
+ stw_be_p(base, \
(sizeof(struct bi_record) + len + \
2 /* length field */ + 3 /* padding */) & ~3); \
base += 2; \
- stw_p(base, len); \
+ stw_be_p(base, len); \
base += 2; \
for (unsigned i_ = 0; i_ < len; ++i_) { \
stb_p(base++, data[i_]); \
diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c
index 183fd3c..a25e782 100644
--- a/hw/m68k/mcf5206.c
+++ b/hw/m68k/mcf5206.c
@@ -16,7 +16,7 @@
#include "hw/m68k/mcf.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/sysbus.h"
/* General purpose timer module. */
@@ -582,7 +582,7 @@ static const MemoryRegionOps m5206_mbar_ops = {
.write = m5206_mbar_writefn,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
};
static void mcf5206_mbar_realize(DeviceState *dev, Error **errp)
@@ -600,13 +600,12 @@ static void mcf5206_mbar_realize(DeviceState *dev, Error **errp)
s->uart[1] = mcf_uart_create(s->pic[13], serial_hd(1));
}
-static Property mcf5206_mbar_properties[] = {
+static const Property mcf5206_mbar_properties[] = {
DEFINE_PROP_LINK("m68k-cpu", m5206_mbar_state, cpu,
TYPE_M68K_CPU, M68kCPU *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mcf5206_mbar_class_init(ObjectClass *oc, void *data)
+static void mcf5206_mbar_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -614,7 +613,7 @@ static void mcf5206_mbar_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "MCF5206 system integration module";
dc->realize = mcf5206_mbar_realize;
- dc->reset = m5206_mbar_reset;
+ device_class_set_legacy_reset(dc, m5206_mbar_reset);
}
static const TypeInfo mcf5206_mbar_info = {
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
index ec14096..75cc076 100644
--- a/hw/m68k/mcf5208.c
+++ b/hw/m68k/mcf5208.c
@@ -4,6 +4,14 @@
* Copyright (c) 2007 CodeSourcery.
*
* This code is licensed under the GPL
+ *
+ * This file models both the MCF5208 SoC, and the
+ * MCF5208EVB evaluation board. For details see
+ *
+ * "MCF5208 Reference Manual"
+ * https://www.nxp.com/docs/en/reference-manual/MCF5208RM.pdf
+ * "M5208EVB-RevB 32-bit Microcontroller User Manual"
+ * https://www.nxp.com/docs/en/reference-manual/M5208EVBUM.pdf
*/
#include "qemu/osdep.h"
@@ -18,8 +26,8 @@
#include "hw/m68k/mcf_fec.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
+#include "system/system.h"
+#include "system/qtest.h"
#include "net/net.h"
#include "hw/boards.h"
#include "hw/loader.h"
@@ -147,7 +155,7 @@ static uint64_t m5208_timer_read(void *opaque, hwaddr addr,
static const MemoryRegionOps m5208_timer_ops = {
.read = m5208_timer_read,
.write = m5208_timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
};
static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
@@ -158,7 +166,7 @@ static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
{
int n;
for (n = 0; n < 32; n++) {
- if (current_machine->ram_size < (2u << n)) {
+ if (current_machine->ram_size < (2ULL << n)) {
break;
}
}
@@ -184,7 +192,7 @@ static void m5208_sys_write(void *opaque, hwaddr addr,
static const MemoryRegionOps m5208_sys_ops = {
.read = m5208_sys_read,
.write = m5208_sys_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
};
static uint64_t m5208_rcm_read(void *opaque, hwaddr addr,
@@ -216,7 +224,7 @@ static void m5208_rcm_write(void *opaque, hwaddr addr,
static const MemoryRegionOps m5208_rcm_ops = {
.read = m5208_rcm_read,
.write = m5208_rcm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
};
static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic,
@@ -351,7 +359,7 @@ static void mcf5208evb_init(MachineState *machine)
/* Initial PC is always at offset 4 in firmware binaries */
ptr = rom_ptr(0x4, 4);
assert(ptr != NULL);
- env->pc = ldl_p(ptr);
+ env->pc = ldl_be_p(ptr);
}
/* Load kernel. */
@@ -364,7 +372,7 @@ static void mcf5208evb_init(MachineState *machine)
}
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
- NULL, NULL, NULL, 1, EM_68K, 0, 0);
+ NULL, NULL, NULL, ELFDATA2MSB, EM_68K, 0, 0);
entry = elf_entry;
if (kernel_size < 0) {
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c
index 1d3b34e..e3055b8 100644
--- a/hw/m68k/mcf_intc.c
+++ b/hw/m68k/mcf_intc.c
@@ -166,7 +166,7 @@ static void mcf_intc_reset(DeviceState *dev)
static const MemoryRegionOps mcf_intc_ops = {
.read = mcf_intc_read,
.write = mcf_intc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
};
static void mcf_intc_instance_init(Object *obj)
@@ -177,19 +177,18 @@ static void mcf_intc_instance_init(Object *obj)
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
}
-static Property mcf_intc_properties[] = {
+static const Property mcf_intc_properties[] = {
DEFINE_PROP_LINK("m68k-cpu", mcf_intc_state, cpu,
TYPE_M68K_CPU, M68kCPU *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mcf_intc_class_init(ObjectClass *oc, void *data)
+static void mcf_intc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, mcf_intc_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = mcf_intc_reset;
+ device_class_set_legacy_reset(dc, mcf_intc_reset);
}
static const TypeInfo mcf_intc_gate_info = {
diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c
index 9f6f90d..957644b 100644
--- a/hw/m68k/next-cube.c
+++ b/hw/m68k/next-cube.c
@@ -2,6 +2,7 @@
* NeXT Cube System Driver
*
* Copyright (c) 2011 Bryce Lanham
+ * Copyright (c) 2024 Mark Cave-Ayland
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
@@ -11,8 +12,9 @@
#include "qemu/osdep.h"
#include "exec/hwaddr.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
+#include "exec/cpu-interrupt.h"
+#include "system/system.h"
+#include "system/qtest.h"
#include "hw/irq.h"
#include "hw/m68k/next-cube.h"
#include "hw/boards.h"
@@ -22,6 +24,7 @@
#include "qom/object.h"
#include "hw/char/escc.h" /* ZILOG 8530 Serial Emulation */
#include "hw/block/fdc.h"
+#include "hw/misc/empty_slot.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -37,31 +40,17 @@
#define DPRINTF(fmt, ...) do { } while (0)
#endif
-#define TYPE_NEXT_MACHINE MACHINE_TYPE_NAME("next-cube")
-OBJECT_DECLARE_SIMPLE_TYPE(NeXTState, NEXT_MACHINE)
-
#define ENTRY 0x0100001e
#define RAM_SIZE 0x4000000
#define ROM_FILE "Rev_2.5_v66.bin"
-typedef struct next_dma {
- uint32_t csr;
- uint32_t saved_next;
- uint32_t saved_limit;
- uint32_t saved_start;
- uint32_t saved_stop;
+#define TYPE_NEXT_RTC "next-rtc"
+OBJECT_DECLARE_SIMPLE_TYPE(NeXTRTC, NEXT_RTC)
- uint32_t next;
- uint32_t limit;
- uint32_t start;
- uint32_t stop;
-
- uint32_t next_initbuf;
- uint32_t size;
-} next_dma;
+struct NeXTRTC {
+ SysBusDevice parent_obj;
-typedef struct NextRtc {
int8_t phase;
uint8_t ram[32];
uint8_t command;
@@ -69,18 +58,25 @@ typedef struct NextRtc {
uint8_t status;
uint8_t control;
uint8_t retval;
-} NextRtc;
-struct NeXTState {
- MachineState parent;
+ qemu_irq data_out_irq;
+ qemu_irq power_irq;
+};
- MemoryRegion rom;
- MemoryRegion rom2;
- MemoryRegion dmamem;
- MemoryRegion bmapm1;
- MemoryRegion bmapm2;
+#define TYPE_NEXT_SCSI "next-scsi"
+OBJECT_DECLARE_SIMPLE_TYPE(NeXTSCSI, NEXT_SCSI)
- next_dma dma[10];
+/* NeXT SCSI Controller */
+struct NeXTSCSI {
+ SysBusDevice parent_obj;
+
+ MemoryRegion scsi_mem;
+
+ SysBusESPState sysbus_esp;
+
+ MemoryRegion scsi_csr_mem;
+ uint8_t scsi_csr_1;
+ uint8_t scsi_csr_2;
};
#define TYPE_NEXT_PC "next-pc"
@@ -92,6 +88,9 @@ struct NeXTPC {
M68kCPU *cpu;
+ MemoryRegion floppy_mem;
+ MemoryRegion timer_mem;
+ MemoryRegion dummyen_mem;
MemoryRegion mmiomem;
MemoryRegion scrmem;
@@ -101,13 +100,49 @@ struct NeXTPC {
uint32_t int_mask;
uint32_t int_status;
uint32_t led;
- uint8_t scsi_csr_1;
- uint8_t scsi_csr_2;
+
+ NeXTSCSI next_scsi;
qemu_irq scsi_reset;
qemu_irq scsi_dma;
- NextRtc rtc;
+ ESCCState escc;
+
+ NeXTRTC rtc;
+ qemu_irq rtc_data_irq;
+ qemu_irq rtc_cmd_reset_irq;
+};
+
+typedef struct next_dma {
+ uint32_t csr;
+
+ uint32_t saved_next;
+ uint32_t saved_limit;
+ uint32_t saved_start;
+ uint32_t saved_stop;
+
+ uint32_t next;
+ uint32_t limit;
+ uint32_t start;
+ uint32_t stop;
+
+ uint32_t next_initbuf;
+ uint32_t size;
+} next_dma;
+
+#define TYPE_NEXT_MACHINE MACHINE_TYPE_NAME("next-cube")
+OBJECT_DECLARE_SIMPLE_TYPE(NeXTState, NEXT_MACHINE)
+
+struct NeXTState {
+ MachineState parent;
+
+ MemoryRegion rom;
+ MemoryRegion rom2;
+ MemoryRegion dmamem;
+ MemoryRegion bmapm1;
+ MemoryRegion bmapm2;
+
+ next_dma dma[10];
};
/* Thanks to NeXT forums for this */
@@ -144,120 +179,26 @@ static void next_scr2_led_update(NeXTPC *s)
static void next_scr2_rtc_update(NeXTPC *s)
{
- uint8_t old_scr2, scr2_2;
- NextRtc *rtc = &s->rtc;
+ uint8_t old_scr2_rtc, scr2_rtc;
- old_scr2 = extract32(s->old_scr2, 8, 8);
- scr2_2 = extract32(s->scr2, 8, 8);
+ old_scr2_rtc = extract32(s->old_scr2, 8, 8);
+ scr2_rtc = extract32(s->scr2, 8, 8);
- if (scr2_2 & 0x1) {
+ if (scr2_rtc & 0x1) {
/* DPRINTF("RTC %x phase %i\n", scr2_2, rtc->phase); */
- if (rtc->phase == -1) {
- rtc->phase = 0;
- }
/* If we are in going down clock... do something */
- if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) &&
- ((scr2_2 & SCR2_RTCLK) == 0)) {
- if (rtc->phase < 8) {
- rtc->command = (rtc->command << 1) |
- ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
- }
- if (rtc->phase >= 8 && rtc->phase < 16) {
- rtc->value = (rtc->value << 1) |
- ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
-
- /* if we read RAM register, output RT_DATA bit */
- if (rtc->command <= 0x1F) {
- scr2_2 = scr2_2 & (~SCR2_RTDATA);
- if (rtc->ram[rtc->command] & (0x80 >> (rtc->phase - 8))) {
- scr2_2 |= SCR2_RTDATA;
- }
-
- rtc->retval = (rtc->retval << 1) |
- ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
- }
- /* read the status 0x30 */
- if (rtc->command == 0x30) {
- scr2_2 = scr2_2 & (~SCR2_RTDATA);
- /* for now status = 0x98 (new rtc + FTU) */
- if (rtc->status & (0x80 >> (rtc->phase - 8))) {
- scr2_2 |= SCR2_RTDATA;
- }
-
- rtc->retval = (rtc->retval << 1) |
- ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
- }
- /* read the status 0x31 */
- if (rtc->command == 0x31) {
- scr2_2 = scr2_2 & (~SCR2_RTDATA);
- if (rtc->control & (0x80 >> (rtc->phase - 8))) {
- scr2_2 |= SCR2_RTDATA;
- }
- rtc->retval = (rtc->retval << 1) |
- ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
- }
-
- if ((rtc->command >= 0x20) && (rtc->command <= 0x2F)) {
- scr2_2 = scr2_2 & (~SCR2_RTDATA);
- /* for now 0x00 */
- time_t time_h = time(NULL);
- struct tm *info = localtime(&time_h);
- int ret = 0;
-
- switch (rtc->command) {
- case 0x20:
- ret = SCR2_TOBCD(info->tm_sec);
- break;
- case 0x21:
- ret = SCR2_TOBCD(info->tm_min);
- break;
- case 0x22:
- ret = SCR2_TOBCD(info->tm_hour);
- break;
- case 0x24:
- ret = SCR2_TOBCD(info->tm_mday);
- break;
- case 0x25:
- ret = SCR2_TOBCD((info->tm_mon + 1));
- break;
- case 0x26:
- ret = SCR2_TOBCD((info->tm_year - 100));
- break;
-
- }
-
- if (ret & (0x80 >> (rtc->phase - 8))) {
- scr2_2 |= SCR2_RTDATA;
- }
- rtc->retval = (rtc->retval << 1) |
- ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
- }
-
- }
-
- rtc->phase++;
- if (rtc->phase == 16) {
- if (rtc->command >= 0x80 && rtc->command <= 0x9F) {
- rtc->ram[rtc->command - 0x80] = rtc->value;
- }
- /* write to x30 register */
- if (rtc->command == 0xB1) {
- /* clear FTU */
- if (rtc->value & 0x04) {
- rtc->status = rtc->status & (~0x18);
- s->int_status = s->int_status & (~0x04);
- }
- }
+ if (((old_scr2_rtc & SCR2_RTCLK) != (scr2_rtc & SCR2_RTCLK)) &&
+ ((scr2_rtc & SCR2_RTCLK) == 0)) {
+ if (scr2_rtc & SCR2_RTDATA) {
+ qemu_irq_raise(s->rtc_data_irq);
+ } else {
+ qemu_irq_lower(s->rtc_data_irq);
}
}
} else {
/* else end or abort */
- rtc->phase = -1;
- rtc->command = 0;
- rtc->value = 0;
+ qemu_irq_raise(s->rtc_cmd_reset_irq);
}
-
- s->scr2 = deposit32(s->scr2, 8, 8, scr2_2);
}
static uint64_t next_mmio_read(void *opaque, hwaddr addr, unsigned size)
@@ -266,30 +207,26 @@ static uint64_t next_mmio_read(void *opaque, hwaddr addr, unsigned size)
uint64_t val;
switch (addr) {
- case 0x7000:
+ case 0x2000: /* 0x2007000 */
/* DPRINTF("Read INT status: %x\n", s->int_status); */
val = s->int_status;
break;
- case 0x7800:
+ case 0x2800: /* 0x2007800 */
DPRINTF("MMIO Read INT mask: %x\n", s->int_mask);
val = s->int_mask;
break;
- case 0xc000 ... 0xc003:
- val = extract32(s->scr1, (4 - (addr - 0xc000) - size) << 3,
+ case 0x7000 ... 0x7003: /* 0x200c000 */
+ val = extract32(s->scr1, (4 - (addr - 0x7000) - size) << 3,
size << 3);
break;
- case 0xd000 ... 0xd003:
- val = extract32(s->scr2, (4 - (addr - 0xd000) - size) << 3,
+ case 0x8000 ... 0x8003: /* 0x200d000 */
+ val = extract32(s->scr2, (4 - (addr - 0x8000) - size) << 3,
size << 3);
break;
- case 0x14020:
- val = 0x7f;
- break;
-
default:
val = 0;
DPRINTF("MMIO Read @ 0x%"HWADDR_PRIx" size %d\n", addr, size);
@@ -305,25 +242,25 @@ static void next_mmio_write(void *opaque, hwaddr addr, uint64_t val,
NeXTPC *s = NEXT_PC(opaque);
switch (addr) {
- case 0x7000:
+ case 0x2000: /* 0x2007000 */
DPRINTF("INT Status old: %x new: %x\n", s->int_status,
(unsigned int)val);
s->int_status = val;
break;
- case 0x7800:
+ case 0x2800: /* 0x2007800 */
DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, (unsigned int)val);
s->int_mask = val;
break;
- case 0xc000 ... 0xc003:
+ case 0x7000 ... 0x7003: /* 0x200c000 */
DPRINTF("SCR1 Write: %x\n", (unsigned int)val);
- s->scr1 = deposit32(s->scr1, (4 - (addr - 0xc000) - size) << 3,
+ s->scr1 = deposit32(s->scr1, (4 - (addr - 0x7000) - size) << 3,
size << 3, val);
break;
- case 0xd000 ... 0xd003:
- s->scr2 = deposit32(s->scr2, (4 - (addr - 0xd000) - size) << 3,
+ case 0x8000 ... 0x8003: /* 0x200d000 */
+ s->scr2 = deposit32(s->scr2, (4 - (addr - 0x8000) - size) << 3,
size << 3, val);
next_scr2_led_update(s);
next_scr2_rtc_update(s);
@@ -351,143 +288,6 @@ static const MemoryRegionOps next_mmio_ops = {
#define SCSICSR_CPUDMA 0x10 /* if set, dma enabled */
#define SCSICSR_INTMASK 0x20 /* if set, interrupt enabled */
-static uint64_t next_scr_readfn(void *opaque, hwaddr addr, unsigned size)
-{
- NeXTPC *s = NEXT_PC(opaque);
- uint64_t val;
-
- switch (addr) {
- case 0x14108:
- DPRINTF("FD read @ %x\n", (unsigned int)addr);
- val = 0x40 | 0x04 | 0x2 | 0x1;
- break;
-
- case 0x14020:
- DPRINTF("SCSI 4020 STATUS READ %X\n", s->scsi_csr_1);
- val = s->scsi_csr_1;
- break;
-
- case 0x14021:
- DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2);
- val = 0x40;
- break;
-
- /*
- * These 4 registers are the hardware timer, not sure which register
- * is the latch instead of data, but no problems so far.
- *
- * Hack: We need to have the LSB change consistently to make it work
- */
- case 0x1a000 ... 0x1a003:
- val = extract32(clock(), (4 - (addr - 0x1a000) - size) << 3,
- size << 3);
- break;
-
- /* For now return dummy byte to allow the Ethernet test to timeout */
- case 0x6000:
- val = 0xff;
- break;
-
- default:
- DPRINTF("BMAP Read @ 0x%x size %u\n", (unsigned int)addr, size);
- val = 0;
- break;
- }
-
- return val;
-}
-
-static void next_scr_writefn(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- NeXTPC *s = NEXT_PC(opaque);
-
- switch (addr) {
- case 0x14108:
- DPRINTF("FDCSR Write: %x\n", value);
- if (val == 0x0) {
- /* qemu_irq_raise(s->fd_irq[0]); */
- }
- break;
-
- case 0x14020: /* SCSI Control Register */
- if (val & SCSICSR_FIFOFL) {
- DPRINTF("SCSICSR FIFO Flush\n");
- /* will have to add another irq to the esp if this is needed */
- /* esp_puflush_fifo(esp_g); */
- }
-
- if (val & SCSICSR_ENABLE) {
- DPRINTF("SCSICSR Enable\n");
- /*
- * qemu_irq_raise(s->scsi_dma);
- * s->scsi_csr_1 = 0xc0;
- * s->scsi_csr_1 |= 0x1;
- * qemu_irq_pulse(s->scsi_dma);
- */
- }
- /*
- * else
- * s->scsi_csr_1 &= ~SCSICSR_ENABLE;
- */
-
- if (val & SCSICSR_RESET) {
- DPRINTF("SCSICSR Reset\n");
- /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */
- qemu_irq_raise(s->scsi_reset);
- s->scsi_csr_1 &= ~(SCSICSR_INTMASK | 0x80 | 0x1);
- qemu_irq_lower(s->scsi_reset);
- }
- if (val & SCSICSR_DMADIR) {
- DPRINTF("SCSICSR DMAdir\n");
- }
- if (val & SCSICSR_CPUDMA) {
- DPRINTF("SCSICSR CPUDMA\n");
- /* qemu_irq_raise(s->scsi_dma); */
- s->int_status |= 0x4000000;
- } else {
- /* fprintf(stderr,"SCSICSR CPUDMA disabled\n"); */
- s->int_status &= ~(0x4000000);
- /* qemu_irq_lower(s->scsi_dma); */
- }
- if (val & SCSICSR_INTMASK) {
- DPRINTF("SCSICSR INTMASK\n");
- /*
- * int_mask &= ~0x1000;
- * s->scsi_csr_1 |= val;
- * s->scsi_csr_1 &= ~SCSICSR_INTMASK;
- * if (s->scsi_queued) {
- * s->scsi_queued = 0;
- * next_irq(s, NEXT_SCSI_I, level);
- * }
- */
- } else {
- /* int_mask |= 0x1000; */
- }
- if (val & 0x80) {
- /* int_mask |= 0x1000; */
- /* s->scsi_csr_1 |= 0x80; */
- }
- DPRINTF("SCSICSR Write: %x\n", val);
- /* s->scsi_csr_1 = val; */
- break;
-
- /* Hardware timer latch - not implemented yet */
- case 0x1a000:
- default:
- DPRINTF("BMAP Write @ 0x%x with 0x%x size %u\n", (unsigned int)addr,
- val, size);
- }
-}
-
-static const MemoryRegionOps next_scr_ops = {
- .read = next_scr_readfn,
- .write = next_scr_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
#define NEXTDMA_SCSI(x) (0x10 + x)
#define NEXTDMA_FD(x) (0x10 + x)
#define NEXTDMA_ENTX(x) (0x110 + x)
@@ -585,7 +385,7 @@ static void next_dma_write(void *opaque, hwaddr addr, uint64_t val,
break;
default:
- DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value);
+ DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)val);
}
}
@@ -828,84 +628,579 @@ static void nextscsi_write(void *opaque, uint8_t *buf, int size)
nextdma_write(opaque, buf, size, NEXTDMA_SCSI);
}
-static void next_scsi_init(DeviceState *pcdev, M68kCPU *cpu)
+static void next_scsi_csr_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ NeXTSCSI *s = NEXT_SCSI(opaque);
+ NeXTPC *pc = NEXT_PC(container_of(s, NeXTPC, next_scsi));
+
+ switch (addr) {
+ case 0:
+ if (val & SCSICSR_FIFOFL) {
+ DPRINTF("SCSICSR FIFO Flush\n");
+ /* will have to add another irq to the esp if this is needed */
+ /* esp_puflush_fifo(esp_g); */
+ }
+
+ if (val & SCSICSR_ENABLE) {
+ DPRINTF("SCSICSR Enable\n");
+ /*
+ * qemu_irq_raise(s->scsi_dma);
+ * s->scsi_csr_1 = 0xc0;
+ * s->scsi_csr_1 |= 0x1;
+ * qemu_irq_pulse(s->scsi_dma);
+ */
+ }
+ /*
+ * else
+ * s->scsi_csr_1 &= ~SCSICSR_ENABLE;
+ */
+
+ if (val & SCSICSR_RESET) {
+ DPRINTF("SCSICSR Reset\n");
+ /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */
+ qemu_irq_raise(pc->scsi_reset);
+ s->scsi_csr_1 &= ~(SCSICSR_INTMASK | 0x80 | 0x1);
+ qemu_irq_lower(pc->scsi_reset);
+ }
+ if (val & SCSICSR_DMADIR) {
+ DPRINTF("SCSICSR DMAdir\n");
+ }
+ if (val & SCSICSR_CPUDMA) {
+ DPRINTF("SCSICSR CPUDMA\n");
+ /* qemu_irq_raise(s->scsi_dma); */
+ pc->int_status |= 0x4000000;
+ } else {
+ /* fprintf(stderr,"SCSICSR CPUDMA disabled\n"); */
+ pc->int_status &= ~(0x4000000);
+ /* qemu_irq_lower(s->scsi_dma); */
+ }
+ if (val & SCSICSR_INTMASK) {
+ DPRINTF("SCSICSR INTMASK\n");
+ /*
+ * int_mask &= ~0x1000;
+ * s->scsi_csr_1 |= val;
+ * s->scsi_csr_1 &= ~SCSICSR_INTMASK;
+ * if (s->scsi_queued) {
+ * s->scsi_queued = 0;
+ * next_irq(s, NEXT_SCSI_I, level);
+ * }
+ */
+ } else {
+ /* int_mask |= 0x1000; */
+ }
+ if (val & 0x80) {
+ /* int_mask |= 0x1000; */
+ /* s->scsi_csr_1 |= 0x80; */
+ }
+ DPRINTF("SCSICSR1 Write: %"PRIx64 "\n", val);
+ s->scsi_csr_1 = val;
+ break;
+
+ case 1:
+ DPRINTF("SCSICSR2 Write: %"PRIx64 "\n", val);
+ s->scsi_csr_2 = val;
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static uint64_t next_scsi_csr_read(void *opaque, hwaddr addr, unsigned size)
+{
+ NeXTSCSI *s = NEXT_SCSI(opaque);
+ uint64_t val;
+
+ switch (addr) {
+ case 0:
+ DPRINTF("SCSI 4020 STATUS READ %X\n", s->scsi_csr_1);
+ val = s->scsi_csr_1;
+ break;
+
+ case 1:
+ DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2);
+ val = s->scsi_csr_2;
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ return val;
+}
+
+static const MemoryRegionOps next_scsi_csr_ops = {
+ .read = next_scsi_csr_read,
+ .write = next_scsi_csr_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 1,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void next_scsi_init(Object *obj)
{
- struct NeXTPC *next_pc = NEXT_PC(pcdev);
- DeviceState *dev;
- SysBusDevice *sysbusdev;
+ NeXTSCSI *s = NEXT_SCSI(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ object_initialize_child(obj, "esp", &s->sysbus_esp, TYPE_SYSBUS_ESP);
+
+ memory_region_init_io(&s->scsi_csr_mem, obj, &next_scsi_csr_ops,
+ s, "csrs", 2);
+
+ memory_region_init(&s->scsi_mem, obj, "next.scsi", 0x40);
+ sysbus_init_mmio(sbd, &s->scsi_mem);
+}
+
+static void next_scsi_realize(DeviceState *dev, Error **errp)
+{
+ NeXTSCSI *s = NEXT_SCSI(dev);
SysBusESPState *sysbus_esp;
+ SysBusDevice *sbd;
ESPState *esp;
+ NeXTPC *pcdev;
+
+ pcdev = NEXT_PC(container_of(s, NeXTPC, next_scsi));
- dev = qdev_new(TYPE_SYSBUS_ESP);
- sysbus_esp = SYSBUS_ESP(dev);
+ /* ESP */
+ sysbus_esp = SYSBUS_ESP(&s->sysbus_esp);
esp = &sysbus_esp->esp;
esp->dma_memory_read = nextscsi_read;
esp->dma_memory_write = nextscsi_write;
esp->dma_opaque = pcdev;
sysbus_esp->it_shift = 0;
esp->dma_enabled = 1;
- sysbusdev = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(sysbusdev, &error_fatal);
- sysbus_connect_irq(sysbusdev, 0, qdev_get_gpio_in(pcdev, NEXT_SCSI_I));
- sysbus_mmio_map(sysbusdev, 0, 0x2114000);
+ sbd = SYS_BUS_DEVICE(sysbus_esp);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ memory_region_add_subregion(&s->scsi_mem, 0x0,
+ sysbus_mmio_get_region(sbd, 0));
- next_pc->scsi_reset = qdev_get_gpio_in(dev, 0);
- next_pc->scsi_dma = qdev_get_gpio_in(dev, 1);
+ /* SCSI CSRs */
+ memory_region_add_subregion(&s->scsi_mem, 0x20, &s->scsi_csr_mem);
- scsi_bus_legacy_handle_cmdline(&esp->bus);
+ scsi_bus_legacy_handle_cmdline(&s->sysbus_esp.esp.bus);
}
-static void next_escc_init(DeviceState *pcdev)
+static const VMStateDescription next_scsi_vmstate = {
+ .name = "next-scsi",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT8(scsi_csr_1, NeXTSCSI),
+ VMSTATE_UINT8(scsi_csr_2, NeXTSCSI),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void next_scsi_class_init(ObjectClass *klass, const void *data)
{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_new(TYPE_ESCC);
- qdev_prop_set_uint32(dev, "disabled", 0);
- qdev_prop_set_uint32(dev, "frequency", 9600 * 384);
- qdev_prop_set_uint32(dev, "it_shift", 0);
- qdev_prop_set_bit(dev, "bit_swap", true);
- qdev_prop_set_chr(dev, "chrB", serial_hd(1));
- qdev_prop_set_chr(dev, "chrA", serial_hd(0));
- qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
- qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_connect_irq(s, 0, qdev_get_gpio_in(pcdev, NEXT_SCC_I));
- sysbus_connect_irq(s, 1, qdev_get_gpio_in(pcdev, NEXT_SCC_DMA_I));
- sysbus_mmio_map(s, 0, 0x2118000);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "NeXT SCSI Controller";
+ dc->realize = next_scsi_realize;
+ dc->vmsd = &next_scsi_vmstate;
}
-static void next_pc_reset(DeviceState *dev)
+static const TypeInfo next_scsi_info = {
+ .name = TYPE_NEXT_SCSI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_init = next_scsi_init,
+ .instance_size = sizeof(NeXTSCSI),
+ .class_init = next_scsi_class_init,
+};
+
+static void next_floppy_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
{
- NeXTPC *s = NEXT_PC(dev);
+ switch (addr) {
+ case 0:
+ DPRINTF("FDCSR Write: %"PRIx64 "\n", val);
+ if (val == 0x0) {
+ /* qemu_irq_raise(s->fd_irq[0]); */
+ }
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static uint64_t next_floppy_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint64_t val;
+
+ switch (addr) {
+ case 0:
+ DPRINTF("FD read @ %x\n", (unsigned int)addr);
+ val = 0x40 | 0x04 | 0x2 | 0x1;
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ return val;
+}
+
+static const MemoryRegionOps next_floppy_ops = {
+ .read = next_floppy_read,
+ .write = next_floppy_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void next_timer_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ switch (addr) {
+ case 0 ... 3:
+ /* Hardware timer latch - not implemented yet */
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static uint64_t next_timer_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint64_t val;
+
+ switch (addr) {
+ case 0 ... 3:
+ /*
+ * These 4 registers are the hardware timer, not sure which register
+ * is the latch instead of data, but no problems so far.
+ *
+ * Hack: We need to have the LSB change consistently to make it work
+ */
+ val = extract32(clock(), (4 - addr - size) << 3,
+ size << 3);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ return val;
+}
+
+static const MemoryRegionOps next_timer_ops = {
+ .read = next_timer_read,
+ .write = next_timer_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void next_dummy_en_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ /* Do nothing */
+}
+
+static uint64_t next_dummy_en_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint64_t val;
+
+ switch (addr) {
+ case 0:
+ /* For now return dummy byte to allow the Ethernet test to timeout */
+ val = 0xff;
+ break;
+
+ default:
+ val = 0;
+ }
+
+ return val;
+}
+
+static const MemoryRegionOps next_dummy_en_ops = {
+ .read = next_dummy_en_read,
+ .write = next_dummy_en_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static bool next_rtc_cmd_is_write(uint8_t cmd)
+{
+ return (cmd >= 0x80 && cmd <= 0x9f) ||
+ (cmd == 0xb1);
+}
+
+static void next_rtc_data_in_irq(void *opaque, int n, int level)
+{
+ NeXTRTC *rtc = NEXT_RTC(opaque);
+
+ if (rtc->phase < 8) {
+ rtc->command = (rtc->command << 1) | level;
+
+ if (rtc->phase == 7 && !next_rtc_cmd_is_write(rtc->command)) {
+ if (rtc->command <= 0x1f) {
+ /* RAM registers */
+ rtc->retval = rtc->ram[rtc->command];
+ }
+ if ((rtc->command >= 0x20) && (rtc->command <= 0x2f)) {
+ /* RTC */
+ time_t time_h = time(NULL);
+ struct tm *info = localtime(&time_h);
+ rtc->retval = 0;
+
+ switch (rtc->command) {
+ case 0x20:
+ rtc->retval = SCR2_TOBCD(info->tm_sec);
+ break;
+ case 0x21:
+ rtc->retval = SCR2_TOBCD(info->tm_min);
+ break;
+ case 0x22:
+ rtc->retval = SCR2_TOBCD(info->tm_hour);
+ break;
+ case 0x24:
+ rtc->retval = SCR2_TOBCD(info->tm_mday);
+ break;
+ case 0x25:
+ rtc->retval = SCR2_TOBCD((info->tm_mon + 1));
+ break;
+ case 0x26:
+ rtc->retval = SCR2_TOBCD((info->tm_year - 100));
+ break;
+ }
+ }
+ if (rtc->command == 0x30) {
+ /* read the status 0x30 */
+ rtc->retval = rtc->status;
+ }
+ if (rtc->command == 0x31) {
+ /* read the control 0x31 */
+ rtc->retval = rtc->control;
+ }
+ }
+ }
+ if (rtc->phase >= 8 && rtc->phase < 16) {
+ if (next_rtc_cmd_is_write(rtc->command)) {
+ /* Shift in value to write */
+ rtc->value = (rtc->value << 1) | level;
+ } else {
+ /* Shift out value to read */
+ if (rtc->retval & (0x80 >> (rtc->phase - 8))) {
+ qemu_irq_raise(rtc->data_out_irq);
+ } else {
+ qemu_irq_lower(rtc->data_out_irq);
+ }
+ }
+ }
+
+ rtc->phase++;
+ if (rtc->phase == 16 && next_rtc_cmd_is_write(rtc->command)) {
+ if (rtc->command >= 0x80 && rtc->command <= 0x9f) {
+ /* RAM registers */
+ rtc->ram[rtc->command - 0x80] = rtc->value;
+ }
+ if (rtc->command == 0xb1) {
+ /* write to 0x30 register */
+ if (rtc->value & 0x04) {
+ /* clear FTU */
+ rtc->status = rtc->status & (~0x18);
+ qemu_irq_lower(rtc->power_irq);
+ }
+ }
+ }
+}
+
+static void next_rtc_cmd_reset_irq(void *opaque, int n, int level)
+{
+ NeXTRTC *rtc = NEXT_RTC(opaque);
+
+ if (level) {
+ rtc->phase = 0;
+ rtc->command = 0;
+ rtc->value = 0;
+ }
+}
+
+static void next_rtc_reset_hold(Object *obj, ResetType type)
+{
+ NeXTRTC *rtc = NEXT_RTC(obj);
+
+ rtc->status = 0x90;
+
+ /* Load RTC RAM - TODO: provide possibility to load contents from file */
+ memcpy(rtc->ram, rtc_ram2, 32);
+}
+
+static void next_rtc_init(Object *obj)
+{
+ NeXTRTC *rtc = NEXT_RTC(obj);
+
+ qdev_init_gpio_in_named(DEVICE(obj), next_rtc_data_in_irq,
+ "rtc-data-in", 1);
+ qdev_init_gpio_out_named(DEVICE(obj), &rtc->data_out_irq,
+ "rtc-data-out", 1);
+ qdev_init_gpio_in_named(DEVICE(obj), next_rtc_cmd_reset_irq,
+ "rtc-cmd-reset", 1);
+ qdev_init_gpio_out_named(DEVICE(obj), &rtc->power_irq,
+ "rtc-power-out", 1);
+}
+
+static const VMStateDescription next_rtc_vmstate = {
+ .name = "next-rtc",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .fields = (const VMStateField[]) {
+ VMSTATE_INT8(phase, NeXTRTC),
+ VMSTATE_UINT8_ARRAY(ram, NeXTRTC, 32),
+ VMSTATE_UINT8(command, NeXTRTC),
+ VMSTATE_UINT8(value, NeXTRTC),
+ VMSTATE_UINT8(status, NeXTRTC),
+ VMSTATE_UINT8(control, NeXTRTC),
+ VMSTATE_UINT8(retval, NeXTRTC),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void next_rtc_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->desc = "NeXT RTC";
+ dc->vmsd = &next_rtc_vmstate;
+ rc->phases.hold = next_rtc_reset_hold;
+}
+
+static const TypeInfo next_rtc_info = {
+ .name = TYPE_NEXT_RTC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_init = next_rtc_init,
+ .instance_size = sizeof(NeXTRTC),
+ .class_init = next_rtc_class_init,
+};
+
+static void next_pc_rtc_data_in_irq(void *opaque, int n, int level)
+{
+ NeXTPC *s = NEXT_PC(opaque);
+ uint8_t scr2_2 = extract32(s->scr2, 8, 8);
+
+ if (level) {
+ scr2_2 |= SCR2_RTDATA;
+ } else {
+ scr2_2 &= ~SCR2_RTDATA;
+ }
+
+ s->scr2 = deposit32(s->scr2, 8, 8, scr2_2);
+}
+
+static void next_pc_reset_hold(Object *obj, ResetType type)
+{
+ NeXTPC *s = NEXT_PC(obj);
/* Set internal registers to initial values */
/* 0x0000XX00 << vital bits */
s->scr1 = 0x00011102;
s->scr2 = 0x00ff0c80;
s->old_scr2 = s->scr2;
-
- s->rtc.status = 0x90;
-
- /* Load RTC RAM - TODO: provide possibility to load contents from file */
- memcpy(s->rtc.ram, rtc_ram2, 32);
}
static void next_pc_realize(DeviceState *dev, Error **errp)
{
NeXTPC *s = NEXT_PC(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ SysBusDevice *sbd;
+ DeviceState *d;
+
+ /* SCSI */
+ sbd = SYS_BUS_DEVICE(&s->next_scsi);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
- qdev_init_gpio_in(dev, next_irq, NEXT_NUM_IRQS);
+ d = DEVICE(object_resolve_path_component(OBJECT(&s->next_scsi), "esp"));
+ sysbus_connect_irq(SYS_BUS_DEVICE(d), 0,
+ qdev_get_gpio_in(DEVICE(s), NEXT_SCSI_I));
+
+ s->scsi_reset = qdev_get_gpio_in(d, 0);
+ s->scsi_dma = qdev_get_gpio_in(d, 1);
+
+ /* ESCC */
+ d = DEVICE(&s->escc);
+ qdev_prop_set_uint32(d, "disabled", 0);
+ qdev_prop_set_uint32(d, "frequency", 9600 * 384);
+ qdev_prop_set_uint32(d, "it_shift", 0);
+ qdev_prop_set_bit(d, "bit_swap", true);
+ qdev_prop_set_chr(d, "chrB", serial_hd(1));
+ qdev_prop_set_chr(d, "chrA", serial_hd(0));
+ qdev_prop_set_uint32(d, "chnBtype", escc_serial);
+ qdev_prop_set_uint32(d, "chnAtype", escc_serial);
+
+ sbd = SYS_BUS_DEVICE(d);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(dev, NEXT_SCC_I));
+ sysbus_connect_irq(sbd, 1, qdev_get_gpio_in(dev, NEXT_SCC_DMA_I));
+
+ /* RTC */
+ d = DEVICE(&s->rtc);
+ if (!sysbus_realize(SYS_BUS_DEVICE(d), errp)) {
+ return;
+ }
+ /* Data from NeXTPC to RTC */
+ qdev_connect_gpio_out_named(dev, "rtc-data-out", 0,
+ qdev_get_gpio_in_named(d, "rtc-data-in", 0));
+ /* Data from RTC to NeXTPC */
+ qdev_connect_gpio_out_named(d, "rtc-data-out", 0,
+ qdev_get_gpio_in_named(dev,
+ "rtc-data-in", 0));
+ qdev_connect_gpio_out_named(dev, "rtc-cmd-reset", 0,
+ qdev_get_gpio_in_named(d, "rtc-cmd-reset", 0));
+ qdev_connect_gpio_out_named(d, "rtc-power-out", 0,
+ qdev_get_gpio_in(dev, NEXT_PWR_I));
+}
+
+static void next_pc_init(Object *obj)
+{
+ NeXTPC *s = NEXT_PC(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ qdev_init_gpio_in(DEVICE(obj), next_irq, NEXT_NUM_IRQS);
memory_region_init_io(&s->mmiomem, OBJECT(s), &next_mmio_ops, s,
- "next.mmio", 0xd0000);
- memory_region_init_io(&s->scrmem, OBJECT(s), &next_scr_ops, s,
- "next.scr", 0x20000);
+ "next.mmio", 0x9000);
sysbus_init_mmio(sbd, &s->mmiomem);
- sysbus_init_mmio(sbd, &s->scrmem);
+
+ memory_region_init_io(&s->dummyen_mem, OBJECT(s), &next_dummy_en_ops, s,
+ "next.en", 0x20);
+ sysbus_init_mmio(sbd, &s->dummyen_mem);
+
+ object_initialize_child(obj, "next-scsi", &s->next_scsi, TYPE_NEXT_SCSI);
+ sysbus_init_mmio(sbd,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->next_scsi), 0));
+
+ memory_region_init_io(&s->floppy_mem, OBJECT(s), &next_floppy_ops, s,
+ "next.floppy", 4);
+ sysbus_init_mmio(sbd, &s->floppy_mem);
+
+ object_initialize_child(obj, "escc", &s->escc, TYPE_ESCC);
+ sysbus_init_mmio(sbd,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->escc), 0));
+
+ memory_region_init_io(&s->timer_mem, OBJECT(s), &next_timer_ops, s,
+ "next.timer", 4);
+ sysbus_init_mmio(sbd, &s->timer_mem);
+
+ object_initialize_child(obj, "rtc", &s->rtc, TYPE_NEXT_RTC);
+
+ qdev_init_gpio_in_named(DEVICE(obj), next_pc_rtc_data_in_irq,
+ "rtc-data-in", 1);
+ qdev_init_gpio_out_named(DEVICE(obj), &s->rtc_data_irq,
+ "rtc-data-out", 1);
+ qdev_init_gpio_out_named(DEVICE(obj), &s->rtc_cmd_reset_irq,
+ "rtc-cmd-reset", 1);
}
/*
@@ -914,31 +1209,14 @@ static void next_pc_realize(DeviceState *dev, Error **errp)
* this cpu link property and could instead provide outbound IRQ lines
* that the board could wire up to the CPU.
*/
-static Property next_pc_properties[] = {
+static const Property next_pc_properties[] = {
DEFINE_PROP_LINK("cpu", NeXTPC, cpu, TYPE_M68K_CPU, M68kCPU *),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription next_rtc_vmstate = {
- .name = "next-rtc",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_INT8(phase, NextRtc),
- VMSTATE_UINT8_ARRAY(ram, NextRtc, 32),
- VMSTATE_UINT8(command, NextRtc),
- VMSTATE_UINT8(value, NextRtc),
- VMSTATE_UINT8(status, NextRtc),
- VMSTATE_UINT8(control, NextRtc),
- VMSTATE_UINT8(retval, NextRtc),
- VMSTATE_END_OF_LIST()
- },
};
static const VMStateDescription next_pc_vmstate = {
.name = "next-pc",
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 4,
+ .minimum_version_id = 4,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(scr1, NeXTPC),
VMSTATE_UINT32(scr2, NeXTPC),
@@ -946,27 +1224,26 @@ static const VMStateDescription next_pc_vmstate = {
VMSTATE_UINT32(int_mask, NeXTPC),
VMSTATE_UINT32(int_status, NeXTPC),
VMSTATE_UINT32(led, NeXTPC),
- VMSTATE_UINT8(scsi_csr_1, NeXTPC),
- VMSTATE_UINT8(scsi_csr_2, NeXTPC),
- VMSTATE_STRUCT(rtc, NeXTPC, 0, next_rtc_vmstate, NextRtc),
VMSTATE_END_OF_LIST()
},
};
-static void next_pc_class_init(ObjectClass *klass, void *data)
+static void next_pc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->desc = "NeXT Peripheral Controller";
dc->realize = next_pc_realize;
- dc->reset = next_pc_reset;
device_class_set_props(dc, next_pc_properties);
dc->vmsd = &next_pc_vmstate;
+ rc->phases.hold = next_pc_reset_hold;
}
static const TypeInfo next_pc_info = {
.name = TYPE_NEXT_PC,
.parent = TYPE_SYS_BUS_DEVICE,
+ .instance_init = next_pc_init,
.instance_size = sizeof(NeXTPC),
.class_init = next_pc_class_init,
};
@@ -1004,11 +1281,32 @@ static void next_cube_init(MachineState *machine)
sysbus_create_simple(TYPE_NEXTFB, 0x0B000000, NULL);
/* MMIO */
- sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02000000);
+ sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 0, 0x02005000);
/* BMAP IO - acts as a catch-all for now */
sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02100000);
+ /* en network (dummy) */
+ sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 1, 0x02106000);
+
+ /* unknown: Brightness control register? */
+ empty_slot_init("next.unknown.0", 0x02110000, 0x10);
+ /* unknown: Magneto-Optical drive controller? */
+ empty_slot_init("next.unknown.1", 0x02112000, 0x10);
+
+ /* SCSI */
+ sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 2, 0x02114000);
+ /* Floppy */
+ sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 3, 0x02114108);
+ /* ESCC */
+ sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 4, 0x02118000);
+
+ /* unknown: Serial clock configuration register? */
+ empty_slot_init("next.unknown.2", 0x02118004, 0x10);
+
+ /* Timer */
+ sysbus_mmio_map(SYS_BUS_DEVICE(pcdev), 5, 0x0211a000);
+
/* BMAP memory */
memory_region_init_ram_flags_nomigrate(&m->bmapm1, NULL, "next.bmapmem",
64, RAM_SHARED, &error_fatal);
@@ -1036,7 +1334,7 @@ static void next_cube_init(MachineState *machine)
/* Initial PC is always at offset 4 in firmware binaries */
ptr = rom_ptr(0x01000004, 4);
g_assert(ptr != NULL);
- env->pc = ldl_p(ptr);
+ env->pc = ldl_be_p(ptr);
if (env->pc >= 0x01020000) {
error_report("'%s' does not seem to be a valid firmware image.",
bios_name);
@@ -1044,21 +1342,13 @@ static void next_cube_init(MachineState *machine)
}
}
- /* Serial */
- next_escc_init(pcdev);
-
- /* TODO: */
- /* Network */
- /* SCSI */
- next_scsi_init(pcdev, cpu);
-
/* DMA */
memory_region_init_io(&m->dmamem, NULL, &next_dma_ops, machine,
"next.dma", 0x5000);
memory_region_add_subregion(sysmem, 0x02000000, &m->dmamem);
}
-static void next_machine_class_init(ObjectClass *oc, void *data)
+static void next_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1068,6 +1358,7 @@ static void next_machine_class_init(ObjectClass *oc, void *data)
mc->default_ram_size = RAM_SIZE;
mc->default_ram_id = "next.ram";
mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
+ mc->no_cdrom = true;
}
static const TypeInfo next_typeinfo = {
@@ -1081,6 +1372,8 @@ static void next_register_type(void)
{
type_register_static(&next_typeinfo);
type_register_static(&next_pc_info);
+ type_register_static(&next_scsi_info);
+ type_register_static(&next_rtc_info);
}
type_init(next_register_type)
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index 0c348c1..2bec945 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -68,7 +68,6 @@ struct NextKBDState {
uint16_t shift;
};
-static void queue_code(void *opaque, int code);
/* lots of magic numbers here */
static uint32_t kbd_read_byte(void *opaque, hwaddr addr)
@@ -163,71 +162,73 @@ static const MemoryRegionOps kbd_ops = {
.write = kbd_writefn,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
};
-static void nextkbd_event(void *opaque, int ch)
-{
- /*
- * Will want to set vars for caps/num lock
- * if (ch & 0x80) -> key release
- * there's also e0 escaped scancodes that might need to be handled
- */
- queue_code(opaque, ch);
-}
-
-static const unsigned char next_keycodes[128] = {
- 0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F,
- 0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00,
- 0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06,
- 0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A,
- 0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C,
- 0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
- 0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00,
- 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+static const int qcode_to_nextkbd_keycode[] = {
+ [Q_KEY_CODE_ESC] = 0x49,
+ [Q_KEY_CODE_1] = 0x4a,
+ [Q_KEY_CODE_2] = 0x4b,
+ [Q_KEY_CODE_3] = 0x4c,
+ [Q_KEY_CODE_4] = 0x4d,
+ [Q_KEY_CODE_5] = 0x50,
+ [Q_KEY_CODE_6] = 0x4f,
+ [Q_KEY_CODE_7] = 0x4e,
+ [Q_KEY_CODE_8] = 0x1e,
+ [Q_KEY_CODE_9] = 0x1f,
+ [Q_KEY_CODE_0] = 0x20,
+ [Q_KEY_CODE_MINUS] = 0x1d,
+ [Q_KEY_CODE_EQUAL] = 0x1c,
+ [Q_KEY_CODE_BACKSPACE] = 0x1b,
+
+ [Q_KEY_CODE_Q] = 0x42,
+ [Q_KEY_CODE_W] = 0x43,
+ [Q_KEY_CODE_E] = 0x44,
+ [Q_KEY_CODE_R] = 0x45,
+ [Q_KEY_CODE_T] = 0x48,
+ [Q_KEY_CODE_Y] = 0x47,
+ [Q_KEY_CODE_U] = 0x46,
+ [Q_KEY_CODE_I] = 0x06,
+ [Q_KEY_CODE_O] = 0x07,
+ [Q_KEY_CODE_P] = 0x08,
+ [Q_KEY_CODE_RET] = 0x2a,
+ [Q_KEY_CODE_A] = 0x39,
+ [Q_KEY_CODE_S] = 0x3a,
+
+ [Q_KEY_CODE_D] = 0x3b,
+ [Q_KEY_CODE_F] = 0x3c,
+ [Q_KEY_CODE_G] = 0x3d,
+ [Q_KEY_CODE_H] = 0x40,
+ [Q_KEY_CODE_J] = 0x3f,
+ [Q_KEY_CODE_K] = 0x3e,
+ [Q_KEY_CODE_L] = 0x2d,
+ [Q_KEY_CODE_SEMICOLON] = 0x2c,
+ [Q_KEY_CODE_APOSTROPHE] = 0x2b,
+ [Q_KEY_CODE_GRAVE_ACCENT] = 0x26,
+ [Q_KEY_CODE_Z] = 0x31,
+ [Q_KEY_CODE_X] = 0x32,
+ [Q_KEY_CODE_C] = 0x33,
+ [Q_KEY_CODE_V] = 0x34,
+
+ [Q_KEY_CODE_B] = 0x35,
+ [Q_KEY_CODE_N] = 0x37,
+ [Q_KEY_CODE_M] = 0x36,
+ [Q_KEY_CODE_COMMA] = 0x2e,
+ [Q_KEY_CODE_DOT] = 0x2f,
+ [Q_KEY_CODE_SLASH] = 0x30,
+
+ [Q_KEY_CODE_SPC] = 0x38,
};
-static void queue_code(void *opaque, int code)
+static void nextkbd_put_keycode(NextKBDState *s, int keycode)
{
- NextKBDState *s = NEXTKBD(opaque);
KBDQueue *q = &s->queue;
- int key = code & KD_KEYMASK;
- int release = code & 0x80;
- static int ext;
-
- if (code == 0xE0) {
- ext = 1;
- }
-
- if (code == 0x2A || code == 0x1D || code == 0x36) {
- if (code == 0x2A) {
- s->shift = KD_LSHIFT;
- } else if (code == 0x36) {
- s->shift = KD_RSHIFT;
- ext = 0;
- } else if (code == 0x1D && !ext) {
- s->shift = KD_LCOMM;
- } else if (code == 0x1D && ext) {
- ext = 0;
- s->shift = KD_RCOMM;
- }
- return;
- } else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) ||
- code == (0x36 | 0x80)) {
- s->shift = 0;
- return;
- }
if (q->count >= KBD_QUEUE_SIZE) {
return;
}
- q->data[q->wptr] = next_keycodes[key] | release;
-
+ q->data[q->wptr] = keycode;
if (++q->wptr == KBD_QUEUE_SIZE) {
q->wptr = 0;
}
@@ -241,6 +242,53 @@ static void queue_code(void *opaque, int code)
/* s->update_irq(s->update_arg, 1); */
}
+static void nextkbd_event(DeviceState *dev, QemuConsole *src, InputEvent *evt)
+{
+ NextKBDState *s = NEXTKBD(dev);
+ int qcode, keycode;
+ bool key_down = evt->u.key.data->down;
+
+ qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key);
+ if (qcode >= ARRAY_SIZE(qcode_to_nextkbd_keycode)) {
+ return;
+ }
+
+ /* Shift key currently has no keycode, so handle separately */
+ if (qcode == Q_KEY_CODE_SHIFT) {
+ if (key_down) {
+ s->shift |= KD_LSHIFT;
+ } else {
+ s->shift &= ~KD_LSHIFT;
+ }
+ }
+
+ if (qcode == Q_KEY_CODE_SHIFT_R) {
+ if (key_down) {
+ s->shift |= KD_RSHIFT;
+ } else {
+ s->shift &= ~KD_RSHIFT;
+ }
+ }
+
+ keycode = qcode_to_nextkbd_keycode[qcode];
+ if (!keycode) {
+ return;
+ }
+
+ /* If key release event, create keyboard break code */
+ if (!key_down) {
+ keycode |= 0x80;
+ }
+
+ nextkbd_put_keycode(s, keycode);
+}
+
+static const QemuInputHandler nextkbd_handler = {
+ .name = "QEMU NeXT Keyboard",
+ .mask = INPUT_EVENT_MASK_KEY,
+ .event = nextkbd_event,
+};
+
static void nextkbd_reset(DeviceState *dev)
{
NextKBDState *nks = NEXTKBD(dev);
@@ -256,7 +304,7 @@ static void nextkbd_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
- qemu_add_kbd_event_handler(nextkbd_event, s);
+ qemu_input_handler_register(dev, &nextkbd_handler);
}
static const VMStateDescription nextkbd_vmstate = {
@@ -264,14 +312,14 @@ static const VMStateDescription nextkbd_vmstate = {
.unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */
};
-static void nextkbd_class_init(ObjectClass *oc, void *data)
+static void nextkbd_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->vmsd = &nextkbd_vmstate;
dc->realize = nextkbd_realize;
- dc->reset = nextkbd_reset;
+ device_class_set_legacy_reset(dc, nextkbd_reset);
}
static const TypeInfo nextkbd_info = {
diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c
index e2ae7c3..36de67c 100644
--- a/hw/m68k/q800-glue.c
+++ b/hw/m68k/q800-glue.c
@@ -203,9 +203,8 @@ static const VMStateDescription vmstate_glue = {
* this cpu link property and could instead provide outbound IRQ lines
* that the board could wire up to the CPU.
*/
-static Property glue_properties[] = {
+static const Property glue_properties[] = {
DEFINE_PROP_LINK("cpu", GLUEState, cpu, TYPE_M68K_CPU, M68kCPU *),
- DEFINE_PROP_END_OF_LIST(),
};
static void glue_finalize(Object *obj)
@@ -229,7 +228,7 @@ static void glue_init(Object *obj)
s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s);
}
-static void glue_class_init(ObjectClass *klass, void *data)
+static void glue_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -249,7 +248,7 @@ static const TypeInfo glue_info_types[] = {
.instance_init = glue_init,
.instance_finalize = glue_finalize,
.class_init = glue_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NMI },
{ }
},
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index fa7683b..793b23f 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -24,7 +24,8 @@
#include "qemu/units.h"
#include "qemu/datadir.h"
#include "qemu/guest-random.h"
-#include "sysemu/sysemu.h"
+#include "exec/target_page.h"
+#include "system/system.h"
#include "cpu.h"
#include "hw/boards.h"
#include "hw/or-irq.h"
@@ -51,9 +52,9 @@
#include "net/util.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
-#include "sysemu/runstate.h"
-#include "sysemu/reset.h"
+#include "system/qtest.h"
+#include "system/runstate.h"
+#include "system/reset.h"
#include "migration/vmstate.h"
#define MACROM_ADDR 0x40800000
@@ -210,7 +211,6 @@ static uint64_t machine_id_read(void *opaque, hwaddr addr, unsigned size)
static void machine_id_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
- return;
}
static const MemoryRegionOps machine_id_ops = {
@@ -231,7 +231,6 @@ static uint64_t ramio_read(void *opaque, hwaddr addr, unsigned size)
static void ramio_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
- return;
}
static const MemoryRegionOps ramio_ops = {
@@ -585,7 +584,7 @@ static void q800_machine_init(MachineState *machine)
}
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
- &elf_entry, NULL, &high, NULL, 1,
+ &elf_entry, NULL, &high, NULL, ELFDATA2MSB,
EM_68K, 0, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s'", kernel_filename);
@@ -684,9 +683,9 @@ static void q800_machine_init(MachineState *machine)
ptr = rom_ptr(MACROM_ADDR, bios_size);
assert(ptr != NULL);
- stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */
+ stl_phys(cs->as, 0, ldl_be_p(ptr)); /* reset initial SP */
stl_phys(cs->as, 4,
- MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */
+ MACROM_ADDR + ldl_be_p(ptr + 4)); /* reset initial PC */
}
}
}
@@ -728,7 +727,7 @@ static GlobalProperty hw_compat_q800[] = {
};
static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800);
-static void q800_machine_class_init(ObjectClass *oc, void *data)
+static void q800_machine_class_init(ObjectClass *oc, const void *data)
{
static const char * const valid_cpu_types[] = {
M68K_CPU_TYPE_NAME("m68040"),
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
index cda199a..875fd00 100644
--- a/hw/m68k/virt.c
+++ b/hw/m68k/virt.c
@@ -10,7 +10,8 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/guest-random.h"
-#include "sysemu/sysemu.h"
+#include "exec/target_page.h"
+#include "system/system.h"
#include "cpu.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
@@ -24,9 +25,9 @@
#include "net/net.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
-#include "sysemu/runstate.h"
-#include "sysemu/reset.h"
+#include "system/qtest.h"
+#include "system/runstate.h"
+#include "system/reset.h"
#include "hw/intc/m68k_irqc.h"
#include "hw/misc/virt_ctrl.h"
@@ -228,7 +229,7 @@ static void virt_init(MachineState *machine)
}
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
- &elf_entry, NULL, &high, NULL, 1,
+ &elf_entry, NULL, &high, NULL, ELFDATA2MSB,
EM_68K, 0, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s'", kernel_filename);
@@ -309,7 +310,7 @@ static void virt_init(MachineState *machine)
}
}
-static void virt_machine_class_init(ObjectClass *oc, void *data)
+static void virt_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "QEMU M68K Virtual Machine";
@@ -338,7 +339,7 @@ type_init(virt_machine_register_types)
#define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \
static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \
ObjectClass *oc, \
- void *data) \
+ const void *data) \
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
@@ -366,10 +367,31 @@ type_init(virt_machine_register_types)
#define DEFINE_VIRT_MACHINE(major, minor) \
DEFINE_VIRT_MACHINE_IMPL(false, major, minor)
+static void virt_machine_10_1_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(10, 1)
+
+static void virt_machine_10_0_options(MachineClass *mc)
+{
+ virt_machine_10_1_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len);
+}
+DEFINE_VIRT_MACHINE(10, 0)
+
+static void virt_machine_9_2_options(MachineClass *mc)
+{
+ virt_machine_10_0_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_2, hw_compat_9_2_len);
+}
+DEFINE_VIRT_MACHINE(9, 2)
+
static void virt_machine_9_1_options(MachineClass *mc)
{
+ virt_machine_9_2_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
+DEFINE_VIRT_MACHINE(9, 1)
static void virt_machine_9_0_options(MachineClass *mc)
{
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index d648192..94e7274 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -17,6 +17,7 @@
#include "hw/mem/pc-dimm.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -24,11 +25,19 @@
#include "qemu/range.h"
#include "qemu/rcu.h"
#include "qemu/guest-random.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/numa.h"
+#include "system/hostmem.h"
+#include "system/numa.h"
#include "hw/cxl/cxl.h"
#include "hw/pci/msix.h"
+/* type3 device private */
+enum CXL_T3_MSIX_VECTOR {
+ CXL_T3_MSIX_PCIE_DOE_TABLE_ACCESS = 0,
+ CXL_T3_MSIX_EVENT_START = 2,
+ CXL_T3_MSIX_MBOX = CXL_T3_MSIX_EVENT_START + CXL_EVENT_TYPE_MAX,
+ CXL_T3_MSIX_VECTOR_NR
+};
+
#define DWORD_BYTE 4
#define CXL_CAPACITY_MULTIPLIER (256 * MiB)
@@ -834,6 +843,19 @@ static DOEProtocol doe_cdat_prot[] = {
{ }
};
+/* Initialize CXL device alerts with default threshold values. */
+static void init_alert_config(CXLType3Dev *ct3d)
+{
+ ct3d->alert_config = (CXLAlertConfig) {
+ .life_used_crit_alert_thresh = 75,
+ .life_used_warn_thresh = 40,
+ .over_temp_crit_alert_thresh = 35,
+ .under_temp_crit_alert_thresh = 10,
+ .over_temp_warn_thresh = 25,
+ .under_temp_warn_thresh = 20
+ };
+}
+
static void ct3_realize(PCIDevice *pci_dev, Error **errp)
{
ERRP_GUARD();
@@ -842,7 +864,6 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
ComponentRegisters *regs = &cxl_cstate->crb;
MemoryRegion *mr = &regs->component_registers;
uint8_t *pci_conf = pci_dev->config;
- unsigned short msix_num = 6;
int i, rc;
uint16_t count;
@@ -883,31 +904,33 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
&ct3d->cxl_dstate.device_registers);
/* MSI(-X) Initialization */
- rc = msix_init_exclusive_bar(pci_dev, msix_num, 4, NULL);
+ rc = msix_init_exclusive_bar(pci_dev, CXL_T3_MSIX_VECTOR_NR, 4, errp);
if (rc) {
- goto err_address_space_free;
+ goto err_free_special_ops;
}
- for (i = 0; i < msix_num; i++) {
+ for (i = 0; i < CXL_T3_MSIX_VECTOR_NR; i++) {
msix_vector_use(pci_dev, i);
}
/* DOE Initialization */
- pcie_doe_init(pci_dev, &ct3d->doe_cdat, 0x190, doe_cdat_prot, true, 0);
+ pcie_doe_init(pci_dev, &ct3d->doe_cdat, 0x190, doe_cdat_prot, true,
+ CXL_T3_MSIX_PCIE_DOE_TABLE_ACCESS);
cxl_cstate->cdat.build_cdat_table = ct3_build_cdat_table;
cxl_cstate->cdat.free_cdat_table = ct3_free_cdat_table;
cxl_cstate->cdat.private = ct3d;
if (!cxl_doe_cdat_init(cxl_cstate, errp)) {
- goto err_free_special_ops;
+ goto err_msix_uninit;
}
+ init_alert_config(ct3d);
pcie_cap_deverr_init(pci_dev);
/* Leave a bit of room for expansion */
- rc = pcie_aer_init(pci_dev, PCI_ERR_VER, 0x200, PCI_ERR_SIZEOF, NULL);
+ rc = pcie_aer_init(pci_dev, PCI_ERR_VER, 0x200, PCI_ERR_SIZEOF, errp);
if (rc) {
goto err_release_cdat;
}
- cxl_event_init(&ct3d->cxl_dstate, 2);
+ cxl_event_init(&ct3d->cxl_dstate, CXL_T3_MSIX_EVENT_START);
/* Set default value for patrol scrub attributes */
ct3d->patrol_scrub_attrs.scrub_cycle_cap =
@@ -919,25 +942,25 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
ct3d->patrol_scrub_attrs.scrub_flags = CXL_MEMDEV_PS_ENABLE_DEFAULT;
/* Set default value for DDR5 ECS read attributes */
+ ct3d->ecs_attrs.ecs_log_cap = CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
- ct3d->ecs_attrs[count].ecs_log_cap =
- CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
- ct3d->ecs_attrs[count].ecs_cap =
+ ct3d->ecs_attrs.fru_attrs[count].ecs_cap =
CXL_ECS_REALTIME_REPORT_CAP_DEFAULT;
- ct3d->ecs_attrs[count].ecs_config =
+ ct3d->ecs_attrs.fru_attrs[count].ecs_config =
CXL_ECS_THRESHOLD_COUNT_DEFAULT |
(CXL_ECS_MODE_DEFAULT << 3);
/* Reserved */
- ct3d->ecs_attrs[count].ecs_flags = 0;
+ ct3d->ecs_attrs.fru_attrs[count].ecs_flags = 0;
}
return;
err_release_cdat:
cxl_doe_cdat_release(cxl_cstate);
+err_msix_uninit:
+ msix_uninit_exclusive_bar(pci_dev);
err_free_special_ops:
g_free(regs->special_ops);
-err_address_space_free:
if (ct3d->dc.host_dc) {
cxl_destroy_dc_regions(ct3d);
address_space_destroy(&ct3d->dc.host_dc_as);
@@ -948,7 +971,6 @@ err_address_space_free:
if (ct3d->hostvmem) {
address_space_destroy(&ct3d->hostvmem_as);
}
- return;
}
static void ct3_exit(PCIDevice *pci_dev)
@@ -959,7 +981,9 @@ static void ct3_exit(PCIDevice *pci_dev)
pcie_aer_exit(pci_dev);
cxl_doe_cdat_release(cxl_cstate);
+ msix_uninit_exclusive_bar(pci_dev);
g_free(regs->special_ops);
+ cxl_destroy_cci(&ct3d->cci);
if (ct3d->dc.host_dc) {
cxl_destroy_dc_regions(ct3d);
address_space_destroy(&ct3d->dc.host_dc_as);
@@ -1090,10 +1114,17 @@ static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa)
continue;
}
- *dpa = dpa_base +
- ((MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) |
- ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset)
- >> iw));
+ if (iw < 8) {
+ *dpa = dpa_base +
+ ((MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) |
+ ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset)
+ >> iw));
+ } else {
+ *dpa = dpa_base +
+ ((MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) |
+ ((((MAKE_64BIT_MASK(ig + iw, 64 - ig - iw) & hpa_offset)
+ >> (ig + iw)) / 3) << (ig + 8)));
+ }
return true;
}
@@ -1200,22 +1231,28 @@ static void ct3d_reset(DeviceState *dev)
uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask;
+ pcie_cap_fill_link_ep_usp(PCI_DEVICE(dev), ct3d->width, ct3d->speed);
cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE);
- cxl_device_register_init_t3(ct3d);
+ cxl_device_register_init_t3(ct3d, CXL_T3_MSIX_MBOX);
/*
* Bring up an endpoint to target with MCTP over VDM.
* This device is emulating an MLD with single LD for now.
*/
+ if (ct3d->vdm_fm_owned_ld_mctp_cci.initialized) {
+ cxl_destroy_cci(&ct3d->vdm_fm_owned_ld_mctp_cci);
+ }
cxl_initialize_t3_fm_owned_ld_mctpcci(&ct3d->vdm_fm_owned_ld_mctp_cci,
DEVICE(ct3d), DEVICE(ct3d),
512); /* Max payload made up */
+ if (ct3d->ld0_cci.initialized) {
+ cxl_destroy_cci(&ct3d->ld0_cci);
+ }
cxl_initialize_t3_ld_cci(&ct3d->ld0_cci, DEVICE(ct3d), DEVICE(ct3d),
512); /* Max payload made up */
-
}
-static Property ct3_props[] = {
+static const Property ct3_props[] = {
DEFINE_PROP_LINK("memdev", CXLType3Dev, hostmem, TYPE_MEMORY_BACKEND,
HostMemoryBackend *), /* for backward compatibility */
DEFINE_PROP_LINK("persistent-memdev", CXLType3Dev, hostpmem,
@@ -1229,7 +1266,10 @@ static Property ct3_props[] = {
DEFINE_PROP_UINT8("num-dc-regions", CXLType3Dev, dc.num_regions, 0),
DEFINE_PROP_LINK("volatile-dc-memdev", CXLType3Dev, dc.host_dc,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLType3Dev,
+ speed, PCIE_LINK_SPEED_32),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLType3Dev,
+ width, PCIE_LINK_WIDTH_16),
};
static uint64_t get_lsa_size(CXLType3Dev *ct3d)
@@ -1375,9 +1415,7 @@ void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
ct3d = CXL_TYPE3(obj);
QLIST_FOREACH(p, &ct3d->poison_list, node) {
- if (((start >= p->start) && (start < p->start + p->length)) ||
- ((start + length > p->start) &&
- (start + length <= p->start + p->length))) {
+ if ((start < p->start + p->length) && (start + length > p->start)) {
error_setg(errp,
"Overlap with existing poisoned region not supported");
return;
@@ -1492,8 +1530,6 @@ void qmp_cxl_inject_uncorrectable_errors(const char *path,
stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, unc_err);
pcie_aer_inject_error(PCI_DEVICE(obj), &err);
-
- return;
}
void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type,
@@ -1769,7 +1805,6 @@ void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags,
if (cxl_event_insert(cxlds, enc_log, (CXLEventRecordRaw *)&dram)) {
cxl_event_irq_assert(ct3d);
}
- return;
}
void qmp_cxl_inject_memory_module_event(const char *path, CxlEventLog log,
@@ -2060,11 +2095,11 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
stw_le_p(&dCap.host_id, hid);
/* only valid for DC_REGION_CONFIG_UPDATED event */
dCap.updated_region_id = 0;
- dCap.flags = 0;
for (i = 0; i < num_extents; i++) {
memcpy(&dCap.dynamic_capacity_extent, &extents[i],
sizeof(CXLDCExtentRaw));
+ dCap.flags = 0;
if (i < num_extents - 1) {
/* Set "More" flag */
dCap.flags |= BIT(0);
@@ -2126,7 +2161,7 @@ void qmp_cxl_release_dynamic_capacity(const char *path, uint16_t host_id,
}
}
-static void ct3_class_init(ObjectClass *oc, void *data)
+static void ct3_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
@@ -2144,7 +2179,7 @@ static void ct3_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = "CXL Memory Device (Type 3)";
- dc->reset = ct3d_reset;
+ device_class_set_legacy_reset(dc, ct3d_reset);
device_class_set_props(dc, ct3_props);
cvc->get_lsa_size = get_lsa_size;
@@ -2159,7 +2194,7 @@ static const TypeInfo ct3d_info = {
.class_size = sizeof(struct CXLType3Class),
.class_init = ct3_class_init,
.instance_size = sizeof(CXLType3Dev),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CXL_DEVICE },
{ INTERFACE_PCIE_DEVICE },
{}
diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c
index a5f279a..1a432e9 100644
--- a/hw/mem/memory-device.c
+++ b/hw/mem/memory-device.c
@@ -16,8 +16,8 @@
#include "hw/boards.h"
#include "qemu/range.h"
#include "hw/virtio/vhost.h"
-#include "sysemu/kvm.h"
-#include "exec/address-spaces.h"
+#include "system/kvm.h"
+#include "system/address-spaces.h"
#include "trace.h"
static bool memory_device_is_empty(const MemoryDeviceState *md)
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
index abc5af5..07fc108 100644
--- a/hw/mem/npcm7xx_mc.c
+++ b/hw/mem/npcm7xx_mc.c
@@ -65,7 +65,7 @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
}
-static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_mc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 1631a7d..23ab143e 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -30,7 +30,7 @@
#include "hw/mem/nvdimm.h"
#include "hw/qdev-properties.h"
#include "hw/mem/memory-device.h"
-#include "sysemu/hostmem.h"
+#include "system/hostmem.h"
static void nvdimm_get_label_size(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
@@ -246,12 +246,11 @@ static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf,
memory_region_set_dirty(mr, backend_offset, size);
}
-static Property nvdimm_properties[] = {
+static const Property nvdimm_properties[] = {
DEFINE_PROP_BOOL(NVDIMM_UNARMED_PROP, NVDIMMDevice, unarmed, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nvdimm_class_init(ObjectClass *oc, void *data)
+static void nvdimm_class_init(ObjectClass *oc, const void *data)
{
PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc);
MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 27919ca..f701d5b 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -28,8 +28,8 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/module.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/numa.h"
+#include "system/hostmem.h"
+#include "system/numa.h"
#include "trace.h"
static int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp);
@@ -150,14 +150,13 @@ out:
return slot;
}
-static Property pc_dimm_properties[] = {
+static const Property pc_dimm_properties[] = {
DEFINE_PROP_UINT64(PC_DIMM_ADDR_PROP, PCDIMMDevice, addr, 0),
DEFINE_PROP_UINT32(PC_DIMM_NODE_PROP, PCDIMMDevice, node, 0),
DEFINE_PROP_INT32(PC_DIMM_SLOT_PROP, PCDIMMDevice, slot,
PC_DIMM_UNASSIGNED_SLOT),
DEFINE_PROP_LINK(PC_DIMM_MEMDEV_PROP, PCDIMMDevice, hostmem,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
- DEFINE_PROP_END_OF_LIST(),
};
static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
@@ -277,7 +276,7 @@ static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md,
}
}
-static void pc_dimm_class_init(ObjectClass *oc, void *data)
+static void pc_dimm_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
@@ -302,7 +301,7 @@ static const TypeInfo pc_dimm_info = {
.instance_init = pc_dimm_init,
.class_init = pc_dimm_class_init,
.class_size = sizeof(PCDIMMDeviceClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_MEMORY_DEVICE },
{ }
},
diff --git a/hw/mem/sparse-mem.c b/hw/mem/sparse-mem.c
index 6e8f4f8..d7b00e5 100644
--- a/hw/mem/sparse-mem.c
+++ b/hw/mem/sparse-mem.c
@@ -17,7 +17,7 @@
#include "hw/sysbus.h"
#include "qapi/error.h"
#include "qemu/units.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#include "hw/mem/sparse-mem.h"
#define SPARSE_MEM(obj) OBJECT_CHECK(SparseMemState, (obj), TYPE_SPARSE_MEM)
@@ -82,7 +82,6 @@ static void sparse_mem_enter_reset(Object *obj, ResetType type)
{
SparseMemState *s = SPARSE_MEM(obj);
g_hash_table_remove_all(s->mapped);
- return;
}
static const MemoryRegionOps sparse_mem_ops = {
@@ -96,14 +95,13 @@ static const MemoryRegionOps sparse_mem_ops = {
},
};
-static Property sparse_mem_properties[] = {
+static const Property sparse_mem_properties[] = {
/* The base address of the memory */
DEFINE_PROP_UINT64("baseaddr", SparseMemState, baseaddr, 0x0),
/* The length of the sparse memory region */
DEFINE_PROP_UINT64("length", SparseMemState, length, UINT64_MAX),
/* Max amount of actual memory that can be used to back the sparse memory */
DEFINE_PROP_UINT64("maxsize", SparseMemState, maxsize, 10 * MiB),
- DEFINE_PROP_END_OF_LIST(),
};
MemoryRegion *sparse_mem_init(uint64_t addr, uint64_t length)
@@ -138,7 +136,7 @@ static void sparse_mem_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->mmio);
}
-static void sparse_mem_class_init(ObjectClass *klass, void *data)
+static void sparse_mem_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/meson.build b/hw/meson.build
index 1c6308f..791ce21 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -27,7 +27,6 @@ subdir('nvram')
subdir('pci')
subdir('pci-bridge')
subdir('pci-host')
-subdir('pcmcia')
subdir('rtc')
subdir('scsi')
subdir('sd')
@@ -36,10 +35,13 @@ subdir('smbios')
subdir('ssi')
subdir('timer')
subdir('tpm')
+subdir('uefi')
subdir('ufs')
subdir('usb')
subdir('vfio')
+subdir('vfio-user')
subdir('virtio')
+subdir('vmapple')
subdir('watchdog')
subdir('xen')
subdir('xenpv')
@@ -48,7 +50,6 @@ subdir('fsi')
subdir('alpha')
subdir('arm')
subdir('avr')
-subdir('cris')
subdir('hppa')
subdir('i386')
subdir('loongarch')
diff --git a/hw/microblaze/Kconfig b/hw/microblaze/Kconfig
index d78ba84..b0214b2 100644
--- a/hw/microblaze/Kconfig
+++ b/hw/microblaze/Kconfig
@@ -13,7 +13,7 @@ config PETALOGIX_ML605
default y
depends on MICROBLAZE
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select SSI_M25P80
select XILINX
select XILINX_AXI
diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c
index ed61e48..4a9c9df 100644
--- a/hw/microblaze/boot.c
+++ b/hw/microblaze/boot.c
@@ -31,8 +31,8 @@
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "qemu/guest-random.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/reset.h"
+#include "system/device_tree.h"
+#include "system/reset.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "elf.h"
@@ -114,8 +114,8 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
return addr - 0x30000000LL;
}
-void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
- uint32_t ramsize,
+void microblaze_load_kernel(MicroBlazeCPU *cpu, bool is_little_endian,
+ hwaddr ddr_base, uint32_t ramsize,
const char *initrd_filename,
const char *dtb_filename,
void (*machine_cpu_reset)(MicroBlazeCPU *))
@@ -130,7 +130,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
dtb_arg = current_machine->dtb;
/* default to pcbios dtb as passed by machine_init */
if (!dtb_arg && dtb_filename) {
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
+ filename = qemu_find_file(QEMU_FILE_TYPE_DTB, dtb_filename);
}
boot_info.machine_cpu_reset = machine_cpu_reset;
@@ -144,13 +144,15 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
/* Boots a kernel elf binary. */
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
&entry, NULL, &high, NULL,
- TARGET_BIG_ENDIAN, EM_MICROBLAZE, 0, 0);
+ is_little_endian ? ELFDATA2LSB : ELFDATA2MSB,
+ EM_MICROBLAZE, 0, 0);
base32 = entry;
if (base32 == 0xc0000000) {
kernel_size = load_elf(kernel_filename, NULL,
translate_kernel_address, NULL,
&entry, NULL, NULL, NULL,
- TARGET_BIG_ENDIAN, EM_MICROBLAZE, 0, 0);
+ is_little_endian ? ELFDATA2LSB : ELFDATA2MSB,
+ EM_MICROBLAZE, 0, 0);
}
/* Always boot into physical ram. */
boot_info.bootstrap_pc = (uint32_t)entry;
diff --git a/hw/microblaze/boot.h b/hw/microblaze/boot.h
index 5a8c2f7..d179a55 100644
--- a/hw/microblaze/boot.h
+++ b/hw/microblaze/boot.h
@@ -2,8 +2,8 @@
#define MICROBLAZE_BOOT_H
-void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
- uint32_t ramsize,
+void microblaze_load_kernel(MicroBlazeCPU *cpu, bool is_little_endian,
+ hwaddr ddr_base, uint32_t ramsize,
const char *initrd_filename,
const char *dtb_filename,
void (*machine_cpu_reset)(MicroBlazeCPU *));
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index 0f5fabc..6e923c4 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -32,11 +32,11 @@
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/qdev-properties.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/ssi/ssi.h"
#include "boot.h"
@@ -90,7 +90,7 @@ petalogix_ml605_init(MachineState *machine)
object_property_set_int(OBJECT(cpu), "use-fpu", 1, &error_abort);
object_property_set_bool(OBJECT(cpu), "dcache-writeback", true,
&error_abort);
- object_property_set_bool(OBJECT(cpu), "endianness", true, &error_abort);
+ object_property_set_bool(OBJECT(cpu), "little-endian", true, &error_abort);
qdev_realize(DEVICE(cpu), NULL, &error_abort);
/* Attach emulated BRAM through the LMB. */
@@ -111,6 +111,7 @@ petalogix_ml605_init(MachineState *machine)
dev = qdev_new("xlnx.xps-intc");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
@@ -126,6 +127,7 @@ petalogix_ml605_init(MachineState *machine)
/* 2 timers at irq 2 @ 100 Mhz. */
dev = qdev_new("xlnx.xps-timer");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
qdev_prop_set_uint32(dev, "one-timer-only", 0);
qdev_prop_set_uint32(dev, "clock-frequency", 100 * 1000000);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -173,6 +175,7 @@ petalogix_ml605_init(MachineState *machine)
SSIBus *spi;
dev = qdev_new("xlnx.xps-spi");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
@@ -204,7 +207,7 @@ petalogix_ml605_init(MachineState *machine)
cpu->cfg.pvr_regs[5] = 0xc56be000;
cpu->cfg.pvr_regs[10] = 0x0e000000; /* virtex 6 */
- microblaze_load_kernel(cpu, MEMORY_BASEADDR, ram_size,
+ microblaze_load_kernel(cpu, true, MEMORY_BASEADDR, ram_size,
machine->initrd_filename,
BINARY_DEVICE_TREE_FILE,
NULL);
@@ -213,7 +216,7 @@ petalogix_ml605_init(MachineState *machine)
static void petalogix_ml605_machine_init(MachineClass *mc)
{
- mc->desc = "PetaLogix linux refdesign for xilinx ml605 little endian";
+ mc->desc = "PetaLogix linux refdesign for xilinx ml605 (little endian)";
mc->init = petalogix_ml605_init;
}
diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c
index dad46bd..e8d0ddf 100644
--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c
+++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c
@@ -30,10 +30,10 @@
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/misc/unimp.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/char/xilinx_uartlite.h"
#include "boot.h"
@@ -55,9 +55,23 @@
#define ETHLITE_IRQ 1
#define UARTLITE_IRQ 3
+#define TYPE_PETALOGIX_S3ADSP1800_MACHINE \
+ MACHINE_TYPE_NAME("petalogix-s3adsp1800")
+
+struct S3Adsp1800MachineState {
+ MachineState parent_class;
+
+ EndianMode endianness;
+};
+
+OBJECT_DECLARE_TYPE(S3Adsp1800MachineState, MachineClass,
+ PETALOGIX_S3ADSP1800_MACHINE)
+
+
static void
petalogix_s3adsp1800_init(MachineState *machine)
{
+ S3Adsp1800MachineState *psms = PETALOGIX_S3ADSP1800_MACHINE(machine);
ram_addr_t ram_size = machine->ram_size;
DeviceState *dev;
MicroBlazeCPU *cpu;
@@ -68,9 +82,12 @@ petalogix_s3adsp1800_init(MachineState *machine)
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
qemu_irq irq[32];
MemoryRegion *sysmem = get_system_memory();
+ EndianMode endianness = psms->endianness;
cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
object_property_set_str(OBJECT(cpu), "version", "7.10.d", &error_abort);
+ object_property_set_bool(OBJECT(cpu), "little-endian",
+ endianness == ENDIAN_MODE_LITTLE, &error_abort);
qdev_realize(DEVICE(cpu), NULL, &error_abort);
/* Attach emulated BRAM through the LMB. */
@@ -90,6 +107,7 @@ petalogix_s3adsp1800_init(MachineState *machine)
64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1);
dev = qdev_new("xlnx.xps-intc");
+ qdev_prop_set_enum(dev, "endianness", endianness);
qdev_prop_set_uint32(dev, "kind-of-intr",
1 << ETHLITE_IRQ | 1 << UARTLITE_IRQ);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -101,6 +119,7 @@ petalogix_s3adsp1800_init(MachineState *machine)
}
dev = qdev_new(TYPE_XILINX_UARTLITE);
+ qdev_prop_set_enum(dev, "endianness", endianness);
qdev_prop_set_chr(dev, "chardev", serial_hd(0));
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, UARTLITE_BASEADDR);
@@ -108,6 +127,7 @@ petalogix_s3adsp1800_init(MachineState *machine)
/* 2 timers at irq 2 @ 62 Mhz. */
dev = qdev_new("xlnx.xps-timer");
+ qdev_prop_set_enum(dev, "endianness", endianness);
qdev_prop_set_uint32(dev, "one-timer-only", 0);
qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -115,6 +135,7 @@ petalogix_s3adsp1800_init(MachineState *machine)
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
dev = qdev_new("xlnx.xps-ethernetlite");
+ qdev_prop_set_enum(dev, "endianness", endianness);
qemu_configure_nic_device(dev, true, NULL);
qdev_prop_set_uint32(dev, "tx-ping-pong", 0);
qdev_prop_set_uint32(dev, "rx-ping-pong", 0);
@@ -122,19 +143,52 @@ petalogix_s3adsp1800_init(MachineState *machine)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]);
- create_unimplemented_device("gpio", GPIO_BASEADDR, 0x10000);
+ create_unimplemented_device("xps_gpio", GPIO_BASEADDR, 0x10000);
- microblaze_load_kernel(cpu, ddr_base, ram_size,
- machine->initrd_filename,
+ microblaze_load_kernel(cpu, endianness == ENDIAN_MODE_LITTLE, ddr_base,
+ ram_size, machine->initrd_filename,
BINARY_DEVICE_TREE_FILE,
NULL);
}
-static void petalogix_s3adsp1800_machine_init(MachineClass *mc)
+static int machine_get_endianness(Object *obj, Error **errp G_GNUC_UNUSED)
+{
+ S3Adsp1800MachineState *ms = PETALOGIX_S3ADSP1800_MACHINE(obj);
+ return ms->endianness;
+}
+
+static void machine_set_endianness(Object *obj, int endianness, Error **errp)
+{
+ S3Adsp1800MachineState *ms = PETALOGIX_S3ADSP1800_MACHINE(obj);
+ ms->endianness = endianness;
+}
+
+static void petalogix_s3adsp1800_machine_class_init(ObjectClass *oc,
+ const void *data)
{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ ObjectProperty *prop;
+
mc->desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800";
mc->init = petalogix_s3adsp1800_init;
mc->is_default = true;
+
+ prop = object_class_property_add_enum(oc, "endianness", "EndianMode",
+ &EndianMode_lookup,
+ machine_get_endianness,
+ machine_set_endianness);
+ object_property_set_default_str(prop, TARGET_BIG_ENDIAN ? "big" : "little");
+ object_class_property_set_description(oc, "endianness",
+ "Defines whether the machine runs in big or little endian mode");
}
-DEFINE_MACHINE("petalogix-s3adsp1800", petalogix_s3adsp1800_machine_init)
+static const TypeInfo petalogix_s3adsp1800_machine_types[] = {
+ {
+ .name = TYPE_PETALOGIX_S3ADSP1800_MACHINE,
+ .parent = TYPE_MACHINE,
+ .class_init = petalogix_s3adsp1800_machine_class_init,
+ .instance_size = sizeof(S3Adsp1800MachineState),
+ },
+};
+
+DEFINE_TYPES(petalogix_s3adsp1800_machine_types)
diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c
index 1bfc964..e909802 100644
--- a/hw/microblaze/xlnx-zynqmp-pmu.c
+++ b/hw/microblaze/xlnx-zynqmp-pmu.c
@@ -17,7 +17,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/boards.h"
#include "cpu.h"
#include "boot.h"
@@ -90,7 +90,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp)
object_property_set_bool(OBJECT(&s->cpu), "use-pcmp-instr", true,
&error_abort);
object_property_set_bool(OBJECT(&s->cpu), "use-mmu", false, &error_abort);
- object_property_set_bool(OBJECT(&s->cpu), "endianness", true,
+ object_property_set_bool(OBJECT(&s->cpu), "little-endian", true,
&error_abort);
object_property_set_str(OBJECT(&s->cpu), "version", "8.40.b",
&error_abort);
@@ -121,7 +121,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp)
}
}
-static void xlnx_zynqmp_pmu_soc_class_init(ObjectClass *oc, void *data)
+static void xlnx_zynqmp_pmu_soc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -172,7 +172,7 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine)
qdev_realize(DEVICE(pmu), NULL, &error_fatal);
/* Load the kernel */
- microblaze_load_kernel(&pmu->cpu, XLNX_ZYNQMP_PMU_RAM_ADDR,
+ microblaze_load_kernel(&pmu->cpu, true, XLNX_ZYNQMP_PMU_RAM_ADDR,
machine->ram_size,
machine->initrd_filename,
machine->dtb,
@@ -181,9 +181,8 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine)
static void xlnx_zynqmp_pmu_machine_init(MachineClass *mc)
{
- mc->desc = "Xilinx ZynqMP PMU machine";
+ mc->desc = "Xilinx ZynqMP PMU machine (little endian)";
mc->init = xlnx_zynqmp_pmu_init;
}
DEFINE_MACHINE("xlnx-zynqmp-pmu", xlnx_zynqmp_pmu_machine_init)
-
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index 692bede..b09c89a 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -10,14 +10,14 @@ config MALTA
select MIPS_CPS
select PIIX
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select SMBUS_EEPROM
config MIPSSIM
bool
default y
depends on MIPS
- select SERIAL
+ select SERIAL_MM
select MIPSNET
config JAZZ
@@ -37,7 +37,7 @@ config JAZZ
select FDC_SYSBUS
select MC146818RTC
select PCKBD
- select SERIAL
+ select SERIAL_MM
select PARALLEL
select DS1225Y
select JAZZ_LED
@@ -65,7 +65,7 @@ config LOONGSON3V
imply VIRTIO_VGA
imply QXL if SPICE
imply USB_OHCI_PCI
- select SERIAL
+ select SERIAL_MM
select GOLDFISH_RTC
select LOONGSON_IPI
select LOONGSON_LIOINTC
@@ -89,7 +89,7 @@ config MIPS_BOSTON
select MIPS_CPS
select PCI_EXPRESS_XILINX
select AHCI_ICH9
- select SERIAL
+ select SERIAL_MM
config FW_CFG_MIPS
bool
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 1b44fb3..149a263 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -22,7 +22,7 @@
#include "elf.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/ide/pci.h"
#include "hw/ide/ahci-pci.h"
#include "hw/loader.h"
@@ -37,11 +37,11 @@
#include "qemu/guest-random.h"
#include "qemu/log.h"
#include "chardev/char.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/runstate.h"
-#include "sysemu/reset.h"
+#include "system/device_tree.h"
+#include "system/system.h"
+#include "system/qtest.h"
+#include "system/runstate.h"
+#include "system/reset.h"
#include <libfdt.h>
#include "qom/object.h"
@@ -220,7 +220,7 @@ static void boston_lcd_write(void *opaque, hwaddr addr,
static const MemoryRegionOps boston_lcd_ops = {
.read = boston_lcd_read,
.write = boston_lcd_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static uint64_t boston_platreg_read(void *opaque, hwaddr addr,
@@ -299,7 +299,7 @@ static void boston_platreg_write(void *opaque, hwaddr addr,
static const MemoryRegionOps boston_platreg_ops = {
.read = boston_platreg_read,
.write = boston_platreg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void mips_boston_instance_init(Object *obj)
@@ -358,8 +358,8 @@ static void gen_firmware(void *p, hwaddr kernel_entry, hwaddr fdt_addr)
kernel_entry);
}
-static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
- const void *match_data, hwaddr *load_addr)
+static void *boston_fdt_filter(void *opaque, const void *fdt_orig,
+ const void *match_data, hwaddr *load_addr)
{
BostonState *s = BOSTON(opaque);
MachineState *machine = s->mach;
@@ -395,7 +395,6 @@ static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
1, ram_high_sz);
fdt = g_realloc(fdt, fdt_totalsize(fdt));
- qemu_fdt_dumpdtb(fdt, fdt_sz);
s->fdt_base = *load_addr;
@@ -758,7 +757,7 @@ static void boston_mach_init(MachineState *machine)
s->uart = serial_mm_init(sys_mem, boston_memmap[BOSTON_UART].base, 2,
get_cps_irq(&s->cps, 3), 10000000,
- serial_hd(0), DEVICE_NATIVE_ENDIAN);
+ serial_hd(0), DEVICE_LITTLE_ENDIAN);
lcd = g_new(MemoryRegion, 1);
memory_region_init_io(lcd, NULL, &boston_lcd_ops, s, "boston-lcd", 0x8);
@@ -792,12 +791,12 @@ static void boston_mach_init(MachineState *machine)
kernel_size = load_elf(machine->kernel_filename, NULL,
cpu_mips_kseg0_to_phys, NULL,
&kernel_entry, NULL, &kernel_high,
- NULL, 0, EM_MIPS, 1, 0);
+ NULL, ELFDATA2LSB, EM_MIPS, 1, 0);
if (kernel_size > 0) {
int dt_size;
g_autofree const void *dtb_file_data = NULL;
- g_autofree const void *dtb_load_data = NULL;
+ void *dtb_load_data = NULL;
hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB);
hwaddr dtb_vaddr = cpu_mips_phys_to_kseg0(NULL, dtb_paddr);
@@ -810,6 +809,12 @@ static void boston_mach_init(MachineState *machine)
dtb_load_data = boston_fdt_filter(s, dtb_file_data,
NULL, &dtb_vaddr);
+ if (!dtb_load_data) {
+ /* boston_fdt_filter() already printed the error for us */
+ exit(1);
+ }
+
+ machine->fdt = dtb_load_data;
/* Calculate real fdt size after filter */
dt_size = fdt_totalsize(dtb_load_data);
@@ -818,7 +823,8 @@ static void boston_mach_init(MachineState *machine)
rom_ptr(dtb_paddr, dt_size));
} else {
/* Try to load file as FIT */
- fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s);
+ fit_err = load_fit(&boston_fit_loader, machine->kernel_filename,
+ &machine->fdt, s);
if (fit_err) {
error_report("unable to load kernel image");
exit(1);
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
index 07b73b0..2a3ba3f 100644
--- a/hw/mips/cps.c
+++ b/hw/mips/cps.c
@@ -24,8 +24,8 @@
#include "hw/mips/mips.h"
#include "hw/qdev-clock.h"
#include "hw/qdev-properties.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
+#include "system/kvm.h"
+#include "system/reset.h"
qemu_irq get_cps_irq(MIPSCPSState *s, int pin_number)
{
@@ -77,6 +77,9 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
MIPSCPU *cpu = MIPS_CPU(object_new(s->cpu_type));
CPUMIPSState *env = &cpu->env;
+ object_property_set_bool(OBJECT(cpu), "big-endian", s->cpu_is_bigendian,
+ &error_abort);
+
/* All VPs are halted on reset. Leave powering up to CPC. */
object_property_set_bool(OBJECT(cpu), "start-powered-off", true,
&error_abort);
@@ -163,14 +166,14 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0));
}
-static Property mips_cps_properties[] = {
+static const Property mips_cps_properties[] = {
DEFINE_PROP_UINT32("num-vp", MIPSCPSState, num_vp, 1),
DEFINE_PROP_UINT32("num-irq", MIPSCPSState, num_irq, 256),
DEFINE_PROP_STRING("cpu-type", MIPSCPSState, cpu_type),
- DEFINE_PROP_END_OF_LIST()
+ DEFINE_PROP_BOOL("cpu-big-endian", MIPSCPSState, cpu_is_bigendian, false),
};
-static void mips_cps_class_init(ObjectClass *klass, void *data)
+static void mips_cps_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c
index 6e4303b..2a8507b 100644
--- a/hw/mips/fuloong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -36,10 +36,11 @@
#include "hw/qdev-properties.h"
#include "elf.h"
#include "hw/isa/vt82c686.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
+#include "system/qtest.h"
+#include "system/reset.h"
+#include "system/system.h"
#include "qemu/error-report.h"
+#include "exec/tswap.h"
#define ENVP_PADDR 0x2000
#define ENVP_VADDR cpu_mips_phys_to_kseg0(NULL, ENVP_PADDR)
@@ -105,7 +106,7 @@ static uint64_t load_kernel(MIPSCPU *cpu)
cpu_mips_kseg0_to_phys, NULL,
&kernel_entry, NULL,
&kernel_high, NULL,
- 0, EM_MIPS, 1, 0);
+ ELFDATA2LSB, EM_MIPS, 1, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
loaderparams.kernel_filename,
@@ -229,7 +230,7 @@ static void mips_fuloong2e_init(MachineState *machine)
clock_set_hz(cpuclk, 533080000); /* ~533 MHz */
/* init CPUs */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk, false);
env = &cpu->env;
qemu_register_reset(main_cpu_reset, cpu);
@@ -333,7 +334,6 @@ static void mips_fuloong2e_machine_init(MachineClass *mc)
mc->default_cpu_type = MIPS_CPU_TYPE_NAME("Loongson-2E");
mc->default_ram_size = 256 * MiB;
mc->default_ram_id = "fuloong2e.ram";
- mc->minimum_page_bits = 14;
machine_add_audiodev_property(mc);
}
diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c
index 1bc17e6..7fb0b97 100644
--- a/hw/mips/jazz.c
+++ b/hw/mips/jazz.c
@@ -28,11 +28,11 @@
#include "hw/mips/mips.h"
#include "hw/intc/i8259.h"
#include "hw/dma/i8257.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/char/parallel.h"
#include "hw/isa/isa.h"
#include "hw/block/fdc.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "net/net.h"
#include "hw/scsi/esp.h"
@@ -44,13 +44,13 @@
#include "hw/audio/pcspk.h"
#include "hw/input/i8042.h"
#include "hw/sysbus.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
+#include "system/qtest.h"
+#include "system/reset.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/help_option.h"
#ifdef CONFIG_TCG
-#include "hw/core/tcg-cpu-ops.h"
+#include "accel/tcg/cpu-ops.h"
#endif /* CONFIG_TCG */
#include "cpu.h"
@@ -59,12 +59,6 @@ enum jazz_model_e {
JAZZ_PICA61,
};
-#if TARGET_BIG_ENDIAN
-#define BIOS_FILENAME "mips_bios.bin"
-#else
-#define BIOS_FILENAME "mipsel_bios.bin"
-#endif
-
static void main_cpu_reset(void *opaque)
{
MIPSCPU *cpu = opaque;
@@ -128,7 +122,7 @@ static void mips_jazz_init_net(IOMMUMemoryRegion *rc4030_dma_mr,
uint8_t *prom;
NICInfo *nd;
- nd = qemu_find_nic_info("dp8393x", true, "dp82932");
+ nd = qemu_find_nic_info("dp8393x", true, "dp83932");
if (!nd) {
return;
}
@@ -168,6 +162,8 @@ static void mips_jazz_init_net(IOMMUMemoryRegion *rc4030_dma_mr,
static void mips_jazz_init(MachineState *machine,
enum jazz_model_e jazz_model)
{
+ const char *bios_name = TARGET_BIG_ENDIAN ? "mips_bios.bin"
+ : "mipsel_bios.bin";
MemoryRegion *address_space = get_system_memory();
char *filename;
int bios_size, n;
@@ -212,7 +208,8 @@ static void mips_jazz_init(MachineState *machine,
* ext_clk[jazz_model].pll_mult);
/* init CPUs */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk,
+ TARGET_BIG_ENDIAN);
env = &cpu->env;
qemu_register_reset(main_cpu_reset, cpu);
@@ -244,7 +241,8 @@ static void mips_jazz_init(MachineState *machine,
memory_region_add_subregion(address_space, 0xfff00000LL, bios2);
/* load the BIOS image. */
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware ?: BIOS_FILENAME);
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
+ machine->firmware ?: bios_name);
if (filename) {
bios_size = load_image_targphys(filename, 0xfff00000LL,
MAGNUM_BIOS_SIZE);
@@ -414,7 +412,7 @@ void mips_pica61_init(MachineState *machine)
mips_jazz_init(machine, JAZZ_PICA61);
}
-static void mips_magnum_class_init(ObjectClass *oc, void *data)
+static void mips_magnum_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -431,7 +429,7 @@ static const TypeInfo mips_magnum_type = {
.class_init = mips_magnum_class_init,
};
-static void mips_pica61_class_init(ObjectClass *oc, void *data)
+static void mips_pica61_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/mips/loongson3_bootp.c b/hw/mips/loongson3_bootp.c
index b97b819..6781266 100644
--- a/hw/mips/loongson3_bootp.c
+++ b/hw/mips/loongson3_bootp.c
@@ -21,16 +21,17 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
-#include "cpu.h"
-#include "hw/boards.h"
+#include "qemu/bswap.h"
+#include "exec/hwaddr.h"
#include "hw/mips/loongson3_bootp.h"
-static void init_cpu_info(void *g_cpuinfo, uint64_t cpu_freq)
+static void init_cpu_info(void *g_cpuinfo, uint32_t cpu_count,
+ uint32_t processor_id, uint64_t cpu_freq)
{
struct efi_cpuinfo_loongson *c = g_cpuinfo;
c->cputype = cpu_to_le32(Loongson_3A);
- c->processor_id = cpu_to_le32(MIPS_CPU(first_cpu)->env.CP0_PRid);
+ c->processor_id = cpu_to_le32(processor_id);
if (cpu_freq > UINT_MAX) {
c->cpu_clock_freq = cpu_to_le32(UINT_MAX);
} else {
@@ -38,8 +39,8 @@ static void init_cpu_info(void *g_cpuinfo, uint64_t cpu_freq)
}
c->cpu_startup_core_id = cpu_to_le16(0);
- c->nr_cpus = cpu_to_le32(current_machine->smp.cpus);
- c->total_node = cpu_to_le32(DIV_ROUND_UP(current_machine->smp.cpus,
+ c->nr_cpus = cpu_to_le32(cpu_count);
+ c->total_node = cpu_to_le32(DIV_ROUND_UP(cpu_count,
LOONGSON3_CORE_PER_NODE));
}
@@ -110,9 +111,10 @@ static void init_special_info(void *g_special)
}
void init_loongson_params(struct loongson_params *lp, void *p,
+ uint32_t cpu_count, uint32_t processor_id,
uint64_t cpu_freq, uint64_t ram_size)
{
- init_cpu_info(p, cpu_freq);
+ init_cpu_info(p, cpu_count, processor_id, cpu_freq);
lp->cpu_offset = cpu_to_le64((uintptr_t)p - (uintptr_t)lp);
p += ROUND_UP(sizeof(struct efi_cpuinfo_loongson), 64);
diff --git a/hw/mips/loongson3_bootp.h b/hw/mips/loongson3_bootp.h
index 9091265..9dc325a 100644
--- a/hw/mips/loongson3_bootp.h
+++ b/hw/mips/loongson3_bootp.h
@@ -233,6 +233,7 @@ enum {
extern const MemMapEntry virt_memmap[];
void init_loongson_params(struct loongson_params *lp, void *p,
+ uint32_t cpu_count, uint32_t processor_id,
uint64_t cpu_freq, uint64_t ram_size);
void init_reset_system(struct efi_reset_system_t *reset);
diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
index 2067b4f..de6fbcc 100644
--- a/hw/mips/loongson3_virt.c
+++ b/hw/mips/loongson3_virt.c
@@ -29,7 +29,7 @@
#include "qemu/datadir.h"
#include "qapi/error.h"
#include "elf.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/intc/loongson_liointc.h"
#include "hw/mips/mips.h"
#include "hw/mips/fw_cfg.h"
@@ -45,10 +45,10 @@
#include "hw/pci-host/gpex.h"
#include "hw/usb.h"
#include "net/net.h"
-#include "sysemu/kvm.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/kvm.h"
+#include "system/qtest.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "qemu/error-report.h"
#define PM_CNTL_MODE 0x10
@@ -144,7 +144,7 @@ static void loongson3_pm_write(void *opaque, hwaddr addr,
static const MemoryRegionOps loongson3_pm_ops = {
.read = loongson3_pm_read,
.write = loongson3_pm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 1
@@ -153,7 +153,7 @@ static const MemoryRegionOps loongson3_pm_ops = {
#define DEF_LOONGSON3_FREQ (800 * 1000 * 1000)
-static uint64_t get_cpu_freq_hz(void)
+static uint64_t get_cpu_freq_hz(const MIPSCPU *cpu)
{
#ifdef CONFIG_KVM
int ret;
@@ -164,7 +164,7 @@ static uint64_t get_cpu_freq_hz(void)
};
if (kvm_enabled()) {
- ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_ONE_REG, &freq_reg);
if (ret >= 0) {
return freq * 2;
}
@@ -173,7 +173,7 @@ static uint64_t get_cpu_freq_hz(void)
return DEF_LOONGSON3_FREQ;
}
-static void init_boot_param(void)
+static void init_boot_param(unsigned cpu_count, uint32_t processor_id)
{
static void *p;
struct boot_params *bp;
@@ -184,7 +184,7 @@ static void init_boot_param(void)
bp->efi.smbios.vers = cpu_to_le16(1);
init_reset_system(&(bp->reset_system));
p += ROUND_UP(sizeof(struct boot_params), 64);
- init_loongson_params(&(bp->efi.smbios.lp), p,
+ init_loongson_params(&(bp->efi.smbios.lp), p, cpu_count, processor_id,
loaderparams.cpu_freq, loaderparams.ram_size);
rom_add_blob_fixed("params_rom", bp,
@@ -280,7 +280,7 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device,
fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
-static void fw_conf_init(unsigned long ram_size)
+static void fw_conf_init(void)
{
static const uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
FWCfgState *fw_cfg;
@@ -289,9 +289,9 @@ static void fw_conf_init(unsigned long ram_size)
fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
- fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+ fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, loaderparams.ram_size);
fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
- fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq_hz());
+ fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, loaderparams.cpu_freq);
fw_cfg_add_file(fw_cfg, "etc/system-states",
g_memdup2(suspend, sizeof(suspend)), sizeof(suspend));
@@ -358,7 +358,7 @@ static uint64_t load_kernel(CPUMIPSState *env)
cpu_mips_kseg0_to_phys, NULL,
&kernel_entry,
&kernel_low, &kernel_high,
- NULL, 0, EM_MIPS, 1, 0);
+ NULL, ELFDATA2LSB, EM_MIPS, 1, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
loaderparams.kernel_filename,
@@ -399,25 +399,33 @@ static uint64_t load_kernel(CPUMIPSState *env)
return kernel_entry;
}
-static void main_cpu_reset(void *opaque)
+static void generic_cpu_reset(void *opaque)
{
MIPSCPU *cpu = opaque;
CPUMIPSState *env = &cpu->env;
cpu_reset(CPU(cpu));
- /* Loongson-3 reset stuff */
if (loaderparams.kernel_filename) {
- if (cpu == MIPS_CPU(first_cpu)) {
- env->active_tc.gpr[4] = loaderparams.a0;
- env->active_tc.gpr[5] = loaderparams.a1;
- env->active_tc.gpr[6] = loaderparams.a2;
- env->active_tc.PC = loaderparams.kernel_entry;
- }
env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
}
}
+static void main_cpu_reset(void *opaque)
+{
+ generic_cpu_reset(opaque);
+
+ if (loaderparams.kernel_filename) {
+ MIPSCPU *cpu = opaque;
+ CPUMIPSState *env = &cpu->env;
+
+ env->active_tc.gpr[4] = loaderparams.a0;
+ env->active_tc.gpr[5] = loaderparams.a1;
+ env->active_tc.gpr[6] = loaderparams.a2;
+ env->active_tc.PC = loaderparams.kernel_entry;
+ }
+}
+
static inline void loongson3_virt_devices_init(MachineState *machine,
DeviceState *pic)
{
@@ -458,7 +466,7 @@ static inline void loongson3_virt_devices_init(MachineState *machine,
virt_memmap[VIRT_PCIE_PIO].base, s->pio_alias);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
@@ -484,9 +492,8 @@ static void mips_loongson3_virt_init(MachineState *machine)
{
int i;
long bios_size;
- MIPSCPU *cpu;
+ MIPSCPU *cpu = NULL;
Clock *cpuclk;
- CPUMIPSState *env;
DeviceState *liointc;
DeviceState *ipi = NULL;
char *filename;
@@ -553,7 +560,7 @@ static void mips_loongson3_virt_init(MachineState *machine)
serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0,
qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0),
- DEVICE_NATIVE_ENDIAN);
+ DEVICE_LITTLE_ENDIAN);
sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base,
qdev_get_gpio_in(liointc, RTC_IRQ));
@@ -561,18 +568,18 @@ static void mips_loongson3_virt_init(MachineState *machine)
cpuclk = clock_new(OBJECT(machine), "cpu-refclk");
clock_set_hz(cpuclk, DEF_LOONGSON3_FREQ);
- for (i = 0; i < machine->smp.cpus; i++) {
+ for (i = machine->smp.cpus - 1; i >= 0; --i) {
int node = i / LOONGSON3_CORE_PER_NODE;
int core = i % LOONGSON3_CORE_PER_NODE;
int ip;
/* init CPUs */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk, false);
/* Init internal devices */
cpu_mips_irq_init_cpu(cpu);
cpu_mips_clock_init(cpu);
- qemu_register_reset(main_cpu_reset, cpu);
+ qemu_register_reset(i ? generic_cpu_reset : main_cpu_reset, cpu);
if (!kvm_enabled()) {
hwaddr base = ((hwaddr)node << 44) + virt_memmap[VIRT_IPI].base;
@@ -601,7 +608,7 @@ static void mips_loongson3_virt_init(MachineState *machine)
pin, cpu->env.irq[ip + 2]);
}
}
- env = &MIPS_CPU(first_cpu)->env;
+ assert(cpu); /* This variable points to the first created cpu. */
/* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
memory_region_init_rom(bios, NULL, "loongson3.bios",
@@ -626,16 +633,16 @@ static void mips_loongson3_virt_init(MachineState *machine)
* Please use -L to set the BIOS path and -bios to set bios name.
*/
+ loaderparams.cpu_freq = get_cpu_freq_hz(cpu);
+ loaderparams.ram_size = ram_size;
if (kernel_filename) {
- loaderparams.cpu_freq = get_cpu_freq_hz();
- loaderparams.ram_size = ram_size;
loaderparams.kernel_filename = kernel_filename;
loaderparams.kernel_cmdline = kernel_cmdline;
loaderparams.initrd_filename = initrd_filename;
- loaderparams.kernel_entry = load_kernel(env);
+ loaderparams.kernel_entry = load_kernel(&cpu->env);
init_boot_rom();
- init_boot_param();
+ init_boot_param(machine->smp.cpus, cpu->env.CP0_PRid);
} else {
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
machine->firmware ?: LOONGSON3_BIOSNAME);
@@ -654,13 +661,13 @@ static void mips_loongson3_virt_init(MachineState *machine)
exit(1);
}
- fw_conf_init(ram_size);
+ fw_conf_init();
}
loongson3_virt_devices_init(machine, liointc);
}
-static void loongson3v_machine_class_init(ObjectClass *oc, void *data)
+static void loongson3v_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -670,7 +677,6 @@ static void loongson3v_machine_class_init(ObjectClass *oc, void *data)
mc->max_cpus = LOONGSON_MAX_VCPUS;
mc->default_ram_id = "loongson3.highram";
mc->default_ram_size = 1600 * MiB;
- mc->minimum_page_bits = 14;
mc->default_nic = "virtio-net-pci";
}
diff --git a/hw/mips/malta.c b/hw/mips/malta.c
index 664a2ae..cbdbb21 100644
--- a/hw/mips/malta.c
+++ b/hw/mips/malta.c
@@ -28,10 +28,11 @@
#include "qemu/datadir.h"
#include "qemu/cutils.h"
#include "qemu/guest-random.h"
+#include "exec/tswap.h"
#include "hw/clock.h"
#include "hw/southbridge/piix.h"
#include "hw/isa/superio.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
#include "hw/boards.h"
#include "hw/i2c/smbus_eeprom.h"
@@ -48,12 +49,12 @@
#include "qom/object.h"
#include "hw/sysbus.h" /* SysBusDevice */
#include "qemu/host-utils.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/qtest.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "semihosting/semihost.h"
#include "hw/mips/cps.h"
#include "hw/qdev-clock.h"
@@ -93,12 +94,6 @@ typedef struct {
bool display_inited;
} MaltaFPGAState;
-#if TARGET_BIG_ENDIAN
-#define BIOS_FILENAME "mips_bios.bin"
-#else
-#define BIOS_FILENAME "mipsel_bios.bin"
-#endif
-
#define TYPE_MIPS_MALTA "mips-malta"
OBJECT_DECLARE_SIMPLE_TYPE(MaltaState, MIPS_MALTA)
@@ -382,11 +377,7 @@ static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
/* STATUS Register */
case 0x00208:
-#if TARGET_BIG_ENDIAN
- val = 0x00000012;
-#else
- val = 0x00000010;
-#endif
+ val = TARGET_BIG_ENDIAN ? 0x00000012 : 0x00000010;
break;
/* JMPRS Register */
@@ -879,8 +870,9 @@ static uint64_t load_kernel(void)
kernel_size = load_elf(loaderparams.kernel_filename, NULL,
cpu_mips_kseg0_to_phys, NULL,
&kernel_entry, NULL,
- &kernel_high, NULL, TARGET_BIG_ENDIAN, EM_MIPS,
- 1, 0);
+ &kernel_high, NULL,
+ TARGET_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
+ EM_MIPS, 1, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
loaderparams.kernel_filename,
@@ -1034,7 +1026,8 @@ static void create_cpu_without_cps(MachineState *ms, MaltaState *s,
int i;
for (i = 0; i < ms->smp.cpus; i++) {
- cpu = mips_cpu_create_with_clock(ms->cpu_type, s->cpuclk);
+ cpu = mips_cpu_create_with_clock(ms->cpu_type, s->cpuclk,
+ TARGET_BIG_ENDIAN);
/* Init internal devices */
cpu_mips_irq_init_cpu(cpu);
@@ -1054,6 +1047,8 @@ static void create_cps(MachineState *ms, MaltaState *s,
object_initialize_child(OBJECT(s), "cps", &s->cps, TYPE_MIPS_CPS);
object_property_set_str(OBJECT(&s->cps), "cpu-type", ms->cpu_type,
&error_fatal);
+ object_property_set_bool(OBJECT(&s->cps), "cpu-big-endian",
+ TARGET_BIG_ENDIAN, &error_abort);
object_property_set_uint(OBJECT(&s->cps), "num-vp", ms->smp.cpus,
&error_fatal);
qdev_connect_clock_in(DEVICE(&s->cps), "clk-in", s->cpuclk);
@@ -1172,9 +1167,12 @@ void mips_malta_init(MachineState *machine)
target_long bios_size = FLASH_SIZE;
/* Load firmware from flash. */
if (!dinfo) {
+ const char *bios_name = TARGET_BIG_ENDIAN ? "mips_bios.bin"
+ : "mipsel_bios.bin";
+
/* Load a BIOS image. */
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
- machine->firmware ?: BIOS_FILENAME);
+ machine->firmware ?: bios_name);
if (filename) {
bios_size = load_image_targphys(filename, FLASH_ADDRESS,
BIOS_SIZE);
@@ -1192,8 +1190,7 @@ void mips_malta_init(MachineState *machine)
* In little endian mode the 32bit words in the bios are swapped,
* a neat trick which allows bi-endian firmware.
*/
-#if !TARGET_BIG_ENDIAN
- {
+ if (!TARGET_BIG_ENDIAN) {
uint32_t *end, *addr;
const size_t swapsize = MIN(bios_size, 0x3e0000);
addr = rom_ptr(FLASH_ADDRESS, swapsize);
@@ -1206,7 +1203,6 @@ void mips_malta_init(MachineState *machine)
addr++;
}
}
-#endif
}
/*
diff --git a/hw/mips/meson.build b/hw/mips/meson.build
index ca37c42..31dbd2b 100644
--- a/hw/mips/meson.build
+++ b/hw/mips/meson.build
@@ -1,7 +1,8 @@
mips_ss = ss.source_set()
mips_ss.add(files('bootloader.c', 'mips_int.c'))
-mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c'))
-mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
+common_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c'))
+common_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c'))
+mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_virt.c'))
mips_ss.add(when: 'CONFIG_MALTA', if_true: files('malta.c'))
mips_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('cps.c'))
diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c
index eef2fd2..26fdb93 100644
--- a/hw/mips/mips_int.c
+++ b/hw/mips/mips_int.c
@@ -23,7 +23,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "hw/irq.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_mips.h"
static void cpu_mips_irq_request(void *opaque, int irq, int level)
diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c
index 9170d6c..e843307 100644
--- a/hw/mips/mipssim.c
+++ b/hw/mips/mipssim.c
@@ -28,30 +28,24 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/datadir.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/clock.h"
#include "hw/mips/mips.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "elf.h"
#include "hw/sysbus.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
+#include "system/qtest.h"
+#include "system/reset.h"
#include "cpu.h"
#define BIOS_SIZE (4 * MiB)
-#if TARGET_BIG_ENDIAN
-#define BIOS_FILENAME "mips_bios.bin"
-#else
-#define BIOS_FILENAME "mipsel_bios.bin"
-#endif
-
static struct _loaderparams {
int ram_size;
const char *kernel_filename;
@@ -73,7 +67,8 @@ static uint64_t load_kernel(void)
kernel_size = load_elf(loaderparams.kernel_filename, NULL,
cpu_mips_kseg0_to_phys, NULL,
&entry, NULL,
- &kernel_high, NULL, TARGET_BIG_ENDIAN,
+ &kernel_high, NULL,
+ TARGET_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
EM_MIPS, 1, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
@@ -142,6 +137,8 @@ mips_mipssim_init(MachineState *machine)
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
+ const char *bios_name = TARGET_BIG_ENDIAN ? "mips_bios.bin"
+ : "mipsel_bios.bin";
char *filename;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1);
@@ -160,7 +157,8 @@ mips_mipssim_init(MachineState *machine)
#endif
/* Init CPUs. */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk,
+ TARGET_BIG_ENDIAN);
env = &cpu->env;
reset_info = g_new0(ResetData, 1);
@@ -177,7 +175,8 @@ mips_mipssim_init(MachineState *machine)
/* Map the BIOS / boot exception handler. */
memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
/* Load a BIOS / boot exception handler image. */
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware ?: BIOS_FILENAME);
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
+ machine->firmware ?: bios_name);
if (filename) {
bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
g_free(filename);
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1e08785..ec0fa5a 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -30,14 +30,6 @@ config EDU
default y if TEST_DEVICES
depends on PCI && MSI_NONBROKEN
-config PCA9552
- bool
- depends on I2C
-
-config PCA9554
- bool
- depends on I2C
-
config I2C_ECHO
bool
default y if TEST_DEVICES
@@ -72,9 +64,13 @@ config IVSHMEM_DEVICE
default y if PCI_DEVICES
depends on PCI && LINUX && IVSHMEM && MSI_NONBROKEN
+config IVSHMEM_FLAT_DEVICE
+ bool
+ default y
+ depends on LINUX && IVSHMEM
+
config ECCMEMCTL
bool
- select ECC
config IMX
bool
@@ -82,6 +78,15 @@ config IMX
select SSI
select USB_EHCI_SYSBUS
+config FSL_IMX8MP_ANALOG
+ bool
+
+config FSL_IMX8MP_CCM
+ bool
+
+config STM32_RCC
+ bool
+
config STM32F2XX_SYSCFG
bool
@@ -143,6 +148,10 @@ config PVPANIC_ISA
depends on ISA_BUS
select PVPANIC_COMMON
+config PVPANIC_MMIO
+ bool
+ select PVPANIC_COMMON
+
config AUX
bool
select I2C
diff --git a/hw/misc/a9scu.c b/hw/misc/a9scu.c
index 04225df..bb00ae2 100644
--- a/hw/misc/a9scu.c
+++ b/hw/misc/a9scu.c
@@ -123,18 +123,17 @@ static const VMStateDescription vmstate_a9_scu = {
}
};
-static Property a9_scu_properties[] = {
+static const Property a9_scu_properties[] = {
DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void a9_scu_class_init(ObjectClass *klass, void *data)
+static void a9_scu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, a9_scu_properties);
dc->vmsd = &vmstate_a9_scu;
- dc->reset = a9_scu_reset;
+ device_class_set_legacy_reset(dc, a9_scu_reset);
dc->realize = a9_scu_realize;
}
diff --git a/hw/misc/allwinner-a10-ccm.c b/hw/misc/allwinner-a10-ccm.c
index 575b018..6b188c2 100644
--- a/hw/misc/allwinner-a10-ccm.c
+++ b/hw/misc/allwinner-a10-ccm.c
@@ -147,7 +147,7 @@ static void allwinner_a10_ccm_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_a10_ccm_ops = {
.read = allwinner_a10_ccm_read,
.write = allwinner_a10_ccm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -199,7 +199,7 @@ static const VMStateDescription allwinner_a10_ccm_vmstate = {
}
};
-static void allwinner_a10_ccm_class_init(ObjectClass *klass, void *data)
+static void allwinner_a10_ccm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/misc/allwinner-a10-dramc.c b/hw/misc/allwinner-a10-dramc.c
index a7c58fa..c16814c 100644
--- a/hw/misc/allwinner-a10-dramc.c
+++ b/hw/misc/allwinner-a10-dramc.c
@@ -114,7 +114,7 @@ static void allwinner_a10_dramc_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_a10_dramc_ops = {
.read = allwinner_a10_dramc_read,
.write = allwinner_a10_dramc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -154,7 +154,7 @@ static const VMStateDescription allwinner_a10_dramc_vmstate = {
}
};
-static void allwinner_a10_dramc_class_init(ObjectClass *klass, void *data)
+static void allwinner_a10_dramc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/misc/allwinner-cpucfg.c b/hw/misc/allwinner-cpucfg.c
index 31b9780..90dd872 100644
--- a/hw/misc/allwinner-cpucfg.c
+++ b/hw/misc/allwinner-cpucfg.c
@@ -217,7 +217,7 @@ static void allwinner_cpucfg_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_cpucfg_ops = {
.read = allwinner_cpucfg_read,
.write = allwinner_cpucfg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -258,11 +258,11 @@ static const VMStateDescription allwinner_cpucfg_vmstate = {
}
};
-static void allwinner_cpucfg_class_init(ObjectClass *klass, void *data)
+static void allwinner_cpucfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_cpucfg_reset;
+ device_class_set_legacy_reset(dc, allwinner_cpucfg_reset);
dc->vmsd = &allwinner_cpucfg_vmstate;
}
diff --git a/hw/misc/allwinner-h3-ccu.c b/hw/misc/allwinner-h3-ccu.c
index cfc6852..be91c0c 100644
--- a/hw/misc/allwinner-h3-ccu.c
+++ b/hw/misc/allwinner-h3-ccu.c
@@ -155,7 +155,7 @@ static void allwinner_h3_ccu_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_h3_ccu_ops = {
.read = allwinner_h3_ccu_read,
.write = allwinner_h3_ccu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -218,11 +218,11 @@ static const VMStateDescription allwinner_h3_ccu_vmstate = {
}
};
-static void allwinner_h3_ccu_class_init(ObjectClass *klass, void *data)
+static void allwinner_h3_ccu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_h3_ccu_reset;
+ device_class_set_legacy_reset(dc, allwinner_h3_ccu_reset);
dc->vmsd = &allwinner_h3_ccu_vmstate;
}
diff --git a/hw/misc/allwinner-h3-dramc.c b/hw/misc/allwinner-h3-dramc.c
index e168ffe..8834524 100644
--- a/hw/misc/allwinner-h3-dramc.c
+++ b/hw/misc/allwinner-h3-dramc.c
@@ -24,7 +24,7 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "hw/misc/allwinner-h3-dramc.h"
@@ -219,7 +219,7 @@ static void allwinner_h3_dramphy_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_h3_dramcom_ops = {
.read = allwinner_h3_dramcom_read,
.write = allwinner_h3_dramcom_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -230,7 +230,7 @@ static const MemoryRegionOps allwinner_h3_dramcom_ops = {
static const MemoryRegionOps allwinner_h3_dramctl_ops = {
.read = allwinner_h3_dramctl_read,
.write = allwinner_h3_dramctl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -241,7 +241,7 @@ static const MemoryRegionOps allwinner_h3_dramctl_ops = {
static const MemoryRegionOps allwinner_h3_dramphy_ops = {
.read = allwinner_h3_dramphy_read,
.write = allwinner_h3_dramphy_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -314,10 +314,9 @@ static void allwinner_h3_dramc_init(Object *obj)
sysbus_init_mmio(sbd, &s->dramphy_iomem);
}
-static Property allwinner_h3_dramc_properties[] = {
+static const Property allwinner_h3_dramc_properties[] = {
DEFINE_PROP_UINT64("ram-addr", AwH3DramCtlState, ram_addr, 0x0),
DEFINE_PROP_UINT32("ram-size", AwH3DramCtlState, ram_size, 256 * MiB),
- DEFINE_PROP_END_OF_LIST()
};
static const VMStateDescription allwinner_h3_dramc_vmstate = {
@@ -332,11 +331,11 @@ static const VMStateDescription allwinner_h3_dramc_vmstate = {
}
};
-static void allwinner_h3_dramc_class_init(ObjectClass *klass, void *data)
+static void allwinner_h3_dramc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_h3_dramc_reset;
+ device_class_set_legacy_reset(dc, allwinner_h3_dramc_reset);
dc->vmsd = &allwinner_h3_dramc_vmstate;
dc->realize = allwinner_h3_dramc_realize;
device_class_set_props(dc, allwinner_h3_dramc_properties);
diff --git a/hw/misc/allwinner-h3-sysctrl.c b/hw/misc/allwinner-h3-sysctrl.c
index 2d29be8..6b86524 100644
--- a/hw/misc/allwinner-h3-sysctrl.c
+++ b/hw/misc/allwinner-h3-sysctrl.c
@@ -78,7 +78,7 @@ static void allwinner_h3_sysctrl_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_h3_sysctrl_ops = {
.read = allwinner_h3_sysctrl_read,
.write = allwinner_h3_sysctrl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -116,11 +116,12 @@ static const VMStateDescription allwinner_h3_sysctrl_vmstate = {
}
};
-static void allwinner_h3_sysctrl_class_init(ObjectClass *klass, void *data)
+static void allwinner_h3_sysctrl_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_h3_sysctrl_reset;
+ device_class_set_legacy_reset(dc, allwinner_h3_sysctrl_reset);
dc->vmsd = &allwinner_h3_sysctrl_vmstate;
}
diff --git a/hw/misc/allwinner-r40-ccu.c b/hw/misc/allwinner-r40-ccu.c
index 33baf44..4e21eea 100644
--- a/hw/misc/allwinner-r40-ccu.c
+++ b/hw/misc/allwinner-r40-ccu.c
@@ -129,7 +129,7 @@ static void allwinner_r40_ccu_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_r40_ccu_ops = {
.read = allwinner_r40_ccu_read,
.write = allwinner_r40_ccu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -185,11 +185,11 @@ static const VMStateDescription allwinner_r40_ccu_vmstate = {
}
};
-static void allwinner_r40_ccu_class_init(ObjectClass *klass, void *data)
+static void allwinner_r40_ccu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_r40_ccu_reset;
+ device_class_set_legacy_reset(dc, allwinner_r40_ccu_reset);
dc->vmsd = &allwinner_r40_ccu_vmstate;
}
diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c
index 75b0bef..1c8e17e 100644
--- a/hw/misc/allwinner-r40-dramc.c
+++ b/hw/misc/allwinner-r40-dramc.c
@@ -24,7 +24,7 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/bitops.h"
@@ -297,7 +297,7 @@ static void allwinner_r40_dramphy_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_r40_dramcom_ops = {
.read = allwinner_r40_dramcom_read,
.write = allwinner_r40_dramcom_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -308,7 +308,7 @@ static const MemoryRegionOps allwinner_r40_dramcom_ops = {
static const MemoryRegionOps allwinner_r40_dramctl_ops = {
.read = allwinner_r40_dramctl_read,
.write = allwinner_r40_dramctl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -319,7 +319,7 @@ static const MemoryRegionOps allwinner_r40_dramctl_ops = {
static const MemoryRegionOps allwinner_r40_dramphy_ops = {
.read = allwinner_r40_dramphy_read,
.write = allwinner_r40_dramphy_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -358,7 +358,7 @@ static void allwinner_r40_detect_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_r40_detect_ops = {
.read = allwinner_r40_detect_read,
.write = allwinner_r40_detect_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -393,7 +393,7 @@ static uint64_t allwinner_r40_dualrank_detect_read(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_r40_dualrank_detect_ops = {
.read = allwinner_r40_dualrank_detect_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -464,10 +464,9 @@ static void allwinner_r40_dramc_init(Object *obj)
sysbus_init_mmio(sbd, &s->dramphy_iomem);
}
-static Property allwinner_r40_dramc_properties[] = {
+static const Property allwinner_r40_dramc_properties[] = {
DEFINE_PROP_UINT64("ram-addr", AwR40DramCtlState, ram_addr, 0x0),
DEFINE_PROP_UINT32("ram-size", AwR40DramCtlState, ram_size, 256), /* MiB */
- DEFINE_PROP_END_OF_LIST()
};
static const VMStateDescription allwinner_r40_dramc_vmstate = {
@@ -485,11 +484,11 @@ static const VMStateDescription allwinner_r40_dramc_vmstate = {
}
};
-static void allwinner_r40_dramc_class_init(ObjectClass *klass, void *data)
+static void allwinner_r40_dramc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_r40_dramc_reset;
+ device_class_set_legacy_reset(dc, allwinner_r40_dramc_reset);
dc->vmsd = &allwinner_r40_dramc_vmstate;
dc->realize = allwinner_r40_dramc_realize;
device_class_set_props(dc, allwinner_r40_dramc_properties);
diff --git a/hw/misc/allwinner-sid.c b/hw/misc/allwinner-sid.c
index e5cd431..1e66c14 100644
--- a/hw/misc/allwinner-sid.c
+++ b/hw/misc/allwinner-sid.c
@@ -99,7 +99,7 @@ static void allwinner_sid_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_sid_ops = {
.read = allwinner_sid_read,
.write = allwinner_sid_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -127,9 +127,8 @@ static void allwinner_sid_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property allwinner_sid_properties[] = {
+static const Property allwinner_sid_properties[] = {
DEFINE_PROP_UUID_NODEFAULT("identifier", AwSidState, identifier),
- DEFINE_PROP_END_OF_LIST()
};
static const VMStateDescription allwinner_sid_vmstate = {
@@ -144,11 +143,11 @@ static const VMStateDescription allwinner_sid_vmstate = {
}
};
-static void allwinner_sid_class_init(ObjectClass *klass, void *data)
+static void allwinner_sid_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_sid_reset;
+ device_class_set_legacy_reset(dc, allwinner_sid_reset);
dc->vmsd = &allwinner_sid_vmstate;
device_class_set_props(dc, allwinner_sid_properties);
}
diff --git a/hw/misc/allwinner-sramc.c b/hw/misc/allwinner-sramc.c
index cf10ca8..ed299ec 100644
--- a/hw/misc/allwinner-sramc.c
+++ b/hw/misc/allwinner-sramc.c
@@ -104,7 +104,7 @@ static void allwinner_sramc_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_sramc_ops = {
.read = allwinner_sramc_read,
.write = allwinner_sramc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -135,11 +135,11 @@ static void allwinner_sramc_reset(DeviceState *dev)
}
}
-static void allwinner_sramc_class_init(ObjectClass *klass, void *data)
+static void allwinner_sramc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_sramc_reset;
+ device_class_set_legacy_reset(dc, allwinner_sramc_reset);
dc->vmsd = &allwinner_sramc_vmstate;
}
@@ -163,7 +163,7 @@ static const TypeInfo allwinner_sramc_info = {
.class_init = allwinner_sramc_class_init,
};
-static void allwinner_r40_sramc_class_init(ObjectClass *klass, void *data)
+static void allwinner_r40_sramc_class_init(ObjectClass *klass, const void *data)
{
AwSRAMCClass *sc = AW_SRAMC_CLASS(klass);
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
index 59a4899..a015d4a 100644
--- a/hw/misc/applesmc.c
+++ b/hw/misc/applesmc.c
@@ -350,11 +350,10 @@ static void applesmc_unrealize(DeviceState *dev)
}
}
-static Property applesmc_isa_properties[] = {
+static const Property applesmc_isa_properties[] = {
DEFINE_PROP_UINT32(APPLESMC_PROP_IO_BASE, AppleSMCState, iobase,
APPLESMC_DEFAULT_IOBASE),
DEFINE_PROP_STRING("osk", AppleSMCState, osk),
- DEFINE_PROP_END_OF_LIST(),
};
static void build_applesmc_aml(AcpiDevAmlIf *adev, Aml *scope)
@@ -376,14 +375,14 @@ static void build_applesmc_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(scope, dev);
}
-static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
+static void qdev_applesmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->realize = applesmc_isa_realize;
dc->unrealize = applesmc_unrealize;
- dc->reset = qdev_applesmc_isa_reset;
+ device_class_set_legacy_reset(dc, qdev_applesmc_isa_reset);
device_class_set_props(dc, applesmc_isa_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
adevc->build_dev_aml = build_applesmc_aml;
@@ -394,7 +393,7 @@ static const TypeInfo applesmc_isa_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(AppleSMCState),
.class_init = qdev_applesmc_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/misc/arm11scu.c b/hw/misc/arm11scu.c
index 17c36a0..2ad4fd1 100644
--- a/hw/misc/arm11scu.c
+++ b/hw/misc/arm11scu.c
@@ -75,12 +75,11 @@ static void arm11_scu_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property arm11_scu_properties[] = {
+static const Property arm11_scu_properties[] = {
DEFINE_PROP_UINT32("num-cpu", ARM11SCUState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST()
};
-static void arm11_scu_class_init(ObjectClass *oc, void *data)
+static void arm11_scu_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/misc/arm_l2x0.c b/hw/misc/arm_l2x0.c
index b14d0a2..8b4b61e 100644
--- a/hw/misc/arm_l2x0.c
+++ b/hw/misc/arm_l2x0.c
@@ -173,18 +173,17 @@ static void l2x0_priv_init(Object *obj)
sysbus_init_mmio(dev, &s->iomem);
}
-static Property l2x0_properties[] = {
+static const Property l2x0_properties[] = {
DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100),
- DEFINE_PROP_END_OF_LIST(),
};
-static void l2x0_class_init(ObjectClass *klass, void *data)
+static void l2x0_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_l2x0;
device_class_set_props(dc, l2x0_properties);
- dc->reset = l2x0_priv_reset;
+ device_class_set_legacy_reset(dc, l2x0_priv_reset);
}
static const TypeInfo l2x0_info = {
diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c
index 5108f3e..0f4e37c 100644
--- a/hw/misc/arm_sysctl.c
+++ b/hw/misc/arm_sysctl.c
@@ -11,7 +11,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "qemu/bitops.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
@@ -520,7 +520,7 @@ static void arm_sysctl_write(void *opaque, hwaddr offset,
* as zero.
*/
s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
- if (val & (1 << 31)) {
+ if (extract64(val, 31, 1)) {
/* Start bit set -- actually do something */
unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
@@ -623,7 +623,7 @@ static void arm_sysctl_finalize(Object *obj)
g_free(s->db_clock_reset);
}
-static Property arm_sysctl_properties[] = {
+static const Property arm_sysctl_properties[] = {
DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
/* Daughterboard power supply voltages (as reported via SYS_CFG) */
@@ -632,15 +632,14 @@ static Property arm_sysctl_properties[] = {
/* Daughterboard clock reset values (as reported via SYS_CFG) */
DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks,
db_clock_reset, qdev_prop_uint32, uint32_t),
- DEFINE_PROP_END_OF_LIST(),
};
-static void arm_sysctl_class_init(ObjectClass *klass, void *data)
+static void arm_sysctl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = arm_sysctl_realize;
- dc->reset = arm_sysctl_reset;
+ device_class_set_legacy_reset(dc, arm_sysctl_reset);
dc->vmsd = &vmstate_arm_sysctl;
device_class_set_props(dc, arm_sysctl_properties);
}
diff --git a/hw/misc/armsse-cpu-pwrctrl.c b/hw/misc/armsse-cpu-pwrctrl.c
index bfc51d1..66e9218 100644
--- a/hw/misc/armsse-cpu-pwrctrl.c
+++ b/hw/misc/armsse-cpu-pwrctrl.c
@@ -125,11 +125,11 @@ static void pwrctrl_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void pwrctrl_class_init(ObjectClass *klass, void *data)
+static void pwrctrl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pwrctrl_reset;
+ device_class_set_legacy_reset(dc, pwrctrl_reset);
dc->vmsd = &pwrctrl_vmstate;
}
diff --git a/hw/misc/armsse-cpuid.c b/hw/misc/armsse-cpuid.c
index e785a09..a57764d 100644
--- a/hw/misc/armsse-cpuid.c
+++ b/hw/misc/armsse-cpuid.c
@@ -92,9 +92,8 @@ static const MemoryRegionOps armsse_cpuid_ops = {
.valid.max_access_size = 4,
};
-static Property armsse_cpuid_props[] = {
+static const Property armsse_cpuid_props[] = {
DEFINE_PROP_UINT32("CPUID", ARMSSECPUID, cpuid, 0),
- DEFINE_PROP_END_OF_LIST()
};
static void armsse_cpuid_init(Object *obj)
@@ -107,7 +106,7 @@ static void armsse_cpuid_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void armsse_cpuid_class_init(ObjectClass *klass, void *data)
+static void armsse_cpuid_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/armsse-mhu.c b/hw/misc/armsse-mhu.c
index 55625b2..d5d307a 100644
--- a/hw/misc/armsse-mhu.c
+++ b/hw/misc/armsse-mhu.c
@@ -176,11 +176,11 @@ static void armsse_mhu_init(Object *obj)
sysbus_init_irq(sbd, &s->cpu1irq);
}
-static void armsse_mhu_class_init(ObjectClass *klass, void *data)
+static void armsse_mhu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = armsse_mhu_reset;
+ device_class_set_legacy_reset(dc, armsse_mhu_reset);
dc->vmsd = &armsse_mhu_vmstate;
}
diff --git a/hw/misc/armv7m_ras.c b/hw/misc/armv7m_ras.c
index de24922..7bf5acd 100644
--- a/hw/misc/armv7m_ras.c
+++ b/hw/misc/armv7m_ras.c
@@ -72,7 +72,7 @@ static void armv7m_ras_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void armv7m_ras_class_init(ObjectClass *klass, void *data)
+static void armv7m_ras_class_init(ObjectClass *klass, const void *data)
{
/* This device has no state: no need for vmstate or reset */
}
diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
index c06c04d..726368f 100644
--- a/hw/misc/aspeed_hace.c
+++ b/hw/misc/aspeed_hace.c
@@ -1,6 +1,7 @@
/*
* ASPEED Hash and Crypto Engine
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2021 IBM Corp.
*
* Joel Stanley <joel@jms.id.au>
@@ -9,14 +10,17 @@
*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
+#include "qemu/iov.h"
#include "hw/misc/aspeed_hace.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "crypto/hash.h"
#include "hw/qdev-properties.h"
#include "hw/irq.h"
+#include "trace.h"
#define R_CRYPT_CMD (0x10 / 4)
@@ -26,9 +30,12 @@
#define TAG_IRQ BIT(15)
#define R_HASH_SRC (0x20 / 4)
-#define R_HASH_DEST (0x24 / 4)
+#define R_HASH_DIGEST (0x24 / 4)
#define R_HASH_KEY_BUFF (0x28 / 4)
#define R_HASH_SRC_LEN (0x2c / 4)
+#define R_HASH_SRC_HI (0x90 / 4)
+#define R_HASH_DIGEST_HI (0x94 / 4)
+#define R_HASH_KEY_BUFF_HI (0x98 / 4)
#define R_HASH_CMD (0x30 / 4)
/* Hash algorithm selection */
@@ -58,6 +65,7 @@
/* Other cmd bits */
#define HASH_IRQ_EN BIT(9)
#define HASH_SG_EN BIT(18)
+#define CRYPT_IRQ_EN BIT(12)
/* Scatter-gather data list */
#define SG_LIST_LEN_SIZE 4
#define SG_LIST_LEN_MASK 0x0FFFFFFF
@@ -68,17 +76,56 @@
static const struct {
uint32_t mask;
- QCryptoHashAlgorithm algo;
+ QCryptoHashAlgo algo;
} hash_algo_map[] = {
- { HASH_ALGO_MD5, QCRYPTO_HASH_ALG_MD5 },
- { HASH_ALGO_SHA1, QCRYPTO_HASH_ALG_SHA1 },
- { HASH_ALGO_SHA224, QCRYPTO_HASH_ALG_SHA224 },
- { HASH_ALGO_SHA256, QCRYPTO_HASH_ALG_SHA256 },
- { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALG_SHA512 },
- { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALG_SHA384 },
- { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALG_SHA256 },
+ { HASH_ALGO_MD5, QCRYPTO_HASH_ALGO_MD5 },
+ { HASH_ALGO_SHA1, QCRYPTO_HASH_ALGO_SHA1 },
+ { HASH_ALGO_SHA224, QCRYPTO_HASH_ALGO_SHA224 },
+ { HASH_ALGO_SHA256, QCRYPTO_HASH_ALGO_SHA256 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512,
+ QCRYPTO_HASH_ALGO_SHA512 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384,
+ QCRYPTO_HASH_ALGO_SHA384 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256,
+ QCRYPTO_HASH_ALGO_SHA256 },
};
+static void hace_hexdump(const char *desc, const char *buf, size_t size)
+{
+ g_autoptr(GString) str = g_string_sized_new(64);
+ size_t len;
+ size_t i;
+
+ for (i = 0; i < size; i += len) {
+ len = MIN(16, size - i);
+ g_string_truncate(str, 0);
+ qemu_hexdump_line(str, buf + i, len, 1, 4);
+ trace_aspeed_hace_hexdump(desc, i, str->str);
+ }
+}
+
+static void hace_iov_hexdump(const char *desc, const struct iovec *iov,
+ const unsigned int iov_cnt)
+{
+ size_t size = 0;
+ char *buf;
+ int i;
+
+ for (i = 0; i < iov_cnt; i++) {
+ size += iov[i].iov_len;
+ }
+
+ buf = g_malloc(size);
+
+ if (!buf) {
+ return;
+ }
+
+ iov_to_buf(iov, iov_cnt, 0, buf, size);
+ hace_hexdump(desc, buf, size);
+ g_free(buf);
+}
+
static int hash_algo_lookup(uint32_t reg)
{
int i;
@@ -123,6 +170,11 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov,
if (*total_msg_len <= s->total_req_len) {
uint32_t padding_size = s->total_req_len - *total_msg_len;
uint8_t *padding = iov->iov_base;
+
+ if (padding_size > req_len) {
+ return false;
+ }
+
*pad_offset = req_len - padding_size;
if (padding[*pad_offset] == 0x80) {
return true;
@@ -132,162 +184,269 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov,
return false;
}
-static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id,
- uint32_t *pad_offset)
+static uint64_t hash_get_source_addr(AspeedHACEState *s)
{
- int i, iov_count;
- if (*pad_offset != 0) {
- s->iov_cache[s->iov_count].iov_base = iov[id].iov_base;
- s->iov_cache[s->iov_count].iov_len = *pad_offset;
- ++s->iov_count;
- }
- for (i = 0; i < s->iov_count; i++) {
- iov[i].iov_base = s->iov_cache[i].iov_base;
- iov[i].iov_len = s->iov_cache[i].iov_len;
+ AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s);
+ uint64_t src_addr = 0;
+
+ src_addr = deposit64(src_addr, 0, 32, s->regs[R_HASH_SRC]);
+ if (ahc->has_dma64) {
+ src_addr = deposit64(src_addr, 32, 32, s->regs[R_HASH_SRC_HI]);
}
- iov_count = s->iov_count;
- s->iov_count = 0;
- s->total_req_len = 0;
- return iov_count;
+
+ return src_addr;
}
-/**
- * Generate iov for accumulative mode.
- *
- * @param s aspeed hace state object
- * @param iov iov of the current request
- * @param id index of the current iov
- * @param req_len length of the current request
- *
- * @return count of iov
- */
-static int gen_acc_mode_iov(AspeedHACEState *s, struct iovec *iov, int id,
- hwaddr *req_len)
+static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov,
+ bool acc_mode, bool *acc_final_request)
{
- uint32_t pad_offset;
uint32_t total_msg_len;
- s->total_req_len += *req_len;
+ uint32_t pad_offset;
+ uint64_t src;
+ void *haddr;
+ hwaddr plen;
+ int iov_idx;
+
+ plen = s->regs[R_HASH_SRC_LEN];
+ src = hash_get_source_addr(s);
+ trace_aspeed_hace_hash_addr("src", src);
+ haddr = address_space_map(&s->dram_as, src, &plen, false,
+ MEMTXATTRS_UNSPECIFIED);
+ if (haddr == NULL) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unable to map address, addr=0x%" HWADDR_PRIx
+ " ,plen=0x%" HWADDR_PRIx "\n",
+ __func__, src, plen);
+ return -1;
+ }
- if (has_padding(s, &iov[id], *req_len, &total_msg_len, &pad_offset)) {
- if (s->iov_count) {
- return reconstruct_iov(s, iov, id, &pad_offset);
- }
+ iov[0].iov_base = haddr;
+ iov_idx = 1;
- *req_len -= s->total_req_len - total_msg_len;
- s->total_req_len = 0;
- iov[id].iov_len = *req_len;
+ if (acc_mode) {
+ s->total_req_len += plen;
+
+ if (has_padding(s, &iov[0], plen, &total_msg_len,
+ &pad_offset)) {
+ /* Padding being present indicates the final request */
+ *acc_final_request = true;
+ iov[0].iov_len = pad_offset;
+ } else {
+ iov[0].iov_len = plen;
+ }
} else {
- s->iov_cache[s->iov_count].iov_base = iov->iov_base;
- s->iov_cache[s->iov_count].iov_len = *req_len;
- ++s->iov_count;
+ iov[0].iov_len = plen;
}
- return id + 1;
+ return iov_idx;
}
-static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
- bool acc_mode)
+static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov,
+ bool acc_mode, bool *acc_final_request)
{
- struct iovec iov[ASPEED_HACE_MAX_SG];
- g_autofree uint8_t *digest_buf = NULL;
- size_t digest_len = 0;
- int niov = 0;
- int i;
+ uint32_t total_msg_len;
+ uint32_t pad_offset;
+ uint32_t len = 0;
+ uint32_t sg_addr;
+ uint64_t src;
+ int iov_idx;
+ hwaddr plen;
void *haddr;
- if (sg_mode) {
- uint32_t len = 0;
-
- for (i = 0; !(len & SG_LIST_LEN_LAST); i++) {
- uint32_t addr, src;
- hwaddr plen;
-
- if (i == ASPEED_HACE_MAX_SG) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "aspeed_hace: guest failed to set end of sg list marker\n");
- break;
- }
-
- src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE);
+ src = hash_get_source_addr(s);
+ for (iov_idx = 0; !(len & SG_LIST_LEN_LAST); iov_idx++) {
+ if (iov_idx == ASPEED_HACE_MAX_SG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Failed to set end of sg list marker\n",
+ __func__);
+ return -1;
+ }
- len = address_space_ldl_le(&s->dram_as, src,
+ len = address_space_ldl_le(&s->dram_as, src,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ sg_addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE,
MEMTXATTRS_UNSPECIFIED, NULL);
+ sg_addr &= SG_LIST_ADDR_MASK;
+ trace_aspeed_hace_hash_sg(iov_idx, src, sg_addr, len);
+ /*
+ * To maintain compatibility with older SoCs such as the AST2600,
+ * the AST2700 HW automatically set bit 34 of the 64-bit sg_addr.
+ * As a result, the firmware only needs to provide a 32-bit sg_addr
+ * containing bits [31:0]. This is sufficient for the AST2700, as
+ * it uses a DRAM offset rather than a DRAM address.
+ */
+ plen = len & SG_LIST_LEN_MASK;
+ haddr = address_space_map(&s->dram_as, sg_addr, &plen, false,
+ MEMTXATTRS_UNSPECIFIED);
- addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE,
- MEMTXATTRS_UNSPECIFIED, NULL);
- addr &= SG_LIST_ADDR_MASK;
+ if (haddr == NULL) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unable to map address, sg_addr=0x%x, "
+ "plen=0x%" HWADDR_PRIx "\n",
+ __func__, sg_addr, plen);
+ return -1;
+ }
- plen = len & SG_LIST_LEN_MASK;
- haddr = address_space_map(&s->dram_as, addr, &plen, false,
- MEMTXATTRS_UNSPECIFIED);
- if (haddr == NULL) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__);
- return;
- }
- iov[i].iov_base = haddr;
- if (acc_mode) {
- niov = gen_acc_mode_iov(s, iov, i, &plen);
+ src += SG_LIST_ENTRY_SIZE;
+
+ iov[iov_idx].iov_base = haddr;
+ if (acc_mode) {
+ s->total_req_len += plen;
+ if (has_padding(s, &iov[iov_idx], plen, &total_msg_len,
+ &pad_offset)) {
+ /* Padding being present indicates the final request */
+ *acc_final_request = true;
+ iov[iov_idx].iov_len = pad_offset;
} else {
- iov[i].iov_len = plen;
+ iov[iov_idx].iov_len = plen;
}
+ } else {
+ iov[iov_idx].iov_len = plen;
}
- } else {
- hwaddr len = s->regs[R_HASH_SRC_LEN];
+ }
- haddr = address_space_map(&s->dram_as, s->regs[R_HASH_SRC],
- &len, false, MEMTXATTRS_UNSPECIFIED);
- if (haddr == NULL) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__);
+ return iov_idx;
+}
+
+static uint64_t hash_get_digest_addr(AspeedHACEState *s)
+{
+ AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s);
+ uint64_t digest_addr = 0;
+
+ digest_addr = deposit64(digest_addr, 0, 32, s->regs[R_HASH_DIGEST]);
+ if (ahc->has_dma64) {
+ digest_addr = deposit64(digest_addr, 32, 32, s->regs[R_HASH_DIGEST_HI]);
+ }
+
+ return digest_addr;
+}
+
+static void hash_write_digest_and_unmap_iov(AspeedHACEState *s,
+ struct iovec *iov,
+ int iov_idx,
+ uint8_t *digest_buf,
+ size_t digest_len)
+{
+ uint64_t digest_addr = 0;
+
+ digest_addr = hash_get_digest_addr(s);
+ trace_aspeed_hace_hash_addr("digest", digest_addr);
+ if (address_space_write(&s->dram_as, digest_addr,
+ MEMTXATTRS_UNSPECIFIED,
+ digest_buf, digest_len)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Failed to write digest to 0x%" HWADDR_PRIx "\n",
+ __func__, digest_addr);
+ }
+
+ if (trace_event_get_state_backends(TRACE_ASPEED_HACE_HEXDUMP)) {
+ hace_hexdump("digest", (char *)digest_buf, digest_len);
+ }
+
+ for (; iov_idx > 0; iov_idx--) {
+ address_space_unmap(&s->dram_as, iov[iov_idx - 1].iov_base,
+ iov[iov_idx - 1].iov_len, false,
+ iov[iov_idx - 1].iov_len);
+ }
+}
+
+static void hash_execute_non_acc_mode(AspeedHACEState *s, int algo,
+ struct iovec *iov, int iov_idx)
+{
+ g_autofree uint8_t *digest_buf = NULL;
+ Error *local_err = NULL;
+ size_t digest_len = 0;
+
+ if (qcrypto_hash_bytesv(algo, iov, iov_idx, &digest_buf,
+ &digest_len, &local_err) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: qcrypto hash bytesv failed : %s",
+ __func__, error_get_pretty(local_err));
+ error_free(local_err);
+ return;
+ }
+
+ hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len);
+}
+
+static void hash_execute_acc_mode(AspeedHACEState *s, int algo,
+ struct iovec *iov, int iov_idx,
+ bool final_request)
+{
+ g_autofree uint8_t *digest_buf = NULL;
+ Error *local_err = NULL;
+ size_t digest_len = 0;
+
+ trace_aspeed_hace_hash_execute_acc_mode(final_request);
+
+ if (s->hash_ctx == NULL) {
+ s->hash_ctx = qcrypto_hash_new(algo, &local_err);
+ if (s->hash_ctx == NULL) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto hash new failed : %s",
+ __func__, error_get_pretty(local_err));
+ error_free(local_err);
return;
}
- iov[0].iov_base = haddr;
- iov[0].iov_len = len;
- i = 1;
-
- if (s->iov_count) {
- /*
- * In aspeed sdk kernel driver, sg_mode is disabled in hash_final().
- * Thus if we received a request with sg_mode disabled, it is
- * required to check whether cache is empty. If no, we should
- * combine cached iov and the current iov.
- */
- uint32_t total_msg_len;
- uint32_t pad_offset;
- s->total_req_len += len;
- if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) {
- niov = reconstruct_iov(s, iov, 0, &pad_offset);
- }
- }
}
- if (niov) {
- i = niov;
+ if (qcrypto_hash_updatev(s->hash_ctx, iov, iov_idx, &local_err) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto hash updatev failed : %s",
+ __func__, error_get_pretty(local_err));
+ error_free(local_err);
+ return;
}
- if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__);
- return;
+ if (final_request) {
+ if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf,
+ &digest_len, &local_err)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: qcrypto hash finalize bytes failed : %s",
+ __func__, error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ }
+
+ qcrypto_hash_free(s->hash_ctx);
+
+ s->hash_ctx = NULL;
+ s->total_req_len = 0;
}
- if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST],
- MEMTXATTRS_UNSPECIFIED,
- digest_buf, digest_len)) {
+ hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len);
+}
+
+static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
+ bool acc_mode)
+{
+ QEMU_UNINITIALIZED struct iovec iov[ASPEED_HACE_MAX_SG];
+ bool acc_final_request = false;
+ int iov_idx = -1;
+
+ /* Prepares the iov for hashing operations based on the selected mode */
+ if (sg_mode) {
+ iov_idx = hash_prepare_sg_iov(s, iov, acc_mode, &acc_final_request);
+ } else {
+ iov_idx = hash_prepare_direct_iov(s, iov, acc_mode,
+ &acc_final_request);
+ }
+
+ if (iov_idx <= 0) {
qemu_log_mask(LOG_GUEST_ERROR,
- "aspeed_hace: address space write failed\n");
+ "%s: Failed to prepare iov\n", __func__);
+ return;
}
- for (; i > 0; i--) {
- address_space_unmap(&s->dram_as, iov[i - 1].iov_base,
- iov[i - 1].iov_len, false,
- iov[i - 1].iov_len);
+ if (trace_event_get_state_backends(TRACE_ASPEED_HACE_HEXDUMP)) {
+ hace_iov_hexdump("plaintext", iov, iov_idx);
}
- /*
- * Set status bits to indicate completion. Testing shows hardware sets
- * these irrespective of HASH_IRQ_EN.
- */
- s->regs[R_STATUS] |= HASH_IRQ;
+ /* Executes the hash operation */
+ if (acc_mode) {
+ hash_execute_acc_mode(s, algo, iov, iov_idx, acc_final_request);
+ } else {
+ hash_execute_non_acc_mode(s, algo, iov, iov_idx);
+ }
}
static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size)
@@ -296,12 +455,7 @@ static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size)
addr >>= 2;
- if (addr >= ASPEED_HACE_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
- __func__, addr << 2);
- return 0;
- }
+ trace_aspeed_hace_read(addr << 2, s->regs[addr]);
return s->regs[addr];
}
@@ -314,12 +468,7 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
addr >>= 2;
- if (addr >= ASPEED_HACE_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
- __func__, addr << 2);
- return;
- }
+ trace_aspeed_hace_write(addr << 2, data);
switch (addr) {
case R_STATUS:
@@ -330,11 +479,20 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
qemu_irq_lower(s->irq);
}
}
+ if (ahc->raise_crypt_interrupt_workaround) {
+ if (data & CRYPT_IRQ) {
+ data &= ~CRYPT_IRQ;
+
+ if (s->regs[addr] & CRYPT_IRQ) {
+ qemu_irq_lower(s->irq);
+ }
+ }
+ }
break;
case R_HASH_SRC:
data &= ahc->src_mask;
break;
- case R_HASH_DEST:
+ case R_HASH_DIGEST:
data &= ahc->dest_mask;
break;
case R_HASH_KEY_BUFF:
@@ -362,10 +520,16 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Invalid hash algorithm selection 0x%"PRIx64"\n",
__func__, data & ahc->hash_mask);
- break;
+ } else {
+ do_hash_operation(s, algo, data & HASH_SG_EN,
+ ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM));
}
- do_hash_operation(s, algo, data & HASH_SG_EN,
- ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM));
+
+ /*
+ * Set status bits to indicate completion. Testing shows hardware sets
+ * these irrespective of HASH_IRQ_EN.
+ */
+ s->regs[R_STATUS] |= HASH_IRQ;
if (data & HASH_IRQ_EN) {
qemu_irq_raise(s->irq);
@@ -375,6 +539,21 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
case R_CRYPT_CMD:
qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n",
__func__);
+ if (ahc->raise_crypt_interrupt_workaround) {
+ s->regs[R_STATUS] |= CRYPT_IRQ;
+ if (data & CRYPT_IRQ_EN) {
+ qemu_irq_raise(s->irq);
+ }
+ }
+ break;
+ case R_HASH_SRC_HI:
+ data &= ahc->src_hi_mask;
+ break;
+ case R_HASH_DIGEST_HI:
+ data &= ahc->dest_hi_mask;
+ break;
+ case R_HASH_KEY_BUFF_HI:
+ data &= ahc->key_hi_mask;
break;
default:
break;
@@ -396,9 +575,14 @@ static const MemoryRegionOps aspeed_hace_ops = {
static void aspeed_hace_reset(DeviceState *dev)
{
struct AspeedHACEState *s = ASPEED_HACE(dev);
+ AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s);
- memset(s->regs, 0, sizeof(s->regs));
- s->iov_count = 0;
+ if (s->hash_ctx != NULL) {
+ qcrypto_hash_free(s->hash_ctx);
+ s->hash_ctx = NULL;
+ }
+
+ memset(s->regs, 0, ahc->nr_regs << 2);
s->total_req_len = 0;
}
@@ -406,11 +590,13 @@ static void aspeed_hace_realize(DeviceState *dev, Error **errp)
{
AspeedHACEState *s = ASPEED_HACE(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s);
sysbus_init_irq(sbd, &s->irq);
+ s->regs = g_new(uint32_t, ahc->nr_regs);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s,
- TYPE_ASPEED_HACE, 0x1000);
+ TYPE_ASPEED_HACE, ahc->nr_regs << 2);
if (!s->dram_mr) {
error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set");
@@ -422,31 +608,37 @@ static void aspeed_hace_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property aspeed_hace_properties[] = {
+static const Property aspeed_hace_properties[] = {
DEFINE_PROP_LINK("dram", AspeedHACEState, dram_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_aspeed_hace = {
.name = TYPE_ASPEED_HACE,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS),
VMSTATE_UINT32(total_req_len, AspeedHACEState),
- VMSTATE_UINT32(iov_count, AspeedHACEState),
VMSTATE_END_OF_LIST(),
}
};
-static void aspeed_hace_class_init(ObjectClass *klass, void *data)
+static void aspeed_hace_unrealize(DeviceState *dev)
+{
+ AspeedHACEState *s = ASPEED_HACE(dev);
+
+ g_free(s->regs);
+ s->regs = NULL;
+}
+
+static void aspeed_hace_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_hace_realize;
- dc->reset = aspeed_hace_reset;
+ dc->unrealize = aspeed_hace_unrealize;
+ device_class_set_legacy_reset(dc, aspeed_hace_reset);
device_class_set_props(dc, aspeed_hace_properties);
dc->vmsd = &vmstate_aspeed_hace;
}
@@ -459,13 +651,14 @@ static const TypeInfo aspeed_hace_info = {
.class_size = sizeof(AspeedHACEClass)
};
-static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data)
+static void aspeed_ast2400_hace_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
dc->desc = "AST2400 Hash and Crypto Engine";
+ ahc->nr_regs = 0x64 >> 2;
ahc->src_mask = 0x0FFFFFFF;
ahc->dest_mask = 0x0FFFFFF8;
ahc->key_mask = 0x0FFFFFC0;
@@ -478,13 +671,14 @@ static const TypeInfo aspeed_ast2400_hace_info = {
.class_init = aspeed_ast2400_hace_class_init,
};
-static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data)
+static void aspeed_ast2500_hace_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
dc->desc = "AST2500 Hash and Crypto Engine";
+ ahc->nr_regs = 0x64 >> 2;
ahc->src_mask = 0x3fffffff;
ahc->dest_mask = 0x3ffffff8;
ahc->key_mask = 0x3FFFFFC0;
@@ -497,13 +691,14 @@ static const TypeInfo aspeed_ast2500_hace_info = {
.class_init = aspeed_ast2500_hace_class_init,
};
-static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data)
+static void aspeed_ast2600_hace_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
dc->desc = "AST2600 Hash and Crypto Engine";
+ ahc->nr_regs = 0x64 >> 2;
ahc->src_mask = 0x7FFFFFFF;
ahc->dest_mask = 0x7FFFFFF8;
ahc->key_mask = 0x7FFFFFF8;
@@ -516,13 +711,14 @@ static const TypeInfo aspeed_ast2600_hace_info = {
.class_init = aspeed_ast2600_hace_class_init,
};
-static void aspeed_ast1030_hace_class_init(ObjectClass *klass, void *data)
+static void aspeed_ast1030_hace_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
dc->desc = "AST1030 Hash and Crypto Engine";
+ ahc->nr_regs = 0x64 >> 2;
ahc->src_mask = 0x7FFFFFFF;
ahc->dest_mask = 0x7FFFFFF8;
ahc->key_mask = 0x7FFFFFF8;
@@ -535,12 +731,58 @@ static const TypeInfo aspeed_ast1030_hace_info = {
.class_init = aspeed_ast1030_hace_class_init,
};
+static void aspeed_ast2700_hace_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
+
+ dc->desc = "AST2700 Hash and Crypto Engine";
+
+ ahc->nr_regs = 0x9C >> 2;
+ ahc->src_mask = 0x7FFFFFFF;
+ ahc->dest_mask = 0x7FFFFFF8;
+ ahc->key_mask = 0x7FFFFFF8;
+ ahc->hash_mask = 0x00147FFF;
+
+ /*
+ * The AST2700 supports a maximum DRAM size of 8 GB, with a DRAM
+ * addressable range from 0x0_0000_0000 to 0x1_FFFF_FFFF. Since this range
+ * fits within 34 bits, only bits [33:0] are needed to store the DRAM
+ * offset. To optimize address storage, the high physical address bits
+ * [1:0] of the source, digest and key buffer addresses are stored as
+ * dram_offset bits [33:32].
+ *
+ * This approach eliminates the need to reduce the high part of the DRAM
+ * physical address for DMA operations. Previously, this was calculated as
+ * (high physical address bits [7:0] - 4), since the DRAM start address is
+ * 0x4_00000000, making the high part address [7:0] - 4.
+ */
+ ahc->src_hi_mask = 0x00000003;
+ ahc->dest_hi_mask = 0x00000003;
+ ahc->key_hi_mask = 0x00000003;
+
+ /*
+ * Currently, it does not support the CRYPT command. Instead, it only
+ * sends an interrupt to notify the firmware that the crypt command
+ * has completed. It is a temporary workaround.
+ */
+ ahc->raise_crypt_interrupt_workaround = true;
+ ahc->has_dma64 = true;
+}
+
+static const TypeInfo aspeed_ast2700_hace_info = {
+ .name = TYPE_ASPEED_AST2700_HACE,
+ .parent = TYPE_ASPEED_HACE,
+ .class_init = aspeed_ast2700_hace_class_init,
+};
+
static void aspeed_hace_register_types(void)
{
type_register_static(&aspeed_ast2400_hace_info);
type_register_static(&aspeed_ast2500_hace_info);
type_register_static(&aspeed_ast2600_hace_info);
type_register_static(&aspeed_ast1030_hace_info);
+ type_register_static(&aspeed_ast2700_hace_info);
type_register_static(&aspeed_hace_info);
}
diff --git a/hw/misc/aspeed_i3c.c b/hw/misc/aspeed_i3c.c
index 827c9e5..3bef1c8 100644
--- a/hw/misc/aspeed_i3c.c
+++ b/hw/misc/aspeed_i3c.c
@@ -323,18 +323,17 @@ static void aspeed_i3c_realize(DeviceState *dev, Error **errp)
}
-static Property aspeed_i3c_device_properties[] = {
+static const Property aspeed_i3c_device_properties[] = {
DEFINE_PROP_UINT8("device-id", AspeedI3CDevice, id, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_i3c_device_class_init(ObjectClass *klass, void *data)
+static void aspeed_i3c_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "Aspeed I3C Device";
dc->realize = aspeed_i3c_device_realize;
- dc->reset = aspeed_i3c_device_reset;
+ device_class_set_legacy_reset(dc, aspeed_i3c_device_reset);
device_class_set_props(dc, aspeed_i3c_device_properties);
}
@@ -357,12 +356,12 @@ static const VMStateDescription vmstate_aspeed_i3c = {
}
};
-static void aspeed_i3c_class_init(ObjectClass *klass, void *data)
+static void aspeed_i3c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_i3c_realize;
- dc->reset = aspeed_i3c_reset;
+ device_class_set_legacy_reset(dc, aspeed_i3c_reset);
dc->desc = "Aspeed I3C Controller";
dc->vmsd = &vmstate_aspeed_i3c;
}
diff --git a/hw/misc/aspeed_lpc.c b/hw/misc/aspeed_lpc.c
index 193f0de..78406da 100644
--- a/hw/misc/aspeed_lpc.c
+++ b/hw/misc/aspeed_lpc.c
@@ -454,17 +454,16 @@ static const VMStateDescription vmstate_aspeed_lpc = {
}
};
-static Property aspeed_lpc_properties[] = {
+static const Property aspeed_lpc_properties[] = {
DEFINE_PROP_UINT32("hicr7", AspeedLPCState, hicr7, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_lpc_class_init(ObjectClass *klass, void *data)
+static void aspeed_lpc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_lpc_realize;
- dc->reset = aspeed_lpc_reset;
+ device_class_set_legacy_reset(dc, aspeed_lpc_reset);
dc->desc = "Aspeed LPC Controller",
dc->vmsd = &vmstate_aspeed_lpc;
device_class_set_props(dc, aspeed_lpc_properties);
diff --git a/hw/misc/aspeed_peci.c b/hw/misc/aspeed_peci.c
index 93cc672..a7a449a 100644
--- a/hw/misc/aspeed_peci.c
+++ b/hw/misc/aspeed_peci.c
@@ -130,12 +130,12 @@ static void aspeed_peci_reset(DeviceState *dev)
memset(s->regs, 0, sizeof(s->regs));
}
-static void aspeed_peci_class_init(ObjectClass *klass, void *data)
+static void aspeed_peci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_peci_realize;
- dc->reset = aspeed_peci_reset;
+ device_class_set_legacy_reset(dc, aspeed_peci_reset);
dc->desc = "Aspeed PECI Controller";
}
diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
index 8bb1f90..a7d101b 100644
--- a/hw/misc/aspeed_sbc.c
+++ b/hw/misc/aspeed_sbc.c
@@ -136,18 +136,17 @@ static const VMStateDescription vmstate_aspeed_sbc = {
}
};
-static Property aspeed_sbc_properties[] = {
+static const Property aspeed_sbc_properties[] = {
DEFINE_PROP_BOOL("emmc-abr", AspeedSBCState, emmc_abr, 0),
DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_settings, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_sbc_class_init(ObjectClass *klass, void *data)
+static void aspeed_sbc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_sbc_realize;
- dc->reset = aspeed_sbc_reset;
+ device_class_set_legacy_reset(dc, aspeed_sbc_reset);
dc->vmsd = &vmstate_aspeed_sbc;
device_class_set_props(dc, aspeed_sbc_properties);
}
@@ -160,7 +159,7 @@ static const TypeInfo aspeed_sbc_info = {
.class_size = sizeof(AspeedSBCClass)
};
-static void aspeed_ast2600_sbc_class_init(ObjectClass *klass, void *data)
+static void aspeed_ast2600_sbc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 451e837..4930e00 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -157,6 +157,7 @@
#define AST2700_SCU_FREQ_CNTR TO_REG(0x3b0)
#define AST2700_SCU_CPU_SCRATCH_0 TO_REG(0x780)
#define AST2700_SCU_CPU_SCRATCH_1 TO_REG(0x784)
+#define AST2700_SCU_VGA_SCRATCH_0 TO_REG(0x900)
#define AST2700_SCUIO_CLK_STOP_CTL_1 TO_REG(0x240)
#define AST2700_SCUIO_CLK_STOP_CLR_1 TO_REG(0x244)
@@ -426,6 +427,10 @@ static const MemoryRegionOps aspeed_ast2400_scu_ops = {
.read = aspeed_scu_read,
.write = aspeed_ast2400_scu_write,
.endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
.valid = {
.min_access_size = 1,
.max_access_size = 4,
@@ -436,7 +441,9 @@ static const MemoryRegionOps aspeed_ast2500_scu_ops = {
.read = aspeed_scu_read,
.write = aspeed_ast2500_scu_write,
.endianness = DEVICE_LITTLE_ENDIAN,
- .valid.min_access_size = 4,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 1,
.valid.max_access_size = 4,
.valid.unaligned = false,
};
@@ -559,6 +566,8 @@ static uint32_t aspeed_silicon_revs[] = {
AST2700_A0_SILICON_REV,
AST2720_A0_SILICON_REV,
AST2750_A0_SILICON_REV,
+ AST2700_A1_SILICON_REV,
+ AST2750_A1_SILICON_REV,
};
bool is_supported_silicon_rev(uint32_t silicon_rev)
@@ -602,19 +611,18 @@ static const VMStateDescription vmstate_aspeed_scu = {
}
};
-static Property aspeed_scu_properties[] = {
+static const Property aspeed_scu_properties[] = {
DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0),
DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0),
DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0),
DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_scu_class_init(ObjectClass *klass, void *data)
+static void aspeed_scu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_scu_realize;
- dc->reset = aspeed_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_scu_reset);
dc->desc = "ASPEED System Control Unit";
dc->vmsd = &vmstate_aspeed_scu;
device_class_set_props(dc, aspeed_scu_properties);
@@ -629,7 +637,7 @@ static const TypeInfo aspeed_scu_info = {
.abstract = true,
};
-static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_scu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
@@ -651,7 +659,7 @@ static const TypeInfo aspeed_2400_scu_info = {
.class_init = aspeed_2400_scu_class_init,
};
-static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_scu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
@@ -777,7 +785,9 @@ static const MemoryRegionOps aspeed_ast2600_scu_ops = {
.read = aspeed_ast2600_scu_read,
.write = aspeed_ast2600_scu_write,
.endianness = DEVICE_LITTLE_ENDIAN,
- .valid.min_access_size = 4,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 1,
.valid.max_access_size = 4,
.valid.unaligned = false,
};
@@ -825,13 +835,13 @@ static void aspeed_ast2600_scu_reset(DeviceState *dev)
s->regs[PROT_KEY] = s->hw_prot_key;
}
-static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_scu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2600 System Control Unit";
- dc->reset = aspeed_ast2600_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast2600_scu_reset);
asc->resets = ast2600_a3_resets;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2600_scu_get_apb_freq;
@@ -904,14 +914,14 @@ static const MemoryRegionOps aspeed_ast2700_scu_ops = {
.read = aspeed_ast2700_scu_read,
.write = aspeed_ast2700_scu_write,
.endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.valid.unaligned = false,
};
static const uint32_t ast2700_a0_resets[ASPEED_AST2700_SCU_NR_REGS] = {
- [AST2700_SILICON_REV] = AST2700_A0_SILICON_REV,
- [AST2700_HW_STRAP1] = 0x00000800,
[AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0,
[AST2700_HW_STRAP1_LOCK] = 0x00000FFF,
[AST2700_HW_STRAP1_SEC1] = 0x000000FF,
@@ -931,6 +941,7 @@ static const uint32_t ast2700_a0_resets[ASPEED_AST2700_SCU_NR_REGS] = {
[AST2700_SCU_FREQ_CNTR] = 0x000375eb,
[AST2700_SCU_CPU_SCRATCH_0] = 0x00000000,
[AST2700_SCU_CPU_SCRATCH_1] = 0x00000004,
+ [AST2700_SCU_VGA_SCRATCH_0] = 0x00000040,
};
static void aspeed_ast2700_scu_reset(DeviceState *dev)
@@ -939,15 +950,17 @@ static void aspeed_ast2700_scu_reset(DeviceState *dev)
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
memcpy(s->regs, asc->resets, asc->nr_regs * 4);
+ s->regs[AST2700_SILICON_REV] = s->silicon_rev;
+ s->regs[AST2700_HW_STRAP1] = s->hw_strap1;
}
-static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_scu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2700 System Control Unit";
- dc->reset = aspeed_ast2700_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset);
asc->resets = ast2700_a0_resets;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2700_scu_get_apb_freq;
@@ -1025,14 +1038,14 @@ static const MemoryRegionOps aspeed_ast2700_scuio_ops = {
.read = aspeed_ast2700_scuio_read,
.write = aspeed_ast2700_scuio_write,
.endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.valid.unaligned = false,
};
static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = {
- [AST2700_SILICON_REV] = 0x06000003,
- [AST2700_HW_STRAP1] = 0x00000504,
[AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0,
[AST2700_HW_STRAP1_LOCK] = 0x00000FFF,
[AST2700_HW_STRAP1_SEC1] = 0x000000FF,
@@ -1055,13 +1068,13 @@ static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = {
[AST2700_SCUIO_CLK_DUTY_MEAS_RST] = 0x0c9100d2,
};
-static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_scuio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2700 System Control Unit I/O";
- dc->reset = aspeed_ast2700_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset);
asc->resets = ast2700_a0_resets_io;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2700_scuio_get_apb_freq;
@@ -1113,13 +1126,13 @@ static void aspeed_ast1030_scu_reset(DeviceState *dev)
s->regs[PROT_KEY] = s->hw_prot_key;
}
-static void aspeed_1030_scu_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_scu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 1030 System Control Unit";
- dc->reset = aspeed_ast1030_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast1030_scu_reset);
asc->resets = ast1030_a1_resets;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_1030_scu_get_apb_freq;
diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index ebf139c..f04d993 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -294,17 +294,16 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
}
};
-static Property aspeed_sdmc_properties[] = {
+static const Property aspeed_sdmc_properties[] = {
DEFINE_PROP_UINT64("max-ram-size", AspeedSDMCState, max_ram_size, 0),
DEFINE_PROP_BOOL("unlocked", AspeedSDMCState, unlocked, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_sdmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_sdmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_sdmc_realize;
- dc->reset = aspeed_sdmc_reset;
+ device_class_set_legacy_reset(dc, aspeed_sdmc_reset);
dc->desc = "ASPEED SDRAM Memory Controller";
dc->vmsd = &vmstate_aspeed_sdmc;
device_class_set_props(dc, aspeed_sdmc_properties);
@@ -381,7 +380,7 @@ static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg,
static const uint64_t
aspeed_2400_ram_sizes[] = { 64 * MiB, 128 * MiB, 256 * MiB, 512 * MiB, 0};
-static void aspeed_2400_sdmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_sdmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
@@ -449,7 +448,7 @@ static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg,
static const uint64_t
aspeed_2500_ram_sizes[] = { 128 * MiB, 256 * MiB, 512 * MiB, 1024 * MiB, 0};
-static void aspeed_2500_sdmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_sdmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
@@ -543,7 +542,7 @@ static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg,
static const uint64_t
aspeed_2600_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB, 2048 * MiB, 0};
-static void aspeed_2600_sdmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_sdmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
@@ -671,13 +670,13 @@ static const uint64_t
aspeed_2700_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB,
2048 * MiB, 4096 * MiB, 8192 * MiB, 0};
-static void aspeed_2700_sdmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_sdmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
dc->desc = "ASPEED 2700 SDRAM Memory Controller";
- dc->reset = aspeed_2700_sdmc_reset;
+ device_class_set_legacy_reset(dc, aspeed_2700_sdmc_reset);
asc->is_bus64bit = true;
asc->max_ram_size = 8 * GiB;
diff --git a/hw/misc/aspeed_sli.c b/hw/misc/aspeed_sli.c
index fe720ea..c514840 100644
--- a/hw/misc/aspeed_sli.c
+++ b/hw/misc/aspeed_sli.c
@@ -124,7 +124,7 @@ static void aspeed_sliio_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void aspeed_sli_class_init(ObjectClass *klass, void *data)
+static void aspeed_sli_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -140,14 +140,14 @@ static const TypeInfo aspeed_sli_info = {
.abstract = true,
};
-static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_sli_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "AST2700 SLI Controller";
}
-static void aspeed_2700_sliio_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_sliio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c
index 76ab846..cc03c42 100644
--- a/hw/misc/aspeed_xdma.c
+++ b/hw/misc/aspeed_xdma.c
@@ -150,7 +150,7 @@ static const VMStateDescription aspeed_xdma_vmstate = {
},
};
-static void aspeed_2600_xdma_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_xdma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
@@ -173,7 +173,7 @@ static const TypeInfo aspeed_2600_xdma_info = {
.class_init = aspeed_2600_xdma_class_init,
};
-static void aspeed_2500_xdma_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_xdma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
@@ -195,7 +195,7 @@ static const TypeInfo aspeed_2500_xdma_info = {
.class_init = aspeed_2500_xdma_class_init,
};
-static void aspeed_2400_xdma_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_xdma_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
@@ -217,12 +217,12 @@ static const TypeInfo aspeed_2400_xdma_info = {
.class_init = aspeed_2400_xdma_class_init,
};
-static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
+static void aspeed_xdma_class_init(ObjectClass *classp, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->realize = aspeed_xdma_realize;
- dc->reset = aspeed_xdma_reset;
+ device_class_set_legacy_reset(dc, aspeed_xdma_reset);
dc->vmsd = &aspeed_xdma_vmstate;
}
diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c
index 28d50d9..877f345 100644
--- a/hw/misc/auxbus.c
+++ b/hw/misc/auxbus.c
@@ -50,7 +50,7 @@ static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent);
static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge);
/* aux-bus implementation (internal not public) */
-static void aux_bus_class_init(ObjectClass *klass, void *data)
+static void aux_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
@@ -256,7 +256,7 @@ struct AUXTOI2CState {
I2CBus *i2c_bus;
};
-static void aux_bridge_class_init(ObjectClass *oc, void *data)
+static void aux_bridge_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -311,7 +311,7 @@ void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio)
aux_slave->mmio = mmio;
}
-static void aux_slave_class_init(ObjectClass *klass, void *data)
+static void aux_slave_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
diff --git a/hw/misc/avr_power.c b/hw/misc/avr_power.c
index a5412f2..411f016 100644
--- a/hw/misc/avr_power.c
+++ b/hw/misc/avr_power.c
@@ -90,11 +90,11 @@ static void avr_mask_init(Object *dev)
s->val = 0x00;
}
-static void avr_mask_class_init(ObjectClass *klass, void *data)
+static void avr_mask_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = avr_mask_reset;
+ device_class_set_legacy_reset(dc, avr_mask_reset);
}
static const TypeInfo avr_mask_info = {
diff --git a/hw/misc/axp2xx.c b/hw/misc/axp2xx.c
index af64687..46d1771 100644
--- a/hw/misc/axp2xx.c
+++ b/hw/misc/axp2xx.c
@@ -225,7 +225,7 @@ static const VMStateDescription vmstate_axp2xx = {
}
};
-static void axp2xx_class_init(ObjectClass *oc, void *data)
+static void axp2xx_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
@@ -247,7 +247,7 @@ static const TypeInfo axp2xx_info = {
.abstract = true,
};
-static void axp209_class_init(ObjectClass *oc, void *data)
+static void axp209_class_init(ObjectClass *oc, const void *data)
{
AXP2xxClass *sc = AXP2XX_CLASS(oc);
@@ -260,7 +260,7 @@ static const TypeInfo axp209_info = {
.class_init = axp209_class_init
};
-static void axp221_class_init(ObjectClass *oc, void *data)
+static void axp221_class_init(ObjectClass *oc, const void *data)
{
AXP2xxClass *sc = AXP2XX_CLASS(oc);
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
index 91c8f7b..efe6f90 100644
--- a/hw/misc/bcm2835_cprman.c
+++ b/hw/misc/bcm2835_cprman.c
@@ -131,12 +131,14 @@ static const VMStateDescription pll_vmstate = {
}
};
-static void pll_class_init(ObjectClass *klass, void *data)
+static void pll_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pll_reset;
+ device_class_set_legacy_reset(dc, pll_reset);
dc->vmsd = &pll_vmstate;
+ /* Reason: Part of BCM2835CprmanState component */
+ dc->user_creatable = false;
}
static const TypeInfo cprman_pll_info = {
@@ -235,12 +237,14 @@ static const VMStateDescription pll_channel_vmstate = {
}
};
-static void pll_channel_class_init(ObjectClass *klass, void *data)
+static void pll_channel_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pll_channel_reset;
+ device_class_set_legacy_reset(dc, pll_channel_reset);
dc->vmsd = &pll_channel_vmstate;
+ /* Reason: Part of BCM2835CprmanState component */
+ dc->user_creatable = false;
}
static const TypeInfo cprman_pll_channel_info = {
@@ -356,12 +360,14 @@ static const VMStateDescription clock_mux_vmstate = {
}
};
-static void clock_mux_class_init(ObjectClass *klass, void *data)
+static void clock_mux_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = clock_mux_reset;
+ device_class_set_legacy_reset(dc, clock_mux_reset);
dc->vmsd = &clock_mux_vmstate;
+ /* Reason: Part of BCM2835CprmanState component */
+ dc->user_creatable = false;
}
static const TypeInfo cprman_clock_mux_info = {
@@ -411,11 +417,13 @@ static const VMStateDescription dsi0hsck_mux_vmstate = {
}
};
-static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data)
+static void dsi0hsck_mux_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &dsi0hsck_mux_vmstate;
+ /* Reason: Part of BCM2835CprmanState component */
+ dc->user_creatable = false;
}
static const TypeInfo cprman_dsi0hsck_mux_info = {
@@ -778,17 +786,16 @@ static const VMStateDescription cprman_vmstate = {
}
};
-static Property cprman_properties[] = {
+static const Property cprman_properties[] = {
DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000),
- DEFINE_PROP_END_OF_LIST()
};
-static void cprman_class_init(ObjectClass *klass, void *data)
+static void cprman_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cprman_realize;
- dc->reset = cprman_reset;
+ device_class_set_legacy_reset(dc, cprman_reset);
dc->vmsd = &cprman_vmstate;
device_class_set_props(dc, cprman_properties);
}
diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c
index 67bfc3b..603eaaa 100644
--- a/hw/misc/bcm2835_mbox.c
+++ b/hw/misc/bcm2835_mbox.c
@@ -314,12 +314,12 @@ static void bcm2835_mbox_realize(DeviceState *dev, Error **errp)
bcm2835_mbox_reset(dev);
}
-static void bcm2835_mbox_class_init(ObjectClass *klass, void *data)
+static void bcm2835_mbox_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_mbox_realize;
- dc->reset = bcm2835_mbox_reset;
+ device_class_set_legacy_reset(dc, bcm2835_mbox_reset);
dc->vmsd = &vmstate_bcm2835_mbox;
}
diff --git a/hw/misc/bcm2835_mphi.c b/hw/misc/bcm2835_mphi.c
index f1eeda2..55d79e7 100644
--- a/hw/misc/bcm2835_mphi.c
+++ b/hw/misc/bcm2835_mphi.c
@@ -166,12 +166,12 @@ const VMStateDescription vmstate_mphi_state = {
}
};
-static void mphi_class_init(ObjectClass *klass, void *data)
+static void mphi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mphi_realize;
- dc->reset = mphi_reset;
+ device_class_set_legacy_reset(dc, mphi_reset);
dc->vmsd = &vmstate_mphi_state;
}
diff --git a/hw/misc/bcm2835_powermgt.c b/hw/misc/bcm2835_powermgt.c
index 1649da8..3ec7aba 100644
--- a/hw/misc/bcm2835_powermgt.c
+++ b/hw/misc/bcm2835_powermgt.c
@@ -13,7 +13,7 @@
#include "qemu/module.h"
#include "hw/misc/bcm2835_powermgt.h"
#include "migration/vmstate.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#define PASSWORD 0x5a000000
#define PASSWORD_MASK 0xff000000
@@ -136,11 +136,11 @@ static void bcm2835_powermgt_reset(DeviceState *dev)
s->wdog = 0x00000000;
}
-static void bcm2835_powermgt_class_init(ObjectClass *klass, void *data)
+static void bcm2835_powermgt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_powermgt_reset;
+ device_class_set_legacy_reset(dc, bcm2835_powermgt_reset);
dc->vmsd = &vmstate_bcm2835_powermgt;
}
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index 8ca3128..a21c6a5 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -13,7 +13,7 @@
#include "hw/irq.h"
#include "hw/misc/bcm2835_mbox_defs.h"
#include "hw/arm/raspberrypi-fw-defs.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
@@ -551,13 +551,12 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp)
bcm2835_property_reset(dev);
}
-static Property bcm2835_property_props[] = {
+static const Property bcm2835_property_props[] = {
DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0),
DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line),
- DEFINE_PROP_END_OF_LIST()
};
-static void bcm2835_property_class_init(ObjectClass *klass, void *data)
+static void bcm2835_property_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/bcm2835_rng.c b/hw/misc/bcm2835_rng.c
index 10e741b..e4d2c22 100644
--- a/hw/misc/bcm2835_rng.c
+++ b/hw/misc/bcm2835_rng.c
@@ -123,11 +123,11 @@ static void bcm2835_rng_reset(DeviceState *dev)
s->rng_status = 0;
}
-static void bcm2835_rng_class_init(ObjectClass *klass, void *data)
+static void bcm2835_rng_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_rng_reset;
+ device_class_set_legacy_reset(dc, bcm2835_rng_reset);
dc->vmsd = &vmstate_bcm2835_rng;
}
diff --git a/hw/misc/bcm2835_thermal.c b/hw/misc/bcm2835_thermal.c
index 0c49c08..33bfc91 100644
--- a/hw/misc/bcm2835_thermal.c
+++ b/hw/misc/bcm2835_thermal.c
@@ -113,12 +113,12 @@ static const VMStateDescription bcm2835_thermal_vmstate = {
}
};
-static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
+static void bcm2835_thermal_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_thermal_realize;
- dc->reset = bcm2835_thermal_reset;
+ device_class_set_legacy_reset(dc, bcm2835_thermal_reset);
dc->vmsd = &bcm2835_thermal_vmstate;
}
diff --git a/hw/misc/cbus.c b/hw/misc/cbus.c
deleted file mode 100644
index 653e8dd..0000000
--- a/hw/misc/cbus.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
- * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/misc/cbus.h"
-#include "sysemu/runstate.h"
-
-//#define DEBUG
-
-typedef struct {
- void *opaque;
- void (*io)(void *opaque, int rw, int reg, uint16_t *val);
- int addr;
-} CBusSlave;
-
-typedef struct {
- CBus cbus;
-
- int sel;
- int dat;
- int clk;
- int bit;
- int dir;
- uint16_t val;
- qemu_irq dat_out;
-
- int addr;
- int reg;
- int rw;
- enum {
- cbus_address,
- cbus_value,
- } cycle;
-
- CBusSlave *slave[8];
-} CBusPriv;
-
-static void cbus_io(CBusPriv *s)
-{
- if (s->slave[s->addr])
- s->slave[s->addr]->io(s->slave[s->addr]->opaque,
- s->rw, s->reg, &s->val);
- else
- hw_error("%s: bad slave address %i\n", __func__, s->addr);
-}
-
-static void cbus_cycle(CBusPriv *s)
-{
- switch (s->cycle) {
- case cbus_address:
- s->addr = (s->val >> 6) & 7;
- s->rw = (s->val >> 5) & 1;
- s->reg = (s->val >> 0) & 0x1f;
-
- s->cycle = cbus_value;
- s->bit = 15;
- s->dir = !s->rw;
- s->val = 0;
-
- if (s->rw)
- cbus_io(s);
- break;
-
- case cbus_value:
- if (!s->rw)
- cbus_io(s);
-
- s->cycle = cbus_address;
- s->bit = 8;
- s->dir = 1;
- s->val = 0;
- break;
- }
-}
-
-static void cbus_clk(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- if (!s->sel && level && !s->clk) {
- if (s->dir)
- s->val |= s->dat << (s->bit --);
- else
- qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
-
- if (s->bit < 0)
- cbus_cycle(s);
- }
-
- s->clk = level;
-}
-
-static void cbus_dat(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- s->dat = level;
-}
-
-static void cbus_sel(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- if (!level) {
- s->dir = 1;
- s->bit = 8;
- s->val = 0;
- }
-
- s->sel = level;
-}
-
-CBus *cbus_init(qemu_irq dat)
-{
- CBusPriv *s = g_malloc0(sizeof(*s));
-
- s->dat_out = dat;
- s->cbus.clk = qemu_allocate_irq(cbus_clk, s, 0);
- s->cbus.dat = qemu_allocate_irq(cbus_dat, s, 0);
- s->cbus.sel = qemu_allocate_irq(cbus_sel, s, 0);
-
- s->sel = 1;
- s->clk = 0;
- s->dat = 0;
-
- return &s->cbus;
-}
-
-void cbus_attach(CBus *bus, void *slave_opaque)
-{
- CBusSlave *slave = (CBusSlave *) slave_opaque;
- CBusPriv *s = (CBusPriv *) bus;
-
- s->slave[slave->addr] = slave;
-}
-
-/* Retu/Vilma */
-typedef struct {
- uint16_t irqst;
- uint16_t irqen;
- uint16_t cc[2];
- int channel;
- uint16_t result[16];
- uint16_t sample;
- uint16_t status;
-
- struct {
- uint16_t cal;
- } rtc;
-
- int is_vilma;
- qemu_irq irq;
- CBusSlave cbus;
-} CBusRetu;
-
-static void retu_interrupt_update(CBusRetu *s)
-{
- qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
-#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
-#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
-#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
-#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
-#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
-#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
-#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
-#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
-#define RETU_REG_AFCR 0x0a /* (RW) AFC register */
-#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
-#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
-#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
-#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
-#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
-#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
-#define RETU_REG_TXCR 0x11 /* (RW) TxC register */
-#define RETU_REG_STATUS 0x16 /* (RO) Status register */
-#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
-#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
-#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
-#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
-#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
-#define RETU_REG_SGR1 0x1c /* (RW) */
-#define RETU_REG_SCR1 0x1d /* (RW) */
-#define RETU_REG_SGR2 0x1e /* (RW) */
-#define RETU_REG_SCR2 0x1f /* (RW) */
-
-/* Retu Interrupt sources */
-enum {
- retu_int_pwr = 0, /* Power button */
- retu_int_char = 1, /* Charger */
- retu_int_rtcs = 2, /* Seconds */
- retu_int_rtcm = 3, /* Minutes */
- retu_int_rtcd = 4, /* Days */
- retu_int_rtca = 5, /* Alarm */
- retu_int_hook = 6, /* Hook */
- retu_int_head = 7, /* Headset */
- retu_int_adcs = 8, /* ADC sample */
-};
-
-/* Retu ADC channel wiring */
-enum {
- retu_adc_bsi = 1, /* BSI */
- retu_adc_batt_temp = 2, /* Battery temperature */
- retu_adc_chg_volt = 3, /* Charger voltage */
- retu_adc_head_det = 4, /* Headset detection */
- retu_adc_hook_det = 5, /* Hook detection */
- retu_adc_rf_gp = 6, /* RF GP */
- retu_adc_tx_det = 7, /* Wideband Tx detection */
- retu_adc_batt_volt = 8, /* Battery voltage */
- retu_adc_sens = 10, /* Light sensor */
- retu_adc_sens_temp = 11, /* Light sensor temperature */
- retu_adc_bbatt_volt = 12, /* Backup battery voltage */
- retu_adc_self_temp = 13, /* RETU temperature */
-};
-
-static inline uint16_t retu_read(CBusRetu *s, int reg)
-{
-#ifdef DEBUG
- printf("RETU read at %02x\n", reg);
-#endif
-
- switch (reg) {
- case RETU_REG_ASICR:
- return 0x0215 | (s->is_vilma << 7);
-
- case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
- return s->irqst;
-
- case RETU_REG_IMR:
- return s->irqen;
-
- case RETU_REG_RTCDSR:
- case RETU_REG_RTCHMR:
- case RETU_REG_RTCHMAR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_RTCCALR:
- return s->rtc.cal;
-
- case RETU_REG_ADCR:
- return (s->channel << 10) | s->result[s->channel];
- case RETU_REG_ADCSCR:
- return s->sample;
-
- case RETU_REG_AFCR:
- case RETU_REG_ANTIFR:
- case RETU_REG_CALIBR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_CCR1:
- return s->cc[0];
- case RETU_REG_CCR2:
- return s->cc[1];
-
- case RETU_REG_RCTRL_CLR:
- case RETU_REG_RCTRL_SET:
- case RETU_REG_TXCR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_STATUS:
- return s->status;
-
- case RETU_REG_WATCHDOG:
- case RETU_REG_AUDTXR:
- case RETU_REG_AUDPAR:
- case RETU_REG_AUDRXR1:
- case RETU_REG_AUDRXR2:
- case RETU_REG_SGR1:
- case RETU_REG_SCR1:
- case RETU_REG_SGR2:
- case RETU_REG_SCR2:
- /* TODO */
- return 0x0000;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
- printf("RETU write of %04x at %02x\n", val, reg);
-#endif
-
- switch (reg) {
- case RETU_REG_IDR:
- s->irqst ^= val;
- retu_interrupt_update(s);
- break;
-
- case RETU_REG_IMR:
- s->irqen = val;
- retu_interrupt_update(s);
- break;
-
- case RETU_REG_RTCDSR:
- case RETU_REG_RTCHMAR:
- /* TODO */
- break;
-
- case RETU_REG_RTCCALR:
- s->rtc.cal = val;
- break;
-
- case RETU_REG_ADCR:
- s->channel = (val >> 10) & 0xf;
- s->irqst |= 1 << retu_int_adcs;
- retu_interrupt_update(s);
- break;
- case RETU_REG_ADCSCR:
- s->sample &= ~val;
- break;
-
- case RETU_REG_AFCR:
- case RETU_REG_ANTIFR:
- case RETU_REG_CALIBR:
-
- case RETU_REG_CCR1:
- s->cc[0] = val;
- break;
- case RETU_REG_CCR2:
- s->cc[1] = val;
- break;
-
- case RETU_REG_RCTRL_CLR:
- case RETU_REG_RCTRL_SET:
- /* TODO */
- break;
-
- case RETU_REG_WATCHDOG:
- if (val == 0 && (s->cc[0] & 2))
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
- break;
-
- case RETU_REG_TXCR:
- case RETU_REG_AUDTXR:
- case RETU_REG_AUDPAR:
- case RETU_REG_AUDRXR1:
- case RETU_REG_AUDRXR2:
- case RETU_REG_SGR1:
- case RETU_REG_SCR1:
- case RETU_REG_SGR2:
- case RETU_REG_SCR2:
- /* TODO */
- break;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
-{
- CBusRetu *s = (CBusRetu *) opaque;
-
- if (rw)
- *val = retu_read(s, reg);
- else
- retu_write(s, reg, *val);
-}
-
-void *retu_init(qemu_irq irq, int vilma)
-{
- CBusRetu *s = g_malloc0(sizeof(*s));
-
- s->irq = irq;
- s->irqen = 0xffff;
- s->irqst = 0x0000;
- s->status = 0x0020;
- s->is_vilma = !!vilma;
- s->rtc.cal = 0x01;
- s->result[retu_adc_bsi] = 0x3c2;
- s->result[retu_adc_batt_temp] = 0x0fc;
- s->result[retu_adc_chg_volt] = 0x165;
- s->result[retu_adc_head_det] = 123;
- s->result[retu_adc_hook_det] = 1023;
- s->result[retu_adc_rf_gp] = 0x11;
- s->result[retu_adc_tx_det] = 0x11;
- s->result[retu_adc_batt_volt] = 0x250;
- s->result[retu_adc_sens] = 2;
- s->result[retu_adc_sens_temp] = 0x11;
- s->result[retu_adc_bbatt_volt] = 0x3d0;
- s->result[retu_adc_self_temp] = 0x330;
-
- s->cbus.opaque = s;
- s->cbus.io = retu_io;
- s->cbus.addr = 1;
-
- return &s->cbus;
-}
-
-void retu_key_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- s->irqst |= 1 << retu_int_pwr;
- retu_interrupt_update(s);
-
- if (state)
- s->status &= ~(1 << 5);
- else
- s->status |= 1 << 5;
-}
-
-#if 0
-static void retu_head_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
- /* TODO: reissue the interrupt every 100ms or so. */
- s->irqst |= 1 << retu_int_head;
- retu_interrupt_update(s);
- }
-
- if (state)
- s->result[retu_adc_head_det] = 50;
- else
- s->result[retu_adc_head_det] = 123;
-}
-
-static void retu_hook_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- if ((s->cc[0] & 0x500) == 0x500) {
- /* TODO: reissue the interrupt every 100ms or so. */
- s->irqst |= 1 << retu_int_hook;
- retu_interrupt_update(s);
- }
-
- if (state)
- s->result[retu_adc_hook_det] = 50;
- else
- s->result[retu_adc_hook_det] = 123;
-}
-#endif
-
-/* Tahvo/Betty */
-typedef struct {
- uint16_t irqst;
- uint16_t irqen;
- uint8_t charger;
- uint8_t backlight;
- uint16_t usbr;
- uint16_t power;
-
- int is_betty;
- qemu_irq irq;
- CBusSlave cbus;
-} CBusTahvo;
-
-static void tahvo_interrupt_update(CBusTahvo *s)
-{
- qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
-#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
-#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
-#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
-#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
-#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
-#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
-#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
-#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
-#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
-#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
-#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
-#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
-#define TAHVO_REG_FRR 0x0d /* (RO) FR */
-
-static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
-{
-#ifdef DEBUG
- printf("TAHVO read at %02x\n", reg);
-#endif
-
- switch (reg) {
- case TAHVO_REG_ASICR:
- return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
-
- case TAHVO_REG_IDR:
- case TAHVO_REG_IDSR: /* XXX: what does this do? */
- return s->irqst;
-
- case TAHVO_REG_IMR:
- return s->irqen;
-
- case TAHVO_REG_CHAPWMR:
- return s->charger;
-
- case TAHVO_REG_LEDPWMR:
- return s->backlight;
-
- case TAHVO_REG_USBR:
- return s->usbr;
-
- case TAHVO_REG_RCR:
- return s->power;
-
- case TAHVO_REG_CCR1:
- case TAHVO_REG_CCR2:
- case TAHVO_REG_TESTR1:
- case TAHVO_REG_TESTR2:
- case TAHVO_REG_NOPR:
- case TAHVO_REG_FRR:
- return 0x0000;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
- printf("TAHVO write of %04x at %02x\n", val, reg);
-#endif
-
- switch (reg) {
- case TAHVO_REG_IDR:
- s->irqst ^= val;
- tahvo_interrupt_update(s);
- break;
-
- case TAHVO_REG_IMR:
- s->irqen = val;
- tahvo_interrupt_update(s);
- break;
-
- case TAHVO_REG_CHAPWMR:
- s->charger = val;
- break;
-
- case TAHVO_REG_LEDPWMR:
- if (s->backlight != (val & 0x7f)) {
- s->backlight = val & 0x7f;
- printf("%s: LCD backlight now at %i / 127\n",
- __func__, s->backlight);
- }
- break;
-
- case TAHVO_REG_USBR:
- s->usbr = val;
- break;
-
- case TAHVO_REG_RCR:
- s->power = val;
- break;
-
- case TAHVO_REG_CCR1:
- case TAHVO_REG_CCR2:
- case TAHVO_REG_TESTR1:
- case TAHVO_REG_TESTR2:
- case TAHVO_REG_NOPR:
- case TAHVO_REG_FRR:
- break;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
-{
- CBusTahvo *s = (CBusTahvo *) opaque;
-
- if (rw)
- *val = tahvo_read(s, reg);
- else
- tahvo_write(s, reg, *val);
-}
-
-void *tahvo_init(qemu_irq irq, int betty)
-{
- CBusTahvo *s = g_malloc0(sizeof(*s));
-
- s->irq = irq;
- s->irqen = 0xffff;
- s->irqst = 0x0000;
- s->is_betty = !!betty;
-
- s->cbus.opaque = s;
- s->cbus.io = tahvo_io;
- s->cbus.addr = 2;
-
- return &s->cbus;
-}
diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c
index c5c562f..04a9fc3 100644
--- a/hw/misc/debugexit.c
+++ b/hw/misc/debugexit.c
@@ -12,7 +12,7 @@
#include "hw/qdev-properties.h"
#include "qemu/module.h"
#include "qom/object.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit"
OBJECT_DECLARE_SIMPLE_TYPE(ISADebugExitState, ISA_DEBUG_EXIT_DEVICE)
@@ -56,13 +56,12 @@ static void debug_exit_realizefn(DeviceState *d, Error **errp)
isa->iobase, &isa->io);
}
-static Property debug_exit_properties[] = {
+static const Property debug_exit_properties[] = {
DEFINE_PROP_UINT32("iobase", ISADebugExitState, iobase, 0x501),
DEFINE_PROP_UINT32("iosize", ISADebugExitState, iosize, 0x02),
- DEFINE_PROP_END_OF_LIST(),
};
-static void debug_exit_class_initfn(ObjectClass *klass, void *data)
+static void debug_exit_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/djmemc.c b/hw/misc/djmemc.c
index 96d5efb..c5b09f5 100644
--- a/hw/misc/djmemc.c
+++ b/hw/misc/djmemc.c
@@ -113,7 +113,7 @@ static const VMStateDescription vmstate_djmemc = {
}
};
-static void djmemc_class_init(ObjectClass *oc, void *data)
+static void djmemc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
diff --git a/hw/misc/eccmemctl.c b/hw/misc/eccmemctl.c
index 5a14a48..81fc536 100644
--- a/hw/misc/eccmemctl.c
+++ b/hw/misc/eccmemctl.c
@@ -325,17 +325,16 @@ static void ecc_realize(DeviceState *dev, Error **errp)
}
}
-static Property ecc_properties[] = {
+static const Property ecc_properties[] = {
DEFINE_PROP_UINT32("version", ECCState, version, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ecc_class_init(ObjectClass *klass, void *data)
+static void ecc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ecc_realize;
- dc->reset = ecc_reset;
+ device_class_set_legacy_reset(dc, ecc_reset);
dc->vmsd = &vmstate_ecc;
device_class_set_props(dc, ecc_properties);
}
diff --git a/hw/misc/edu.c b/hw/misc/edu.c
index 504178b..cece633 100644
--- a/hw/misc/edu.c
+++ b/hw/misc/edu.c
@@ -415,7 +415,7 @@ static void edu_instance_init(Object *obj)
&edu->dma_mask, OBJ_PROP_FLAG_READWRITE);
}
-static void edu_class_init(ObjectClass *class, void *data)
+static void edu_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
PCIDeviceClass *k = PCI_DEVICE_CLASS(class);
@@ -429,21 +429,18 @@ static void edu_class_init(ObjectClass *class, void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
-static void pci_edu_register_types(void)
-{
- static InterfaceInfo interfaces[] = {
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- { },
- };
- static const TypeInfo edu_info = {
+static const TypeInfo edu_types[] = {
+ {
.name = TYPE_PCI_EDU_DEVICE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(EduState),
.instance_init = edu_instance_init,
.class_init = edu_class_init,
- .interfaces = interfaces,
- };
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+ }
+};
- type_register_static(&edu_info);
-}
-type_init(pci_edu_register_types)
+DEFINE_TYPES(edu_types)
diff --git a/hw/misc/empty_slot.c b/hw/misc/empty_slot.c
index 37b0ddf..239d760 100644
--- a/hw/misc/empty_slot.c
+++ b/hw/misc/empty_slot.c
@@ -79,13 +79,12 @@ static void empty_slot_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
-static Property empty_slot_properties[] = {
+static const Property empty_slot_properties[] = {
DEFINE_PROP_UINT64("size", EmptySlot, size, 0),
DEFINE_PROP_STRING("name", EmptySlot, name),
- DEFINE_PROP_END_OF_LIST(),
};
-static void empty_slot_class_init(ObjectClass *klass, void *data)
+static void empty_slot_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/exynos4210_clk.c b/hw/misc/exynos4210_clk.c
index 4566a42..fdf5bdd 100644
--- a/hw/misc/exynos4210_clk.c
+++ b/hw/misc/exynos4210_clk.c
@@ -141,11 +141,11 @@ static const VMStateDescription exynos4210_clk_vmstate = {
}
};
-static void exynos4210_clk_class_init(ObjectClass *klass, void *data)
+static void exynos4210_clk_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_clk_reset;
+ device_class_set_legacy_reset(dc, exynos4210_clk_reset);
dc->vmsd = &exynos4210_clk_vmstate;
}
diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c
index 7e28e79..a86ec9a 100644
--- a/hw/misc/exynos4210_pmu.c
+++ b/hw/misc/exynos4210_pmu.c
@@ -28,7 +28,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "qom/object.h"
#ifndef DEBUG_PMU
@@ -498,11 +498,11 @@ static const VMStateDescription exynos4210_pmu_vmstate = {
}
};
-static void exynos4210_pmu_class_init(ObjectClass *klass, void *data)
+static void exynos4210_pmu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_pmu_reset;
+ device_class_set_legacy_reset(dc, exynos4210_pmu_reset);
dc->vmsd = &exynos4210_pmu_vmstate;
}
diff --git a/hw/misc/exynos4210_rng.c b/hw/misc/exynos4210_rng.c
index 674d8ee..2d0ebc4 100644
--- a/hw/misc/exynos4210_rng.c
+++ b/hw/misc/exynos4210_rng.c
@@ -255,11 +255,11 @@ static const VMStateDescription exynos4210_rng_vmstate = {
}
};
-static void exynos4210_rng_class_init(ObjectClass *klass, void *data)
+static void exynos4210_rng_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_rng_reset;
+ device_class_set_legacy_reset(dc, exynos4210_rng_reset);
dc->vmsd = &exynos4210_rng_vmstate;
}
diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c
index 5b05f15..cdca00a 100644
--- a/hw/misc/grlib_ahb_apb_pnp.c
+++ b/hw/misc/grlib_ahb_apb_pnp.c
@@ -168,7 +168,7 @@ static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &ahb_pnp->iomem);
}
-static void grlib_ahb_pnp_class_init(ObjectClass *klass, void *data)
+static void grlib_ahb_pnp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -280,7 +280,7 @@ static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &apb_pnp->iomem);
}
-static void grlib_apb_pnp_class_init(ObjectClass *klass, void *data)
+static void grlib_apb_pnp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/i2c-echo.c b/hw/misc/i2c-echo.c
index 5ae3d08..2bb99ec 100644
--- a/hw/misc/i2c-echo.c
+++ b/hw/misc/i2c-echo.c
@@ -13,6 +13,7 @@
#include "qemu/main-loop.h"
#include "block/aio.h"
#include "hw/i2c/i2c.h"
+#include "trace.h"
#define TYPE_I2C_ECHO "i2c-echo"
OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO)
@@ -80,11 +81,13 @@ static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
case I2C_START_RECV:
state->pos = 0;
+ trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_START_RECV");
break;
case I2C_START_SEND:
state->pos = 0;
+ trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_START_SEND");
break;
case I2C_FINISH:
@@ -92,12 +95,15 @@ static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
state->state = I2C_ECHO_STATE_START_SEND;
i2c_bus_master(state->bus, state->bh);
+ trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_FINISH");
break;
case I2C_NACK:
+ trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_NACK");
break;
default:
+ trace_i2c_echo_event(DEVICE(s)->canonical_path, "UNHANDLED");
return -1;
}
@@ -112,6 +118,7 @@ static uint8_t i2c_echo_recv(I2CSlave *s)
return 0xff;
}
+ trace_i2c_echo_recv(DEVICE(s)->canonical_path, state->data[state->pos]);
return state->data[state->pos++];
}
@@ -119,6 +126,7 @@ static int i2c_echo_send(I2CSlave *s, uint8_t data)
{
I2CEchoState *state = I2C_ECHO(s);
+ trace_i2c_echo_send(DEVICE(s)->canonical_path, data);
if (state->pos > 2) {
return -1;
}
@@ -135,11 +143,9 @@ static void i2c_echo_realize(DeviceState *dev, Error **errp)
state->bus = I2C_BUS(bus);
state->bh = qemu_bh_new(i2c_echo_bh, state);
-
- return;
}
-static void i2c_echo_class_init(ObjectClass *oc, void *data)
+static void i2c_echo_class_init(ObjectClass *oc, const void *data)
{
I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c
index faa726a..a6665d5 100644
--- a/hw/misc/imx25_ccm.c
+++ b/hw/misc/imx25_ccm.c
@@ -292,12 +292,12 @@ static void imx25_ccm_init(Object *obj)
sysbus_init_mmio(sd, &s->iomem);
}
-static void imx25_ccm_class_init(ObjectClass *klass, void *data)
+static void imx25_ccm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx25_ccm_reset;
+ device_class_set_legacy_reset(dc, imx25_ccm_reset);
dc->vmsd = &vmstate_imx25_ccm;
dc->desc = "i.MX25 Clock Control Module";
diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c
index 125d4fc..339458e 100644
--- a/hw/misc/imx31_ccm.c
+++ b/hw/misc/imx31_ccm.c
@@ -319,12 +319,12 @@ static void imx31_ccm_init(Object *obj)
sysbus_init_mmio(sd, &s->iomem);
}
-static void imx31_ccm_class_init(ObjectClass *klass, void *data)
+static void imx31_ccm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx31_ccm_reset;
+ device_class_set_legacy_reset(dc, imx31_ccm_reset);
dc->vmsd = &vmstate_imx31_ccm;
dc->desc = "i.MX31 Clock Control Module";
diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c
index b1def7f..a10b67d 100644
--- a/hw/misc/imx6_ccm.c
+++ b/hw/misc/imx6_ccm.c
@@ -301,7 +301,6 @@ static uint64_t imx6_analog_get_periph_clk(IMX6CCMState *dev)
default:
/* We should never get there */
g_assert_not_reached();
- break;
}
trace_imx6_analog_get_periph_clk(freq);
@@ -742,12 +741,12 @@ static void imx6_ccm_init(Object *obj)
sysbus_init_mmio(sd, &s->container);
}
-static void imx6_ccm_class_init(ObjectClass *klass, void *data)
+static void imx6_ccm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx6_ccm_reset;
+ device_class_set_legacy_reset(dc, imx6_ccm_reset);
dc->vmsd = &vmstate_imx6_ccm;
dc->desc = "i.MX6 Clock Control Module";
diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c
index 3766bdf..8d2c417 100644
--- a/hw/misc/imx6_src.c
+++ b/hw/misc/imx6_src.c
@@ -17,18 +17,7 @@
#include "qemu/module.h"
#include "target/arm/arm-powerctl.h"
#include "hw/core/cpu.h"
-
-#ifndef DEBUG_IMX6_SRC
-#define DEBUG_IMX6_SRC 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX6_SRC) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_SRC, \
- __func__, ##args); \
- } \
- } while (0)
+#include "trace.h"
static const char *imx6_src_reg_name(uint32_t reg)
{
@@ -87,7 +76,7 @@ static void imx6_src_reset(DeviceState *dev)
{
IMX6SRCState *s = IMX6_SRC(dev);
- DPRINTF("\n");
+ trace_imx6_src_reset();
memset(s->regs, 0, sizeof(s->regs));
@@ -111,7 +100,7 @@ static uint64_t imx6_src_read(void *opaque, hwaddr offset, unsigned size)
}
- DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_src_reg_name(index), value);
+ trace_imx6_src_read(imx6_src_reg_name(index), value);
return value;
}
@@ -134,8 +123,7 @@ static void imx6_clear_reset_bit(CPUState *cpu, run_on_cpu_data data)
assert(bql_locked());
s->regs[SRC_SCR] = deposit32(s->regs[SRC_SCR], ri->reset_bit, 1, 0);
- DPRINTF("reg[%s] <= 0x%" PRIx32 "\n",
- imx6_src_reg_name(SRC_SCR), s->regs[SRC_SCR]);
+ trace_imx6_clear_reset_bit(imx6_src_reg_name(SRC_SCR), s->regs[SRC_SCR]);
g_free(ri);
}
@@ -173,8 +161,7 @@ static void imx6_src_write(void *opaque, hwaddr offset, uint64_t value,
return;
}
- DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_src_reg_name(index),
- (uint32_t)current_value);
+ trace_imx6_src_write(imx6_src_reg_name(index), value);
change_mask = s->regs[index] ^ (uint32_t)current_value;
@@ -286,12 +273,12 @@ static void imx6_src_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
-static void imx6_src_class_init(ObjectClass *klass, void *data)
+static void imx6_src_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx6_src_realize;
- dc->reset = imx6_src_reset;
+ device_class_set_legacy_reset(dc, imx6_src_reset);
dc->vmsd = &vmstate_imx6_src;
dc->desc = "i.MX6 System Reset Controller";
}
diff --git a/hw/misc/imx6ul_ccm.c b/hw/misc/imx6ul_ccm.c
index 0ac49ea..7f3ae61 100644
--- a/hw/misc/imx6ul_ccm.c
+++ b/hw/misc/imx6ul_ccm.c
@@ -904,12 +904,12 @@ static void imx6ul_ccm_init(Object *obj)
sysbus_init_mmio(sd, &s->container);
}
-static void imx6ul_ccm_class_init(ObjectClass *klass, void *data)
+static void imx6ul_ccm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx6ul_ccm_reset;
+ device_class_set_legacy_reset(dc, imx6ul_ccm_reset);
dc->vmsd = &vmstate_imx6ul_ccm;
dc->desc = "i.MX6UL Clock Control Module";
diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c
index 88354f0..c061a58 100644
--- a/hw/misc/imx7_ccm.c
+++ b/hw/misc/imx7_ccm.c
@@ -262,12 +262,12 @@ static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
return freq;
}
-static void imx7_ccm_class_init(ObjectClass *klass, void *data)
+static void imx7_ccm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx7_ccm_reset;
+ device_class_set_legacy_reset(dc, imx7_ccm_reset);
dc->vmsd = &vmstate_imx7_ccm;
dc->desc = "i.MX7 Clock Control Module";
@@ -293,11 +293,11 @@ static const VMStateDescription vmstate_imx7_analog = {
},
};
-static void imx7_analog_class_init(ObjectClass *klass, void *data)
+static void imx7_analog_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx7_analog_reset;
+ device_class_set_legacy_reset(dc, imx7_analog_reset);
dc->vmsd = &vmstate_imx7_analog;
dc->desc = "i.MX7 Analog Module";
}
diff --git a/hw/misc/imx7_gpr.c b/hw/misc/imx7_gpr.c
index b03341a..e12b496 100644
--- a/hw/misc/imx7_gpr.c
+++ b/hw/misc/imx7_gpr.c
@@ -102,7 +102,7 @@ static void imx7_gpr_init(Object *obj)
sysbus_init_mmio(sd, &s->mmio);
}
-static void imx7_gpr_class_init(ObjectClass *klass, void *data)
+static void imx7_gpr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c
index edb2df2..6a8733d 100644
--- a/hw/misc/imx7_snvs.c
+++ b/hw/misc/imx7_snvs.c
@@ -19,9 +19,9 @@
#include "hw/misc/imx7_snvs.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/rtc.h"
+#include "system/runstate.h"
#include "trace.h"
#define RTC_FREQ 32768ULL
@@ -143,11 +143,11 @@ static void imx7_snvs_init(Object *obj)
qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
}
-static void imx7_snvs_class_init(ObjectClass *klass, void *data)
+static void imx7_snvs_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx7_snvs_reset;
+ device_class_set_legacy_reset(dc, imx7_snvs_reset);
dc->vmsd = &vmstate_imx7_snvs;
dc->desc = "i.MX7 Secure Non-Volatile Storage Module";
}
diff --git a/hw/misc/imx7_src.c b/hw/misc/imx7_src.c
index d19f045..df0b0a6 100644
--- a/hw/misc/imx7_src.c
+++ b/hw/misc/imx7_src.c
@@ -251,12 +251,12 @@ static void imx7_src_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
-static void imx7_src_class_init(ObjectClass *klass, void *data)
+static void imx7_src_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx7_src_realize;
- dc->reset = imx7_src_reset;
+ device_class_set_legacy_reset(dc, imx7_src_reset);
dc->vmsd = &vmstate_imx7_src;
dc->desc = "i.MX6 System Reset Controller";
}
diff --git a/hw/misc/imx8mp_analog.c b/hw/misc/imx8mp_analog.c
new file mode 100644
index 0000000..23ffae8
--- /dev/null
+++ b/hw/misc/imx8mp_analog.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * i.MX 8M Plus ANALOG IP block emulation code
+ *
+ * Based on hw/misc/imx7_ccm.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+
+#include "hw/misc/imx8mp_analog.h"
+#include "migration/vmstate.h"
+
+#define ANALOG_PLL_LOCK BIT(31)
+
+static void imx8mp_analog_reset(DeviceState *dev)
+{
+ IMX8MPAnalogState *s = IMX8MP_ANALOG(dev);
+
+ memset(s->analog, 0, sizeof(s->analog));
+
+ s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL0] = 0x00145032;
+ s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL1_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL1_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL0] = 0x00145032;
+ s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL2_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL2_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL0] = 0x00145032;
+ s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_VIDEO_PLL1_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_VIDEO_PLL1_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_DRAM_PLL_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_DRAM_PLL_FDIV_CTL0] = 0x0012c032;
+ s->analog[ANALOG_DRAM_PLL_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_DRAM_PLL_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_DRAM_PLL_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_GPU_PLL_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_GPU_PLL_FDIV_CTL0] = 0x000c8031;
+ s->analog[ANALOG_GPU_PLL_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_GPU_PLL_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_VPU_PLL_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_VPU_PLL_FDIV_CTL0] = 0x0012c032;
+ s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = 0x000fa031;
+ s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810;
+ s->analog[ANALOG_SYS_PLL1_FDIV_CTL0] = 0x00190032;
+ s->analog[ANALOG_SYS_PLL1_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_SYS_PLL1_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_SYS_PLL2_GEN_CTRL] = 0x0aaaa810;
+ s->analog[ANALOG_SYS_PLL2_FDIV_CTL0] = 0x000fa031;
+ s->analog[ANALOG_SYS_PLL2_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_SYS_PLL2_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_SYS_PLL3_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_SYS_PLL3_FDIV_CTL0] = 0x000fa031;
+ s->analog[ANALOG_SYS_PLL3_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_SYS_PLL3_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_OSC_MISC_CFG] = 0x00000000;
+ s->analog[ANALOG_ANAMIX_PLL_MNIT_CTL] = 0x00000000;
+ s->analog[ANALOG_DIGPROG] = 0x00824010;
+
+ /* all PLLs need to be locked */
+ s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_DRAM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_GPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_VPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_ARM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_SYS_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_SYS_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_SYS_PLL3_GEN_CTRL] |= ANALOG_PLL_LOCK;
+}
+
+static uint64_t imx8mp_analog_read(void *opaque, hwaddr offset, unsigned size)
+{
+ IMX8MPAnalogState *s = opaque;
+
+ return s->analog[offset >> 2];
+}
+
+static void imx8mp_analog_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IMX8MPAnalogState *s = opaque;
+
+ if (offset >> 2 == ANALOG_DIGPROG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Guest write to read-only ANALOG_DIGPROG register\n");
+ } else {
+ s->analog[offset >> 2] = value;
+ }
+}
+
+static const struct MemoryRegionOps imx8mp_analog_ops = {
+ .read = imx8mp_analog_read,
+ .write = imx8mp_analog_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void imx8mp_analog_init(Object *obj)
+{
+ IMX8MPAnalogState *s = IMX8MP_ANALOG(obj);
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init(&s->mmio.container, obj, TYPE_IMX8MP_ANALOG, 0x10000);
+
+ memory_region_init_io(&s->mmio.analog, obj, &imx8mp_analog_ops, s,
+ TYPE_IMX8MP_ANALOG, sizeof(s->analog));
+ memory_region_add_subregion(&s->mmio.container, 0, &s->mmio.analog);
+
+ sysbus_init_mmio(sd, &s->mmio.container);
+}
+
+static const VMStateDescription imx8mp_analog_vmstate = {
+ .name = TYPE_IMX8MP_ANALOG,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(analog, IMX8MPAnalogState, ANALOG_MAX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void imx8mp_analog_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_legacy_reset(dc, imx8mp_analog_reset);
+ dc->vmsd = &imx8mp_analog_vmstate;
+ dc->desc = "i.MX 8M Plus Analog Module";
+}
+
+static const TypeInfo imx8mp_analog_types[] = {
+ {
+ .name = TYPE_IMX8MP_ANALOG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMX8MPAnalogState),
+ .instance_init = imx8mp_analog_init,
+ .class_init = imx8mp_analog_class_init,
+ }
+};
+
+DEFINE_TYPES(imx8mp_analog_types);
diff --git a/hw/misc/imx8mp_ccm.c b/hw/misc/imx8mp_ccm.c
new file mode 100644
index 0000000..911911e
--- /dev/null
+++ b/hw/misc/imx8mp_ccm.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * i.MX 8M Plus CCM IP block emulation code
+ *
+ * Based on hw/misc/imx7_ccm.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+
+#include "hw/misc/imx8mp_ccm.h"
+#include "migration/vmstate.h"
+
+#include "trace.h"
+
+#define CKIH_FREQ 16000000 /* 16MHz crystal input */
+
+static void imx8mp_ccm_reset(DeviceState *dev)
+{
+ IMX8MPCCMState *s = IMX8MP_CCM(dev);
+
+ memset(s->ccm, 0, sizeof(s->ccm));
+}
+
+#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
+#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF)
+
+enum {
+ CCM_BITOP_NONE = 0x00,
+ CCM_BITOP_SET = 0x04,
+ CCM_BITOP_CLR = 0x08,
+ CCM_BITOP_TOG = 0x0C,
+};
+
+static uint64_t imx8mp_set_clr_tog_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ const uint32_t *mmio = opaque;
+
+ return mmio[CCM_INDEX(offset)];
+}
+
+static void imx8mp_set_clr_tog_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ const uint8_t bitop = CCM_BITOP(offset);
+ const uint32_t index = CCM_INDEX(offset);
+ uint32_t *mmio = opaque;
+
+ switch (bitop) {
+ case CCM_BITOP_NONE:
+ mmio[index] = value;
+ break;
+ case CCM_BITOP_SET:
+ mmio[index] |= value;
+ break;
+ case CCM_BITOP_CLR:
+ mmio[index] &= ~value;
+ break;
+ case CCM_BITOP_TOG:
+ mmio[index] ^= value;
+ break;
+ };
+}
+
+static const struct MemoryRegionOps imx8mp_set_clr_tog_ops = {
+ .read = imx8mp_set_clr_tog_read,
+ .write = imx8mp_set_clr_tog_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ /*
+ * Our device would not work correctly if the guest was doing
+ * unaligned access. This might not be a limitation on the real
+ * device but in practice there is no reason for a guest to access
+ * this device unaligned.
+ */
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void imx8mp_ccm_init(Object *obj)
+{
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+ IMX8MPCCMState *s = IMX8MP_CCM(obj);
+
+ memory_region_init_io(&s->iomem,
+ obj,
+ &imx8mp_set_clr_tog_ops,
+ s->ccm,
+ TYPE_IMX8MP_CCM ".ccm",
+ sizeof(s->ccm));
+
+ sysbus_init_mmio(sd, &s->iomem);
+}
+
+static const VMStateDescription imx8mp_ccm_vmstate = {
+ .name = TYPE_IMX8MP_CCM,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(ccm, IMX8MPCCMState, CCM_MAX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
+{
+ /*
+ * This function is "consumed" by GPT emulation code. Some clocks
+ * have fixed frequencies and we can provide requested frequency
+ * easily. However for CCM provided clocks (like IPG) each GPT
+ * timer can have its own clock root.
+ * This means we need additional information when calling this
+ * function to know the requester's identity.
+ */
+ uint32_t freq = 0;
+
+ switch (clock) {
+ case CLK_NONE:
+ break;
+ case CLK_32k:
+ freq = CKIL_FREQ;
+ break;
+ case CLK_HIGH:
+ freq = CKIH_FREQ;
+ break;
+ case CLK_IPG:
+ case CLK_IPG_HIGH:
+ /*
+ * For now we don't have a way to figure out the device this
+ * function is called for. Until then the IPG derived clocks
+ * are left unimplemented.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Clock %d Not implemented\n",
+ TYPE_IMX8MP_CCM, __func__, clock);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
+ TYPE_IMX8MP_CCM, __func__, clock);
+ break;
+ }
+
+ trace_ccm_clock_freq(clock, freq);
+
+ return freq;
+}
+
+static void imx8mp_ccm_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
+
+ device_class_set_legacy_reset(dc, imx8mp_ccm_reset);
+ dc->vmsd = &imx8mp_ccm_vmstate;
+ dc->desc = "i.MX 8M Plus Clock Control Module";
+
+ ccm->get_clock_frequency = imx8mp_ccm_get_clock_frequency;
+}
+
+static const TypeInfo imx8mp_ccm_types[] = {
+ {
+ .name = TYPE_IMX8MP_CCM,
+ .parent = TYPE_IMX_CCM,
+ .instance_size = sizeof(IMX8MPCCMState),
+ .instance_init = imx8mp_ccm_init,
+ .class_init = imx8mp_ccm_class_init,
+ },
+};
+
+DEFINE_TYPES(imx8mp_ccm_types);
diff --git a/hw/misc/imx_rngc.c b/hw/misc/imx_rngc.c
index ab7775e..630f6cb 100644
--- a/hw/misc/imx_rngc.c
+++ b/hw/misc/imx_rngc.c
@@ -254,12 +254,12 @@ static const VMStateDescription vmstate_imx_rngc = {
}
};
-static void imx_rngc_class_init(ObjectClass *klass, void *data)
+static void imx_rngc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_rngc_realize;
- dc->reset = imx_rngc_reset;
+ device_class_set_legacy_reset(dc, imx_rngc_reset);
dc->desc = RNGC_NAME,
dc->vmsd = &vmstate_imx_rngc;
}
diff --git a/hw/misc/iosb.c b/hw/misc/iosb.c
index 31927ea..96221e1 100644
--- a/hw/misc/iosb.c
+++ b/hw/misc/iosb.c
@@ -111,7 +111,7 @@ static const VMStateDescription vmstate_iosb = {
}
};
-static void iosb_class_init(ObjectClass *oc, void *data)
+static void iosb_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
index f9c45f6..afd9ab4 100644
--- a/hw/misc/iotkit-secctl.c
+++ b/hw/misc/iotkit-secctl.c
@@ -814,17 +814,16 @@ static const VMStateDescription iotkit_secctl_vmstate = {
},
};
-static Property iotkit_secctl_props[] = {
+static const Property iotkit_secctl_props[] = {
DEFINE_PROP_UINT32("sse-version", IoTKitSecCtl, sse_version, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void iotkit_secctl_class_init(ObjectClass *klass, void *data)
+static void iotkit_secctl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &iotkit_secctl_vmstate;
- dc->reset = iotkit_secctl_reset;
+ device_class_set_legacy_reset(dc, iotkit_secctl_reset);
dc->realize = iotkit_secctl_realize;
device_class_set_props(dc, iotkit_secctl_props);
}
diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
index 45393e8..d70e51a 100644
--- a/hw/misc/iotkit-sysctl.c
+++ b/hw/misc/iotkit-sysctl.c
@@ -20,7 +20,7 @@
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "trace.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
@@ -835,22 +835,21 @@ static const VMStateDescription iotkit_sysctl_vmstate = {
}
};
-static Property iotkit_sysctl_props[] = {
+static const Property iotkit_sysctl_props[] = {
DEFINE_PROP_UINT32("sse-version", IoTKitSysCtl, sse_version, 0),
DEFINE_PROP_UINT32("CPUWAIT_RST", IoTKitSysCtl, cpuwait_rst, 0),
DEFINE_PROP_UINT32("INITSVTOR0_RST", IoTKitSysCtl, initsvtor0_rst,
0x10000000),
DEFINE_PROP_UINT32("INITSVTOR1_RST", IoTKitSysCtl, initsvtor1_rst,
0x10000000),
- DEFINE_PROP_END_OF_LIST()
};
-static void iotkit_sysctl_class_init(ObjectClass *klass, void *data)
+static void iotkit_sysctl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &iotkit_sysctl_vmstate;
- dc->reset = iotkit_sysctl_reset;
+ device_class_set_legacy_reset(dc, iotkit_sysctl_reset);
device_class_set_props(dc, iotkit_sysctl_props);
dc->realize = iotkit_sysctl_realize;
}
diff --git a/hw/misc/iotkit-sysinfo.c b/hw/misc/iotkit-sysinfo.c
index aaa9305..57405cb 100644
--- a/hw/misc/iotkit-sysinfo.c
+++ b/hw/misc/iotkit-sysinfo.c
@@ -131,12 +131,11 @@ static const MemoryRegionOps iotkit_sysinfo_ops = {
.valid.max_access_size = 4,
};
-static Property iotkit_sysinfo_props[] = {
+static const Property iotkit_sysinfo_props[] = {
DEFINE_PROP_UINT32("SYS_VERSION", IoTKitSysInfo, sys_version, 0),
DEFINE_PROP_UINT32("SYS_CONFIG", IoTKitSysInfo, sys_config, 0),
DEFINE_PROP_UINT32("sse-version", IoTKitSysInfo, sse_version, 0),
DEFINE_PROP_UINT32("IIDR", IoTKitSysInfo, iidr, 0),
- DEFINE_PROP_END_OF_LIST()
};
static void iotkit_sysinfo_init(Object *obj)
@@ -159,7 +158,7 @@ static void iotkit_sysinfo_realize(DeviceState *dev, Error **errp)
}
}
-static void iotkit_sysinfo_class_init(ObjectClass *klass, void *data)
+static void iotkit_sysinfo_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/ivshmem-flat.c b/hw/misc/ivshmem-flat.c
new file mode 100644
index 0000000..be28c24
--- /dev/null
+++ b/hw/misc/ivshmem-flat.c
@@ -0,0 +1,458 @@
+/*
+ * Inter-VM Shared Memory Flat Device
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2023 Linaro Ltd.
+ * Authors:
+ * Gustavo Romero
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/sysbus.h"
+#include "chardev/char-fe.h"
+#include "system/address-spaces.h"
+#include "trace.h"
+
+#include "hw/misc/ivshmem-flat.h"
+
+static int64_t ivshmem_flat_recv_msg(IvshmemFTState *s, int *pfd)
+{
+ int64_t msg;
+ int n, ret;
+
+ n = 0;
+ do {
+ ret = qemu_chr_fe_read_all(&s->server_chr, (uint8_t *)&msg + n,
+ sizeof(msg) - n);
+ if (ret < 0) {
+ if (ret == -EINTR) {
+ continue;
+ }
+ exit(1);
+ }
+ n += ret;
+ } while (n < sizeof(msg));
+
+ if (pfd) {
+ *pfd = qemu_chr_fe_get_msgfd(&s->server_chr);
+ }
+ return le64_to_cpu(msg);
+}
+
+static void ivshmem_flat_irq_handler(void *opaque)
+{
+ VectorInfo *vi = opaque;
+ EventNotifier *e = &vi->event_notifier;
+ uint16_t vector_id;
+ const VectorInfo (*v)[64];
+
+ assert(e->initialized);
+
+ vector_id = vi->id;
+
+ /*
+ * The vector info struct is passed to the handler via the 'opaque' pointer.
+ * This struct pointer allows the retrieval of the vector ID and its
+ * associated event notifier. However, for triggering an interrupt using
+ * qemu_set_irq, it's necessary to also have a pointer to the device state,
+ * i.e., a pointer to the IvshmemFTState struct. Since the vector info
+ * struct is contained within the IvshmemFTState struct, its pointer can be
+ * used to obtain the pointer to IvshmemFTState through simple pointer math.
+ */
+ v = (void *)(vi - vector_id); /* v = &IvshmemPeer->vector[0] */
+ IvshmemPeer *own_peer = container_of(v, IvshmemPeer, vector);
+ IvshmemFTState *s = container_of(own_peer, IvshmemFTState, own);
+
+ /* Clear event */
+ if (!event_notifier_test_and_clear(e)) {
+ return;
+ }
+
+ trace_ivshmem_flat_irq_handler(vector_id);
+
+ /*
+ * Toggle device's output line, which is connected to interrupt controller,
+ * generating an interrupt request to the CPU.
+ */
+ qemu_irq_pulse(s->irq);
+}
+
+static IvshmemPeer *ivshmem_flat_find_peer(IvshmemFTState *s, uint16_t peer_id)
+{
+ IvshmemPeer *peer;
+
+ /* Own ID */
+ if (s->own.id == peer_id) {
+ return &s->own;
+ }
+
+ /* Peer ID */
+ QTAILQ_FOREACH(peer, &s->peer, next) {
+ if (peer->id == peer_id) {
+ return peer;
+ }
+ }
+
+ return NULL;
+}
+
+static IvshmemPeer *ivshmem_flat_add_peer(IvshmemFTState *s, uint16_t peer_id)
+{
+ IvshmemPeer *new_peer;
+
+ new_peer = g_malloc0(sizeof(*new_peer));
+ new_peer->id = peer_id;
+ new_peer->vector_counter = 0;
+
+ QTAILQ_INSERT_TAIL(&s->peer, new_peer, next);
+
+ trace_ivshmem_flat_new_peer(peer_id);
+
+ return new_peer;
+}
+
+static void ivshmem_flat_remove_peer(IvshmemFTState *s, uint16_t peer_id)
+{
+ IvshmemPeer *peer;
+
+ peer = ivshmem_flat_find_peer(s, peer_id);
+ assert(peer);
+
+ QTAILQ_REMOVE(&s->peer, peer, next);
+ for (int n = 0; n < peer->vector_counter; n++) {
+ int efd;
+ efd = event_notifier_get_fd(&(peer->vector[n].event_notifier));
+ close(efd);
+ }
+
+ g_free(peer);
+}
+
+static void ivshmem_flat_add_vector(IvshmemFTState *s, IvshmemPeer *peer,
+ int vector_fd)
+{
+ if (peer->vector_counter >= IVSHMEM_MAX_VECTOR_NUM) {
+ trace_ivshmem_flat_add_vector_failure(peer->vector_counter,
+ vector_fd, peer->id);
+ close(vector_fd);
+
+ return;
+ }
+
+ trace_ivshmem_flat_add_vector_success(peer->vector_counter,
+ vector_fd, peer->id);
+
+ /*
+ * Set vector ID and its associated eventfd notifier and add them to the
+ * peer.
+ */
+ peer->vector[peer->vector_counter].id = peer->vector_counter;
+ g_unix_set_fd_nonblocking(vector_fd, true, NULL);
+ event_notifier_init_fd(&peer->vector[peer->vector_counter].event_notifier,
+ vector_fd);
+
+ /*
+ * If it's the device's own ID, register also the handler for the eventfd
+ * so the device can be notified by the other peers.
+ */
+ if (peer == &s->own) {
+ qemu_set_fd_handler(vector_fd, ivshmem_flat_irq_handler, NULL,
+ &peer->vector);
+ }
+
+ peer->vector_counter++;
+}
+
+static void ivshmem_flat_process_msg(IvshmemFTState *s, uint64_t msg, int fd)
+{
+ uint16_t peer_id;
+ IvshmemPeer *peer;
+
+ peer_id = msg & 0xFFFF;
+ peer = ivshmem_flat_find_peer(s, peer_id);
+
+ if (!peer) {
+ peer = ivshmem_flat_add_peer(s, peer_id);
+ }
+
+ if (fd >= 0) {
+ ivshmem_flat_add_vector(s, peer, fd);
+ } else { /* fd == -1, which is received when peers disconnect. */
+ ivshmem_flat_remove_peer(s, peer_id);
+ }
+}
+
+static int ivshmem_flat_can_receive_data(void *opaque)
+{
+ IvshmemFTState *s = opaque;
+
+ assert(s->msg_buffered_bytes < sizeof(s->msg_buf));
+ return sizeof(s->msg_buf) - s->msg_buffered_bytes;
+}
+
+static void ivshmem_flat_read_msg(void *opaque, const uint8_t *buf, int size)
+{
+ IvshmemFTState *s = opaque;
+ int fd;
+ int64_t msg;
+
+ assert(size >= 0 && s->msg_buffered_bytes + size <= sizeof(s->msg_buf));
+ memcpy((unsigned char *)&s->msg_buf + s->msg_buffered_bytes, buf, size);
+ s->msg_buffered_bytes += size;
+ if (s->msg_buffered_bytes < sizeof(s->msg_buf)) {
+ return;
+ }
+ msg = le64_to_cpu(s->msg_buf);
+ s->msg_buffered_bytes = 0;
+
+ fd = qemu_chr_fe_get_msgfd(&s->server_chr);
+
+ ivshmem_flat_process_msg(s, msg, fd);
+}
+
+static uint64_t ivshmem_flat_iomem_read(void *opaque,
+ hwaddr offset, unsigned size)
+{
+ IvshmemFTState *s = opaque;
+ uint32_t ret;
+
+ trace_ivshmem_flat_read_mmr(offset);
+
+ switch (offset) {
+ case INTMASK:
+ ret = 0; /* Ignore read since all bits are reserved in rev 1. */
+ break;
+ case INTSTATUS:
+ ret = 0; /* Ignore read since all bits are reserved in rev 1. */
+ break;
+ case IVPOSITION:
+ ret = s->own.id;
+ break;
+ case DOORBELL:
+ trace_ivshmem_flat_read_mmr_doorbell(); /* DOORBELL is write-only */
+ ret = 0;
+ break;
+ default:
+ /* Should never reach out here due to iomem map range being exact */
+ trace_ivshmem_flat_read_write_mmr_invalid(offset);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int ivshmem_flat_interrupt_peer(IvshmemFTState *s,
+ uint16_t peer_id, uint16_t vector_id)
+{
+ IvshmemPeer *peer;
+
+ peer = ivshmem_flat_find_peer(s, peer_id);
+ if (!peer) {
+ trace_ivshmem_flat_interrupt_invalid_peer(peer_id);
+ return 1;
+ }
+
+ event_notifier_set(&(peer->vector[vector_id].event_notifier));
+
+ return 0;
+}
+
+static void ivshmem_flat_iomem_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IvshmemFTState *s = opaque;
+ uint16_t peer_id = (value >> 16) & 0xFFFF;
+ uint16_t vector_id = value & 0xFFFF;
+
+ trace_ivshmem_flat_write_mmr(offset);
+
+ switch (offset) {
+ case INTMASK:
+ break;
+ case INTSTATUS:
+ break;
+ case IVPOSITION:
+ break;
+ case DOORBELL:
+ trace_ivshmem_flat_interrupt_peer(peer_id, vector_id);
+ ivshmem_flat_interrupt_peer(s, peer_id, vector_id);
+ break;
+ default:
+ /* Should never reach out here due to iomem map range being exact. */
+ trace_ivshmem_flat_read_write_mmr_invalid(offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps ivshmem_flat_ops = {
+ .read = ivshmem_flat_iomem_read,
+ .write = ivshmem_flat_iomem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = { /* Read/write aligned at 32 bits. */
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void ivshmem_flat_instance_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ IvshmemFTState *s = IVSHMEM_FLAT(obj);
+
+ /*
+ * Init mem region for 4 MMRs (ivshmem_registers),
+ * 32 bits each => 16 bytes (0x10).
+ */
+ memory_region_init_io(&s->iomem, obj, &ivshmem_flat_ops, s,
+ "ivshmem-mmio", 0x10);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ /*
+ * Create one output IRQ that will be connect to the
+ * machine's interrupt controller.
+ */
+ sysbus_init_irq(sbd, &s->irq);
+
+ QTAILQ_INIT(&s->peer);
+}
+
+static bool ivshmem_flat_connect_server(DeviceState *dev, Error **errp)
+{
+ IvshmemFTState *s = IVSHMEM_FLAT(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ int64_t protocol_version, msg;
+ int shmem_fd;
+ uint16_t peer_id;
+ struct stat fdstat;
+
+ /* Check ivshmem server connection. */
+ if (!qemu_chr_fe_backend_connected(&s->server_chr)) {
+ error_setg(errp, "ivshmem server socket not specified or incorret."
+ " Can't create device.");
+ return false;
+ }
+
+ /*
+ * Message sequence from server on new connection:
+ * _____________________________________
+ * |STEP| uint64_t msg | int fd |
+ * -------------------------------------
+ *
+ * 0 PROTOCOL -1 \
+ * 1 OWN PEER ID -1 |-- Header/Greeting
+ * 2 -1 shmem fd /
+ *
+ * 3 PEER IDx Other peer's Vector 0 eventfd
+ * 4 PEER IDx Other peer's Vector 1 eventfd
+ * . .
+ * . .
+ * . .
+ * N PEER IDy Other peer's Vector 0 eventfd
+ * N+1 PEER IDy Other peer's Vector 1 eventfd
+ * . .
+ * . .
+ * . .
+ *
+ * ivshmem_flat_recv_msg() calls return 'msg' and 'fd'.
+ *
+ * See ./docs/specs/ivshmem-spec.txt for details on the protocol.
+ */
+
+ /* Step 0 */
+ protocol_version = ivshmem_flat_recv_msg(s, NULL);
+
+ /* Step 1 */
+ msg = ivshmem_flat_recv_msg(s, NULL);
+ peer_id = 0xFFFF & msg;
+ s->own.id = peer_id;
+ s->own.vector_counter = 0;
+
+ trace_ivshmem_flat_proto_ver_own_id(protocol_version, s->own.id);
+
+ /* Step 2 */
+ msg = ivshmem_flat_recv_msg(s, &shmem_fd);
+ /* Map shmem fd and MMRs into memory regions. */
+ if (msg != -1 || shmem_fd < 0) {
+ error_setg(errp, "Could not receive valid shmem fd."
+ " Can't create device!");
+ return false;
+ }
+
+ if (fstat(shmem_fd, &fdstat) != 0) {
+ error_setg(errp, "Could not determine shmem fd size."
+ " Can't create device!");
+ return false;
+ }
+ trace_ivshmem_flat_shmem_size(shmem_fd, fdstat.st_size);
+
+ /*
+ * Shmem size provided by the ivshmem server must be equal to
+ * device's shmem size.
+ */
+ if (fdstat.st_size != s->shmem_size) {
+ error_setg(errp, "Can't map shmem fd: shmem size different"
+ " from device size!");
+ return false;
+ }
+
+ /*
+ * Beyond step 2 ivshmem_process_msg, called by ivshmem_flat_read_msg
+ * handler -- when data is available on the server socket -- will handle
+ * the additional messages that will be generated by the server as peers
+ * connect or disconnect.
+ */
+ qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_flat_can_receive_data,
+ ivshmem_flat_read_msg, NULL, NULL, s, NULL, true);
+
+ memory_region_init_ram_from_fd(&s->shmem, OBJECT(s),
+ "ivshmem-shmem", s->shmem_size,
+ RAM_SHARED, shmem_fd, 0, NULL);
+ sysbus_init_mmio(sbd, &s->shmem);
+
+ return true;
+}
+
+static void ivshmem_flat_realize(DeviceState *dev, Error **errp)
+{
+ if (!ivshmem_flat_connect_server(dev, errp)) {
+ return;
+ }
+}
+
+static const Property ivshmem_flat_props[] = {
+ DEFINE_PROP_CHR("chardev", IvshmemFTState, server_chr),
+ DEFINE_PROP_UINT32("shmem-size", IvshmemFTState, shmem_size, 4 * MiB),
+};
+
+static void ivshmem_flat_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->hotpluggable = true;
+ dc->realize = ivshmem_flat_realize;
+
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ device_class_set_props(dc, ivshmem_flat_props);
+
+ /* Reason: Must be wired up in code (sysbus MRs and IRQ) */
+ dc->user_creatable = false;
+}
+
+static const TypeInfo ivshmem_flat_types[] = {
+ {
+ .name = TYPE_IVSHMEM_FLAT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IvshmemFTState),
+ .instance_init = ivshmem_flat_instance_init,
+ .class_init = ivshmem_flat_class_init,
+ },
+};
+
+DEFINE_TYPES(ivshmem_flat_types)
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem-pci.c
index de49d1b..5a10bca 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem-pci.c
@@ -26,7 +26,7 @@
#include "hw/qdev-properties-system.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "migration/blocker.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
@@ -34,7 +34,7 @@
#include "qemu/module.h"
#include "qom/object_interfaces.h"
#include "chardev/char-fe.h"
-#include "sysemu/hostmem.h"
+#include "system/hostmem.h"
#include "qapi/visitor.h"
#include "hw/misc/ivshmem.h"
@@ -979,7 +979,7 @@ static int ivshmem_post_load(void *opaque, int version_id)
return 0;
}
-static void ivshmem_common_class_init(ObjectClass *klass, void *data)
+static void ivshmem_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -991,7 +991,7 @@ static void ivshmem_common_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_IVSHMEM;
k->class_id = PCI_CLASS_MEMORY_RAM;
k->revision = 1;
- dc->reset = ivshmem_reset;
+ device_class_set_legacy_reset(dc, ivshmem_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "Inter-VM shared memory";
}
@@ -1002,7 +1002,7 @@ static const TypeInfo ivshmem_common_info = {
.instance_size = sizeof(IVShmemState),
.abstract = true,
.class_init = ivshmem_common_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -1022,11 +1022,10 @@ static const VMStateDescription ivshmem_plain_vmsd = {
},
};
-static Property ivshmem_plain_properties[] = {
+static const Property ivshmem_plain_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
DEFINE_PROP_LINK("memdev", IVShmemState, hostmem, TYPE_MEMORY_BACKEND,
HostMemoryBackend *),
- DEFINE_PROP_END_OF_LIST(),
};
static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
@@ -1045,7 +1044,7 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
ivshmem_common_realize(dev, errp);
}
-static void ivshmem_plain_class_init(ObjectClass *klass, void *data)
+static void ivshmem_plain_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1077,13 +1076,12 @@ static const VMStateDescription ivshmem_doorbell_vmsd = {
},
};
-static Property ivshmem_doorbell_properties[] = {
+static const Property ivshmem_doorbell_properties[] = {
DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD,
true),
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
- DEFINE_PROP_END_OF_LIST(),
};
static void ivshmem_doorbell_init(Object *obj)
@@ -1105,7 +1103,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
ivshmem_common_realize(dev, errp);
}
-static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data)
+static void ivshmem_doorbell_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/misc/lasi.c b/hw/misc/lasi.c
index 970fc98..9f758c6 100644
--- a/hw/misc/lasi.c
+++ b/hw/misc/lasi.c
@@ -15,8 +15,8 @@
#include "qapi/error.h"
#include "trace.h"
#include "hw/irq.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/runstate.h"
#include "migration/vmstate.h"
#include "qom/object.h"
#include "hw/misc/lasi.h"
@@ -263,11 +263,11 @@ static void lasi_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), lasi_set_irq, LASI_IRQS);
}
-static void lasi_class_init(ObjectClass *klass, void *data)
+static void lasi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = lasi_reset;
+ device_class_set_legacy_reset(dc, lasi_reset);
dc->vmsd = &vmstate_lasi;
}
diff --git a/hw/misc/led.c b/hw/misc/led.c
index d9998ab..f7f7090 100644
--- a/hw/misc/led.c
+++ b/hw/misc/led.c
@@ -101,20 +101,19 @@ static void led_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(DEVICE(s), led_set_state_gpio_handler, 1);
}
-static Property led_properties[] = {
+static const Property led_properties[] = {
DEFINE_PROP_STRING("color", LEDState, color),
DEFINE_PROP_STRING("description", LEDState, description),
DEFINE_PROP_BOOL("gpio-active-high", LEDState, gpio_active_high, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void led_class_init(ObjectClass *klass, void *data)
+static void led_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "LED";
dc->vmsd = &vmstate_led;
- dc->reset = led_reset;
+ device_class_set_legacy_reset(dc, led_reset);
dc->realize = led_realize;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
device_class_set_props(dc, led_properties);
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index 652395b..bc37e2a 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -16,7 +16,7 @@
*/
#include "qemu/osdep.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "migration/vmstate.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
@@ -24,13 +24,13 @@
#include "hw/misc/mac_via.h"
#include "hw/misc/mos6522.h"
#include "hw/input/adb.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/rtc.h"
+#include "system/block-backend.h"
+#include "system/rtc.h"
#include "trace.h"
#include "qemu/log.h"
@@ -495,7 +495,6 @@ static void via1_rtc_update(MOS6522Q800VIA1State *v1s)
break;
default:
g_assert_not_reached();
- break;
}
return;
}
@@ -556,7 +555,6 @@ static void via1_rtc_update(MOS6522Q800VIA1State *v1s)
break;
default:
g_assert_not_reached();
- break;
}
return;
}
@@ -1324,12 +1322,11 @@ static const VMStateDescription vmstate_q800_via1 = {
}
};
-static Property mos6522_q800_via1_properties[] = {
+static const Property mos6522_q800_via1_properties[] = {
DEFINE_PROP_DRIVE("drive", MOS6522Q800VIA1State, blk),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data)
+static void mos6522_q800_via1_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
@@ -1418,7 +1415,7 @@ static const VMStateDescription vmstate_q800_via2 = {
}
};
-static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data)
+static void mos6522_q800_via2_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index beab0ff..bcd00c9 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -29,8 +29,8 @@
#include "migration/vmstate.h"
#include "hw/misc/macio/cuda.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
-#include "sysemu/rtc.h"
+#include "system/runstate.h"
+#include "system/rtc.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
@@ -554,17 +554,16 @@ static void cuda_init(Object *obj)
DEVICE(obj), "adb.0");
}
-static Property cuda_properties[] = {
+static const Property cuda_properties[] = {
DEFINE_PROP_UINT64("timebase-frequency", CUDAState, tb_frequency, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void cuda_class_init(ObjectClass *oc, void *data)
+static void cuda_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = cuda_realize;
- dc->reset = cuda_reset;
+ device_class_set_legacy_reset(dc, cuda_reset);
dc->vmsd = &vmstate_cuda;
device_class_set_props(dc, cuda_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
@@ -599,7 +598,7 @@ static void mos6522_cuda_reset_hold(Object *obj, ResetType type)
ms->timers[1].frequency = (SCALE_US * 6000) / 4700;
}
-static void mos6522_cuda_class_init(ObjectClass *oc, void *data)
+static void mos6522_cuda_class_init(ObjectClass *oc, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(oc);
MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c
index 5495637..990551f 100644
--- a/hw/misc/macio/gpio.c
+++ b/hw/misc/macio/gpio.c
@@ -34,6 +34,11 @@
#include "qemu/module.h"
#include "trace.h"
+enum MacioGPIORegisterBits {
+ OUT_DATA = 1,
+ IN_DATA = 2,
+ OUT_ENABLE = 4,
+};
void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool state)
{
@@ -41,14 +46,14 @@ void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool state)
trace_macio_set_gpio(gpio, state);
- if (s->gpio_regs[gpio] & 4) {
+ if (s->gpio_regs[gpio] & OUT_ENABLE) {
qemu_log_mask(LOG_GUEST_ERROR,
"GPIO: Setting GPIO %d while it's an output\n", gpio);
}
- new_reg = s->gpio_regs[gpio] & ~2;
+ new_reg = s->gpio_regs[gpio] & ~IN_DATA;
if (state) {
- new_reg |= 2;
+ new_reg |= IN_DATA;
}
if (new_reg == s->gpio_regs[gpio]) {
@@ -107,12 +112,12 @@ static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
addr -= 8;
if (addr < 36) {
- value &= ~2;
+ value &= ~IN_DATA;
- if (value & 4) {
- ibit = (value & 1) << 1;
+ if (value & OUT_ENABLE) {
+ ibit = (value & OUT_DATA) << 1;
} else {
- ibit = s->gpio_regs[addr] & 2;
+ ibit = s->gpio_regs[addr] & IN_DATA;
}
s->gpio_regs[addr] = value | ibit;
@@ -135,7 +140,7 @@ static uint64_t macio_gpio_read(void *opaque, hwaddr addr, unsigned size)
}
}
- trace_macio_gpio_write(addr, val);
+ trace_macio_gpio_read(addr, val);
return val;
}
@@ -189,12 +194,12 @@ static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp)
macio_set_gpio(MACIO_GPIO(n), 9, false);
}
-static void macio_gpio_class_init(ObjectClass *oc, void *data)
+static void macio_gpio_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
- dc->reset = macio_gpio_reset;
+ device_class_set_legacy_reset(dc, macio_gpio_reset);
dc->vmsd = &vmstate_macio_gpio;
nc->nmi_monitor_handler = macio_gpio_nmi;
}
@@ -205,7 +210,7 @@ static const TypeInfo macio_gpio_init_info = {
.instance_size = sizeof(MacIOGPIOState),
.instance_init = macio_gpio_init,
.class_init = macio_gpio_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NMI },
{ }
},
diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
index 2a528ea..b2b42dd 100644
--- a/hw/misc/macio/mac_dbdma.c
+++ b/hw/misc/macio/mac_dbdma.c
@@ -44,7 +44,7 @@
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/log.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
/* debug DBDMA */
#define DEBUG_DBDMA 0
@@ -917,12 +917,12 @@ static void mac_dbdma_realize(DeviceState *dev, Error **errp)
s->bh = qemu_bh_new_guarded(DBDMA_run_bh, s, &dev->mem_reentrancy_guard);
}
-static void mac_dbdma_class_init(ObjectClass *oc, void *data)
+static void mac_dbdma_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mac_dbdma_realize;
- dc->reset = mac_dbdma_reset;
+ device_class_set_legacy_reset(dc, mac_dbdma_reset);
dc->vmsd = &vmstate_dbdma;
}
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index 3f449f9..6710485 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -385,7 +385,7 @@ static const VMStateDescription vmstate_macio_oldworld = {
}
};
-static void macio_oldworld_class_init(ObjectClass *oc, void *data)
+static void macio_oldworld_class_init(ObjectClass *oc, const void *data)
{
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -405,13 +405,12 @@ static const VMStateDescription vmstate_macio_newworld = {
}
};
-static Property macio_newworld_properties[] = {
+static const Property macio_newworld_properties[] = {
DEFINE_PROP_BOOL("has-pmu", NewWorldMacIOState, has_pmu, false),
DEFINE_PROP_BOOL("has-adb", NewWorldMacIOState, has_adb, false),
- DEFINE_PROP_END_OF_LIST()
};
-static void macio_newworld_class_init(ObjectClass *oc, void *data)
+static void macio_newworld_class_init(ObjectClass *oc, const void *data)
{
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -422,12 +421,11 @@ static void macio_newworld_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, macio_newworld_properties);
}
-static Property macio_properties[] = {
+static const Property macio_properties[] = {
DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void macio_class_init(ObjectClass *klass, void *data)
+static void macio_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -467,7 +465,7 @@ static const TypeInfo macio_type_info = {
.instance_init = macio_instance_init,
.abstract = true,
.class_init = macio_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c
index 238da58..3734913 100644
--- a/hw/misc/macio/pmu.c
+++ b/hw/misc/macio/pmu.c
@@ -34,8 +34,8 @@
#include "hw/irq.h"
#include "hw/misc/macio/pmu.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
-#include "sysemu/rtc.h"
+#include "system/runstate.h"
+#include "system/rtc.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
@@ -760,17 +760,16 @@ static void pmu_init(Object *obj)
sysbus_init_mmio(d, &s->mem);
}
-static Property pmu_properties[] = {
+static const Property pmu_properties[] = {
DEFINE_PROP_BOOL("has-adb", PMUState, has_adb, true),
- DEFINE_PROP_END_OF_LIST()
};
-static void pmu_class_init(ObjectClass *oc, void *data)
+static void pmu_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = pmu_realize;
- dc->reset = pmu_reset;
+ device_class_set_legacy_reset(dc, pmu_reset);
dc->vmsd = &vmstate_pmu;
device_class_set_props(dc, pmu_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
@@ -809,7 +808,7 @@ static void mos6522_pmu_reset_hold(Object *obj, ResetType type)
s->last_b = ms->b = TACK | TREQ;
}
-static void mos6522_pmu_class_init(ObjectClass *oc, void *data)
+static void mos6522_pmu_class_init(ObjectClass *oc, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(oc);
MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
diff --git a/hw/misc/macio/trace-events b/hw/misc/macio/trace-events
index ad4b9d1..055a407 100644
--- a/hw/misc/macio/trace-events
+++ b/hw/misc/macio/trace-events
@@ -18,7 +18,8 @@ macio_timer_read(uint64_t addr, unsigned len, uint32_t val) "read addr 0x%"PRIx6
macio_set_gpio(int gpio, bool state) "setting GPIO %d to %d"
macio_gpio_irq_assert(int gpio) "asserting GPIO %d"
macio_gpio_irq_deassert(int gpio) "deasserting GPIO %d"
-macio_gpio_write(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64" value: 0x%"PRIx64
+macio_gpio_write(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" val 0x%"PRIx64
+macio_gpio_read(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" val 0x%"PRIx64
# pmu.c
pmu_adb_poll(int olen) "ADB autopoll, olen=%d"
diff --git a/hw/misc/mchp_pfsoc_dmc.c b/hw/misc/mchp_pfsoc_dmc.c
index 43d8e97..599f845 100644
--- a/hw/misc/mchp_pfsoc_dmc.c
+++ b/hw/misc/mchp_pfsoc_dmc.c
@@ -110,7 +110,8 @@ static void mchp_pfsoc_ddr_sgmii_phy_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sgmii_phy);
}
-static void mchp_pfsoc_ddr_sgmii_phy_class_init(ObjectClass *klass, void *data)
+static void mchp_pfsoc_ddr_sgmii_phy_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -192,7 +193,7 @@ static void mchp_pfsoc_ddr_cfg_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->cfg);
}
-static void mchp_pfsoc_ddr_cfg_class_init(ObjectClass *klass, void *data)
+static void mchp_pfsoc_ddr_cfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c
index a71d134..10fc7ea 100644
--- a/hw/misc/mchp_pfsoc_ioscb.c
+++ b/hw/misc/mchp_pfsoc_ioscb.c
@@ -292,7 +292,7 @@ static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
}
-static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, void *data)
+static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c
index 7876fe0..f47c835 100644
--- a/hw/misc/mchp_pfsoc_sysreg.c
+++ b/hw/misc/mchp_pfsoc_sysreg.c
@@ -27,7 +27,9 @@
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/misc/mchp_pfsoc_sysreg.h"
+#include "system/runstate.h"
+#define MSS_RESET_CR 0x18
#define ENVM_CR 0xb8
#define MESSAGE_INT 0x118c
@@ -56,6 +58,11 @@ static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset,
{
MchpPfSoCSysregState *s = opaque;
switch (offset) {
+ case MSS_RESET_CR:
+ if (value == 0xdead) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ }
+ break;
case MESSAGE_INT:
qemu_irq_lower(s->irq);
break;
@@ -85,7 +92,7 @@ static void mchp_pfsoc_sysreg_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
}
-static void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, void *data)
+static void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 2ca8717..6d47de4 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -37,7 +37,9 @@ system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c'))
subdir('macio')
-system_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c'))
+# ivshmem devices
+system_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem-pci.c'))
+system_ss.add(when: 'CONFIG_IVSHMEM_FLAT_DEVICE', if_true: files('ivshmem-flat.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_SRAMC', if_true: files('allwinner-sramc.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_A10_CCM', if_true: files('allwinner-a10-ccm.c'))
@@ -51,9 +53,10 @@ system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-ccu.c'
system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-dramc.c'))
system_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
-system_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c'))
system_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c'))
+system_ss.add(when: 'CONFIG_FSL_IMX8MP_ANALOG', if_true: files('imx8mp_analog.c'))
+system_ss.add(when: 'CONFIG_FSL_IMX8MP_CCM', if_true: files('imx8mp_ccm.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx25_ccm.c',
'imx31_ccm.c',
@@ -67,20 +70,15 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx_ccm.c',
'imx_rngc.c',
))
-system_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
- 'npcm7xx_clk.c',
- 'npcm7xx_gcr.c',
+ 'npcm_clk.c',
+ 'npcm_gcr.c',
'npcm7xx_mft.c',
'npcm7xx_pwm.c',
'npcm7xx_rng.c',
))
system_ss.add(when: 'CONFIG_OMAP', if_true: files(
'omap_clk.c',
- 'omap_gpmc.c',
- 'omap_l4.c',
- 'omap_sdrc.c',
- 'omap_tap.c',
))
system_ss.add(when: 'CONFIG_RASPI', if_true: files(
'bcm2835_mbox.c',
@@ -106,6 +104,7 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files(
system_ss.add(when: 'CONFIG_XLNX_VERSAL_TRNG', if_true: files(
'xlnx-versal-trng.c',
))
+system_ss.add(when: 'CONFIG_STM32_RCC', if_true: files('stm32_rcc.c'))
system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c'))
system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))
@@ -127,6 +126,7 @@ system_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files('armsse-mhu.c'))
system_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
system_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
+system_ss.add(when: 'CONFIG_PVPANIC_MMIO', if_true: files('pvpanic-mmio.c'))
system_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_hace.c',
diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c
index 2703040..5484b73 100644
--- a/hw/misc/mips_cmgcr.c
+++ b/hw/misc/mips_cmgcr.c
@@ -211,7 +211,7 @@ static const VMStateDescription vmstate_mips_gcr = {
},
};
-static Property mips_gcr_properties[] = {
+static const Property mips_gcr_properties[] = {
DEFINE_PROP_UINT32("num-vp", MIPSGCRState, num_vps, 1),
DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800),
DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR),
@@ -219,7 +219,6 @@ static Property mips_gcr_properties[] = {
MemoryRegion *),
DEFINE_PROP_LINK("cpc", MIPSGCRState, cpc_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
static void mips_gcr_realize(DeviceState *dev, Error **errp)
@@ -230,12 +229,12 @@ static void mips_gcr_realize(DeviceState *dev, Error **errp)
s->vps = g_new(MIPSGCRVPState, s->num_vps);
}
-static void mips_gcr_class_init(ObjectClass *klass, void *data)
+static void mips_gcr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, mips_gcr_properties);
dc->vmsd = &vmstate_mips_gcr;
- dc->reset = mips_gcr_reset;
+ device_class_set_legacy_reset(dc, mips_gcr_reset);
dc->realize = mips_gcr_realize;
}
diff --git a/hw/misc/mips_cpc.c b/hw/misc/mips_cpc.c
index 1e8fd2e..9bfb7c9 100644
--- a/hw/misc/mips_cpc.c
+++ b/hw/misc/mips_cpc.c
@@ -92,8 +92,6 @@ static void cpc_write(void *opaque, hwaddr offset, uint64_t data,
"%s: Bad offset 0x%x\n", __func__, (int)offset);
break;
}
-
- return;
}
static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size)
@@ -163,18 +161,17 @@ static const VMStateDescription vmstate_mips_cpc = {
},
};
-static Property mips_cpc_properties[] = {
+static const Property mips_cpc_properties[] = {
DEFINE_PROP_UINT32("num-vp", MIPSCPCState, num_vp, 0x1),
DEFINE_PROP_UINT64("vp-start-running", MIPSCPCState, vp_start_running, 0x1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mips_cpc_class_init(ObjectClass *klass, void *data)
+static void mips_cpc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mips_cpc_realize;
- dc->reset = mips_cpc_reset;
+ device_class_set_legacy_reset(dc, mips_cpc_reset);
dc->vmsd = &vmstate_mips_cpc;
device_class_set_props(dc, mips_cpc_properties);
}
diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c
index f8acfb3..fc17385 100644
--- a/hw/misc/mips_itu.c
+++ b/hw/misc/mips_itu.c
@@ -533,21 +533,20 @@ static void mips_itu_reset(DeviceState *dev)
itc_reset_cells(s);
}
-static Property mips_itu_properties[] = {
+static const Property mips_itu_properties[] = {
DEFINE_PROP_UINT32("num-fifo", MIPSITUState, num_fifo,
ITC_FIFO_NUM_MAX),
DEFINE_PROP_UINT32("num-semaphores", MIPSITUState, num_semaphores,
ITC_SEMAPH_NUM_MAX),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mips_itu_class_init(ObjectClass *klass, void *data)
+static void mips_itu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, mips_itu_properties);
dc->realize = mips_itu_realize;
- dc->reset = mips_itu_reset;
+ device_class_set_legacy_reset(dc, mips_itu_reset);
}
static const TypeInfo mips_itu_info = {
diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c
index 515f62e..8dd6b82 100644
--- a/hw/misc/mos6522.c
+++ b/hw/misc/mos6522.c
@@ -696,12 +696,11 @@ static void mos6522_finalize(Object *obj)
timer_free(s->timers[1].timer);
}
-static Property mos6522_properties[] = {
+static const Property mos6522_properties[] = {
DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void mos6522_class_init(ObjectClass *oc, void *data)
+static void mos6522_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
index aa1bb83..bee1309 100644
--- a/hw/misc/mps2-fpgaio.c
+++ b/hw/misc/mps2-fpgaio.c
@@ -198,7 +198,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
s->led0 = value & MAKE_64BIT_MASK(0, s->num_leds);
for (i = 0; i < s->num_leds; i++) {
- led_set_state(s->led[i], value & (1 << i));
+ led_set_state(s->led[i], extract64(value, i, 1));
}
}
break;
@@ -319,23 +319,22 @@ static const VMStateDescription mps2_fpgaio_vmstate = {
},
};
-static Property mps2_fpgaio_properties[] = {
+static const Property mps2_fpgaio_properties[] = {
/* Frequency of the prescale counter */
DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000),
/* Number of LEDs controlled by LED0 register */
DEFINE_PROP_UINT32("num-leds", MPS2FPGAIO, num_leds, 2),
DEFINE_PROP_BOOL("has-switches", MPS2FPGAIO, has_switches, false),
DEFINE_PROP_BOOL("has-dbgctrl", MPS2FPGAIO, has_dbgctrl, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mps2_fpgaio_class_init(ObjectClass *klass, void *data)
+static void mps2_fpgaio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &mps2_fpgaio_vmstate;
dc->realize = mps2_fpgaio_realize;
- dc->reset = mps2_fpgaio_reset;
+ device_class_set_legacy_reset(dc, mps2_fpgaio_reset);
device_class_set_props(dc, mps2_fpgaio_properties);
}
diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c
index 18be741..a9a5d4a 100644
--- a/hw/misc/mps2-scc.c
+++ b/hw/misc/mps2-scc.c
@@ -456,7 +456,7 @@ static const VMStateDescription mps2_scc_vmstate = {
}
};
-static Property mps2_scc_properties[] = {
+static const Property mps2_scc_properties[] = {
/* Values for various read-only ID registers (which are specific
* to the board model or FPGA image)
*/
@@ -472,16 +472,15 @@ static Property mps2_scc_properties[] = {
*/
DEFINE_PROP_ARRAY("oscclk", MPS2SCC, num_oscclk, oscclk_reset,
qdev_prop_uint32, uint32_t),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mps2_scc_class_init(ObjectClass *klass, void *data)
+static void mps2_scc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mps2_scc_realize;
dc->vmsd = &mps2_scc_vmstate;
- dc->reset = mps2_scc_reset;
+ device_class_set_legacy_reset(dc, mps2_scc_reset);
device_class_set_props(dc, mps2_scc_properties);
}
diff --git a/hw/misc/msf2-sysreg.c b/hw/misc/msf2-sysreg.c
index f54382a..ce0ad50 100644
--- a/hw/misc/msf2-sysreg.c
+++ b/hw/misc/msf2-sysreg.c
@@ -118,11 +118,10 @@ static const VMStateDescription vmstate_msf2_sysreg = {
}
};
-static Property msf2_sysreg_properties[] = {
+static const Property msf2_sysreg_properties[] = {
/* default divisors in Libero GUI */
DEFINE_PROP_UINT8("apb0divisor", MSF2SysregState, apb0div, 2),
DEFINE_PROP_UINT8("apb1divisor", MSF2SysregState, apb1div, 2),
- DEFINE_PROP_END_OF_LIST(),
};
static void msf2_sysreg_realize(DeviceState *dev, Error **errp)
@@ -137,12 +136,12 @@ static void msf2_sysreg_realize(DeviceState *dev, Error **errp)
}
}
-static void msf2_sysreg_class_init(ObjectClass *klass, void *data)
+static void msf2_sysreg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_msf2_sysreg;
- dc->reset = msf2_sysreg_reset;
+ device_class_set_legacy_reset(dc, msf2_sysreg_reset);
device_class_set_props(dc, msf2_sysreg_properties);
dc->realize = msf2_sysreg_realize;
}
diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c
deleted file mode 100644
index 2d7bfa5..0000000
--- a/hw/misc/mst_fpga.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- * FPGA driver
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- * <akuster@mvista.com>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-/* Mainstone FPGA for extern irqs */
-#define FPGA_GPIO_PIN 0
-#define MST_NUM_IRQS 16
-#define MST_LEDDAT1 0x10
-#define MST_LEDDAT2 0x14
-#define MST_LEDCTRL 0x40
-#define MST_GPSWR 0x60
-#define MST_MSCWR1 0x80
-#define MST_MSCWR2 0x84
-#define MST_MSCWR3 0x88
-#define MST_MSCRD 0x90
-#define MST_INTMSKENA 0xc0
-#define MST_INTSETCLR 0xd0
-#define MST_PCMCIA0 0xe0
-#define MST_PCMCIA1 0xe4
-
-#define MST_PCMCIAx_READY (1 << 10)
-#define MST_PCMCIAx_nCD (1 << 5)
-
-#define MST_PCMCIA_CD0_IRQ 9
-#define MST_PCMCIA_CD1_IRQ 13
-
-#define TYPE_MAINSTONE_FPGA "mainstone-fpga"
-OBJECT_DECLARE_SIMPLE_TYPE(mst_irq_state, MAINSTONE_FPGA)
-
-struct mst_irq_state {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- qemu_irq parent;
-
- uint32_t prev_level;
- uint32_t leddat1;
- uint32_t leddat2;
- uint32_t ledctrl;
- uint32_t gpswr;
- uint32_t mscwr1;
- uint32_t mscwr2;
- uint32_t mscwr3;
- uint32_t mscrd;
- uint32_t intmskena;
- uint32_t intsetclr;
- uint32_t pcmcia0;
- uint32_t pcmcia1;
-};
-
-static void
-mst_fpga_set_irq(void *opaque, int irq, int level)
-{
- mst_irq_state *s = (mst_irq_state *)opaque;
- uint32_t oldint = s->intsetclr & s->intmskena;
-
- if (level)
- s->prev_level |= 1u << irq;
- else
- s->prev_level &= ~(1u << irq);
-
- switch(irq) {
- case MST_PCMCIA_CD0_IRQ:
- if (level)
- s->pcmcia0 &= ~MST_PCMCIAx_nCD;
- else
- s->pcmcia0 |= MST_PCMCIAx_nCD;
- break;
- case MST_PCMCIA_CD1_IRQ:
- if (level)
- s->pcmcia1 &= ~MST_PCMCIAx_nCD;
- else
- s->pcmcia1 |= MST_PCMCIAx_nCD;
- break;
- }
-
- if ((s->intmskena & (1u << irq)) && level)
- s->intsetclr |= 1u << irq;
-
- if (oldint != (s->intsetclr & s->intmskena))
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
-}
-
-
-static uint64_t
-mst_fpga_readb(void *opaque, hwaddr addr, unsigned size)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
-
- switch (addr) {
- case MST_LEDDAT1:
- return s->leddat1;
- case MST_LEDDAT2:
- return s->leddat2;
- case MST_LEDCTRL:
- return s->ledctrl;
- case MST_GPSWR:
- return s->gpswr;
- case MST_MSCWR1:
- return s->mscwr1;
- case MST_MSCWR2:
- return s->mscwr2;
- case MST_MSCWR3:
- return s->mscwr3;
- case MST_MSCRD:
- return s->mscrd;
- case MST_INTMSKENA:
- return s->intmskena;
- case MST_INTSETCLR:
- return s->intsetclr;
- case MST_PCMCIA0:
- return s->pcmcia0;
- case MST_PCMCIA1:
- return s->pcmcia1;
- default:
- printf("Mainstone - mst_fpga_readb: Bad register offset "
- "0x" HWADDR_FMT_plx "\n", addr);
- }
- return 0;
-}
-
-static void
-mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
- value &= 0xffffffff;
-
- switch (addr) {
- case MST_LEDDAT1:
- s->leddat1 = value;
- break;
- case MST_LEDDAT2:
- s->leddat2 = value;
- break;
- case MST_LEDCTRL:
- s->ledctrl = value;
- break;
- case MST_GPSWR:
- s->gpswr = value;
- break;
- case MST_MSCWR1:
- s->mscwr1 = value;
- break;
- case MST_MSCWR2:
- s->mscwr2 = value;
- break;
- case MST_MSCWR3:
- s->mscwr3 = value;
- break;
- case MST_MSCRD:
- s->mscrd = value;
- break;
- case MST_INTMSKENA: /* Mask interrupt */
- s->intmskena = (value & 0xFEEFF);
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- break;
- case MST_INTSETCLR: /* clear or set interrupt */
- s->intsetclr = (value & 0xFEEFF);
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- break;
- /* For PCMCIAx allow the to change only power and reset */
- case MST_PCMCIA0:
- s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
- break;
- case MST_PCMCIA1:
- s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
- break;
- default:
- printf("Mainstone - mst_fpga_writeb: Bad register offset "
- "0x" HWADDR_FMT_plx "\n", addr);
- }
-}
-
-static const MemoryRegionOps mst_fpga_ops = {
- .read = mst_fpga_readb,
- .write = mst_fpga_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mst_fpga_post_load(void *opaque, int version_id)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
-
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- return 0;
-}
-
-static void mst_fpga_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- mst_irq_state *s = MAINSTONE_FPGA(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
- s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
-
- sysbus_init_irq(sbd, &s->parent);
-
- /* alloc the external 16 irqs */
- qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS);
-
- memory_region_init_io(&s->iomem, obj, &mst_fpga_ops, s,
- "fpga", 0x00100000);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static const VMStateDescription vmstate_mst_fpga_regs = {
- .name = "mainstone_fpga",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = mst_fpga_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(prev_level, mst_irq_state),
- VMSTATE_UINT32(leddat1, mst_irq_state),
- VMSTATE_UINT32(leddat2, mst_irq_state),
- VMSTATE_UINT32(ledctrl, mst_irq_state),
- VMSTATE_UINT32(gpswr, mst_irq_state),
- VMSTATE_UINT32(mscwr1, mst_irq_state),
- VMSTATE_UINT32(mscwr2, mst_irq_state),
- VMSTATE_UINT32(mscwr3, mst_irq_state),
- VMSTATE_UINT32(mscrd, mst_irq_state),
- VMSTATE_UINT32(intmskena, mst_irq_state),
- VMSTATE_UINT32(intsetclr, mst_irq_state),
- VMSTATE_UINT32(pcmcia0, mst_irq_state),
- VMSTATE_UINT32(pcmcia1, mst_irq_state),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void mst_fpga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "Mainstone II FPGA";
- dc->vmsd = &vmstate_mst_fpga_regs;
-}
-
-static const TypeInfo mst_fpga_info = {
- .name = TYPE_MAINSTONE_FPGA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mst_irq_state),
- .instance_init = mst_fpga_init,
- .class_init = mst_fpga_class_init,
-};
-
-static void mst_fpga_register_types(void)
-{
- type_register_static(&mst_fpga_info);
-}
-
-type_init(mst_fpga_register_types)
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
deleted file mode 100644
index c4c4e24..0000000
--- a/hw/misc/npcm7xx_gcr.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Nuvoton NPCM7xx System Global Control Registers.
- *
- * Copyright 2020 Google LLC
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-
-#include "hw/misc/npcm7xx_gcr.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qemu/units.h"
-
-#include "trace.h"
-
-#define NPCM7XX_GCR_MIN_DRAM_SIZE (128 * MiB)
-#define NPCM7XX_GCR_MAX_DRAM_SIZE (2 * GiB)
-
-enum NPCM7xxGCRRegisters {
- NPCM7XX_GCR_PDID,
- NPCM7XX_GCR_PWRON,
- NPCM7XX_GCR_MFSEL1 = 0x0c / sizeof(uint32_t),
- NPCM7XX_GCR_MFSEL2,
- NPCM7XX_GCR_MISCPE,
- NPCM7XX_GCR_SPSWC = 0x038 / sizeof(uint32_t),
- NPCM7XX_GCR_INTCR,
- NPCM7XX_GCR_INTSR,
- NPCM7XX_GCR_HIFCR = 0x050 / sizeof(uint32_t),
- NPCM7XX_GCR_INTCR2 = 0x060 / sizeof(uint32_t),
- NPCM7XX_GCR_MFSEL3,
- NPCM7XX_GCR_SRCNT,
- NPCM7XX_GCR_RESSR,
- NPCM7XX_GCR_RLOCKR1,
- NPCM7XX_GCR_FLOCKR1,
- NPCM7XX_GCR_DSCNT,
- NPCM7XX_GCR_MDLR,
- NPCM7XX_GCR_SCRPAD3,
- NPCM7XX_GCR_SCRPAD2,
- NPCM7XX_GCR_DAVCLVLR = 0x098 / sizeof(uint32_t),
- NPCM7XX_GCR_INTCR3,
- NPCM7XX_GCR_VSINTR = 0x0ac / sizeof(uint32_t),
- NPCM7XX_GCR_MFSEL4,
- NPCM7XX_GCR_CPBPNTR = 0x0c4 / sizeof(uint32_t),
- NPCM7XX_GCR_CPCTL = 0x0d0 / sizeof(uint32_t),
- NPCM7XX_GCR_CP2BST,
- NPCM7XX_GCR_B2CPNT,
- NPCM7XX_GCR_CPPCTL,
- NPCM7XX_GCR_I2CSEGSEL,
- NPCM7XX_GCR_I2CSEGCTL,
- NPCM7XX_GCR_VSRCR,
- NPCM7XX_GCR_MLOCKR,
- NPCM7XX_GCR_SCRPAD = 0x013c / sizeof(uint32_t),
- NPCM7XX_GCR_USB1PHYCTL,
- NPCM7XX_GCR_USB2PHYCTL,
- NPCM7XX_GCR_REGS_END,
-};
-
-static const uint32_t cold_reset_values[NPCM7XX_GCR_NR_REGS] = {
- [NPCM7XX_GCR_PDID] = 0x04a92750, /* Poleg A1 */
- [NPCM7XX_GCR_MISCPE] = 0x0000ffff,
- [NPCM7XX_GCR_SPSWC] = 0x00000003,
- [NPCM7XX_GCR_INTCR] = 0x0000035e,
- [NPCM7XX_GCR_HIFCR] = 0x0000004e,
- [NPCM7XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */
- [NPCM7XX_GCR_RESSR] = 0x80000000,
- [NPCM7XX_GCR_DSCNT] = 0x000000c0,
- [NPCM7XX_GCR_DAVCLVLR] = 0x5a00f3cf,
- [NPCM7XX_GCR_SCRPAD] = 0x00000008,
- [NPCM7XX_GCR_USB1PHYCTL] = 0x034730e4,
- [NPCM7XX_GCR_USB2PHYCTL] = 0x034730e4,
-};
-
-static uint64_t npcm7xx_gcr_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxGCRState *s = opaque;
-
- if (reg >= NPCM7XX_GCR_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
- __func__, offset);
- return 0;
- }
-
- trace_npcm7xx_gcr_read(offset, s->regs[reg]);
-
- return s->regs[reg];
-}
-
-static void npcm7xx_gcr_write(void *opaque, hwaddr offset,
- uint64_t v, unsigned size)
-{
- uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxGCRState *s = opaque;
- uint32_t value = v;
-
- trace_npcm7xx_gcr_write(offset, value);
-
- if (reg >= NPCM7XX_GCR_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
- __func__, offset);
- return;
- }
-
- switch (reg) {
- case NPCM7XX_GCR_PDID:
- case NPCM7XX_GCR_PWRON:
- case NPCM7XX_GCR_INTSR:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
- __func__, offset);
- return;
-
- case NPCM7XX_GCR_RESSR:
- case NPCM7XX_GCR_CP2BST:
- /* Write 1 to clear */
- value = s->regs[reg] & ~value;
- break;
-
- case NPCM7XX_GCR_RLOCKR1:
- case NPCM7XX_GCR_MDLR:
- /* Write 1 to set */
- value |= s->regs[reg];
- break;
- };
-
- s->regs[reg] = value;
-}
-
-static const struct MemoryRegionOps npcm7xx_gcr_ops = {
- .read = npcm7xx_gcr_read,
- .write = npcm7xx_gcr_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
-};
-
-static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
-{
- NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
-
- QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
-
- 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)
-{
- ERRP_GUARD();
- NPCM7xxGCRState *s = NPCM7XX_GCR(dev);
- uint64_t dram_size;
- Object *obj;
-
- obj = object_property_get_link(OBJECT(dev), "dram-mr", errp);
- if (!obj) {
- error_prepend(errp, "%s: required dram-mr link not found: ", __func__);
- return;
- }
- dram_size = memory_region_size(MEMORY_REGION(obj));
- if (!is_power_of_2(dram_size) ||
- dram_size < NPCM7XX_GCR_MIN_DRAM_SIZE ||
- dram_size > NPCM7XX_GCR_MAX_DRAM_SIZE) {
- g_autofree char *sz = size_to_str(dram_size);
- g_autofree char *min_sz = size_to_str(NPCM7XX_GCR_MIN_DRAM_SIZE);
- g_autofree char *max_sz = size_to_str(NPCM7XX_GCR_MAX_DRAM_SIZE);
- error_setg(errp, "%s: unsupported DRAM size %s", __func__, sz);
- error_append_hint(errp,
- "DRAM size must be a power of two between %s and %s,"
- " inclusive.\n", min_sz, max_sz);
- return;
- }
-
- /* Power-on reset value */
- s->reset_intcr3 = 0x00001002;
-
- /*
- * The GMMAP (Graphics Memory Map) field is used by u-boot to detect the
- * DRAM size, and is normally initialized by the boot block as part of DRAM
- * training. However, since we don't have a complete emulation of the
- * memory controller and try to make it look like it has already been
- * initialized, the boot block will skip this initialization, and we need
- * to make sure this field is set correctly up front.
- *
- * WARNING: some versions of u-boot only looks at bits 8 and 9, so 2 GiB of
- * DRAM will be interpreted as 128 MiB.
- *
- * https://github.com/Nuvoton-Israel/u-boot/blob/2aef993bd2aafeb5408dbaad0f3ce099ee40c4aa/board/nuvoton/poleg/poleg.c#L244
- */
- s->reset_intcr3 |= ctz64(dram_size / NPCM7XX_GCR_MIN_DRAM_SIZE) << 8;
-}
-
-static void npcm7xx_gcr_init(Object *obj)
-{
- NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
-
- memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
- TYPE_NPCM7XX_GCR, 4 * KiB);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
-}
-
-static const VMStateDescription vmstate_npcm7xx_gcr = {
- .name = "npcm7xx-gcr",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxGCRState, NPCM7XX_GCR_NR_REGS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property npcm7xx_gcr_properties[] = {
- DEFINE_PROP_UINT32("disabled-modules", NPCM7xxGCRState, reset_mdlr, 0),
- DEFINE_PROP_UINT32("power-on-straps", NPCM7xxGCRState, reset_pwron, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data)
-{
- ResettableClass *rc = RESETTABLE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- QEMU_BUILD_BUG_ON(NPCM7XX_GCR_REGS_END > NPCM7XX_GCR_NR_REGS);
-
- dc->desc = "NPCM7xx System Global Control Registers";
- dc->realize = npcm7xx_gcr_realize;
- dc->vmsd = &vmstate_npcm7xx_gcr;
- rc->phases.enter = npcm7xx_gcr_enter_reset;
-
- device_class_set_props(dc, npcm7xx_gcr_properties);
-}
-
-static const TypeInfo npcm7xx_gcr_info = {
- .name = TYPE_NPCM7XX_GCR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(NPCM7xxGCRState),
- .instance_init = npcm7xx_gcr_init,
- .class_init = npcm7xx_gcr_class_init,
-};
-
-static void npcm7xx_gcr_register_type(void)
-{
- type_register_static(&npcm7xx_gcr_info);
-}
-type_init(npcm7xx_gcr_register_type);
diff --git a/hw/misc/npcm7xx_mft.c b/hw/misc/npcm7xx_mft.c
index 9fcc69f..b35e971 100644
--- a/hw/misc/npcm7xx_mft.c
+++ b/hw/misc/npcm7xx_mft.c
@@ -172,8 +172,9 @@ static NPCM7xxMFTCaptureState npcm7xx_mft_compute_cnt(
* RPM = revolution/min. The time for one revlution (in ns) is
* MINUTE_TO_NANOSECOND / RPM.
*/
- count = clock_ns_to_ticks(clock, (60 * NANOSECONDS_PER_SECOND) /
- (rpm * NPCM7XX_MFT_PULSE_PER_REVOLUTION));
+ count = clock_ns_to_ticks(clock,
+ (uint64_t)(60 * NANOSECONDS_PER_SECOND) /
+ ((uint64_t)rpm * NPCM7XX_MFT_PULSE_PER_REVOLUTION));
}
if (count > NPCM7XX_MFT_MAX_CNT) {
@@ -514,7 +515,7 @@ static const VMStateDescription vmstate_npcm7xx_mft = {
},
};
-static void npcm7xx_mft_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_mft_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
index f7f77e3..2de18d0 100644
--- a/hw/misc/npcm7xx_pwm.c
+++ b/hw/misc/npcm7xx_pwm.c
@@ -543,7 +543,7 @@ static const VMStateDescription vmstate_npcm7xx_pwm_module = {
},
};
-static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_pwm_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
index 7f7e5ec..7d47a1c 100644
--- a/hw/misc/npcm7xx_rng.c
+++ b/hw/misc/npcm7xx_rng.c
@@ -158,7 +158,7 @@ static const VMStateDescription vmstate_npcm7xx_rng = {
},
};
-static void npcm7xx_rng_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_rng_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm_clk.c
index 2098c85..c48d40b 100644
--- a/hw/misc/npcm7xx_clk.c
+++ b/hw/misc/npcm_clk.c
@@ -1,5 +1,5 @@
/*
- * Nuvoton NPCM7xx Clock Control Registers.
+ * Nuvoton NPCM7xx/8xx Clock Control Registers.
*
* Copyright 2020 Google LLC
*
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
-#include "hw/misc/npcm7xx_clk.h"
+#include "hw/misc/npcm_clk.h"
#include "hw/timer/npcm7xx_timer.h"
#include "hw/qdev-clock.h"
#include "migration/vmstate.h"
@@ -26,7 +26,7 @@
#include "qemu/timer.h"
#include "qemu/units.h"
#include "trace.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
/*
* The reference clock hz, and the SECCNT and CNTR25M registers in this module,
@@ -72,7 +72,57 @@ enum NPCM7xxCLKRegisters {
NPCM7XX_CLK_AHBCKFI,
NPCM7XX_CLK_SECCNT,
NPCM7XX_CLK_CNTR25M,
- NPCM7XX_CLK_REGS_END,
+};
+
+enum NPCM8xxCLKRegisters {
+ NPCM8XX_CLK_CLKEN1,
+ NPCM8XX_CLK_CLKSEL,
+ NPCM8XX_CLK_CLKDIV1,
+ NPCM8XX_CLK_PLLCON0,
+ NPCM8XX_CLK_PLLCON1,
+ NPCM8XX_CLK_SWRSTR,
+ NPCM8XX_CLK_IPSRST1 = 0x20 / sizeof(uint32_t),
+ NPCM8XX_CLK_IPSRST2,
+ NPCM8XX_CLK_CLKEN2,
+ NPCM8XX_CLK_CLKDIV2,
+ NPCM8XX_CLK_CLKEN3,
+ NPCM8XX_CLK_IPSRST3,
+ NPCM8XX_CLK_WD0RCR,
+ NPCM8XX_CLK_WD1RCR,
+ NPCM8XX_CLK_WD2RCR,
+ NPCM8XX_CLK_SWRSTC1,
+ NPCM8XX_CLK_SWRSTC2,
+ NPCM8XX_CLK_SWRSTC3,
+ NPCM8XX_CLK_TIPRSTC,
+ NPCM8XX_CLK_PLLCON2,
+ NPCM8XX_CLK_CLKDIV3,
+ NPCM8XX_CLK_CORSTC,
+ NPCM8XX_CLK_PLLCONG,
+ NPCM8XX_CLK_AHBCKFI,
+ NPCM8XX_CLK_SECCNT,
+ NPCM8XX_CLK_CNTR25M,
+ /* Registers unique to NPCM8XX SoC */
+ NPCM8XX_CLK_CLKEN4,
+ NPCM8XX_CLK_IPSRST4,
+ NPCM8XX_CLK_BUSTO,
+ NPCM8XX_CLK_CLKDIV4,
+ NPCM8XX_CLK_WD0RCRB,
+ NPCM8XX_CLK_WD1RCRB,
+ NPCM8XX_CLK_WD2RCRB,
+ NPCM8XX_CLK_SWRSTC1B,
+ NPCM8XX_CLK_SWRSTC2B,
+ NPCM8XX_CLK_SWRSTC3B,
+ NPCM8XX_CLK_TIPRSTCB,
+ NPCM8XX_CLK_CORSTCB,
+ NPCM8XX_CLK_IPSRSTDIS1,
+ NPCM8XX_CLK_IPSRSTDIS2,
+ NPCM8XX_CLK_IPSRSTDIS3,
+ NPCM8XX_CLK_IPSRSTDIS4,
+ NPCM8XX_CLK_CLKENDIS1,
+ NPCM8XX_CLK_CLKENDIS2,
+ NPCM8XX_CLK_CLKENDIS3,
+ NPCM8XX_CLK_CLKENDIS4,
+ NPCM8XX_CLK_THRTL_CNT,
};
/*
@@ -81,7 +131,7 @@ enum NPCM7xxCLKRegisters {
* All are loaded on power-up reset. CLKENx and SWRSTR should also be loaded on
* core domain reset, but this reset type is not yet supported by QEMU.
*/
-static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
+static const uint32_t npcm7xx_cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
[NPCM7XX_CLK_CLKEN1] = 0xffffffff,
[NPCM7XX_CLK_CLKSEL] = 0x004aaaaa,
[NPCM7XX_CLK_CLKDIV1] = 0x5413f855,
@@ -103,6 +153,46 @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
};
+/*
+ * These reset values were taken from version 0.92 of the NPCM8xx data sheet.
+ */
+static const uint32_t npcm8xx_cold_reset_values[NPCM8XX_CLK_NR_REGS] = {
+ [NPCM8XX_CLK_CLKEN1] = 0xffffffff,
+ [NPCM8XX_CLK_CLKSEL] = 0x154aaaaa,
+ [NPCM8XX_CLK_CLKDIV1] = 0x5413f855,
+ [NPCM8XX_CLK_PLLCON0] = 0x00222101 | PLLCON_LOKI,
+ [NPCM8XX_CLK_PLLCON1] = 0x00202101 | PLLCON_LOKI,
+ [NPCM8XX_CLK_IPSRST1] = 0x00001000,
+ [NPCM8XX_CLK_IPSRST2] = 0x80000000,
+ [NPCM8XX_CLK_CLKEN2] = 0xffffffff,
+ [NPCM8XX_CLK_CLKDIV2] = 0xaa4f8f9f,
+ [NPCM8XX_CLK_CLKEN3] = 0xffffffff,
+ [NPCM8XX_CLK_IPSRST3] = 0x03000000,
+ [NPCM8XX_CLK_WD0RCR] = 0xffffffff,
+ [NPCM8XX_CLK_WD1RCR] = 0xffffffff,
+ [NPCM8XX_CLK_WD2RCR] = 0xffffffff,
+ [NPCM8XX_CLK_SWRSTC1] = 0x00000003,
+ [NPCM8XX_CLK_SWRSTC2] = 0x00000001,
+ [NPCM8XX_CLK_SWRSTC3] = 0x00000001,
+ [NPCM8XX_CLK_TIPRSTC] = 0x00000001,
+ [NPCM8XX_CLK_PLLCON2] = 0x00c02105 | PLLCON_LOKI,
+ [NPCM8XX_CLK_CLKDIV3] = 0x00009100,
+ [NPCM8XX_CLK_CORSTC] = 0x04000003,
+ [NPCM8XX_CLK_PLLCONG] = 0x01228606 | PLLCON_LOKI,
+ [NPCM8XX_CLK_AHBCKFI] = 0x000000c8,
+ [NPCM8XX_CLK_CLKEN4] = 0xffffffff,
+ [NPCM8XX_CLK_CLKDIV4] = 0x70009000,
+ [NPCM8XX_CLK_IPSRST4] = 0x02000000,
+ [NPCM8XX_CLK_WD0RCRB] = 0xfffffe71,
+ [NPCM8XX_CLK_WD1RCRB] = 0xfffffe71,
+ [NPCM8XX_CLK_WD2RCRB] = 0xfffffe71,
+ [NPCM8XX_CLK_SWRSTC1B] = 0xfffffe71,
+ [NPCM8XX_CLK_SWRSTC2B] = 0xfffffe71,
+ [NPCM8XX_CLK_SWRSTC3B] = 0xfffffe71,
+ [NPCM8XX_CLK_TIPRSTCB] = 0xfffffe71,
+ [NPCM8XX_CLK_CORSTCB] = 0xfffffe71,
+};
+
/* The number of watchdogs that can trigger a reset. */
#define NPCM7XX_NR_WATCHDOGS (3)
@@ -198,7 +288,7 @@ static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
}
}
-static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_plls(NPCMCLKState *clk)
{
int i;
@@ -207,7 +297,7 @@ static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
}
}
-static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_sels(NPCMCLKState *clk)
{
int i;
@@ -216,7 +306,7 @@ static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
}
}
-static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_dividers(NPCMCLKState *clk)
{
int i;
@@ -225,7 +315,7 @@ static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
}
}
-static void npcm7xx_clk_update_all_clocks(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_clocks(NPCMCLKState *clk)
{
clock_update_hz(clk->clkref, NPCM7XX_CLOCK_REF_HZ);
npcm7xx_clk_update_all_plls(clk);
@@ -635,7 +725,7 @@ static void npcm7xx_clk_divider_init(Object *obj)
}
static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
- NPCM7xxCLKState *clk, const PLLInitInfo *init_info)
+ NPCMCLKState *clk, const PLLInitInfo *init_info)
{
pll->name = init_info->name;
pll->clk = clk;
@@ -647,7 +737,7 @@ static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
}
static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
- NPCM7xxCLKState *clk, const SELInitInfo *init_info)
+ NPCMCLKState *clk, const SELInitInfo *init_info)
{
int input_size = init_info->input_size;
@@ -664,7 +754,7 @@ static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
}
static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
- NPCM7xxCLKState *clk, const DividerInitInfo *init_info)
+ NPCMCLKState *clk, const DividerInitInfo *init_info)
{
div->name = init_info->name;
div->clk = clk;
@@ -683,7 +773,7 @@ static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
}
}
-static Clock *npcm7xx_get_clock(NPCM7xxCLKState *clk, ClockSrcType type,
+static Clock *npcm7xx_get_clock(NPCMCLKState *clk, ClockSrcType type,
int index)
{
switch (type) {
@@ -700,7 +790,7 @@ static Clock *npcm7xx_get_clock(NPCM7xxCLKState *clk, ClockSrcType type,
}
}
-static void npcm7xx_connect_clocks(NPCM7xxCLKState *clk)
+static void npcm7xx_connect_clocks(NPCMCLKState *clk)
{
int i, j;
Clock *src;
@@ -724,14 +814,15 @@ static void npcm7xx_connect_clocks(NPCM7xxCLKState *clk)
}
}
-static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
+static uint64_t npcm_clk_read(void *opaque, hwaddr offset, unsigned size)
{
uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxCLKState *s = opaque;
+ NPCMCLKState *s = opaque;
+ NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
int64_t now_ns;
uint32_t value = 0;
- if (reg >= NPCM7XX_CLK_NR_REGS) {
+ if (reg >= c->nr_regs) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: offset 0x%04" HWADDR_PRIx " out of range\n",
__func__, offset);
@@ -766,21 +857,22 @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
break;
};
- trace_npcm7xx_clk_read(offset, value);
+ trace_npcm_clk_read(offset, value);
return value;
}
-static void npcm7xx_clk_write(void *opaque, hwaddr offset,
+static void npcm_clk_write(void *opaque, hwaddr offset,
uint64_t v, unsigned size)
{
uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxCLKState *s = opaque;
+ NPCMCLKState *s = opaque;
+ NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
uint32_t value = v;
- trace_npcm7xx_clk_write(offset, value);
+ trace_npcm_clk_write(offset, value);
- if (reg >= NPCM7XX_CLK_NR_REGS) {
+ if (reg >= c->nr_regs) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: offset 0x%04" HWADDR_PRIx " out of range\n",
__func__, offset);
@@ -842,7 +934,7 @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
int level)
{
- NPCM7xxCLKState *clk = NPCM7XX_CLK(opaque);
+ NPCMCLKState *clk = NPCM_CLK(opaque);
uint32_t rcr;
g_assert(n >= 0 && n <= NPCM7XX_NR_WATCHDOGS);
@@ -856,9 +948,9 @@ static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
}
}
-static const struct MemoryRegionOps npcm7xx_clk_ops = {
- .read = npcm7xx_clk_read,
- .write = npcm7xx_clk_write,
+static const struct MemoryRegionOps npcm_clk_ops = {
+ .read = npcm_clk_read,
+ .write = npcm_clk_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
@@ -867,13 +959,14 @@ static const struct MemoryRegionOps npcm7xx_clk_ops = {
},
};
-static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
+static void npcm_clk_enter_reset(Object *obj, ResetType type)
{
- NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
+ NPCMCLKState *s = NPCM_CLK(obj);
+ NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
- QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
-
- memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
+ size_t sizeof_regs = c->nr_regs * sizeof(uint32_t);
+ g_assert(sizeof(s->regs) >= sizeof_regs);
+ memcpy(s->regs, c->cold_reset_values, sizeof_regs);
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
npcm7xx_clk_update_all_clocks(s);
/*
@@ -882,7 +975,7 @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
*/
}
-static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
+static void npcm7xx_clk_init_clock_hierarchy(NPCMCLKState *s)
{
int i;
@@ -918,19 +1011,19 @@ static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
}
-static void npcm7xx_clk_init(Object *obj)
+static void npcm_clk_init(Object *obj)
{
- NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
+ NPCMCLKState *s = NPCM_CLK(obj);
- memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
- TYPE_NPCM7XX_CLK, 4 * KiB);
+ memory_region_init_io(&s->iomem, obj, &npcm_clk_ops, s,
+ TYPE_NPCM_CLK, 4 * KiB);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
-static int npcm7xx_clk_post_load(void *opaque, int version_id)
+static int npcm_clk_post_load(void *opaque, int version_id)
{
if (version_id >= 1) {
- NPCM7xxCLKState *clk = opaque;
+ NPCMCLKState *clk = opaque;
npcm7xx_clk_update_all_clocks(clk);
}
@@ -938,10 +1031,10 @@ static int npcm7xx_clk_post_load(void *opaque, int version_id)
return 0;
}
-static void npcm7xx_clk_realize(DeviceState *dev, Error **errp)
+static void npcm_clk_realize(DeviceState *dev, Error **errp)
{
int i;
- NPCM7xxCLKState *s = NPCM7XX_CLK(dev);
+ NPCMCLKState *s = NPCM_CLK(dev);
qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
@@ -996,54 +1089,77 @@ static const VMStateDescription vmstate_npcm7xx_clk_divider = {
},
};
-static const VMStateDescription vmstate_npcm7xx_clk = {
- .name = "npcm7xx-clk",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = npcm7xx_clk_post_load,
+static const VMStateDescription vmstate_npcm_clk = {
+ .name = "npcm-clk",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .post_load = npcm_clk_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
- VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
- VMSTATE_CLOCK(clkref, NPCM7xxCLKState),
+ VMSTATE_UINT32_ARRAY(regs, NPCMCLKState, NPCM_CLK_MAX_NR_REGS),
+ VMSTATE_INT64(ref_ns, NPCMCLKState),
+ VMSTATE_CLOCK(clkref, NPCMCLKState),
VMSTATE_END_OF_LIST(),
},
};
-static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_clk_pll_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "NPCM7xx Clock PLL Module";
dc->vmsd = &vmstate_npcm7xx_clk_pll;
+ /* Reason: Part of NPCMCLKState component */
+ dc->user_creatable = false;
}
-static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_clk_sel_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "NPCM7xx Clock SEL Module";
dc->vmsd = &vmstate_npcm7xx_clk_sel;
+ /* Reason: Part of NPCMCLKState component */
+ dc->user_creatable = false;
}
-static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_clk_divider_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "NPCM7xx Clock Divider Module";
dc->vmsd = &vmstate_npcm7xx_clk_divider;
+ /* Reason: Part of NPCMCLKState component */
+ dc->user_creatable = false;
}
-static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
+static void npcm_clk_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- QEMU_BUILD_BUG_ON(NPCM7XX_CLK_REGS_END > NPCM7XX_CLK_NR_REGS);
+ dc->vmsd = &vmstate_npcm_clk;
+ dc->realize = npcm_clk_realize;
+ rc->phases.enter = npcm_clk_enter_reset;
+}
+
+static void npcm7xx_clk_class_init(ObjectClass *klass, const void *data)
+{
+ NPCMCLKClass *c = NPCM_CLK_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "NPCM7xx Clock Control Registers";
- dc->vmsd = &vmstate_npcm7xx_clk;
- dc->realize = npcm7xx_clk_realize;
- rc->phases.enter = npcm7xx_clk_enter_reset;
+ c->nr_regs = NPCM7XX_CLK_NR_REGS;
+ c->cold_reset_values = npcm7xx_cold_reset_values;
+}
+
+static void npcm8xx_clk_class_init(ObjectClass *klass, const void *data)
+{
+ NPCMCLKClass *c = NPCM_CLK_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "NPCM8xx Clock Control Registers";
+ c->nr_regs = NPCM8XX_CLK_NR_REGS;
+ c->cold_reset_values = npcm8xx_cold_reset_values;
}
static const TypeInfo npcm7xx_clk_pll_info = {
@@ -1070,19 +1186,35 @@ static const TypeInfo npcm7xx_clk_divider_info = {
.class_init = npcm7xx_clk_divider_class_init,
};
+static const TypeInfo npcm_clk_info = {
+ .name = TYPE_NPCM_CLK,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMCLKState),
+ .instance_init = npcm_clk_init,
+ .class_size = sizeof(NPCMCLKClass),
+ .class_init = npcm_clk_class_init,
+ .abstract = true,
+};
+
static const TypeInfo npcm7xx_clk_info = {
.name = TYPE_NPCM7XX_CLK,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(NPCM7xxCLKState),
- .instance_init = npcm7xx_clk_init,
+ .parent = TYPE_NPCM_CLK,
.class_init = npcm7xx_clk_class_init,
};
+static const TypeInfo npcm8xx_clk_info = {
+ .name = TYPE_NPCM8XX_CLK,
+ .parent = TYPE_NPCM_CLK,
+ .class_init = npcm8xx_clk_class_init,
+};
+
static void npcm7xx_clk_register_type(void)
{
type_register_static(&npcm7xx_clk_pll_info);
type_register_static(&npcm7xx_clk_sel_info);
type_register_static(&npcm7xx_clk_divider_info);
+ type_register_static(&npcm_clk_info);
type_register_static(&npcm7xx_clk_info);
+ type_register_static(&npcm8xx_clk_info);
}
type_init(npcm7xx_clk_register_type);
diff --git a/hw/misc/npcm_gcr.c b/hw/misc/npcm_gcr.c
new file mode 100644
index 0000000..2acaa16
--- /dev/null
+++ b/hw/misc/npcm_gcr.c
@@ -0,0 +1,482 @@
+/*
+ * Nuvoton NPCM7xx/8xx System Global Control Registers.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/misc/npcm_gcr.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+
+#include "trace.h"
+
+#define NPCM7XX_GCR_MIN_DRAM_SIZE (128 * MiB)
+#define NPCM7XX_GCR_MAX_DRAM_SIZE (2 * GiB)
+
+enum NPCM7xxGCRRegisters {
+ NPCM7XX_GCR_PDID,
+ NPCM7XX_GCR_PWRON,
+ NPCM7XX_GCR_MFSEL1 = 0x0c / sizeof(uint32_t),
+ NPCM7XX_GCR_MFSEL2,
+ NPCM7XX_GCR_MISCPE,
+ NPCM7XX_GCR_SPSWC = 0x038 / sizeof(uint32_t),
+ NPCM7XX_GCR_INTCR,
+ NPCM7XX_GCR_INTSR,
+ NPCM7XX_GCR_HIFCR = 0x050 / sizeof(uint32_t),
+ NPCM7XX_GCR_INTCR2 = 0x060 / sizeof(uint32_t),
+ NPCM7XX_GCR_MFSEL3,
+ NPCM7XX_GCR_SRCNT,
+ NPCM7XX_GCR_RESSR,
+ NPCM7XX_GCR_RLOCKR1,
+ NPCM7XX_GCR_FLOCKR1,
+ NPCM7XX_GCR_DSCNT,
+ NPCM7XX_GCR_MDLR,
+ NPCM7XX_GCR_SCRPAD3,
+ NPCM7XX_GCR_SCRPAD2,
+ NPCM7XX_GCR_DAVCLVLR = 0x098 / sizeof(uint32_t),
+ NPCM7XX_GCR_INTCR3,
+ NPCM7XX_GCR_VSINTR = 0x0ac / sizeof(uint32_t),
+ NPCM7XX_GCR_MFSEL4,
+ NPCM7XX_GCR_CPBPNTR = 0x0c4 / sizeof(uint32_t),
+ NPCM7XX_GCR_CPCTL = 0x0d0 / sizeof(uint32_t),
+ NPCM7XX_GCR_CP2BST,
+ NPCM7XX_GCR_B2CPNT,
+ NPCM7XX_GCR_CPPCTL,
+ NPCM7XX_GCR_I2CSEGSEL,
+ NPCM7XX_GCR_I2CSEGCTL,
+ NPCM7XX_GCR_VSRCR,
+ NPCM7XX_GCR_MLOCKR,
+ NPCM7XX_GCR_SCRPAD = 0x013c / sizeof(uint32_t),
+ NPCM7XX_GCR_USB1PHYCTL,
+ NPCM7XX_GCR_USB2PHYCTL,
+};
+
+static const uint32_t npcm7xx_cold_reset_values[NPCM7XX_GCR_NR_REGS] = {
+ [NPCM7XX_GCR_PDID] = 0x04a92750, /* Poleg A1 */
+ [NPCM7XX_GCR_MISCPE] = 0x0000ffff,
+ [NPCM7XX_GCR_SPSWC] = 0x00000003,
+ [NPCM7XX_GCR_INTCR] = 0x0000035e,
+ [NPCM7XX_GCR_HIFCR] = 0x0000004e,
+ [NPCM7XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */
+ [NPCM7XX_GCR_RESSR] = 0x80000000,
+ [NPCM7XX_GCR_DSCNT] = 0x000000c0,
+ [NPCM7XX_GCR_DAVCLVLR] = 0x5a00f3cf,
+ [NPCM7XX_GCR_SCRPAD] = 0x00000008,
+ [NPCM7XX_GCR_USB1PHYCTL] = 0x034730e4,
+ [NPCM7XX_GCR_USB2PHYCTL] = 0x034730e4,
+};
+
+enum NPCM8xxGCRRegisters {
+ NPCM8XX_GCR_PDID,
+ NPCM8XX_GCR_PWRON,
+ NPCM8XX_GCR_MISCPE = 0x014 / sizeof(uint32_t),
+ NPCM8XX_GCR_FLOCKR2 = 0x020 / sizeof(uint32_t),
+ NPCM8XX_GCR_FLOCKR3,
+ NPCM8XX_GCR_A35_MODE = 0x034 / sizeof(uint32_t),
+ NPCM8XX_GCR_SPSWC,
+ NPCM8XX_GCR_INTCR,
+ NPCM8XX_GCR_INTSR,
+ NPCM8XX_GCR_HIFCR = 0x050 / sizeof(uint32_t),
+ NPCM8XX_GCR_INTCR2 = 0x060 / sizeof(uint32_t),
+ NPCM8XX_GCR_SRCNT = 0x068 / sizeof(uint32_t),
+ NPCM8XX_GCR_RESSR,
+ NPCM8XX_GCR_RLOCKR1,
+ NPCM8XX_GCR_FLOCKR1,
+ NPCM8XX_GCR_DSCNT,
+ NPCM8XX_GCR_MDLR,
+ NPCM8XX_GCR_SCRPAD_C = 0x080 / sizeof(uint32_t),
+ NPCM8XX_GCR_SCRPAD_B,
+ NPCM8XX_GCR_DAVCLVLR = 0x098 / sizeof(uint32_t),
+ NPCM8XX_GCR_INTCR3,
+ NPCM8XX_GCR_PCIRCTL = 0x0a0 / sizeof(uint32_t),
+ NPCM8XX_GCR_VSINTR,
+ NPCM8XX_GCR_SD2SUR1 = 0x0b4 / sizeof(uint32_t),
+ NPCM8XX_GCR_SD2SUR2,
+ NPCM8XX_GCR_INTCR4 = 0x0c0 / sizeof(uint32_t),
+ NPCM8XX_GCR_CPCTL = 0x0d0 / sizeof(uint32_t),
+ NPCM8XX_GCR_CP2BST,
+ NPCM8XX_GCR_B2CPNT,
+ NPCM8XX_GCR_CPPCTL,
+ NPCM8XX_GCR_I2CSEGSEL = 0x0e0 / sizeof(uint32_t),
+ NPCM8XX_GCR_I2CSEGCTL,
+ NPCM8XX_GCR_VSRCR,
+ NPCM8XX_GCR_MLOCKR,
+ NPCM8XX_GCR_SCRPAD = 0x13c / sizeof(uint32_t),
+ NPCM8XX_GCR_USB1PHYCTL,
+ NPCM8XX_GCR_USB2PHYCTL,
+ NPCM8XX_GCR_USB3PHYCTL,
+ NPCM8XX_GCR_MFSEL1 = 0x260 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL2,
+ NPCM8XX_GCR_MFSEL3,
+ NPCM8XX_GCR_MFSEL4,
+ NPCM8XX_GCR_MFSEL5,
+ NPCM8XX_GCR_MFSEL6,
+ NPCM8XX_GCR_MFSEL7,
+ NPCM8XX_GCR_MFSEL_LK1 = 0x280 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL_LK2,
+ NPCM8XX_GCR_MFSEL_LK3,
+ NPCM8XX_GCR_MFSEL_LK4,
+ NPCM8XX_GCR_MFSEL_LK5,
+ NPCM8XX_GCR_MFSEL_LK6,
+ NPCM8XX_GCR_MFSEL_LK7,
+ NPCM8XX_GCR_MFSEL_SET1 = 0x2a0 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL_SET2,
+ NPCM8XX_GCR_MFSEL_SET3,
+ NPCM8XX_GCR_MFSEL_SET4,
+ NPCM8XX_GCR_MFSEL_SET5,
+ NPCM8XX_GCR_MFSEL_SET6,
+ NPCM8XX_GCR_MFSEL_SET7,
+ NPCM8XX_GCR_MFSEL_CLR1 = 0x2c0 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL_CLR2,
+ NPCM8XX_GCR_MFSEL_CLR3,
+ NPCM8XX_GCR_MFSEL_CLR4,
+ NPCM8XX_GCR_MFSEL_CLR5,
+ NPCM8XX_GCR_MFSEL_CLR6,
+ NPCM8XX_GCR_MFSEL_CLR7,
+ NPCM8XX_GCR_WD0RCRLK = 0x400 / sizeof(uint32_t),
+ NPCM8XX_GCR_WD1RCRLK,
+ NPCM8XX_GCR_WD2RCRLK,
+ NPCM8XX_GCR_SWRSTC1LK,
+ NPCM8XX_GCR_SWRSTC2LK,
+ NPCM8XX_GCR_SWRSTC3LK,
+ NPCM8XX_GCR_TIPRSTCLK,
+ NPCM8XX_GCR_CORSTCLK,
+ NPCM8XX_GCR_WD0RCRBLK,
+ NPCM8XX_GCR_WD1RCRBLK,
+ NPCM8XX_GCR_WD2RCRBLK,
+ NPCM8XX_GCR_SWRSTC1BLK,
+ NPCM8XX_GCR_SWRSTC2BLK,
+ NPCM8XX_GCR_SWRSTC3BLK,
+ NPCM8XX_GCR_TIPRSTCBLK,
+ NPCM8XX_GCR_CORSTCBLK,
+ /* 64 scratch pad registers start here. 0xe00 ~ 0xefc */
+ NPCM8XX_GCR_SCRPAD_00 = 0xe00 / sizeof(uint32_t),
+ /* 32 semaphore registers start here. 0xf00 ~ 0xf7c */
+ NPCM8XX_GCR_GP_SEMFR_00 = 0xf00 / sizeof(uint32_t),
+ NPCM8XX_GCR_GP_SEMFR_31 = 0xf7c / sizeof(uint32_t),
+};
+
+static const uint32_t npcm8xx_cold_reset_values[NPCM8XX_GCR_NR_REGS] = {
+ [NPCM8XX_GCR_PDID] = 0x04a35850, /* Arbel A1 */
+ [NPCM8XX_GCR_MISCPE] = 0x0000ffff,
+ [NPCM8XX_GCR_A35_MODE] = 0xfff4ff30,
+ [NPCM8XX_GCR_SPSWC] = 0x00000003,
+ [NPCM8XX_GCR_INTCR] = 0x0010035e,
+ [NPCM8XX_GCR_HIFCR] = 0x0000004e,
+ [NPCM8XX_GCR_SD2SUR1] = 0xfdc80000,
+ [NPCM8XX_GCR_SD2SUR2] = 0x5200b130,
+ [NPCM8XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */
+ [NPCM8XX_GCR_RESSR] = 0x80000000,
+ [NPCM8XX_GCR_DAVCLVLR] = 0x5a00f3cf,
+ [NPCM8XX_GCR_INTCR3] = 0x5e001002,
+ [NPCM8XX_GCR_VSRCR] = 0x00004800,
+ [NPCM8XX_GCR_SCRPAD] = 0x00000008,
+ [NPCM8XX_GCR_USB1PHYCTL] = 0x034730e4,
+ [NPCM8XX_GCR_USB2PHYCTL] = 0x034730e4,
+ [NPCM8XX_GCR_USB3PHYCTL] = 0x034730e4,
+ /* All 32 semaphores should be initialized to 1. */
+ [NPCM8XX_GCR_GP_SEMFR_00...NPCM8XX_GCR_GP_SEMFR_31] = 0x00000001,
+};
+
+static uint64_t npcm_gcr_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint32_t reg = offset / sizeof(uint32_t);
+ NPCMGCRState *s = opaque;
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(s);
+ uint64_t value;
+
+ if (reg >= c->nr_regs) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (size) {
+ case 4:
+ value = s->regs[reg];
+ break;
+
+ case 8:
+ g_assert(!(reg & 1));
+ value = deposit64(s->regs[reg], 32, 32, s->regs[reg + 1]);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ trace_npcm_gcr_read(offset, value);
+ return value;
+}
+
+static void npcm_gcr_write(void *opaque, hwaddr offset,
+ uint64_t v, unsigned size)
+{
+ uint32_t reg = offset / sizeof(uint32_t);
+ NPCMGCRState *s = opaque;
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(s);
+ uint32_t value = v;
+
+ trace_npcm_gcr_write(offset, v);
+
+ if (reg >= c->nr_regs) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
+ __func__, offset);
+ return;
+ }
+
+ switch (size) {
+ case 4:
+ switch (reg) {
+ case NPCM7XX_GCR_PDID:
+ case NPCM7XX_GCR_PWRON:
+ case NPCM7XX_GCR_INTSR:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
+ __func__, offset);
+ return;
+
+ case NPCM7XX_GCR_RESSR:
+ case NPCM7XX_GCR_CP2BST:
+ /* Write 1 to clear */
+ value = s->regs[reg] & ~value;
+ break;
+
+ case NPCM7XX_GCR_RLOCKR1:
+ case NPCM7XX_GCR_MDLR:
+ /* Write 1 to set */
+ value |= s->regs[reg];
+ break;
+ };
+ s->regs[reg] = value;
+ break;
+
+ case 8:
+ g_assert(!(reg & 1));
+ s->regs[reg] = value;
+ s->regs[reg + 1] = extract64(v, 32, 32);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static bool npcm_gcr_check_mem_op(void *opaque, hwaddr offset,
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
+{
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(opaque);
+
+ if (offset >= c->nr_regs * sizeof(uint32_t)) {
+ return false;
+ }
+
+ switch (size) {
+ case 4:
+ return true;
+ case 8:
+ if (offset >= NPCM8XX_GCR_SCRPAD_00 * sizeof(uint32_t) &&
+ offset < (NPCM8XX_GCR_NR_REGS - 1) * sizeof(uint32_t)) {
+ return true;
+ } else {
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
+static const struct MemoryRegionOps npcm_gcr_ops = {
+ .read = npcm_gcr_read,
+ .write = npcm_gcr_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ .accepts = npcm_gcr_check_mem_op,
+ .unaligned = false,
+ },
+};
+
+static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
+{
+ NPCMGCRState *s = NPCM_GCR(obj);
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(obj);
+
+ g_assert(sizeof(s->regs) >= sizeof(c->cold_reset_values));
+ g_assert(sizeof(s->regs) >= c->nr_regs * sizeof(uint32_t));
+ memcpy(s->regs, c->cold_reset_values, c->nr_regs * sizeof(uint32_t));
+ /* These 3 registers are at the same location in both 7xx and 8xx. */
+ 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 npcm8xx_gcr_enter_reset(Object *obj, ResetType type)
+{
+ NPCMGCRState *s = NPCM_GCR(obj);
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(obj);
+
+ memcpy(s->regs, c->cold_reset_values, c->nr_regs * sizeof(uint32_t));
+ /* These 3 registers are at the same location in both 7xx and 8xx. */
+ s->regs[NPCM8XX_GCR_PWRON] = s->reset_pwron;
+ s->regs[NPCM8XX_GCR_MDLR] = s->reset_mdlr;
+ s->regs[NPCM8XX_GCR_INTCR3] = s->reset_intcr3;
+ s->regs[NPCM8XX_GCR_SCRPAD_B] = s->reset_scrpad_b;
+}
+
+static void npcm_gcr_realize(DeviceState *dev, Error **errp)
+{
+ ERRP_GUARD();
+ NPCMGCRState *s = NPCM_GCR(dev);
+ uint64_t dram_size;
+ Object *obj;
+
+ obj = object_property_get_link(OBJECT(dev), "dram-mr", errp);
+ if (!obj) {
+ error_prepend(errp, "%s: required dram-mr link not found: ", __func__);
+ return;
+ }
+ dram_size = memory_region_size(MEMORY_REGION(obj));
+ if (!is_power_of_2(dram_size) ||
+ dram_size < NPCM7XX_GCR_MIN_DRAM_SIZE ||
+ dram_size > NPCM7XX_GCR_MAX_DRAM_SIZE) {
+ g_autofree char *sz = size_to_str(dram_size);
+ g_autofree char *min_sz = size_to_str(NPCM7XX_GCR_MIN_DRAM_SIZE);
+ g_autofree char *max_sz = size_to_str(NPCM7XX_GCR_MAX_DRAM_SIZE);
+ error_setg(errp, "%s: unsupported DRAM size %s", __func__, sz);
+ error_append_hint(errp,
+ "DRAM size must be a power of two between %s and %s,"
+ " inclusive.\n", min_sz, max_sz);
+ return;
+ }
+
+ /* Power-on reset value */
+ s->reset_intcr3 = 0x00001002;
+
+ /*
+ * The GMMAP (Graphics Memory Map) field is used by u-boot to detect the
+ * DRAM size, and is normally initialized by the boot block as part of DRAM
+ * training. However, since we don't have a complete emulation of the
+ * memory controller and try to make it look like it has already been
+ * initialized, the boot block will skip this initialization, and we need
+ * to make sure this field is set correctly up front.
+ *
+ * WARNING: some versions of u-boot only looks at bits 8 and 9, so 2 GiB of
+ * DRAM will be interpreted as 128 MiB.
+ *
+ * https://github.com/Nuvoton-Israel/u-boot/blob/2aef993bd2aafeb5408dbaad0f3ce099ee40c4aa/board/nuvoton/poleg/poleg.c#L244
+ */
+ s->reset_intcr3 |= ctz64(dram_size / NPCM7XX_GCR_MIN_DRAM_SIZE) << 8;
+
+ /*
+ * The boot block starting from 0.0.6 for NPCM8xx SoCs stores the DRAM size
+ * in the SCRPAD2 registers. We need to set this field correctly since
+ * the initialization is skipped as we mentioned above.
+ * https://github.com/Nuvoton-Israel/u-boot/blob/npcm8mnx-v2019.01_tmp/board/nuvoton/arbel/arbel.c#L737
+ */
+ s->reset_scrpad_b = dram_size;
+}
+
+static void npcm_gcr_init(Object *obj)
+{
+ NPCMGCRState *s = NPCM_GCR(obj);
+
+ memory_region_init_io(&s->iomem, obj, &npcm_gcr_ops, s,
+ TYPE_NPCM_GCR, 4 * KiB);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+}
+
+static const VMStateDescription vmstate_npcm_gcr = {
+ .name = "npcm-gcr",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, NPCMGCRState, NPCM_GCR_MAX_NR_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static const Property npcm_gcr_properties[] = {
+ DEFINE_PROP_UINT32("disabled-modules", NPCMGCRState, reset_mdlr, 0),
+ DEFINE_PROP_UINT32("power-on-straps", NPCMGCRState, reset_pwron, 0),
+};
+
+static void npcm_gcr_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = npcm_gcr_realize;
+ dc->vmsd = &vmstate_npcm_gcr;
+
+ device_class_set_props(dc, npcm_gcr_properties);
+}
+
+static void npcm7xx_gcr_class_init(ObjectClass *klass, const void *data)
+{
+ NPCMGCRClass *c = NPCM_GCR_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->desc = "NPCM7xx System Global Control Registers";
+ rc->phases.enter = npcm7xx_gcr_enter_reset;
+
+ c->nr_regs = NPCM7XX_GCR_NR_REGS;
+ c->cold_reset_values = npcm7xx_cold_reset_values;
+ rc->phases.enter = npcm7xx_gcr_enter_reset;
+}
+
+static void npcm8xx_gcr_class_init(ObjectClass *klass, const void *data)
+{
+ NPCMGCRClass *c = NPCM_GCR_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->desc = "NPCM8xx System Global Control Registers";
+ c->nr_regs = NPCM8XX_GCR_NR_REGS;
+ c->cold_reset_values = npcm8xx_cold_reset_values;
+ rc->phases.enter = npcm8xx_gcr_enter_reset;
+}
+
+static const TypeInfo npcm_gcr_info[] = {
+ {
+ .name = TYPE_NPCM_GCR,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMGCRState),
+ .instance_init = npcm_gcr_init,
+ .class_size = sizeof(NPCMGCRClass),
+ .class_init = npcm_gcr_class_init,
+ .abstract = true,
+ },
+ {
+ .name = TYPE_NPCM7XX_GCR,
+ .parent = TYPE_NPCM_GCR,
+ .class_init = npcm7xx_gcr_class_init,
+ },
+ {
+ .name = TYPE_NPCM8XX_GCR,
+ .parent = TYPE_NPCM_GCR,
+ .class_init = npcm8xx_gcr_class_init,
+ },
+};
+DEFINE_TYPES(npcm_gcr_info)
diff --git a/hw/misc/nrf51_rng.c b/hw/misc/nrf51_rng.c
index 2d76c45..8cd7ffe 100644
--- a/hw/misc/nrf51_rng.c
+++ b/hw/misc/nrf51_rng.c
@@ -107,25 +107,25 @@ static void rng_write(void *opaque, hwaddr offset,
break;
case NRF51_RNG_REG_SHORTS:
s->shortcut_stop_on_valrdy =
- (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
+ (value & BIT(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
break;
case NRF51_RNG_REG_INTEN:
s->interrupt_enabled =
- (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
+ (value & BIT(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
break;
case NRF51_RNG_REG_INTENSET:
- if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
+ if (value & BIT(NRF51_RNG_REG_INTEN_VALRDY)) {
s->interrupt_enabled = 1;
}
break;
case NRF51_RNG_REG_INTENCLR:
- if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
+ if (value & BIT(NRF51_RNG_REG_INTEN_VALRDY)) {
s->interrupt_enabled = 0;
}
break;
case NRF51_RNG_REG_CONFIG:
s->filter_enabled =
- (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
+ (value & BIT(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
break;
default:
@@ -219,12 +219,11 @@ static void nrf51_rng_reset(DeviceState *dev)
}
-static Property nrf51_rng_properties[] = {
+static const Property nrf51_rng_properties[] = {
DEFINE_PROP_UINT16("period_unfiltered_us", NRF51RNGState,
period_unfiltered_us, 167),
DEFINE_PROP_UINT16("period_filtered_us", NRF51RNGState,
period_filtered_us, 660),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_rng = {
@@ -241,13 +240,13 @@ static const VMStateDescription vmstate_rng = {
}
};
-static void nrf51_rng_class_init(ObjectClass *klass, void *data)
+static void nrf51_rng_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, nrf51_rng_properties);
dc->vmsd = &vmstate_rng;
- dc->reset = nrf51_rng_reset;
+ device_class_set_legacy_reset(dc, nrf51_rng_reset);
}
static const TypeInfo nrf51_rng_info = {
diff --git a/hw/misc/omap_clk.c b/hw/misc/omap_clk.c
index c77ca2f..da95c4a 100644
--- a/hw/misc/omap_clk.c
+++ b/hw/misc/omap_clk.c
@@ -30,174 +30,170 @@ struct clk {
struct clk *parent;
struct clk *child1;
struct clk *sibling;
-#define ALWAYS_ENABLED (1 << 0)
-#define CLOCK_IN_OMAP310 (1 << 10)
-#define CLOCK_IN_OMAP730 (1 << 11)
-#define CLOCK_IN_OMAP1510 (1 << 12)
-#define CLOCK_IN_OMAP16XX (1 << 13)
-#define CLOCK_IN_OMAP242X (1 << 14)
-#define CLOCK_IN_OMAP243X (1 << 15)
-#define CLOCK_IN_OMAP343X (1 << 16)
+#define ALWAYS_ENABLED (1 << 0)
+#define CLOCK_IN_OMAP310 (1 << 10)
+#define CLOCK_IN_OMAP730 (1 << 11)
+#define CLOCK_IN_OMAP1510 (1 << 12)
+#define CLOCK_IN_OMAP16XX (1 << 13)
uint32_t flags;
int id;
- int running; /* Is currently ticking */
- int enabled; /* Is enabled, regardless of its input clk */
- unsigned long rate; /* Current rate (if .running) */
- unsigned int divisor; /* Rate relative to input (if .enabled) */
- unsigned int multiplier; /* Rate relative to input (if .enabled) */
- qemu_irq users[16]; /* Who to notify on change */
- int usecount; /* Automatically idle when unused */
+ int running; /* Is currently ticking */
+ int enabled; /* Is enabled, regardless of its input clk */
+ unsigned long rate; /* Current rate (if .running) */
+ unsigned int divisor; /* Rate relative to input (if .enabled) */
+ unsigned int multiplier; /* Rate relative to input (if .enabled) */
+ qemu_irq users[16]; /* Who to notify on change */
+ int usecount; /* Automatically idle when unused */
};
static struct clk xtal_osc12m = {
- .name = "xtal_osc_12m",
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "xtal_osc_12m",
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk xtal_osc32k = {
- .name = "xtal_osc_32k",
- .rate = 32768,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .name = "xtal_osc_32k",
+ .rate = 32768,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk ck_ref = {
- .name = "ck_ref",
- .alias = "clkin",
- .parent = &xtal_osc12m,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "ck_ref",
+ .alias = "clkin",
+ .parent = &xtal_osc12m,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
/* If a dpll is disabled it becomes a bypass, child clocks don't stop */
static struct clk dpll1 = {
- .name = "dpll1",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "dpll1",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk dpll2 = {
- .name = "dpll2",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+ .name = "dpll2",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
};
static struct clk dpll3 = {
- .name = "dpll3",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+ .name = "dpll3",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
};
static struct clk dpll4 = {
- .name = "dpll4",
- .parent = &ck_ref,
- .multiplier = 4,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "dpll4",
+ .parent = &ck_ref,
+ .multiplier = 4,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk apll = {
- .name = "apll",
- .parent = &ck_ref,
- .multiplier = 48,
- .divisor = 12,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "apll",
+ .parent = &ck_ref,
+ .multiplier = 48,
+ .divisor = 12,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk ck_48m = {
- .name = "ck_48m",
- .parent = &dpll4, /* either dpll4 or apll */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "ck_48m",
+ .parent = &dpll4, /* either dpll4 or apll */
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk ck_dpll1out = {
- .name = "ck_dpll1out",
- .parent = &dpll1,
- .flags = CLOCK_IN_OMAP16XX,
+ .name = "ck_dpll1out",
+ .parent = &dpll1,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk sossi_ck = {
- .name = "ck_sossi",
- .parent = &ck_dpll1out,
- .flags = CLOCK_IN_OMAP16XX,
+ .name = "ck_sossi",
+ .parent = &ck_dpll1out,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk clkm1 = {
- .name = "clkm1",
- .alias = "ck_gen1",
- .parent = &dpll1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "clkm1",
+ .alias = "ck_gen1",
+ .parent = &dpll1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk clkm2 = {
- .name = "clkm2",
- .alias = "ck_gen2",
- .parent = &dpll1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "clkm2",
+ .alias = "ck_gen2",
+ .parent = &dpll1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk clkm3 = {
- .name = "clkm3",
- .alias = "ck_gen3",
- .parent = &dpll1, /* either dpll1 or ck_ref */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "clkm3",
+ .alias = "ck_gen3",
+ .parent = &dpll1, /* either dpll1 or ck_ref */
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk arm_ck = {
- .name = "arm_ck",
- .alias = "mpu_ck",
- .parent = &clkm1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "arm_ck",
+ .alias = "mpu_ck",
+ .parent = &clkm1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk armper_ck = {
- .name = "armper_ck",
- .alias = "mpuper_ck",
- .parent = &clkm1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "armper_ck",
+ .alias = "mpuper_ck",
+ .parent = &clkm1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk arm_gpio_ck = {
- .name = "arm_gpio_ck",
- .alias = "mpu_gpio_ck",
- .parent = &clkm1,
- .divisor = 1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+ .name = "arm_gpio_ck",
+ .alias = "mpu_gpio_ck",
+ .parent = &clkm1,
+ .divisor = 1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
};
static struct clk armxor_ck = {
- .name = "armxor_ck",
- .alias = "mpuxor_ck",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "armxor_ck",
+ .alias = "mpuxor_ck",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk armtim_ck = {
- .name = "armtim_ck",
- .alias = "mputim_ck",
- .parent = &ck_ref, /* either CLKIN or DPLL1 */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "armtim_ck",
+ .alias = "mputim_ck",
+ .parent = &ck_ref, /* either CLKIN or DPLL1 */
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk armwdt_ck = {
- .name = "armwdt_ck",
- .alias = "mpuwd_ck",
- .parent = &clkm1,
- .divisor = 14,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "armwdt_ck",
+ .alias = "mpuwd_ck",
+ .parent = &clkm1,
+ .divisor = 14,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk arminth_ck16xx = {
- .name = "arminth_ck",
- .parent = &arm_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+ .name = "arminth_ck",
+ .parent = &arm_ck,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
/* Note: On 16xx the frequency can be divided by 2 by programming
* ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
*
@@ -206,48 +202,48 @@ static struct clk arminth_ck16xx = {
};
static struct clk dsp_ck = {
- .name = "dsp_ck",
- .parent = &clkm2,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .name = "dsp_ck",
+ .parent = &clkm2,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
};
static struct clk dspmmu_ck = {
- .name = "dspmmu_ck",
- .parent = &clkm2,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ .name = "dspmmu_ck",
+ .parent = &clkm2,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
ALWAYS_ENABLED,
};
static struct clk dspper_ck = {
- .name = "dspper_ck",
- .parent = &clkm2,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .name = "dspper_ck",
+ .parent = &clkm2,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
};
static struct clk dspxor_ck = {
- .name = "dspxor_ck",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .name = "dspxor_ck",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
};
static struct clk dsptim_ck = {
- .name = "dsptim_ck",
- .parent = &ck_ref,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .name = "dsptim_ck",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
};
static struct clk tc_ck = {
- .name = "tc_ck",
- .parent = &clkm3,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ .name = "tc_ck",
+ .parent = &clkm3,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk arminth_ck15xx = {
- .name = "arminth_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+ .name = "arminth_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
/* Note: On 1510 the frequency follows TC_CK
*
* 16xx version is in MPU clocks.
@@ -256,698 +252,259 @@ static struct clk arminth_ck15xx = {
static struct clk tipb_ck = {
/* No-idle controlled by "tc_ck" */
- .name = "tipb_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+ .name = "tipb_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
};
static struct clk l3_ocpi_ck = {
/* No-idle controlled by "tc_ck" */
- .name = "l3_ocpi_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .name = "l3_ocpi_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk tc1_ck = {
- .name = "tc1_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .name = "tc1_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk tc2_ck = {
- .name = "tc2_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .name = "tc2_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk dma_ck = {
/* No-idle controlled by "tc_ck" */
- .name = "dma_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .name = "dma_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk dma_lcdfree_ck = {
- .name = "dma_lcdfree_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+ .name = "dma_lcdfree_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
};
static struct clk api_ck = {
- .name = "api_ck",
- .alias = "mpui_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .name = "api_ck",
+ .alias = "mpui_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk lb_ck = {
- .name = "lb_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+ .name = "lb_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
};
static struct clk lbfree_ck = {
- .name = "lbfree_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+ .name = "lbfree_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
};
static struct clk hsab_ck = {
- .name = "hsab_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+ .name = "hsab_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
};
static struct clk rhea1_ck = {
- .name = "rhea1_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+ .name = "rhea1_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
};
static struct clk rhea2_ck = {
- .name = "rhea2_ck",
- .parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+ .name = "rhea2_ck",
+ .parent = &tc_ck,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
};
static struct clk lcd_ck_16xx = {
- .name = "lcd_ck",
- .parent = &clkm3,
- .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730,
+ .name = "lcd_ck",
+ .parent = &clkm3,
+ .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730,
};
static struct clk lcd_ck_1510 = {
- .name = "lcd_ck",
- .parent = &clkm3,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+ .name = "lcd_ck",
+ .parent = &clkm3,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
};
static struct clk uart1_1510 = {
- .name = "uart1_ck",
+ .name = "uart1_ck",
/* Direct from ULPD, no real parent */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+ .parent = &armper_ck, /* either armper_ck or dpll4 */
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
};
static struct clk uart1_16xx = {
- .name = "uart1_ck",
+ .name = "uart1_ck",
/* Direct from ULPD, no real parent */
- .parent = &armper_ck,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX,
+ .parent = &armper_ck,
+ .rate = 48000000,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk uart2_ck = {
- .name = "uart2_ck",
+ .name = "uart2_ck",
/* Direct from ULPD, no real parent */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+ .parent = &armper_ck, /* either armper_ck or dpll4 */
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
ALWAYS_ENABLED,
};
static struct clk uart3_1510 = {
- .name = "uart3_ck",
+ .name = "uart3_ck",
/* Direct from ULPD, no real parent */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+ .parent = &armper_ck, /* either armper_ck or dpll4 */
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
};
static struct clk uart3_16xx = {
- .name = "uart3_ck",
+ .name = "uart3_ck",
/* Direct from ULPD, no real parent */
- .parent = &armper_ck,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX,
+ .parent = &armper_ck,
+ .rate = 48000000,
+ .flags = CLOCK_IN_OMAP16XX,
};
-static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */
- .name = "usb_clk0",
- .alias = "usb.clko",
+static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */
+ .name = "usb_clk0",
+ .alias = "usb.clko",
/* Direct from ULPD, no parent */
- .rate = 6000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .rate = 6000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk usb_hhc_ck1510 = {
- .name = "usb_hhc_ck",
+ .name = "usb_hhc_ck",
/* Direct from ULPD, no parent */
- .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+ .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
};
static struct clk usb_hhc_ck16xx = {
- .name = "usb_hhc_ck",
+ .name = "usb_hhc_ck",
/* Direct from ULPD, no parent */
- .rate = 48000000,
+ .rate = 48000000,
/* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk usb_w2fc_mclk = {
- .name = "usb_w2fc_mclk",
- .alias = "usb_w2fc_ck",
- .parent = &ck_48m,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .name = "usb_w2fc_mclk",
+ .alias = "usb_w2fc_ck",
+ .parent = &ck_48m,
+ .rate = 48000000,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
};
static struct clk mclk_1510 = {
- .name = "mclk",
+ .name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510,
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510,
};
static struct clk bclk_310 = {
- .name = "bt_mclk_out", /* Alias midi_mclk_out? */
- .parent = &armper_ck,
- .flags = CLOCK_IN_OMAP310,
+ .name = "bt_mclk_out", /* Alias midi_mclk_out? */
+ .parent = &armper_ck,
+ .flags = CLOCK_IN_OMAP310,
};
static struct clk mclk_310 = {
- .name = "com_mclk_out",
- .parent = &armper_ck,
- .flags = CLOCK_IN_OMAP310,
+ .name = "com_mclk_out",
+ .parent = &armper_ck,
+ .flags = CLOCK_IN_OMAP310,
};
static struct clk mclk_16xx = {
- .name = "mclk",
+ .name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk bclk_1510 = {
- .name = "bclk",
+ .name = "bclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .rate = 12000000,
- .flags = CLOCK_IN_OMAP1510,
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510,
};
static struct clk bclk_16xx = {
- .name = "bclk",
+ .name = "bclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk mmc1_ck = {
- .name = "mmc_ck",
- .id = 1,
+ .name = "mmc_ck",
+ .id = 1,
/* Functional clock is direct from ULPD, interface clock is ARMPER */
- .parent = &armper_ck, /* either armper_ck or dpll4 */
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+ .parent = &armper_ck, /* either armper_ck or dpll4 */
+ .rate = 48000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk mmc2_ck = {
- .name = "mmc_ck",
- .id = 2,
+ .name = "mmc_ck",
+ .id = 2,
/* Functional clock is direct from ULPD, interface clock is ARMPER */
- .parent = &armper_ck,
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP16XX,
+ .parent = &armper_ck,
+ .rate = 48000000,
+ .flags = CLOCK_IN_OMAP16XX,
};
static struct clk cam_mclk = {
- .name = "cam.mclk",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
- .rate = 12000000,
+ .name = "cam.mclk",
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .rate = 12000000,
};
static struct clk cam_exclk = {
- .name = "cam.exclk",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .name = "cam.exclk",
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
/* Either 12M from cam.mclk or 48M from dpll4 */
- .parent = &cam_mclk,
+ .parent = &cam_mclk,
};
static struct clk cam_lclk = {
- .name = "cam.lclk",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .name = "cam.lclk",
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
};
static struct clk i2c_fck = {
- .name = "i2c_fck",
- .id = 1,
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ .name = "i2c_fck",
+ .id = 1,
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
ALWAYS_ENABLED,
- .parent = &armxor_ck,
+ .parent = &armxor_ck,
};
static struct clk i2c_ick = {
- .name = "i2c_ick",
- .id = 1,
- .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
- .parent = &armper_ck,
+ .name = "i2c_ick",
+ .id = 1,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+ .parent = &armper_ck,
};
static struct clk clk32k = {
- .name = "clk32-kHz",
- .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &xtal_osc32k,
-};
-
-static struct clk ref_clk = {
- .name = "ref_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */
- /*.parent = sys.xtalin */
-};
-
-static struct clk apll_96m = {
- .name = "apll_96m",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 96000000,
- /*.parent = ref_clk */
-};
-
-static struct clk apll_54m = {
- .name = "apll_54m",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 54000000,
- /*.parent = ref_clk */
-};
-
-static struct clk sys_clk = {
- .name = "sys_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk sleep_clk = {
- .name = "sleep_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk dpll_ck = {
- .name = "dpll",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &ref_clk,
-};
-
-static struct clk dpll_x2_ck = {
- .name = "dpll_x2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &ref_clk,
-};
-
-static struct clk wdt1_sys_clk = {
- .name = "wdt1_sys_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk func_96m_clk = {
- .name = "func_96m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 1,
- .parent = &apll_96m,
-};
-
-static struct clk func_48m_clk = {
- .name = "func_48m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &apll_96m,
-};
-
-static struct clk func_12m_clk = {
- .name = "func_12m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 8,
- .parent = &apll_96m,
-};
-
-static struct clk func_54m_clk = {
- .name = "func_54m_clk",
- .flags = CLOCK_IN_OMAP242X,
- .divisor = 1,
- .parent = &apll_54m,
-};
-
-static struct clk sys_clkout = {
- .name = "clkout",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk sys_clkout2 = {
- .name = "clkout2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_clk = {
- .name = "core_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */
-};
-
-static struct clk l3_clk = {
- .name = "l3_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_l4_iclk = {
- .name = "core_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk wu_l4_iclk = {
- .name = "wu_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk core_l3_iclk = {
- .name = "core_l3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_l4_usb_clk = {
- .name = "core_l4_usb_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk wu_gpt1_clk = {
- .name = "wu_gpt1_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk wu_32k_clk = {
- .name = "wu_32k_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk uart1_fclk = {
- .name = "uart1_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart1_iclk = {
- .name = "uart1_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk uart2_fclk = {
- .name = "uart2_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart2_iclk = {
- .name = "uart2_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk uart3_fclk = {
- .name = "uart3_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart3_iclk = {
- .name = "uart3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk mpu_fclk = {
- .name = "mpu_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk mpu_iclk = {
- .name = "mpu_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk int_m_fclk = {
- .name = "int_m_fclk",
- .alias = "mpu_intc_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk int_m_iclk = {
- .name = "int_m_iclk",
- .alias = "mpu_intc_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_gpt2_clk = {
- .name = "core_gpt2_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt3_clk = {
- .name = "core_gpt3_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt4_clk = {
- .name = "core_gpt4_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt5_clk = {
- .name = "core_gpt5_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt6_clk = {
- .name = "core_gpt6_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt7_clk = {
- .name = "core_gpt7_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt8_clk = {
- .name = "core_gpt8_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt9_clk = {
- .name = "core_gpt9_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt10_clk = {
- .name = "core_gpt10_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt11_clk = {
- .name = "core_gpt11_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt12_clk = {
- .name = "core_gpt12_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk mcbsp1_clk = {
- .name = "mcbsp1_cg",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &func_96m_clk,
-};
-
-static struct clk mcbsp2_clk = {
- .name = "mcbsp2_cg",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &func_96m_clk,
-};
-
-static struct clk emul_clk = {
- .name = "emul_ck",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_54m_clk,
-};
-
-static struct clk sdma_fclk = {
- .name = "sdma_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk sdma_iclk = {
- .name = "sdma_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */
-};
-
-static struct clk i2c1_fclk = {
- .name = "i2c1.fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_12m_clk,
- .divisor = 1,
-};
-
-static struct clk i2c1_iclk = {
- .name = "i2c1.iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk i2c2_fclk = {
- .name = "i2c2.fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_12m_clk,
- .divisor = 1,
-};
-
-static struct clk i2c2_iclk = {
- .name = "i2c2.iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk gpio_dbclk[5] = {
- {
- .name = "gpio1_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio2_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio3_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio4_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio5_dbclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- },
-};
-
-static struct clk gpio_iclk = {
- .name = "gpio_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_l4_iclk,
-};
-
-static struct clk mmc_fck = {
- .name = "mmc_fclk",
- .flags = CLOCK_IN_OMAP242X,
- .parent = &func_96m_clk,
-};
-
-static struct clk mmc_ick = {
- .name = "mmc_iclk",
- .flags = CLOCK_IN_OMAP242X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk spi_fclk[3] = {
- {
- .name = "spi1_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- }, {
- .name = "spi2_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- }, {
- .name = "spi3_fclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- },
-};
-
-static struct clk dss_clk[2] = {
- {
- .name = "dss_clk1",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
- }, {
- .name = "dss_clk2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
- },
-};
-
-static struct clk dss_54m_clk = {
- .name = "dss_54m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_54m_clk,
-};
-
-static struct clk dss_l3_iclk = {
- .name = "dss_l3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l3_iclk,
-};
-
-static struct clk dss_l4_iclk = {
- .name = "dss_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk spi_iclk[3] = {
- {
- .name = "spi1_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- }, {
- .name = "spi2_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- }, {
- .name = "spi3_iclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- },
-};
-
-static struct clk omapctrl_clk = {
- .name = "omapctrl_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- /* XXX Should be in WKUP domain */
- .parent = &core_l4_iclk,
+ .name = "clk32-kHz",
+ .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ ALWAYS_ENABLED,
+ .parent = &xtal_osc32k,
};
static struct clk *onchip_clks[] = {
@@ -1019,80 +576,6 @@ static struct clk *onchip_clks[] = {
&i2c_fck,
&i2c_ick,
- /* OMAP 2 */
-
- &ref_clk,
- &apll_96m,
- &apll_54m,
- &sys_clk,
- &sleep_clk,
- &dpll_ck,
- &dpll_x2_ck,
- &wdt1_sys_clk,
- &func_96m_clk,
- &func_48m_clk,
- &func_12m_clk,
- &func_54m_clk,
- &sys_clkout,
- &sys_clkout2,
- &core_clk,
- &l3_clk,
- &core_l4_iclk,
- &wu_l4_iclk,
- &core_l3_iclk,
- &core_l4_usb_clk,
- &wu_gpt1_clk,
- &wu_32k_clk,
- &uart1_fclk,
- &uart1_iclk,
- &uart2_fclk,
- &uart2_iclk,
- &uart3_fclk,
- &uart3_iclk,
- &mpu_fclk,
- &mpu_iclk,
- &int_m_fclk,
- &int_m_iclk,
- &core_gpt2_clk,
- &core_gpt3_clk,
- &core_gpt4_clk,
- &core_gpt5_clk,
- &core_gpt6_clk,
- &core_gpt7_clk,
- &core_gpt8_clk,
- &core_gpt9_clk,
- &core_gpt10_clk,
- &core_gpt11_clk,
- &core_gpt12_clk,
- &mcbsp1_clk,
- &mcbsp2_clk,
- &emul_clk,
- &sdma_fclk,
- &sdma_iclk,
- &i2c1_fclk,
- &i2c1_iclk,
- &i2c2_fclk,
- &i2c2_iclk,
- &gpio_dbclk[0],
- &gpio_dbclk[1],
- &gpio_dbclk[2],
- &gpio_dbclk[3],
- &gpio_iclk,
- &mmc_fck,
- &mmc_ick,
- &spi_fclk[0],
- &spi_iclk[0],
- &spi_fclk[1],
- &spi_iclk[1],
- &spi_fclk[2],
- &spi_iclk[2],
- &dss_clk[0],
- &dss_clk[1],
- &dss_54m_clk,
- &dss_l3_iclk,
- &dss_l4_iclk,
- &omapctrl_clk,
-
NULL
};
@@ -1230,12 +713,6 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
flag = CLOCK_IN_OMAP310;
else if (cpu_is_omap1510(mpu))
flag = CLOCK_IN_OMAP1510;
- else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
- flag = CLOCK_IN_OMAP242X;
- else if (cpu_is_omap2430(mpu))
- flag = CLOCK_IN_OMAP243X;
- else if (cpu_is_omap3430(mpu))
- flag = CLOCK_IN_OMAP243X;
else
return;
diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c
deleted file mode 100644
index 67158eb..0000000
--- a/hw/misc/omap_gpmc.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * TI OMAP general purpose memory controller emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Original code written by Andrzej Zaborowski <andrew@openedhand.com>
- * Enhancements for OMAP3 and NAND support written by Juha Riihimäki
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/block/flash.h"
-#include "hw/arm/omap.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-
-/* General-Purpose Memory Controller */
-struct omap_gpmc_s {
- qemu_irq irq;
- qemu_irq drq;
- MemoryRegion iomem;
- int accept_256;
-
- uint8_t revision;
- uint8_t sysconfig;
- uint16_t irqst;
- uint16_t irqen;
- uint16_t lastirq;
- uint16_t timeout;
- uint16_t config;
- struct omap_gpmc_cs_file_s {
- uint32_t config[7];
- MemoryRegion *iomem;
- MemoryRegion container;
- MemoryRegion nandiomem;
- DeviceState *dev;
- } cs_file[8];
- int ecc_cs;
- int ecc_ptr;
- uint32_t ecc_cfg;
- ECCState ecc[9];
- struct prefetch {
- uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
- uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
- int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
- int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
- int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
- MemoryRegion iomem;
- uint8_t fifo[64];
- } prefetch;
-};
-
-#define OMAP_GPMC_8BIT 0
-#define OMAP_GPMC_16BIT 1
-#define OMAP_GPMC_NOR 0
-#define OMAP_GPMC_NAND 2
-
-static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
-{
- return (f->config[0] >> 10) & 3;
-}
-
-static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
-{
- /* devsize field is really 2 bits but we ignore the high
- * bit to ensure consistent behaviour if the guest sets
- * it (values 2 and 3 are reserved in the TRM)
- */
- return (f->config[0] >> 12) & 1;
-}
-
-/* Extract the chip-select value from the prefetch config1 register */
-static int prefetch_cs(uint32_t config1)
-{
- return (config1 >> 24) & 7;
-}
-
-static int prefetch_threshold(uint32_t config1)
-{
- return (config1 >> 8) & 0x7f;
-}
-
-static void omap_gpmc_int_update(struct omap_gpmc_s *s)
-{
- /* The TRM is a bit unclear, but it seems to say that
- * the TERMINALCOUNTSTATUS bit is set only on the
- * transition when the prefetch engine goes from
- * active to inactive, whereas the FIFOEVENTSTATUS
- * bit is held high as long as the fifo has at
- * least THRESHOLD bytes available.
- * So we do the latter here, but TERMINALCOUNTSTATUS
- * is set elsewhere.
- */
- if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
- s->irqst |= 1;
- }
- if ((s->irqen & s->irqst) != s->lastirq) {
- s->lastirq = s->irqen & s->irqst;
- qemu_set_irq(s->irq, s->lastirq);
- }
-}
-
-static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
-{
- if (s->prefetch.config1 & 4) {
- qemu_set_irq(s->drq, value);
- }
-}
-
-/* Access functions for when a NAND-like device is mapped into memory:
- * all addresses in the region behave like accesses to the relevant
- * GPMC_NAND_DATA_i register (which is actually implemented to call these)
- */
-static uint64_t omap_nand_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_cs_file_s *f = opaque;
- uint64_t v;
- nand_setpins(f->dev, 0, 0, 0, 1, 0);
- switch (omap_gpmc_devsize(f)) {
- case OMAP_GPMC_8BIT:
- v = nand_getio(f->dev);
- if (size == 1) {
- return v;
- }
- v |= (nand_getio(f->dev) << 8);
- if (size == 2) {
- return v;
- }
- v |= (nand_getio(f->dev) << 16);
- v |= (nand_getio(f->dev) << 24);
- return v;
- case OMAP_GPMC_16BIT:
- v = nand_getio(f->dev);
- if (size == 1) {
- /* 8 bit read from 16 bit device : probably a guest bug */
- return v & 0xff;
- }
- if (size == 2) {
- return v;
- }
- v |= (nand_getio(f->dev) << 16);
- return v;
- default:
- abort();
- }
-}
-
-static void omap_nand_setio(DeviceState *dev, uint64_t value,
- int nandsize, int size)
-{
- /* Write the specified value to the NAND device, respecting
- * both size of the NAND device and size of the write access.
- */
- switch (nandsize) {
- case OMAP_GPMC_8BIT:
- switch (size) {
- case 1:
- nand_setio(dev, value & 0xff);
- break;
- case 2:
- nand_setio(dev, value & 0xff);
- nand_setio(dev, (value >> 8) & 0xff);
- break;
- case 4:
- default:
- nand_setio(dev, value & 0xff);
- nand_setio(dev, (value >> 8) & 0xff);
- nand_setio(dev, (value >> 16) & 0xff);
- nand_setio(dev, (value >> 24) & 0xff);
- break;
- }
- break;
- case OMAP_GPMC_16BIT:
- switch (size) {
- case 1:
- /* writing to a 16bit device with 8bit access is probably a guest
- * bug; pass the value through anyway.
- */
- case 2:
- nand_setio(dev, value & 0xffff);
- break;
- case 4:
- default:
- nand_setio(dev, value & 0xffff);
- nand_setio(dev, (value >> 16) & 0xffff);
- break;
- }
- break;
- }
-}
-
-static void omap_nand_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_cs_file_s *f = opaque;
- nand_setpins(f->dev, 0, 0, 0, 1, 0);
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
-}
-
-static const MemoryRegionOps omap_nand_ops = {
- .read = omap_nand_read,
- .write = omap_nand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void fill_prefetch_fifo(struct omap_gpmc_s *s)
-{
- /* Fill the prefetch FIFO by reading data from NAND.
- * We do this synchronously, unlike the hardware which
- * will do this asynchronously. We refill when the
- * FIFO has THRESHOLD bytes free, and we always refill
- * as much data as possible starting at the top end
- * of the FIFO.
- * (We have to refill at THRESHOLD rather than waiting
- * for the FIFO to empty to allow for the case where
- * the FIFO size isn't an exact multiple of THRESHOLD
- * and we're doing DMA transfers.)
- * This means we never need to handle wrap-around in
- * the fifo-reading code, and the next byte of data
- * to read is always fifo[63 - fifopointer].
- */
- int fptr;
- int cs = prefetch_cs(s->prefetch.config1);
- int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
- int bytes;
- /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
- * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
- * Instead believe the bit that says it is always a byte count.
- */
- bytes = 64 - s->prefetch.fifopointer;
- if (bytes > s->prefetch.count) {
- bytes = s->prefetch.count;
- }
- if (is16bit) {
- bytes &= ~1;
- }
-
- s->prefetch.count -= bytes;
- s->prefetch.fifopointer += bytes;
- fptr = 64 - s->prefetch.fifopointer;
- /* Move the existing data in the FIFO so it sits just
- * before what we're about to read in
- */
- while (fptr < (64 - bytes)) {
- s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
- fptr++;
- }
- while (fptr < 64) {
- if (is16bit) {
- uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
- s->prefetch.fifo[fptr++] = v & 0xff;
- s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
- } else {
- s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
- }
- }
- if (s->prefetch.startengine && (s->prefetch.count == 0)) {
- /* This was the final transfer: raise TERMINALCOUNTSTATUS */
- s->irqst |= 2;
- s->prefetch.startengine = 0;
- }
- /* If there are any bytes in the FIFO at this point then
- * we must raise a DMA request (either this is a final part
- * transfer, or we filled the FIFO in which case we certainly
- * have THRESHOLD bytes available)
- */
- if (s->prefetch.fifopointer != 0) {
- omap_gpmc_dma_update(s, 1);
- }
- omap_gpmc_int_update(s);
-}
-
-/* Access functions for a NAND-like device when the prefetch/postwrite
- * engine is enabled -- all addresses in the region behave alike:
- * data is read or written to the FIFO.
- */
-static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- uint32_t data;
- if (s->prefetch.config1 & 1) {
- /* The TRM doesn't define the behaviour if you read from the
- * FIFO when the prefetch engine is in write mode. We choose
- * to always return zero.
- */
- return 0;
- }
- /* Note that trying to read an empty fifo repeats the last byte */
- if (s->prefetch.fifopointer) {
- s->prefetch.fifopointer--;
- }
- data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
- if (s->prefetch.fifopointer ==
- (64 - prefetch_threshold(s->prefetch.config1))) {
- /* We've drained THRESHOLD bytes now. So deassert the
- * DMA request, then refill the FIFO (which will probably
- * assert it again.)
- */
- omap_gpmc_dma_update(s, 0);
- fill_prefetch_fifo(s);
- }
- omap_gpmc_int_update(s);
- return data;
-}
-
-static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- int cs = prefetch_cs(s->prefetch.config1);
- if ((s->prefetch.config1 & 1) == 0) {
- /* The TRM doesn't define the behaviour of writing to the
- * FIFO when the prefetch engine is in read mode. We
- * choose to ignore the write.
- */
- return;
- }
- if (s->prefetch.count == 0) {
- /* The TRM doesn't define the behaviour of writing to the
- * FIFO if the transfer is complete. We choose to ignore.
- */
- return;
- }
- /* The only reason we do any data buffering in postwrite
- * mode is if we are talking to a 16 bit NAND device, in
- * which case we need to buffer the first byte of the
- * 16 bit word until the other byte arrives.
- */
- int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
- if (is16bit) {
- /* fifopointer alternates between 64 (waiting for first
- * byte of word) and 63 (waiting for second byte)
- */
- if (s->prefetch.fifopointer == 64) {
- s->prefetch.fifo[0] = value;
- s->prefetch.fifopointer--;
- } else {
- value = (value << 8) | s->prefetch.fifo[0];
- omap_nand_write(&s->cs_file[cs], 0, value, 2);
- s->prefetch.count--;
- s->prefetch.fifopointer = 64;
- }
- } else {
- /* Just write the byte : fifopointer remains 64 at all times */
- omap_nand_write(&s->cs_file[cs], 0, value, 1);
- s->prefetch.count--;
- }
- if (s->prefetch.count == 0) {
- /* Final transfer: raise TERMINALCOUNTSTATUS */
- s->irqst |= 2;
- s->prefetch.startengine = 0;
- }
- omap_gpmc_int_update(s);
-}
-
-static const MemoryRegionOps omap_prefetch_ops = {
- .read = omap_gpmc_prefetch_read,
- .write = omap_gpmc_prefetch_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
-};
-
-static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
-{
- /* Return the MemoryRegion* to map/unmap for this chipselect */
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
- return f->iomem;
- }
- if ((s->prefetch.config1 & 0x80) &&
- (prefetch_cs(s->prefetch.config1) == cs)) {
- /* The prefetch engine is enabled for this CS: map the FIFO */
- return &s->prefetch.iomem;
- }
- return &f->nandiomem;
-}
-
-static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
-{
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- uint32_t mask = (f->config[6] >> 8) & 0xf;
- uint32_t base = f->config[6] & 0x3f;
- uint32_t size;
-
- if (!f->iomem && !f->dev) {
- return;
- }
-
- if (!(f->config[6] & (1 << 6))) {
- /* Do nothing unless CSVALID */
- return;
- }
-
- /* TODO: check for overlapping regions and report access errors */
- if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
- && !(s->accept_256 && !mask)) {
- fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
- __func__, mask);
- }
-
- base <<= 24;
- size = (0x0fffffff & ~(mask << 24)) + 1;
- /* TODO: rather than setting the size of the mapping (which should be
- * constant), the mask should cause wrapping of the address space, so
- * that the same memory becomes accessible at every <i>size</i> bytes
- * starting from <i>base</i>. */
- memory_region_init(&f->container, NULL, "omap-gpmc-file", size);
- memory_region_add_subregion(&f->container, 0,
- omap_gpmc_cs_memregion(s, cs));
- memory_region_add_subregion(get_system_memory(), base,
- &f->container);
-}
-
-static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
-{
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- if (!(f->config[6] & (1 << 6))) {
- /* Do nothing unless CSVALID */
- return;
- }
- if (!f->iomem && !f->dev) {
- return;
- }
- memory_region_del_subregion(get_system_memory(), &f->container);
- memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
- object_unparent(OBJECT(&f->container));
-}
-
-void omap_gpmc_reset(struct omap_gpmc_s *s)
-{
- int i;
-
- s->sysconfig = 0;
- s->irqst = 0;
- s->irqen = 0;
- omap_gpmc_int_update(s);
- for (i = 0; i < 8; i++) {
- /* This has to happen before we change any of the config
- * used to determine which memory regions are mapped or unmapped.
- */
- omap_gpmc_cs_unmap(s, i);
- }
- s->timeout = 0;
- s->config = 0xa00;
- s->prefetch.config1 = 0x00004000;
- s->prefetch.transfercount = 0x00000000;
- s->prefetch.startengine = 0;
- s->prefetch.fifopointer = 0;
- s->prefetch.count = 0;
- for (i = 0; i < 8; i ++) {
- s->cs_file[i].config[1] = 0x101001;
- s->cs_file[i].config[2] = 0x020201;
- s->cs_file[i].config[3] = 0x10031003;
- s->cs_file[i].config[4] = 0x10f1111;
- s->cs_file[i].config[5] = 0;
- s->cs_file[i].config[6] = 0xf00;
- /* In theory we could probe attached devices for some CFG1
- * bits here, but we just retain them across resets as they
- * were set initially by omap_gpmc_attach().
- */
- if (i == 0) {
- s->cs_file[i].config[0] &= 0x00433e00;
- s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
- omap_gpmc_cs_map(s, i);
- } else {
- s->cs_file[i].config[0] &= 0x00403c00;
- }
- }
- s->ecc_cs = 0;
- s->ecc_ptr = 0;
- s->ecc_cfg = 0x3fcff000;
- for (i = 0; i < 9; i ++)
- ecc_reset(&s->ecc[i]);
-}
-
-static int gpmc_wordaccess_only(hwaddr addr)
-{
- /* Return true if the register offset is to a register that
- * only permits word width accesses.
- * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
- * for any chipselect.
- */
- if (addr >= 0x60 && addr <= 0x1d4) {
- int cs = (addr - 0x60) / 0x30;
- addr -= cs * 0x30;
- if (addr >= 0x7c && addr < 0x88) {
- /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
- return 0;
- }
- }
- return 1;
-}
-
-static uint64_t omap_gpmc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- int cs;
- struct omap_gpmc_cs_file_s *f;
-
- if (size != 4 && gpmc_wordaccess_only(addr)) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* GPMC_REVISION */
- return s->revision;
-
- case 0x010: /* GPMC_SYSCONFIG */
- return s->sysconfig;
-
- case 0x014: /* GPMC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x018: /* GPMC_IRQSTATUS */
- return s->irqst;
-
- case 0x01c: /* GPMC_IRQENABLE */
- return s->irqen;
-
- case 0x040: /* GPMC_TIMEOUT_CONTROL */
- return s->timeout;
-
- case 0x044: /* GPMC_ERR_ADDRESS */
- case 0x048: /* GPMC_ERR_TYPE */
- return 0;
-
- case 0x050: /* GPMC_CONFIG */
- return s->config;
-
- case 0x054: /* GPMC_STATUS */
- return 0x001;
-
- case 0x060 ... 0x1d4:
- cs = (addr - 0x060) / 0x30;
- addr -= cs * 0x30;
- f = s->cs_file + cs;
- switch (addr) {
- case 0x60: /* GPMC_CONFIG1 */
- return f->config[0];
- case 0x64: /* GPMC_CONFIG2 */
- return f->config[1];
- case 0x68: /* GPMC_CONFIG3 */
- return f->config[2];
- case 0x6c: /* GPMC_CONFIG4 */
- return f->config[3];
- case 0x70: /* GPMC_CONFIG5 */
- return f->config[4];
- case 0x74: /* GPMC_CONFIG6 */
- return f->config[5];
- case 0x78: /* GPMC_CONFIG7 */
- return f->config[6];
- case 0x84 ... 0x87: /* GPMC_NAND_DATA */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- return omap_nand_read(f, 0, size);
- }
- return 0;
- }
- break;
-
- case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
- return s->prefetch.config1;
- case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
- return s->prefetch.transfercount;
- case 0x1ec: /* GPMC_PREFETCH_CONTROL */
- return s->prefetch.startengine;
- case 0x1f0: /* GPMC_PREFETCH_STATUS */
- /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
- * FIFOTHRESHOLDSTATUS bit should be set when
- * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
- * Apparently the underlying functional spec from which the TRM was
- * created states that the behaviour is ">=", and this also
- * makes more conceptual sense.
- */
- return (s->prefetch.fifopointer << 24) |
- ((s->prefetch.fifopointer >=
- ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
- s->prefetch.count;
-
- case 0x1f4: /* GPMC_ECC_CONFIG */
- return s->ecc_cs;
- case 0x1f8: /* GPMC_ECC_CONTROL */
- return s->ecc_ptr;
- case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
- return s->ecc_cfg;
- case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
- cs = (addr & 0x1f) >> 2;
- /* TODO: check correctness */
- return
- ((s->ecc[cs].cp & 0x07) << 0) |
- ((s->ecc[cs].cp & 0x38) << 13) |
- ((s->ecc[cs].lp[0] & 0x1ff) << 3) |
- ((s->ecc[cs].lp[1] & 0x1ff) << 19);
-
- case 0x230: /* GPMC_TESTMODE_CTRL */
- return 0;
- case 0x234: /* GPMC_PSA_LSB */
- case 0x238: /* GPMC_PSA_MSB */
- return 0x00000000;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_gpmc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- int cs;
- struct omap_gpmc_cs_file_s *f;
-
- if (size != 4 && gpmc_wordaccess_only(addr)) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x000: /* GPMC_REVISION */
- case 0x014: /* GPMC_SYSSTATUS */
- case 0x054: /* GPMC_STATUS */
- case 0x1f0: /* GPMC_PREFETCH_STATUS */
- case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
- case 0x234: /* GPMC_PSA_LSB */
- case 0x238: /* GPMC_PSA_MSB */
- OMAP_RO_REG(addr);
- break;
-
- case 0x010: /* GPMC_SYSCONFIG */
- if ((value >> 3) == 0x3)
- fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
- __func__, value >> 3);
- if (value & 2)
- omap_gpmc_reset(s);
- s->sysconfig = value & 0x19;
- break;
-
- case 0x018: /* GPMC_IRQSTATUS */
- s->irqst &= ~value;
- omap_gpmc_int_update(s);
- break;
-
- case 0x01c: /* GPMC_IRQENABLE */
- s->irqen = value & 0xf03;
- omap_gpmc_int_update(s);
- break;
-
- case 0x040: /* GPMC_TIMEOUT_CONTROL */
- s->timeout = value & 0x1ff1;
- break;
-
- case 0x044: /* GPMC_ERR_ADDRESS */
- case 0x048: /* GPMC_ERR_TYPE */
- break;
-
- case 0x050: /* GPMC_CONFIG */
- s->config = value & 0xf13;
- break;
-
- case 0x060 ... 0x1d4:
- cs = (addr - 0x060) / 0x30;
- addr -= cs * 0x30;
- f = s->cs_file + cs;
- switch (addr) {
- case 0x60: /* GPMC_CONFIG1 */
- f->config[0] = value & 0xffef3e13;
- break;
- case 0x64: /* GPMC_CONFIG2 */
- f->config[1] = value & 0x001f1f8f;
- break;
- case 0x68: /* GPMC_CONFIG3 */
- f->config[2] = value & 0x001f1f8f;
- break;
- case 0x6c: /* GPMC_CONFIG4 */
- f->config[3] = value & 0x1f8f1f8f;
- break;
- case 0x70: /* GPMC_CONFIG5 */
- f->config[4] = value & 0x0f1f1f1f;
- break;
- case 0x74: /* GPMC_CONFIG6 */
- f->config[5] = value & 0x00000fcf;
- break;
- case 0x78: /* GPMC_CONFIG7 */
- if ((f->config[6] ^ value) & 0xf7f) {
- omap_gpmc_cs_unmap(s, cs);
- f->config[6] = value & 0x00000f7f;
- omap_gpmc_cs_map(s, cs);
- }
- break;
- case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
- }
- break;
- case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
- }
- break;
- case 0x84 ... 0x87: /* GPMC_NAND_DATA */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- omap_nand_write(f, 0, value, size);
- }
- break;
- default:
- goto bad_reg;
- }
- break;
-
- case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
- if (!s->prefetch.startengine) {
- uint32_t newconfig1 = value & 0x7f8f7fbf;
- uint32_t changed;
- changed = newconfig1 ^ s->prefetch.config1;
- if (changed & (0x80 | 0x7000000)) {
- /* Turning the engine on or off, or mapping it somewhere else.
- * cs_map() and cs_unmap() check the prefetch config and
- * overall CSVALID bits, so it is sufficient to unmap-and-map
- * both the old cs and the new one. Note that we adhere to
- * the "unmap/change config/map" order (and not unmap twice
- * if newcs == oldcs), otherwise we'll try to delete the wrong
- * memory region.
- */
- int oldcs = prefetch_cs(s->prefetch.config1);
- int newcs = prefetch_cs(newconfig1);
- omap_gpmc_cs_unmap(s, oldcs);
- if (oldcs != newcs) {
- omap_gpmc_cs_unmap(s, newcs);
- }
- s->prefetch.config1 = newconfig1;
- omap_gpmc_cs_map(s, oldcs);
- if (oldcs != newcs) {
- omap_gpmc_cs_map(s, newcs);
- }
- } else {
- s->prefetch.config1 = newconfig1;
- }
- }
- break;
-
- case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
- if (!s->prefetch.startengine) {
- s->prefetch.transfercount = value & 0x3fff;
- }
- break;
-
- case 0x1ec: /* GPMC_PREFETCH_CONTROL */
- if (s->prefetch.startengine != (value & 1)) {
- s->prefetch.startengine = value & 1;
- if (s->prefetch.startengine) {
- /* Prefetch engine start */
- s->prefetch.count = s->prefetch.transfercount;
- if (s->prefetch.config1 & 1) {
- /* Write */
- s->prefetch.fifopointer = 64;
- } else {
- /* Read */
- s->prefetch.fifopointer = 0;
- fill_prefetch_fifo(s);
- }
- } else {
- /* Prefetch engine forcibly stopped. The TRM
- * doesn't define the behaviour if you do this.
- * We clear the prefetch count, which means that
- * we permit no more writes, and don't read any
- * more data from NAND. The CPU can still drain
- * the FIFO of unread data.
- */
- s->prefetch.count = 0;
- }
- omap_gpmc_int_update(s);
- }
- break;
-
- case 0x1f4: /* GPMC_ECC_CONFIG */
- s->ecc_cs = 0x8f;
- break;
- case 0x1f8: /* GPMC_ECC_CONTROL */
- if (value & (1 << 8))
- for (cs = 0; cs < 9; cs ++)
- ecc_reset(&s->ecc[cs]);
- s->ecc_ptr = value & 0xf;
- if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
- s->ecc_ptr = 0;
- s->ecc_cs &= ~1;
- }
- break;
- case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
- s->ecc_cfg = value & 0x3fcff1ff;
- break;
- case 0x230: /* GPMC_TESTMODE_CTRL */
- if (value & 7)
- fprintf(stderr, "%s: test mode enable attempt\n", __func__);
- break;
-
- default:
- bad_reg:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_gpmc_ops = {
- .read = omap_gpmc_read,
- .write = omap_gpmc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
- hwaddr base,
- qemu_irq irq, qemu_irq drq)
-{
- int cs;
- struct omap_gpmc_s *s = g_new0(struct omap_gpmc_s, 1);
-
- memory_region_init_io(&s->iomem, NULL, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
- memory_region_add_subregion(get_system_memory(), base, &s->iomem);
-
- s->irq = irq;
- s->drq = drq;
- s->accept_256 = cpu_is_omap3630(mpu);
- s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
- s->lastirq = 0;
- omap_gpmc_reset(s);
-
- /* We have to register a different IO memory handler for each
- * chip select region in case a NAND device is mapped there. We
- * make the region the worst-case size of 256MB and rely on the
- * container memory region in cs_map to chop it down to the actual
- * guest-requested size.
- */
- for (cs = 0; cs < 8; cs++) {
- memory_region_init_io(&s->cs_file[cs].nandiomem, NULL,
- &omap_nand_ops,
- &s->cs_file[cs],
- "omap-nand",
- 256 * 1024 * 1024);
- }
-
- memory_region_init_io(&s->prefetch.iomem, NULL, &omap_prefetch_ops, s,
- "omap-gpmc-prefetch", 256 * 1024 * 1024);
- return s;
-}
-
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
-{
- struct omap_gpmc_cs_file_s *f;
- assert(iomem);
-
- if (cs < 0 || cs >= 8) {
- fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
- exit(-1);
- }
- f = &s->cs_file[cs];
-
- omap_gpmc_cs_unmap(s, cs);
- f->config[0] &= ~(0xf << 10);
- f->iomem = iomem;
- omap_gpmc_cs_map(s, cs);
-}
-
-void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
-{
- struct omap_gpmc_cs_file_s *f;
- assert(nand);
-
- if (cs < 0 || cs >= 8) {
- fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
- exit(-1);
- }
- f = &s->cs_file[cs];
-
- omap_gpmc_cs_unmap(s, cs);
- f->config[0] &= ~(0xf << 10);
- f->config[0] |= (OMAP_GPMC_NAND << 10);
- f->dev = nand;
- if (nand_getbuswidth(f->dev) == 16) {
- f->config[0] |= OMAP_GPMC_16BIT << 12;
- }
- omap_gpmc_cs_map(s, cs);
-}
diff --git a/hw/misc/omap_l4.c b/hw/misc/omap_l4.c
deleted file mode 100644
index b787548..0000000
--- a/hw/misc/omap_l4.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * TI OMAP L4 interconnect emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/arm/omap.h"
-
-struct omap_l4_s {
- MemoryRegion *address_space;
- hwaddr base;
- int ta_num;
- struct omap_target_agent_s ta[];
-};
-
-struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
- hwaddr base, int ta_num)
-{
- struct omap_l4_s *bus = g_malloc0(
- sizeof(*bus) + ta_num * sizeof(*bus->ta));
-
- bus->address_space = address_space;
- bus->ta_num = ta_num;
- bus->base = base;
-
- return bus;
-}
-
-hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
- int region)
-{
- return ta->bus->base + ta->start[region].offset;
-}
-
-hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
- int region)
-{
- return ta->start[region].size;
-}
-
-static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_target_agent_s *s = opaque;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* COMPONENT */
- return s->component;
-
- case 0x20: /* AGENT_CONTROL */
- return s->control;
-
- case 0x28: /* AGENT_STATUS */
- return s->status;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_l4ta_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_target_agent_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* COMPONENT */
- case 0x28: /* AGENT_STATUS */
- OMAP_RO_REG(addr);
- break;
-
- case 0x20: /* AGENT_CONTROL */
- s->control = value & 0x01000700;
- if (value & 1) /* OCP_RESET */
- s->status &= ~1; /* REQ_TIMEOUT */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_l4ta_ops = {
- .read = omap_l4ta_read,
- .write = omap_l4ta_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
- const struct omap_l4_region_s *regions,
- const struct omap_l4_agent_info_s *agents,
- int cs)
-{
- int i;
- struct omap_target_agent_s *ta = NULL;
- const struct omap_l4_agent_info_s *info = NULL;
-
- for (i = 0; i < bus->ta_num; i ++)
- if (agents[i].ta == cs) {
- ta = &bus->ta[i];
- info = &agents[i];
- break;
- }
- if (!ta) {
- fprintf(stderr, "%s: bad target agent (%i)\n", __func__, cs);
- exit(-1);
- }
-
- ta->bus = bus;
- ta->start = &regions[info->region];
- ta->regions = info->regions;
-
- ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- ta->status = 0x00000000;
- ta->control = 0x00000200; /* XXX 01000200 for L4TAO */
-
- memory_region_init_io(&ta->iomem, NULL, &omap_l4ta_ops, ta, "omap.l4ta",
- omap_l4_region_size(ta, info->ta_region));
- omap_l4_attach(ta, info->ta_region, &ta->iomem);
-
- return ta;
-}
-
-hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
- int region, MemoryRegion *mr)
-{
- hwaddr base;
-
- if (region < 0 || region >= ta->regions) {
- fprintf(stderr, "%s: bad io region (%i)\n", __func__, region);
- exit(-1);
- }
-
- base = ta->bus->base + ta->start[region].offset;
- if (mr) {
- memory_region_add_subregion(ta->bus->address_space, base, mr);
- }
-
- return base;
-}
diff --git a/hw/misc/omap_sdrc.c b/hw/misc/omap_sdrc.c
deleted file mode 100644
index 6aa1b3e..0000000
--- a/hw/misc/omap_sdrc.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * TI OMAP SDRAM controller emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/arm/omap.h"
-
-/* SDRAM Controller Subsystem */
-struct omap_sdrc_s {
- MemoryRegion iomem;
- uint8_t config;
-};
-
-void omap_sdrc_reset(struct omap_sdrc_s *s)
-{
- s->config = 0x10;
-}
-
-static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_sdrc_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* SDRC_REVISION */
- return 0x20;
-
- case 0x10: /* SDRC_SYSCONFIG */
- return s->config;
-
- case 0x14: /* SDRC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* SDRC_CS_CFG */
- case 0x44: /* SDRC_SHARING */
- case 0x48: /* SDRC_ERR_ADDR */
- case 0x4c: /* SDRC_ERR_TYPE */
- case 0x60: /* SDRC_DLLA_SCTRL */
- case 0x64: /* SDRC_DLLA_STATUS */
- case 0x68: /* SDRC_DLLB_CTRL */
- case 0x6c: /* SDRC_DLLB_STATUS */
- case 0x70: /* SDRC_POWER */
- case 0x80: /* SDRC_MCFG_0 */
- case 0x84: /* SDRC_MR_0 */
- case 0x88: /* SDRC_EMR1_0 */
- case 0x8c: /* SDRC_EMR2_0 */
- case 0x90: /* SDRC_EMR3_0 */
- case 0x94: /* SDRC_DCDL1_CTRL */
- case 0x98: /* SDRC_DCDL2_CTRL */
- case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
- case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
- case 0xa4: /* SDRC_RFR_CTRL_0 */
- case 0xa8: /* SDRC_MANUAL_0 */
- case 0xb0: /* SDRC_MCFG_1 */
- case 0xb4: /* SDRC_MR_1 */
- case 0xb8: /* SDRC_EMR1_1 */
- case 0xbc: /* SDRC_EMR2_1 */
- case 0xc0: /* SDRC_EMR3_1 */
- case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
- case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
- case 0xd4: /* SDRC_RFR_CTRL_1 */
- case 0xd8: /* SDRC_MANUAL_1 */
- return 0x00;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sdrc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sdrc_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* SDRC_REVISION */
- case 0x14: /* SDRC_SYSSTATUS */
- case 0x48: /* SDRC_ERR_ADDR */
- case 0x64: /* SDRC_DLLA_STATUS */
- case 0x6c: /* SDRC_DLLB_STATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* SDRC_SYSCONFIG */
- if ((value >> 3) != 0x2)
- fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
- __func__, (unsigned)value >> 3);
- if (value & 2)
- omap_sdrc_reset(s);
- s->config = value & 0x18;
- break;
-
- case 0x40: /* SDRC_CS_CFG */
- case 0x44: /* SDRC_SHARING */
- case 0x4c: /* SDRC_ERR_TYPE */
- case 0x60: /* SDRC_DLLA_SCTRL */
- case 0x68: /* SDRC_DLLB_CTRL */
- case 0x70: /* SDRC_POWER */
- case 0x80: /* SDRC_MCFG_0 */
- case 0x84: /* SDRC_MR_0 */
- case 0x88: /* SDRC_EMR1_0 */
- case 0x8c: /* SDRC_EMR2_0 */
- case 0x90: /* SDRC_EMR3_0 */
- case 0x94: /* SDRC_DCDL1_CTRL */
- case 0x98: /* SDRC_DCDL2_CTRL */
- case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
- case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
- case 0xa4: /* SDRC_RFR_CTRL_0 */
- case 0xa8: /* SDRC_MANUAL_0 */
- case 0xb0: /* SDRC_MCFG_1 */
- case 0xb4: /* SDRC_MR_1 */
- case 0xb8: /* SDRC_EMR1_1 */
- case 0xbc: /* SDRC_EMR2_1 */
- case 0xc0: /* SDRC_EMR3_1 */
- case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
- case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
- case 0xd4: /* SDRC_RFR_CTRL_1 */
- case 0xd8: /* SDRC_MANUAL_1 */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_sdrc_ops = {
- .read = omap_sdrc_read,
- .write = omap_sdrc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
- hwaddr base)
-{
- struct omap_sdrc_s *s = g_new0(struct omap_sdrc_s, 1);
-
- omap_sdrc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sdrc_ops, s, "omap.sdrc", 0x1000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- return s;
-}
diff --git a/hw/misc/omap_tap.c b/hw/misc/omap_tap.c
deleted file mode 100644
index 4d7fb7d..0000000
--- a/hw/misc/omap_tap.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * TI OMAP TEST-Chip-level TAP emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-/* TEST-Chip-level TAP */
-static uint64_t omap_tap_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_mpu_state_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x204: /* IDCODE_reg */
- switch (s->mpu_model) {
- case omap2420:
- case omap2422:
- case omap2423:
- return 0x5b5d902f; /* ES 2.2 */
- case omap2430:
- return 0x5b68a02f; /* ES 2.2 */
- case omap3430:
- return 0x1b7ae02f; /* ES 2 */
- default:
- hw_error("%s: Bad mpu model\n", __func__);
- }
-
- case 0x208: /* PRODUCTION_ID_reg for OMAP2 */
- case 0x210: /* PRODUCTION_ID_reg for OMAP3 */
- switch (s->mpu_model) {
- case omap2420:
- return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
- case omap2422:
- return 0x000400f0;
- case omap2423:
- return 0x000800f0;
- case omap2430:
- return 0x000000f0;
- case omap3430:
- return 0x000000f0;
- default:
- hw_error("%s: Bad mpu model\n", __func__);
- }
-
- case 0x20c:
- switch (s->mpu_model) {
- case omap2420:
- case omap2422:
- case omap2423:
- return 0xcafeb5d9; /* ES 2.2 */
- case omap2430:
- return 0xcafeb68a; /* ES 2.2 */
- case omap3430:
- return 0xcafeb7ae; /* ES 2 */
- default:
- hw_error("%s: Bad mpu model\n", __func__);
- }
-
- case 0x218: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- case 0x21c: /* DIE_ID_reg */
- return 0x54 << 24;
- case 0x220: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- case 0x224: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_tap_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_tap_ops = {
- .read = omap_tap_read,
- .write = omap_tap_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void omap_tap_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->tap_iomem, NULL, &omap_tap_ops, mpu, "omap.tap",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &mpu->tap_iomem);
-}
diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c
index e389651..67c486f 100644
--- a/hw/misc/pc-testdev.c
+++ b/hw/misc/pc-testdev.c
@@ -193,7 +193,7 @@ static void testdev_realizefn(DeviceState *d, Error **errp)
memory_region_add_subregion(mem, 0xff000000, &dev->iomem);
}
-static void testdev_class_init(ObjectClass *klass, void *data)
+static void testdev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c
index acedd0f..ba71c50 100644
--- a/hw/misc/pci-testdev.c
+++ b/hw/misc/pci-testdev.c
@@ -23,7 +23,7 @@
#include "hw/qdev-properties.h"
#include "qemu/event_notifier.h"
#include "qemu/module.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "qom/object.h"
typedef struct PCITestDevHdr {
@@ -90,6 +90,7 @@ struct PCITestDevState {
int current;
uint64_t membar_size;
+ bool membar_backed;
MemoryRegion membar;
};
@@ -258,8 +259,14 @@ static void pci_testdev_realize(PCIDevice *pci_dev, Error **errp)
pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->portio);
if (d->membar_size) {
- memory_region_init(&d->membar, OBJECT(d), "pci-testdev-membar",
- d->membar_size);
+ if (d->membar_backed)
+ memory_region_init_ram(&d->membar, OBJECT(d),
+ "pci-testdev-membar-backed",
+ d->membar_size, NULL);
+ else
+ memory_region_init(&d->membar, OBJECT(d),
+ "pci-testdev-membar",
+ d->membar_size);
pci_register_bar(pci_dev, 2,
PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_PREFETCH |
@@ -319,12 +326,12 @@ static void qdev_pci_testdev_reset(DeviceState *dev)
pci_testdev_reset(d);
}
-static Property pci_testdev_properties[] = {
+static const Property pci_testdev_properties[] = {
DEFINE_PROP_SIZE("membar", PCITestDevState, membar_size, 0),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("membar-backed", PCITestDevState, membar_backed, false),
};
-static void pci_testdev_class_init(ObjectClass *klass, void *data)
+static void pci_testdev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -337,7 +344,7 @@ static void pci_testdev_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_OTHERS;
dc->desc = "PCI Test Device";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = qdev_pci_testdev_reset;
+ device_class_set_legacy_reset(dc, qdev_pci_testdev_reset);
device_class_set_props(dc, pci_testdev_properties);
}
@@ -346,7 +353,7 @@ static const TypeInfo pci_testdev_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCITestDevState),
.class_init = pci_testdev_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c
index 9a923b7..f7b421c 100644
--- a/hw/misc/pvpanic-isa.c
+++ b/hw/misc/pvpanic-isa.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/qdev-properties.h"
@@ -98,14 +98,13 @@ static void build_pvpanic_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(scope, dev);
}
-static Property pvpanic_isa_properties[] = {
+static const Property pvpanic_isa_properties[] = {
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicISAState, ioport, 0x505),
DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events,
PVPANIC_EVENTS),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
+static void pvpanic_isa_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
@@ -122,7 +121,7 @@ static const TypeInfo pvpanic_isa_info = {
.instance_size = sizeof(PVPanicISAState),
.instance_init = pvpanic_isa_initfn,
.class_init = pvpanic_isa_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/misc/pvpanic-mmio.c b/hw/misc/pvpanic-mmio.c
new file mode 100644
index 0000000..2a36310
--- /dev/null
+++ b/hw/misc/pvpanic-mmio.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU simulated pvpanic device (MMIO frontend)
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/qdev-properties.h"
+#include "hw/misc/pvpanic.h"
+#include "hw/sysbus.h"
+#include "standard-headers/misc/pvpanic.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(PVPanicMMIOState, PVPANIC_MMIO_DEVICE)
+
+#define PVPANIC_MMIO_SIZE 0x2
+
+struct PVPanicMMIOState {
+ SysBusDevice parent_obj;
+
+ PVPanicState pvpanic;
+};
+
+static void pvpanic_mmio_initfn(Object *obj)
+{
+ PVPanicMMIOState *s = PVPANIC_MMIO_DEVICE(obj);
+
+ pvpanic_setup_io(&s->pvpanic, DEVICE(s), PVPANIC_MMIO_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->pvpanic.mr);
+}
+
+static const Property pvpanic_mmio_properties[] = {
+ DEFINE_PROP_UINT8("events", PVPanicMMIOState, pvpanic.events,
+ PVPANIC_PANICKED | PVPANIC_CRASH_LOADED),
+};
+
+static void pvpanic_mmio_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_props(dc, pvpanic_mmio_properties);
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo pvpanic_mmio_info = {
+ .name = TYPE_PVPANIC_MMIO_DEVICE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PVPanicMMIOState),
+ .instance_init = pvpanic_mmio_initfn,
+ .class_init = pvpanic_mmio_class_init,
+};
+
+static void pvpanic_register_types(void)
+{
+ type_register_static(&pvpanic_mmio_info);
+}
+
+type_init(pvpanic_register_types)
diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c
index 106d03c..2869b6a 100644
--- a/hw/misc/pvpanic-pci.c
+++ b/hw/misc/pvpanic-pci.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/qdev-properties.h"
@@ -53,13 +53,12 @@ static void pvpanic_pci_realizefn(PCIDevice *dev, Error **errp)
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &ps->mr);
}
-static Property pvpanic_pci_properties[] = {
+static const Property pvpanic_pci_properties[] = {
DEFINE_PROP_UINT8("events", PVPanicPCIState, pvpanic.events,
PVPANIC_EVENTS),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pvpanic_pci_class_init(ObjectClass *klass, void *data)
+static void pvpanic_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
@@ -81,7 +80,7 @@ static const TypeInfo pvpanic_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PVPanicPCIState),
.class_init = pvpanic_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c
index 3b89334..c83247c 100644
--- a/hw/misc/pvpanic.c
+++ b/hw/misc/pvpanic.c
@@ -15,7 +15,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/qdev-properties.h"
diff --git a/hw/misc/sbsa_ec.c b/hw/misc/sbsa_ec.c
index 86b23a5..dfee1af 100644
--- a/hw/misc/sbsa_ec.c
+++ b/hw/misc/sbsa_ec.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/sysbus.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
typedef struct SECUREECState {
SysBusDevice parent_obj;
@@ -73,7 +73,7 @@ static void sbsa_ec_init(Object *obj)
sysbus_init_mmio(dev, &s->iomem);
}
-static void sbsa_ec_class_init(ObjectClass *klass, void *data)
+static void sbsa_ec_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/sifive_e_aon.c b/hw/misc/sifive_e_aon.c
index 4656457..6eef38d 100644
--- a/hw/misc/sifive_e_aon.c
+++ b/hw/misc/sifive_e_aon.c
@@ -24,7 +24,7 @@
#include "hw/misc/sifive_e_aon.h"
#include "qapi/visitor.h"
#include "qapi/error.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "hw/qdev-properties.h"
REG32(AON_WDT_WDOGCFG, 0x0)
@@ -289,17 +289,16 @@ static void sifive_e_aon_init(Object *obj)
sysbus_init_irq(sbd, &r->wdog_irq);
}
-static Property sifive_e_aon_properties[] = {
+static const Property sifive_e_aon_properties[] = {
DEFINE_PROP_UINT64("wdogclk-frequency", SiFiveEAONState, wdogclk_freq,
SIFIVE_E_LFCLK_DEFAULT_FREQ),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sifive_e_aon_class_init(ObjectClass *oc, void *data)
+static void sifive_e_aon_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = sifive_e_aon_reset;
+ device_class_set_legacy_reset(dc, sifive_e_aon_reset);
device_class_set_props(dc, sifive_e_aon_properties);
}
diff --git a/hw/misc/sifive_test.c b/hw/misc/sifive_test.c
index ad68807..b94bb2d 100644
--- a/hw/misc/sifive_test.c
+++ b/hw/misc/sifive_test.c
@@ -23,9 +23,9 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/misc/sifive_test.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size)
{
diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c
index 8965f5c..1ebed2f 100644
--- a/hw/misc/sifive_u_otp.c
+++ b/hw/misc/sifive_u_otp.c
@@ -27,8 +27,8 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/misc/sifive_u_otp.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/block-backend.h"
+#include "system/blockdev.h"
+#include "system/block-backend.h"
#define WRITTEN_BIT_ON 0x1
@@ -194,10 +194,9 @@ static const MemoryRegionOps sifive_u_otp_ops = {
}
};
-static Property sifive_u_otp_properties[] = {
+static const Property sifive_u_otp_properties[] = {
DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk),
- DEFINE_PROP_END_OF_LIST(),
};
static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
@@ -271,7 +270,7 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo));
}
-static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
+static void sifive_u_otp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/sifive_u_prci.c b/hw/misc/sifive_u_prci.c
index 5d9d446..6e75cb6 100644
--- a/hw/misc/sifive_u_prci.c
+++ b/hw/misc/sifive_u_prci.c
@@ -146,12 +146,12 @@ static void sifive_u_prci_reset(DeviceState *dev)
s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK;
}
-static void sifive_u_prci_class_init(ObjectClass *klass, void *data)
+static void sifive_u_prci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sifive_u_prci_realize;
- dc->reset = sifive_u_prci_reset;
+ device_class_set_legacy_reset(dc, sifive_u_prci_reset);
}
static const TypeInfo sifive_u_prci_info = {
diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c
index 94369e4..a034df3 100644
--- a/hw/misc/slavio_misc.c
+++ b/hw/misc/slavio_misc.c
@@ -27,7 +27,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "trace.h"
#include "qom/object.h"
@@ -483,11 +483,11 @@ static void slavio_misc_init(Object *obj)
qdev_init_gpio_in(dev, slavio_set_power_fail, 1);
}
-static void slavio_misc_class_init(ObjectClass *klass, void *data)
+static void slavio_misc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = slavio_misc_reset;
+ device_class_set_legacy_reset(dc, slavio_misc_reset);
dc->vmsd = &vmstate_misc;
}
diff --git a/hw/misc/stm32_rcc.c b/hw/misc/stm32_rcc.c
new file mode 100644
index 0000000..5815b3e
--- /dev/null
+++ b/hw/misc/stm32_rcc.c
@@ -0,0 +1,162 @@
+/*
+ * STM32 RCC (only reset and enable registers are implemented)
+ *
+ * Copyright (c) 2024 Román Cárdenas <rcardenas.rod@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32_rcc.h"
+
+static void stm32_rcc_reset(DeviceState *dev)
+{
+ STM32RccState *s = STM32_RCC(dev);
+
+ for (int i = 0; i < STM32_RCC_NREGS; i++) {
+ s->regs[i] = 0;
+ }
+}
+
+static uint64_t stm32_rcc_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ STM32RccState *s = STM32_RCC(opaque);
+
+ uint32_t value = 0;
+ if (addr > STM32_RCC_DCKCFGR2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
+ } else {
+ value = s->regs[addr >> 2];
+ }
+ trace_stm32_rcc_read(addr, value);
+ return value;
+}
+
+static void stm32_rcc_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32RccState *s = STM32_RCC(opaque);
+ uint32_t value = val64;
+ uint32_t prev_value, new_value, irq_offset;
+
+ trace_stm32_rcc_write(addr, value);
+
+ if (addr > STM32_RCC_DCKCFGR2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
+ return;
+ }
+
+ switch (addr) {
+ case STM32_RCC_AHB1_RSTR...STM32_RCC_APB2_RSTR:
+ prev_value = s->regs[addr / 4];
+ s->regs[addr / 4] = value;
+
+ irq_offset = ((addr - STM32_RCC_AHB1_RSTR) / 4) * 32;
+ for (int i = 0; i < 32; i++) {
+ new_value = extract32(value, i, 1);
+ if (extract32(prev_value, i, 1) && !new_value) {
+ trace_stm32_rcc_pulse_reset(irq_offset + i, new_value);
+ qemu_set_irq(s->reset_irq[irq_offset + i], new_value);
+ }
+ }
+ return;
+ case STM32_RCC_AHB1_ENR...STM32_RCC_APB2_ENR:
+ prev_value = s->regs[addr / 4];
+ s->regs[addr / 4] = value;
+
+ irq_offset = ((addr - STM32_RCC_AHB1_ENR) / 4) * 32;
+ for (int i = 0; i < 32; i++) {
+ new_value = extract32(value, i, 1);
+ if (!extract32(prev_value, i, 1) && new_value) {
+ trace_stm32_rcc_pulse_enable(irq_offset + i, new_value);
+ qemu_set_irq(s->enable_irq[irq_offset + i], new_value);
+ }
+ }
+ return;
+ default:
+ qemu_log_mask(
+ LOG_UNIMP,
+ "%s: The RCC peripheral only supports enable and reset in QEMU\n",
+ __func__
+ );
+ s->regs[addr >> 2] = value;
+ }
+}
+
+static const MemoryRegionOps stm32_rcc_ops = {
+ .read = stm32_rcc_read,
+ .write = stm32_rcc_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32_rcc_init(Object *obj)
+{
+ STM32RccState *s = STM32_RCC(obj);
+
+ memory_region_init_io(&s->mmio, obj, &stm32_rcc_ops, s,
+ TYPE_STM32_RCC, STM32_RCC_PERIPHERAL_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ qdev_init_gpio_out(DEVICE(obj), s->reset_irq, STM32_RCC_NIRQS);
+ qdev_init_gpio_out(DEVICE(obj), s->enable_irq, STM32_RCC_NIRQS);
+
+ for (int i = 0; i < STM32_RCC_NIRQS; i++) {
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->reset_irq[i]);
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->enable_irq[i]);
+ }
+}
+
+static const VMStateDescription vmstate_stm32_rcc = {
+ .name = TYPE_STM32_RCC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, STM32RccState, STM32_RCC_NREGS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void stm32_rcc_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_stm32_rcc;
+ device_class_set_legacy_reset(dc, stm32_rcc_reset);
+}
+
+static const TypeInfo stm32_rcc_info = {
+ .name = TYPE_STM32_RCC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32RccState),
+ .instance_init = stm32_rcc_init,
+ .class_init = stm32_rcc_class_init,
+};
+
+static void stm32_rcc_register_types(void)
+{
+ type_register_static(&stm32_rcc_info);
+}
+
+type_init(stm32_rcc_register_types)
diff --git a/hw/misc/stm32f2xx_syscfg.c b/hw/misc/stm32f2xx_syscfg.c
index 19c1e86..d285896 100644
--- a/hw/misc/stm32f2xx_syscfg.c
+++ b/hw/misc/stm32f2xx_syscfg.c
@@ -138,11 +138,11 @@ static void stm32f2xx_syscfg_init(Object *obj)
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
-static void stm32f2xx_syscfg_class_init(ObjectClass *klass, void *data)
+static void stm32f2xx_syscfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_syscfg_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_syscfg_reset);
}
static const TypeInfo stm32f2xx_syscfg_info = {
diff --git a/hw/misc/stm32f4xx_exti.c b/hw/misc/stm32f4xx_exti.c
index 7bd3afc..0688e6e 100644
--- a/hw/misc/stm32f4xx_exti.c
+++ b/hw/misc/stm32f4xx_exti.c
@@ -164,11 +164,11 @@ static const VMStateDescription vmstate_stm32f4xx_exti = {
}
};
-static void stm32f4xx_exti_class_init(ObjectClass *klass, void *data)
+static void stm32f4xx_exti_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f4xx_exti_reset;
+ device_class_set_legacy_reset(dc, stm32f4xx_exti_reset);
dc->vmsd = &vmstate_stm32f4xx_exti;
}
diff --git a/hw/misc/stm32f4xx_syscfg.c b/hw/misc/stm32f4xx_syscfg.c
index 854fce6..addfb03 100644
--- a/hw/misc/stm32f4xx_syscfg.c
+++ b/hw/misc/stm32f4xx_syscfg.c
@@ -147,11 +147,11 @@ static const VMStateDescription vmstate_stm32f4xx_syscfg = {
}
};
-static void stm32f4xx_syscfg_class_init(ObjectClass *klass, void *data)
+static void stm32f4xx_syscfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f4xx_syscfg_reset;
+ device_class_set_legacy_reset(dc, stm32f4xx_syscfg_reset);
dc->vmsd = &vmstate_stm32f4xx_syscfg;
}
diff --git a/hw/misc/stm32l4x5_exti.c b/hw/misc/stm32l4x5_exti.c
index e281841..9c00216 100644
--- a/hw/misc/stm32l4x5_exti.c
+++ b/hw/misc/stm32l4x5_exti.c
@@ -271,7 +271,7 @@ static const VMStateDescription vmstate_stm32l4x5_exti = {
}
};
-static void stm32l4x5_exti_class_init(ObjectClass *klass, void *data)
+static void stm32l4x5_exti_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c
index 59d428f..0e1f27f 100644
--- a/hw/misc/stm32l4x5_rcc.c
+++ b/hw/misc/stm32l4x5_rcc.c
@@ -141,7 +141,7 @@ static const VMStateDescription clock_mux_vmstate = {
}
};
-static void clock_mux_class_init(ObjectClass *klass, void *data)
+static void clock_mux_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -150,6 +150,8 @@ static void clock_mux_class_init(ObjectClass *klass, void *data)
rc->phases.hold = clock_mux_reset_hold;
rc->phases.exit = clock_mux_reset_exit;
dc->vmsd = &clock_mux_vmstate;
+ /* Reason: Part of Stm32l4x5RccState component */
+ dc->user_creatable = false;
}
static void clock_mux_set_enable(RccClockMuxState *mux, bool enabled)
@@ -293,7 +295,7 @@ static const VMStateDescription pll_vmstate = {
}
};
-static void pll_class_init(ObjectClass *klass, void *data)
+static void pll_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -302,6 +304,8 @@ static void pll_class_init(ObjectClass *klass, void *data)
rc->phases.hold = pll_reset_hold;
rc->phases.exit = pll_reset_exit;
dc->vmsd = &pll_vmstate;
+ /* Reason: Part of Stm32l4x5RccState component */
+ dc->user_creatable = false;
}
static void pll_set_vco_multiplier(RccPllState *pll, uint32_t vco_multiplier)
@@ -1426,17 +1430,16 @@ static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp)
clock_update(s->gnd, 0);
}
-static Property stm32l4x5_rcc_properties[] = {
+static const Property stm32l4x5_rcc_properties[] = {
DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState,
hse_frequency, HSE_DEFAULT_FRQ),
DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState,
sai1_extclk_frequency, 0),
DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState,
sai2_extclk_frequency, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data)
+static void stm32l4x5_rcc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
index a5a1ce2..4e21756 100644
--- a/hw/misc/stm32l4x5_syscfg.c
+++ b/hw/misc/stm32l4x5_syscfg.c
@@ -26,6 +26,9 @@
#include "trace.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
+#include "hw/clock.h"
+#include "hw/qdev-clock.h"
+#include "qapi/error.h"
#include "hw/misc/stm32l4x5_syscfg.h"
#include "hw/gpio/stm32l4x5_gpio.h"
@@ -225,12 +228,22 @@ static void stm32l4x5_syscfg_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), stm32l4x5_syscfg_set_irq,
GPIO_NUM_PINS * NUM_GPIOS);
qdev_init_gpio_out(DEVICE(obj), s->gpio_out, GPIO_NUM_PINS);
+ s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
+}
+
+static void stm32l4x5_syscfg_realize(DeviceState *dev, Error **errp)
+{
+ Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(dev);
+ if (!clock_has_source(s->clk)) {
+ error_setg(errp, "SYSCFG: clk input must be connected");
+ return;
+ }
}
static const VMStateDescription vmstate_stm32l4x5_syscfg = {
.name = TYPE_STM32L4X5_SYSCFG,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(memrmp, Stm32l4x5SyscfgState),
VMSTATE_UINT32(cfgr1, Stm32l4x5SyscfgState),
@@ -241,16 +254,18 @@ static const VMStateDescription vmstate_stm32l4x5_syscfg = {
VMSTATE_UINT32(swpr, Stm32l4x5SyscfgState),
VMSTATE_UINT32(skr, Stm32l4x5SyscfgState),
VMSTATE_UINT32(swpr2, Stm32l4x5SyscfgState),
+ VMSTATE_CLOCK(clk, Stm32l4x5SyscfgState),
VMSTATE_END_OF_LIST()
}
};
-static void stm32l4x5_syscfg_class_init(ObjectClass *klass, void *data)
+static void stm32l4x5_syscfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->vmsd = &vmstate_stm32l4x5_syscfg;
+ dc->realize = stm32l4x5_syscfg_realize;
rc->phases.hold = stm32l4x5_syscfg_hold_reset;
}
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 1be0717..e3f64c0 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -130,13 +130,13 @@ mos6522_set_sr_int(void) "set sr_int"
mos6522_write(uint64_t addr, const char *name, uint64_t val) "reg=0x%"PRIx64 " [%s] val=0x%"PRIx64
mos6522_read(uint64_t addr, const char *name, unsigned val) "reg=0x%"PRIx64 " [%s] val=0x%x"
-# npcm7xx_clk.c
-npcm7xx_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
-npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+# npcm_clk.c
+npcm_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+npcm_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
-# npcm7xx_gcr.c
-npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
-npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+# npcm_gcr.c
+npcm_gcr_read(uint64_t offset, uint64_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
+npcm_gcr_write(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
# npcm7xx_mft.c
npcm7xx_mft_read(const char *name, uint64_t offset, uint16_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
@@ -156,6 +156,12 @@ npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0
npcm7xx_pwm_update_freq(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Freq: old_freq: %u, new_freq: %u"
npcm7xx_pwm_update_duty(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Duty: old_duty: %u, new_duty: %u"
+# stm32_rcc.c
+stm32_rcc_read(uint64_t addr, uint64_t data) "reg read: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
+stm32_rcc_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
+stm32_rcc_pulse_enable(int line, int level) "Enable: %d to %d"
+stm32_rcc_pulse_reset(int line, int level) "Reset: %d to %d"
+
# stm32f4xx_syscfg.c
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interrupt: GPIO: %d, Line: %d; Level: %d"
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
@@ -247,6 +253,12 @@ ccm_clock_freq(uint32_t clock, uint32_t freq) "(Clock = %d) = %d"
ccm_read_reg(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32
ccm_write_reg(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32
+# imx6_src.c
+imx6_src_read(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32
+imx6_src_write(const char *reg_name, uint64_t value) "reg[%s] <= 0x%" PRIx64
+imx6_clear_reset_bit(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32
+imx6_src_reset(void) ""
+
# imx7_src.c
imx7_src_read(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32
imx7_src_write(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32
@@ -290,6 +302,14 @@ aspeed_peci_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%"
aspeed_peci_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64
aspeed_peci_raise_interrupt(uint32_t ctrl, uint32_t status) "ctrl 0x%" PRIx32 " status 0x%" PRIx32
+# aspeed_hace.c
+aspeed_hace_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64
+aspeed_hace_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64
+aspeed_hace_hash_sg(int index, uint64_t list_addr, uint64_t buf_addr, uint32_t len) "%d: list_addr 0x%" PRIx64 " buf_addr 0x%" PRIx64 " len 0x%" PRIx32
+aspeed_hace_hash_addr(const char *s, uint64_t addr) "%s: 0x%" PRIx64
+aspeed_hace_hash_execute_acc_mode(bool final_request) "final request: %d"
+aspeed_hace_hexdump(const char *desc, uint32_t offset, char *s) "%s: 0x%08x: %s"
+
# bcm2835_property.c
bcm2835_mbox_property(uint32_t tag, uint32_t bufsize, size_t resplen) "mbox property tag:0x%08x in_sz:%u out_sz:%zu"
@@ -362,3 +382,24 @@ aspeed_sli_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx
aspeed_sliio_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_sliio_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+# ivshmem-flat.c
+ivshmem_flat_irq_handler(uint16_t vector_id) "Caught interrupt request: vector %d"
+ivshmem_flat_new_peer(uint16_t peer_id) "New peer ID: %d"
+ivshmem_flat_add_vector_failure(uint16_t vector_id, uint32_t vector_fd, uint16_t peer_id) "Failed to add vector %u (fd = %u) to peer ID %u, maximum number of vectors reached"
+ivshmem_flat_add_vector_success(uint16_t vector_id, uint32_t vector_fd, uint16_t peer_id) "Successful addition of vector %u (fd = %u) to peer ID %u"
+ivshmem_flat_irq_resolved(const char *irq_qompath) "IRQ QOM path '%s' correctly resolved"
+ivshmem_flat_proto_ver_own_id(uint64_t proto_ver, uint16_t peer_id) "Protocol Version = 0x%"PRIx64", Own Peer ID = %u"
+ivshmem_flat_shmem_size(int fd, uint64_t size) "Shmem fd (%d) total size is %"PRIu64" byte(s)"
+ivshmem_flat_shmem_map(uint64_t addr) "Mapping shmem @ 0x%"PRIx64
+ivshmem_flat_mmio_map(uint64_t addr) "Mapping MMRs @ 0x%"PRIx64
+ivshmem_flat_read_mmr(uint64_t addr_offset) "Read access at offset %"PRIu64
+ivshmem_flat_read_mmr_doorbell(void) "DOORBELL register is write-only!"
+ivshmem_flat_read_write_mmr_invalid(uint64_t addr_offset) "No ivshmem register mapped at offset %"PRIu64
+ivshmem_flat_interrupt_invalid_peer(uint16_t peer_id) "Can't interrupt non-existing peer %u"
+ivshmem_flat_write_mmr(uint64_t addr_offset) "Write access at offset %"PRIu64
+ivshmem_flat_interrupt_peer(uint16_t peer_id, uint16_t vector_id) "Interrupting peer ID %u, vector %u..."
+
+# i2c-echo.c
+i2c_echo_event(const char *id, const char *event) "%s: %s"
+i2c_echo_recv(const char *id, uint8_t data) "%s: recv 0x%02" PRIx8
+i2c_echo_send(const char *id, uint8_t data) "%s: send 0x%02" PRIx8
diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
index 92b9949..a158d4a 100644
--- a/hw/misc/tz-mpc.c
+++ b/hw/misc/tz-mpc.c
@@ -587,19 +587,18 @@ static const VMStateDescription tz_mpc_vmstate = {
}
};
-static Property tz_mpc_properties[] = {
+static const Property tz_mpc_properties[] = {
DEFINE_PROP_LINK("downstream", TZMPC, downstream,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void tz_mpc_class_init(ObjectClass *klass, void *data)
+static void tz_mpc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = tz_mpc_realize;
dc->vmsd = &tz_mpc_vmstate;
- dc->reset = tz_mpc_reset;
+ device_class_set_legacy_reset(dc, tz_mpc_reset);
device_class_set_props(dc, tz_mpc_properties);
}
@@ -612,7 +611,7 @@ static const TypeInfo tz_mpc_info = {
};
static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c
index de5a312..af0cc5d 100644
--- a/hw/misc/tz-msc.c
+++ b/hw/misc/tz-msc.c
@@ -278,21 +278,20 @@ static const VMStateDescription tz_msc_vmstate = {
}
};
-static Property tz_msc_properties[] = {
+static const Property tz_msc_properties[] = {
DEFINE_PROP_LINK("downstream", TZMSC, downstream,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_LINK("idau", TZMSC, idau,
TYPE_IDAU_INTERFACE, IDAUInterface *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void tz_msc_class_init(ObjectClass *klass, void *data)
+static void tz_msc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = tz_msc_realize;
dc->vmsd = &tz_msc_vmstate;
- dc->reset = tz_msc_reset;
+ device_class_set_legacy_reset(dc, tz_msc_reset);
device_class_set_props(dc, tz_msc_properties);
}
diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c
index 6450778..e4235a8 100644
--- a/hw/misc/tz-ppc.c
+++ b/hw/misc/tz-ppc.c
@@ -305,7 +305,7 @@ static const VMStateDescription tz_ppc_vmstate = {
DEFINE_PROP_LINK("port[" #N "]", TZPPC, port[N].downstream, \
TYPE_MEMORY_REGION, MemoryRegion *)
-static Property tz_ppc_properties[] = {
+static const Property tz_ppc_properties[] = {
DEFINE_PROP_UINT32("NONSEC_MASK", TZPPC, nonsec_mask, 0),
DEFINE_PORT(0),
DEFINE_PORT(1),
@@ -323,16 +323,15 @@ static Property tz_ppc_properties[] = {
DEFINE_PORT(13),
DEFINE_PORT(14),
DEFINE_PORT(15),
- DEFINE_PROP_END_OF_LIST(),
};
-static void tz_ppc_class_init(ObjectClass *klass, void *data)
+static void tz_ppc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = tz_ppc_realize;
dc->vmsd = &tz_ppc_vmstate;
- dc->reset = tz_ppc_reset;
+ device_class_set_legacy_reset(dc, tz_ppc_reset);
device_class_set_props(dc, tz_ppc_properties);
}
diff --git a/hw/misc/unimp.c b/hw/misc/unimp.c
index 6cfc572..4370c14 100644
--- a/hw/misc/unimp.c
+++ b/hw/misc/unimp.c
@@ -70,13 +70,12 @@ static void unimp_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
-static Property unimp_properties[] = {
+static const Property unimp_properties[] = {
DEFINE_PROP_UINT64("size", UnimplementedDeviceState, size, 0),
DEFINE_PROP_STRING("name", UnimplementedDeviceState, name),
- DEFINE_PROP_END_OF_LIST(),
};
-static void unimp_class_init(ObjectClass *klass, void *data)
+static void unimp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c
index 1a6c744..9f16093 100644
--- a/hw/misc/virt_ctrl.c
+++ b/hw/misc/virt_ctrl.c
@@ -10,7 +10,7 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "trace.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/misc/virt_ctrl.h"
enum {
@@ -125,11 +125,11 @@ static void virt_ctrl_instance_init(Object *obj)
sysbus_init_irq(dev, &s->irq);
}
-static void virt_ctrl_class_init(ObjectClass *oc, void *data)
+static void virt_ctrl_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = virt_ctrl_reset;
+ device_class_set_legacy_reset(dc, virt_ctrl_reset);
dc->realize = virt_ctrl_realize;
dc->vmsd = &vmstate_virt_ctrl;
}
diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c
index 833773a..9c2e900 100644
--- a/hw/misc/vmcoreinfo.c
+++ b/hw/misc/vmcoreinfo.c
@@ -13,22 +13,22 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/nvram/fw_cfg.h"
#include "migration/vmstate.h"
#include "hw/misc/vmcoreinfo.h"
-static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len)
+static void fw_cfg_vmci_write(void *opaque, off_t offset, size_t len)
{
- VMCoreInfoState *s = VMCOREINFO(dev);
+ VMCoreInfoState *s = opaque;
s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo)
&& s->vmcoreinfo.guest_format != FW_CFG_VMCOREINFO_FORMAT_NONE;
}
-static void vmcoreinfo_reset(void *dev)
+static void vmcoreinfo_reset_hold(Object *obj, ResetType type)
{
- VMCoreInfoState *s = VMCOREINFO(dev);
+ VMCoreInfoState *s = VMCOREINFO(obj);
s->has_vmcoreinfo = false;
memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo));
@@ -47,13 +47,13 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp)
*/
if (!vmcoreinfo_find()) {
error_setg(errp, "at most one %s device is permitted",
- VMCOREINFO_DEVICE);
+ TYPE_VMCOREINFO);
return;
}
if (!fw_cfg || !fw_cfg->dma_enabled) {
error_setg(errp, "%s device requires fw_cfg with DMA",
- VMCOREINFO_DEVICE);
+ TYPE_VMCOREINFO);
return;
}
@@ -65,7 +65,7 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp)
* This device requires to register a global reset because it is
* not plugged to a bus (which, as its QOM parent, would reset it).
*/
- qemu_register_reset(vmcoreinfo_reset, dev);
+ qemu_register_resettable(OBJECT(s));
vmcoreinfo_state = s;
}
@@ -83,26 +83,25 @@ static const VMStateDescription vmstate_vmcoreinfo = {
},
};
-static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data)
+static void vmcoreinfo_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->vmsd = &vmstate_vmcoreinfo;
dc->realize = vmcoreinfo_realize;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ rc->phases.hold = vmcoreinfo_reset_hold;
}
-static const TypeInfo vmcoreinfo_device_info = {
- .name = VMCOREINFO_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(VMCoreInfoState),
- .class_init = vmcoreinfo_device_class_init,
+static const TypeInfo vmcoreinfo_types[] = {
+ {
+ .name = TYPE_VMCOREINFO,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VMCoreInfoState),
+ .class_init = vmcoreinfo_device_class_init,
+ }
};
-static void vmcoreinfo_register_types(void)
-{
- type_register_static(&vmcoreinfo_device_info);
-}
-
-type_init(vmcoreinfo_register_types)
+DEFINE_TYPES(vmcoreinfo_types)
diff --git a/hw/misc/xlnx-versal-cframe-reg.c b/hw/misc/xlnx-versal-cframe-reg.c
index 3fc838b..1ce083e 100644
--- a/hw/misc/xlnx-versal-cframe-reg.c
+++ b/hw/misc/xlnx-versal-cframe-reg.c
@@ -720,7 +720,7 @@ static const VMStateDescription vmstate_cframe_reg = {
}
};
-static Property cframe_regs_props[] = {
+static const Property cframe_regs_props[] = {
DEFINE_PROP_LINK("cfu-fdro", XlnxVersalCFrameReg, cfg.cfu_fdro,
TYPE_XLNX_CFI_IF, XlnxCfiIf *),
DEFINE_PROP_UINT32("blktype0-frames", XlnxVersalCFrameReg,
@@ -737,7 +737,6 @@ static Property cframe_regs_props[] = {
cfg.blktype_num_frames[5], 0),
DEFINE_PROP_UINT32("blktype6-frames", XlnxVersalCFrameReg,
cfg.blktype_num_frames[6], 0),
- DEFINE_PROP_END_OF_LIST(),
};
static void cframe_bcast_reg_init(Object *obj)
@@ -771,7 +770,7 @@ static const VMStateDescription vmstate_cframe_bcast_reg = {
}
};
-static Property cframe_bcast_regs_props[] = {
+static const Property cframe_bcast_regs_props[] = {
DEFINE_PROP_LINK("cframe0", XlnxVersalCFrameBcastReg, cfg.cframe[0],
TYPE_XLNX_CFI_IF, XlnxCfiIf *),
DEFINE_PROP_LINK("cframe1", XlnxVersalCFrameBcastReg, cfg.cframe[1],
@@ -802,10 +801,9 @@ static Property cframe_bcast_regs_props[] = {
TYPE_XLNX_CFI_IF, XlnxCfiIf *),
DEFINE_PROP_LINK("cframe14", XlnxVersalCFrameBcastReg, cfg.cframe[14],
TYPE_XLNX_CFI_IF, XlnxCfiIf *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cframe_reg_class_init(ObjectClass *klass, void *data)
+static void cframe_reg_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -819,7 +817,7 @@ static void cframe_reg_class_init(ObjectClass *klass, void *data)
xcic->cfi_transfer_packet = cframe_reg_cfi_transfer_packet;
}
-static void cframe_bcast_reg_class_init(ObjectClass *klass, void *data)
+static void cframe_bcast_reg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -835,7 +833,7 @@ static const TypeInfo cframe_reg_info = {
.instance_size = sizeof(XlnxVersalCFrameReg),
.class_init = cframe_reg_class_init,
.instance_init = cframe_reg_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XLNX_CFI_IF },
{ }
}
diff --git a/hw/misc/xlnx-versal-cfu.c b/hw/misc/xlnx-versal-cfu.c
index 6bb82e5..b920fc7 100644
--- a/hw/misc/xlnx-versal-cfu.c
+++ b/hw/misc/xlnx-versal-cfu.c
@@ -397,6 +397,13 @@ static void cfu_fdro_init(Object *obj)
fifo32_create(&s->fdro_data, 8 * KiB / sizeof(uint32_t));
}
+static void cfu_fdro_finalize(Object *obj)
+{
+ XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(obj);
+
+ fifo32_destroy(&s->fdro_data);
+}
+
static void cfu_fdro_reset_enter(Object *obj, ResetType type)
{
XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(obj);
@@ -419,7 +426,7 @@ static void cfu_fdro_cfi_transfer_packet(XlnxCfiIf *cfi_if, XlnxCfiPacket *pkt)
}
}
-static Property cfu_props[] = {
+static const Property cfu_props[] = {
DEFINE_PROP_LINK("cframe0", XlnxVersalCFUAPB, cfg.cframe[0],
TYPE_XLNX_CFI_IF, XlnxCfiIf *),
DEFINE_PROP_LINK("cframe1", XlnxVersalCFUAPB, cfg.cframe[1],
@@ -450,13 +457,11 @@ static Property cfu_props[] = {
TYPE_XLNX_CFI_IF, XlnxCfiIf *),
DEFINE_PROP_LINK("cframe14", XlnxVersalCFUAPB, cfg.cframe[14],
TYPE_XLNX_CFI_IF, XlnxCfiIf *),
- DEFINE_PROP_END_OF_LIST(),
};
-static Property cfu_sfr_props[] = {
+static const Property cfu_sfr_props[] = {
DEFINE_PROP_LINK("cfu", XlnxVersalCFUSFR, cfg.cfu,
TYPE_XLNX_VERSAL_CFU_APB, XlnxVersalCFUAPB *),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_cfu_apb = {
@@ -491,16 +496,16 @@ static const VMStateDescription vmstate_cfu_sfr = {
}
};
-static void cfu_apb_class_init(ObjectClass *klass, void *data)
+static void cfu_apb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = cfu_apb_reset;
+ device_class_set_legacy_reset(dc, cfu_apb_reset);
dc->vmsd = &vmstate_cfu_apb;
device_class_set_props(dc, cfu_props);
}
-static void cfu_fdro_class_init(ObjectClass *klass, void *data)
+static void cfu_fdro_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -511,7 +516,7 @@ static void cfu_fdro_class_init(ObjectClass *klass, void *data)
rc->phases.enter = cfu_fdro_reset_enter;
}
-static void cfu_sfr_class_init(ObjectClass *klass, void *data)
+static void cfu_sfr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -527,7 +532,7 @@ static const TypeInfo cfu_apb_info = {
.instance_size = sizeof(XlnxVersalCFUAPB),
.class_init = cfu_apb_class_init,
.instance_init = cfu_apb_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XLNX_CFI_IF },
{ }
}
@@ -539,7 +544,8 @@ static const TypeInfo cfu_fdro_info = {
.instance_size = sizeof(XlnxVersalCFUFDRO),
.class_init = cfu_fdro_class_init,
.instance_init = cfu_fdro_init,
- .interfaces = (InterfaceInfo[]) {
+ .instance_finalize = cfu_fdro_finalize,
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XLNX_CFI_IF },
{ }
}
diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c
index f143900..08ff2fc 100644
--- a/hw/misc/xlnx-versal-crl.c
+++ b/hw/misc/xlnx-versal-crl.c
@@ -394,7 +394,7 @@ static const VMStateDescription vmstate_crl = {
}
};
-static void crl_class_init(ObjectClass *klass, void *data)
+static void crl_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/xlnx-versal-pmc-iou-slcr.c b/hw/misc/xlnx-versal-pmc-iou-slcr.c
index e469c04..d76df46 100644
--- a/hw/misc/xlnx-versal-pmc-iou-slcr.c
+++ b/hw/misc/xlnx-versal-pmc-iou-slcr.c
@@ -1419,7 +1419,8 @@ static const VMStateDescription vmstate_pmc_iou_slcr = {
}
};
-static void xlnx_versal_pmc_iou_slcr_class_init(ObjectClass *klass, void *data)
+static void xlnx_versal_pmc_iou_slcr_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/misc/xlnx-versal-trng.c b/hw/misc/xlnx-versal-trng.c
index 51eb760..f34dd3e 100644
--- a/hw/misc/xlnx-versal-trng.c
+++ b/hw/misc/xlnx-versal-trng.c
@@ -608,9 +608,8 @@ static void trng_init(Object *obj)
{
XlnxVersalTRng *s = XLNX_VERSAL_TRNG(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), trng_regs_info,
ARRAY_SIZE(trng_regs_info),
s->regs_info, s->regs,
@@ -618,16 +617,17 @@ static void trng_init(Object *obj)
XLNX_VERSAL_TRNG_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq);
s->prng = g_rand_new();
}
-static void trng_unrealize(DeviceState *dev)
+static void trng_finalize(Object *obj)
{
- XlnxVersalTRng *s = XLNX_VERSAL_TRNG(dev);
+ XlnxVersalTRng *s = XLNX_VERSAL_TRNG(obj);
+ register_finalize_block(s->reg_array);
g_rand_free(s->prng);
s->prng = NULL;
}
@@ -641,7 +641,7 @@ static void trng_prop_fault_event_set(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *events = object_field_prop_ptr(obj, prop);
if (!visit_type_uint32(v, name, events, errp)) {
@@ -652,7 +652,7 @@ static void trng_prop_fault_event_set(Object *obj, Visitor *v,
}
static const PropertyInfo trng_prop_fault_events = {
- .name = "uint32:bits",
+ .type = "uint32",
.description = "Set to trigger TRNG fault events",
.set = trng_prop_fault_event_set,
.realized_set_allowed = true,
@@ -660,13 +660,12 @@ static const PropertyInfo trng_prop_fault_events = {
static PropertyInfo trng_prop_uint64; /* to extend qdev_prop_uint64 */
-static Property trng_props[] = {
- DEFINE_PROP_UINT64("forced-prng", XlnxVersalTRng, forced_prng_seed, 0),
+static const Property trng_props[] = {
+ DEFINE_PROP_UNSIGNED("forced-prng", XlnxVersalTRng, forced_prng_seed,
+ 0, trng_prop_uint64, uint64_t),
DEFINE_PROP_UINT32("hw-version", XlnxVersalTRng, hw_version, 0x0200),
DEFINE_PROP("fips-fault-events", XlnxVersalTRng, forced_faults,
trng_prop_fault_events, uint32_t),
-
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_trng = {
@@ -683,19 +682,17 @@ static const VMStateDescription vmstate_trng = {
}
};
-static void trng_class_init(ObjectClass *klass, void *data)
+static void trng_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->vmsd = &vmstate_trng;
- dc->unrealize = trng_unrealize;
rc->phases.hold = trng_reset_hold;
/* Clone uint64 property with set allowed after realized */
trng_prop_uint64 = qdev_prop_uint64;
trng_prop_uint64.realized_set_allowed = true;
- trng_props[0].info = &trng_prop_uint64;
device_class_set_props(dc, trng_props);
}
@@ -706,6 +703,7 @@ static const TypeInfo trng_info = {
.instance_size = sizeof(XlnxVersalTRng),
.class_init = trng_class_init,
.instance_init = trng_init,
+ .instance_finalize = trng_finalize,
};
static void trng_register_types(void)
diff --git a/hw/misc/xlnx-versal-xramc.c b/hw/misc/xlnx-versal-xramc.c
index ad839ce..07370b8 100644
--- a/hw/misc/xlnx-versal-xramc.c
+++ b/hw/misc/xlnx-versal-xramc.c
@@ -218,12 +218,11 @@ static const VMStateDescription vmstate_xram_ctrl = {
}
};
-static Property xram_ctrl_properties[] = {
+static const Property xram_ctrl_properties[] = {
DEFINE_PROP_UINT64("size", XlnxXramCtrl, cfg.size, 1 * MiB),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xram_ctrl_class_init(ObjectClass *klass, void *data)
+static void xram_ctrl_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/xlnx-zynqmp-apu-ctrl.c b/hw/misc/xlnx-zynqmp-apu-ctrl.c
index 87e4a14..e85da32 100644
--- a/hw/misc/xlnx-zynqmp-apu-ctrl.c
+++ b/hw/misc/xlnx-zynqmp-apu-ctrl.c
@@ -224,7 +224,7 @@ static const VMStateDescription vmstate_zynqmp_apu = {
}
};
-static void zynqmp_apu_class_init(ObjectClass *klass, void *data)
+static void zynqmp_apu_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/xlnx-zynqmp-crf.c b/hw/misc/xlnx-zynqmp-crf.c
index e5aba56..cccca0e 100644
--- a/hw/misc/xlnx-zynqmp-crf.c
+++ b/hw/misc/xlnx-zynqmp-crf.c
@@ -239,7 +239,7 @@ static const VMStateDescription vmstate_crf = {
}
};
-static void crf_class_init(ObjectClass *klass, void *data)
+static void crf_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
index ad814c3..010387b 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
@@ -623,12 +623,11 @@ static const VMStateDescription vmstate_zynq_slcr = {
}
};
-static Property zynq_slcr_props[] = {
+static const Property zynq_slcr_props[] = {
DEFINE_PROP_UINT8("boot-mode", ZynqSLCRState, boot_mode, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void zynq_slcr_class_init(ObjectClass *klass, void *data)
+static void zynq_slcr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
index 7fcc0d7..7f80218 100644
--- a/hw/net/Kconfig
+++ b/hw/net/Kconfig
@@ -62,8 +62,12 @@ config VMXNET3_PCI
config SMC91C111
bool
+config LAN9118_PHY
+ bool
+
config LAN9118
bool
+ select LAN9118_PHY
select PTIMER
config NE2000_ISA
@@ -89,6 +93,7 @@ config ALLWINNER_SUN8I_EMAC
config IMX_FEC
bool
+ select LAN9118_PHY
config CADENCE
bool
diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c
index 108ae9c..30a8157 100644
--- a/hw/net/allwinner-sun8i-emac.c
+++ b/hw/net/allwinner-sun8i-emac.c
@@ -30,7 +30,7 @@
#include "net/checksum.h"
#include "qemu/module.h"
#include "exec/cpu-common.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/net/allwinner-sun8i-emac.h"
/* EMAC register offsets */
@@ -784,7 +784,7 @@ static void allwinner_sun8i_emac_set_link(NetClientState *nc)
static const MemoryRegionOps allwinner_sun8i_emac_mem_ops = {
.read = allwinner_sun8i_emac_read,
.write = allwinner_sun8i_emac_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -829,12 +829,11 @@ static void allwinner_sun8i_emac_realize(DeviceState *dev, Error **errp)
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
}
-static Property allwinner_sun8i_emac_properties[] = {
+static const Property allwinner_sun8i_emac_properties[] = {
DEFINE_NIC_PROPERTIES(AwSun8iEmacState, conf),
DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState, mii_phy_addr, 0),
DEFINE_PROP_LINK("dma-memory", AwSun8iEmacState, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
static int allwinner_sun8i_emac_post_load(void *opaque, int version_id)
@@ -876,12 +875,13 @@ static const VMStateDescription vmstate_aw_emac = {
}
};
-static void allwinner_sun8i_emac_class_init(ObjectClass *klass, void *data)
+static void allwinner_sun8i_emac_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = allwinner_sun8i_emac_realize;
- dc->reset = allwinner_sun8i_emac_reset;
+ device_class_set_legacy_reset(dc, allwinner_sun8i_emac_reset);
dc->vmsd = &vmstate_aw_emac;
device_class_set_props(dc, allwinner_sun8i_emac_properties);
}
diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c
index d40ff37..77d089d 100644
--- a/hw/net/allwinner_emac.c
+++ b/hw/net/allwinner_emac.c
@@ -421,7 +421,7 @@ static void aw_emac_set_link(NetClientState *nc)
static const MemoryRegionOps aw_emac_mem_ops = {
.read = aw_emac_read,
.write = aw_emac_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -462,10 +462,9 @@ static void aw_emac_realize(DeviceState *dev, Error **errp)
fifo8_create(&s->tx_fifo[1], TX_FIFO_SIZE);
}
-static Property aw_emac_properties[] = {
+static const Property aw_emac_properties[] = {
DEFINE_NIC_PROPERTIES(AwEmacState, conf),
DEFINE_PROP_UINT8("phy-addr", AwEmacState, phy_addr, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_mii = {
@@ -515,13 +514,13 @@ static const VMStateDescription vmstate_aw_emac = {
}
};
-static void aw_emac_class_init(ObjectClass *klass, void *data)
+static void aw_emac_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aw_emac_realize;
device_class_set_props(dc, aw_emac_properties);
- dc->reset = aw_emac_reset;
+ device_class_set_legacy_reset(dc, aw_emac_reset);
dc->vmsd = &vmstate_aw_emac;
}
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index ec7bf56..50025d5 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -23,7 +23,7 @@
*/
#include "qemu/osdep.h"
-#include <zlib.h> /* For crc32 */
+#include <zlib.h> /* for crc32 */
#include "hw/irq.h"
#include "hw/net/cadence_gem.h"
@@ -33,7 +33,7 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "net/checksum.h"
#include "net/eth.h"
@@ -909,8 +909,8 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
/* Compare A, B, C */
for (j = 0; j < 3; j++) {
- uint32_t cr0, cr1, mask, compare;
- uint16_t rx_cmp;
+ uint32_t cr0, cr1, mask, compare, disable_mask;
+ uint32_t rx_cmp;
int offset;
int cr_idx = extract32(reg, R_SCREENING_TYPE2_REG0_COMPARE_A_SHIFT + j * 6,
R_SCREENING_TYPE2_REG0_COMPARE_A_LENGTH);
@@ -946,9 +946,25 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
break;
}
- rx_cmp = rxbuf_ptr[offset] << 8 | rxbuf_ptr[offset];
- mask = FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, MASK_VALUE);
- compare = FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, COMPARE_VALUE);
+ disable_mask =
+ FIELD_EX32(cr1, TYPE2_COMPARE_0_WORD_1, DISABLE_MASK);
+ if (disable_mask) {
+ /*
+ * If disable_mask is set, mask_value is used as an
+ * additional 2 byte Compare Value; that is equivalent
+ * to using the whole cr0 register as the comparison value.
+ * Load 32 bits of data from rx_buf, and set mask to
+ * all-ones so we compare all 32 bits.
+ */
+ rx_cmp = ldl_le_p(rxbuf_ptr + offset);
+ mask = 0xFFFFFFFF;
+ compare = cr0;
+ } else {
+ rx_cmp = lduw_le_p(rxbuf_ptr + offset);
+ mask = FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, MASK_VALUE);
+ compare =
+ FIELD_EX32(cr0, TYPE2_COMPARE_0_WORD_0, COMPARE_VALUE);
+ }
if ((rx_cmp & mask) == (compare & mask)) {
matched = true;
@@ -1784,7 +1800,7 @@ static const VMStateDescription vmstate_cadence_gem = {
}
};
-static Property gem_properties[] = {
+static const Property gem_properties[] = {
DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
DEFINE_PROP_UINT32("revision", CadenceGEMState, revision,
GEM_MODID_VALUE),
@@ -1799,17 +1815,16 @@ static Property gem_properties[] = {
jumbo_max_len, 10240),
DEFINE_PROP_LINK("dma", CadenceGEMState, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void gem_class_init(ObjectClass *klass, void *data)
+static void gem_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = gem_realize;
device_class_set_props(dc, gem_properties);
dc->vmsd = &vmstate_cadence_gem;
- dc->reset = gem_reset;
+ device_class_set_legacy_reset(dc, gem_reset);
}
static const TypeInfo gem_info = {
diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c
index bf41e6b..be16769 100644
--- a/hw/net/can/can_kvaser_pci.c
+++ b/hw/net/can/can_kvaser_pci.c
@@ -30,12 +30,8 @@
*/
#include "qemu/osdep.h"
-#include "qemu/event_notifier.h"
#include "qemu/module.h"
-#include "qemu/thread.h"
-#include "qemu/sockets.h"
#include "qapi/error.h"
-#include "chardev/char.h"
#include "hw/irq.h"
#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
@@ -286,7 +282,7 @@ static void kvaser_pci_instance_init(Object *obj)
0);
}
-static void kvaser_pci_class_init(ObjectClass *klass, void *data)
+static void kvaser_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -299,7 +295,7 @@ static void kvaser_pci_class_init(ObjectClass *klass, void *data)
k->class_id = 0x00ff00;
dc->desc = "Kvaser PCICANx";
dc->vmsd = &vmstate_kvaser_pci;
- dc->reset = kvaser_pci_reset;
+ device_class_set_legacy_reset(dc, kvaser_pci_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
@@ -309,7 +305,7 @@ static const TypeInfo kvaser_pci_info = {
.instance_size = sizeof(KvaserPCIState),
.class_init = kvaser_pci_class_init,
.instance_init = kvaser_pci_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c
index 308b17e..44f3ba3 100644
--- a/hw/net/can/can_mioe3680_pci.c
+++ b/hw/net/can/can_mioe3680_pci.c
@@ -26,12 +26,8 @@
*/
#include "qemu/osdep.h"
-#include "qemu/event_notifier.h"
#include "qemu/module.h"
-#include "qemu/thread.h"
-#include "qemu/sockets.h"
#include "qapi/error.h"
-#include "chardev/char.h"
#include "hw/irq.h"
#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
@@ -227,7 +223,7 @@ static void mioe3680_pci_instance_init(Object *obj)
0);
}
-static void mioe3680_pci_class_init(ObjectClass *klass, void *data)
+static void mioe3680_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -243,7 +239,7 @@ static void mioe3680_pci_class_init(ObjectClass *klass, void *data)
dc->desc = "Mioe3680 PCICANx";
dc->vmsd = &vmstate_mioe3680_pci;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = mioe3680_pci_reset;
+ device_class_set_legacy_reset(dc, mioe3680_pci_reset);
}
static const TypeInfo mioe3680_pci_info = {
@@ -252,7 +248,7 @@ static const TypeInfo mioe3680_pci_info = {
.instance_size = sizeof(Mioe3680PCIState),
.class_init = mioe3680_pci_class_init,
.instance_init = mioe3680_pci_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c
index e4c8d93..7296d63 100644
--- a/hw/net/can/can_pcm3680_pci.c
+++ b/hw/net/can/can_pcm3680_pci.c
@@ -26,12 +26,8 @@
*/
#include "qemu/osdep.h"
-#include "qemu/event_notifier.h"
#include "qemu/module.h"
-#include "qemu/thread.h"
-#include "qemu/sockets.h"
#include "qapi/error.h"
-#include "chardev/char.h"
#include "hw/irq.h"
#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
@@ -228,7 +224,7 @@ static void pcm3680i_pci_instance_init(Object *obj)
0);
}
-static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
+static void pcm3680i_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -244,7 +240,7 @@ static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
dc->desc = "Pcm3680i PCICANx";
dc->vmsd = &vmstate_pcm3680i_pci;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = pcm3680i_pci_reset;
+ device_class_set_legacy_reset(dc, pcm3680i_pci_reset);
}
static const TypeInfo pcm3680i_pci_info = {
@@ -253,7 +249,7 @@ static const TypeInfo pcm3680i_pci_info = {
.instance_size = sizeof(Pcm3680iPCIState),
.class_init = pcm3680i_pci_class_init,
.instance_init = pcm3680i_pci_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c
index 6694d7b..5b6ba9d 100644
--- a/hw/net/can/can_sja1000.c
+++ b/hw/net/can/can_sja1000.c
@@ -27,7 +27,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
-#include "chardev/char.h"
+#include "qemu/bitops.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "net/can_emu.h"
diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c
index 812b83e..17131a4 100644
--- a/hw/net/can/ctucan_core.c
+++ b/hw/net/can/ctucan_core.c
@@ -28,7 +28,8 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
-#include "chardev/char.h"
+#include "qemu/bswap.h"
+#include "qemu/bitops.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "net/can_emu.h"
@@ -399,8 +400,6 @@ void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
ctucan_update_irq(s);
}
-
- return;
}
uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size)
diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c
index d8f7344d..bed6785 100644
--- a/hw/net/can/ctucan_pci.c
+++ b/hw/net/can/ctucan_pci.c
@@ -27,12 +27,8 @@
*/
#include "qemu/osdep.h"
-#include "qemu/event_notifier.h"
#include "qemu/module.h"
-#include "qemu/thread.h"
-#include "qemu/sockets.h"
#include "qapi/error.h"
-#include "chardev/char.h"
#include "hw/irq.h"
#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
@@ -241,7 +237,7 @@ static void ctucan_pci_instance_init(Object *obj)
#endif
}
-static void ctucan_pci_class_init(ObjectClass *klass, void *data)
+static void ctucan_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -257,7 +253,7 @@ static void ctucan_pci_class_init(ObjectClass *klass, void *data)
dc->desc = "CTU CAN PCI";
dc->vmsd = &vmstate_ctucan_pci;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = ctucan_pci_reset;
+ device_class_set_legacy_reset(dc, ctucan_pci_reset);
}
static const TypeInfo ctucan_pci_info = {
@@ -266,7 +262,7 @@ static const TypeInfo ctucan_pci_info = {
.instance_size = sizeof(CtuCanPCIState),
.class_init = ctucan_pci_class_init,
.instance_init = ctucan_pci_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c
index 5f083c2..3eb1119 100644
--- a/hw/net/can/xlnx-versal-canfd.c
+++ b/hw/net/can/xlnx-versal-canfd.c
@@ -678,12 +678,10 @@ REG32(RB_DW15_REGISTER_1, 0x4144)
FIELD(RB_DW15_REGISTER_1, DATA_BYTES62, 8, 8)
FIELD(RB_DW15_REGISTER_1, DATA_BYTES63, 0, 8)
-static uint8_t canfd_dlc_array[8] = {8, 12, 16, 20, 24, 32, 48, 64};
-
static void canfd_update_irq(XlnxVersalCANFDState *s)
{
- unsigned int irq = s->regs[R_INTERRUPT_STATUS_REGISTER] &
- s->regs[R_INTERRUPT_ENABLE_REGISTER];
+ const bool irq = (s->regs[R_INTERRUPT_STATUS_REGISTER] &
+ s->regs[R_INTERRUPT_ENABLE_REGISTER]) != 0;
g_autofree char *path = object_get_canonical_path(OBJECT(s));
/* RX watermark interrupts. */
@@ -869,6 +867,10 @@ static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame,
uint32_t val = 0;
uint32_t dlc_reg_val = 0;
uint32_t dlc_value = 0;
+ uint32_t id_reg_val = 0;
+ bool is_rtr = false;
+
+ frame->flags = 0;
/* Check that reg_num should be within TX register space. */
assert(reg_num <= R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE *
@@ -877,56 +879,37 @@ static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame,
dlc_reg_val = s->regs[reg_num + 1];
dlc_value = FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, DLC);
- frame->can_id = s->regs[reg_num];
+ id_reg_val = s->regs[reg_num];
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, IDE)) {
+ frame->can_id = (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID) << 18) |
+ (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID_EXT)) |
+ QEMU_CAN_EFF_FLAG;
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, RTR_RRS)) {
+ is_rtr = true;
+ }
+ } else {
+ frame->can_id = FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID);
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, SRR_RTR_RRS)) {
+ is_rtr = true;
+ }
+ }
if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, FDF)) {
- /*
- * CANFD frame.
- * Converting dlc(0 to 15) 4 Byte data to plain length(i.e. 0 to 64)
- * 1 Byte data. This is done to make it work with SocketCAN.
- * On actual CANFD frame, this value can't be more than 0xF.
- * Conversion table for DLC to plain length:
- *
- * DLC Plain Length
- * 0 - 8 0 - 8
- * 9 9 - 12
- * 10 13 - 16
- * 11 17 - 20
- * 12 21 - 24
- * 13 25 - 32
- * 14 33 - 48
- * 15 49 - 64
- */
-
- frame->flags = QEMU_CAN_FRMF_TYPE_FD;
+ frame->flags |= QEMU_CAN_FRMF_TYPE_FD;
- if (dlc_value < 8) {
- frame->can_dlc = dlc_value;
- } else {
- assert((dlc_value - 8) < ARRAY_SIZE(canfd_dlc_array));
- frame->can_dlc = canfd_dlc_array[dlc_value - 8];
+ if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, BRS)) {
+ frame->flags |= QEMU_CAN_FRMF_BRS;
}
} else {
- /*
- * FD Format bit not set that means it is a CAN Frame.
- * Conversion table for classic CAN:
- *
- * DLC Plain Length
- * 0 - 7 0 - 7
- * 8 - 15 8
- */
-
- if (dlc_value > 8) {
- frame->can_dlc = 8;
- qemu_log_mask(LOG_GUEST_ERROR, "Maximum DLC value for Classic CAN"
- " frame is 8. Only 8 byte data will be sent.\n");
- } else {
- frame->can_dlc = dlc_value;
+ if (is_rtr) {
+ frame->can_id |= QEMU_CAN_RTR_FLAG;
}
}
+ frame->can_dlc = can_dlc2len(dlc_value);
+
for (j = 0; j < frame->can_dlc; j++) {
- val = 8 * i;
+ val = 8 * (3 - i);
frame->data[j] = extract32(s->regs[reg_num + 2 + (j / 4)], val, 8);
i++;
@@ -948,6 +931,33 @@ static void process_cancellation_requests(XlnxVersalCANFDState *s)
canfd_update_irq(s);
}
+static uint32_t frame_to_reg_id(const qemu_can_frame *frame)
+{
+ uint32_t id_reg_val = 0;
+ const bool is_canfd_frame = frame->flags & QEMU_CAN_FRMF_TYPE_FD;
+ const bool is_rtr = !is_canfd_frame && (frame->can_id & QEMU_CAN_RTR_FLAG);
+
+ if (frame->can_id & QEMU_CAN_EFF_FLAG) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID,
+ (frame->can_id & QEMU_CAN_EFF_MASK) >> 18);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID_EXT,
+ frame->can_id & QEMU_CAN_EFF_MASK);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, IDE, 1);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1);
+ if (is_rtr) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, RTR_RRS, 1);
+ }
+ } else {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID,
+ frame->can_id & QEMU_CAN_SFF_MASK);
+ if (is_rtr) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1);
+ }
+ }
+
+ return id_reg_val;
+}
+
static void store_rx_sequential(XlnxVersalCANFDState *s,
const qemu_can_frame *frame,
uint32_t fill_level, uint32_t read_index,
@@ -955,7 +965,6 @@ static void store_rx_sequential(XlnxVersalCANFDState *s,
bool rx_fifo_id, uint8_t filter_index)
{
int i;
- bool is_canfd_frame;
uint8_t dlc = frame->can_dlc;
uint8_t rx_reg_num = 0;
uint32_t dlc_reg_val = 0;
@@ -999,30 +1008,21 @@ static void store_rx_sequential(XlnxVersalCANFDState *s,
NUM_REGS_PER_MSG_SPACE));
}
- s->regs[store_location] = frame->can_id;
+ s->regs[store_location] = frame_to_reg_id(frame);
- dlc = frame->can_dlc;
+ dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, can_len2dlc(dlc));
- if (frame->flags == QEMU_CAN_FRMF_TYPE_FD) {
- is_canfd_frame = true;
+ if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) {
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, 1);
- /* Store dlc value in Xilinx specific format. */
- for (i = 0; i < ARRAY_SIZE(canfd_dlc_array); i++) {
- if (canfd_dlc_array[i] == frame->can_dlc) {
- dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, 8 + i);
- }
+ if (frame->flags & QEMU_CAN_FRMF_BRS) {
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, BRS, 1);
}
- } else {
- is_canfd_frame = false;
-
- if (frame->can_dlc > 8) {
- dlc = 8;
+ if (frame->flags & QEMU_CAN_FRMF_ESI) {
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, ESI, 1);
}
-
- dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, dlc);
}
- dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, is_canfd_frame);
dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, TIMESTAMP, rx_timestamp);
dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, MATCHED_FILTER_INDEX,
filter_index);
@@ -1034,19 +1034,19 @@ static void store_rx_sequential(XlnxVersalCANFDState *s,
case 0:
rx_reg_num = i / 4;
- data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3,
+ data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0,
frame->data[i]);
break;
case 1:
- data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2,
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1,
frame->data[i]);
break;
case 2:
- data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1,
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2,
frame->data[i]);
break;
case 3:
- data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0,
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3,
frame->data[i]);
/*
* Last Bytes data which means we have all 4 bytes ready to
@@ -1090,11 +1090,12 @@ static void update_rx_sequential(XlnxVersalCANFDState *s,
if (s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER]) {
uint32_t acceptance_filter_status =
s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER];
+ const uint32_t reg_id = frame_to_reg_id(frame);
for (i = 0; i < 32; i++) {
if (acceptance_filter_status & 0x1) {
uint32_t msg_id_masked = s->regs[R_AFMR_REGISTER + 2 * i] &
- frame->can_id;
+ reg_id;
uint32_t afir_id_masked = s->regs[R_AFIR_REGISTER + 2 * i] &
s->regs[R_AFMR_REGISTER + 2 * i];
uint16_t std_msg_id_masked = FIELD_EX32(msg_id_masked,
@@ -1143,18 +1144,8 @@ static void update_rx_sequential(XlnxVersalCANFDState *s,
read_index = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, RI);
store_index = read_index + fill_level;
- if (read_index == s->cfg.rx0_fifo - 1) {
- /*
- * When ri is s->cfg.rx0_fifo - 1 i.e. max, it goes cyclic that
- * means we reset the ri to 0x0.
- */
- read_index = 0;
- ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI,
- read_index);
- }
-
if (store_index > s->cfg.rx0_fifo - 1) {
- store_index -= s->cfg.rx0_fifo - 1;
+ store_index -= s->cfg.rx0_fifo;
}
store_location = R_RB_ID_REGISTER +
@@ -1171,18 +1162,8 @@ static void update_rx_sequential(XlnxVersalCANFDState *s,
RI_1);
store_index = read_index + fill_level;
- if (read_index == s->cfg.rx1_fifo - 1) {
- /*
- * When ri is s->cfg.rx1_fifo - 1 i.e. max, it goes cyclic that
- * means we reset the ri to 0x0.
- */
- read_index = 0;
- ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI_1,
- read_index);
- }
-
if (store_index > s->cfg.rx1_fifo - 1) {
- store_index -= s->cfg.rx1_fifo - 1;
+ store_index -= s->cfg.rx1_fifo;
}
store_location = R_RB_ID_REGISTER_1 +
@@ -1264,18 +1245,8 @@ static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid)
" Discarding the message\n");
ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXEOFLW, 1);
} else {
- if (read_index == s->cfg.tx_fifo - 1) {
- /*
- * When ri is s->cfg.tx_fifo - 1 i.e. max, it goes cyclic that
- * means we reset the ri to 0x0.
- */
- read_index = 0;
- ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI,
- read_index);
- }
-
if (store_index > s->cfg.tx_fifo - 1) {
- store_index -= s->cfg.tx_fifo - 1;
+ store_index -= s->cfg.tx_fifo;
}
assert(store_index < s->cfg.tx_fifo);
@@ -1307,7 +1278,7 @@ static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid)
}
}
-static gint g_cmp_ids(gconstpointer data1, gconstpointer data2)
+static gint g_cmp_ids(gconstpointer data1, gconstpointer data2, gpointer d)
{
tx_ready_reg_info *tx_reg_1 = (tx_ready_reg_info *) data1;
tx_ready_reg_info *tx_reg_2 = (tx_ready_reg_info *) data2;
@@ -1327,8 +1298,6 @@ static void free_list(GSList *list)
}
g_slist_free(list);
-
- return;
}
static GSList *prepare_tx_data(XlnxVersalCANFDState *s)
@@ -1347,7 +1316,7 @@ static GSList *prepare_tx_data(XlnxVersalCANFDState *s)
temp->can_id = s->regs[reg_num];
temp->reg_num = reg_num;
list = g_slist_prepend(list, temp);
- list = g_slist_sort(list, g_cmp_ids);
+ list = g_slist_sort_with_data(list, g_cmp_ids, NULL);
}
reg_ready >>= 1;
@@ -2071,7 +2040,7 @@ static const VMStateDescription vmstate_canfd = {
}
};
-static Property canfd_core_properties[] = {
+static const Property canfd_core_properties[] = {
DEFINE_PROP_UINT8("rx-fifo0", XlnxVersalCANFDState, cfg.rx0_fifo, 0x40),
DEFINE_PROP_UINT8("rx-fifo1", XlnxVersalCANFDState, cfg.rx1_fifo, 0x40),
DEFINE_PROP_UINT8("tx-fifo", XlnxVersalCANFDState, cfg.tx_fifo, 0x20),
@@ -2081,14 +2050,13 @@ static Property canfd_core_properties[] = {
CANFD_DEFAULT_CLOCK),
DEFINE_PROP_LINK("canfdbus", XlnxVersalCANFDState, canfdbus, TYPE_CAN_BUS,
CanBusState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void canfd_class_init(ObjectClass *klass, void *data)
+static void canfd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = canfd_reset;
+ device_class_set_legacy_reset(dc, canfd_reset);
dc->realize = canfd_realize;
device_class_set_props(dc, canfd_core_properties);
dc->vmsd = &vmstate_canfd;
diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c
index 58f1432..ca9edd4 100644
--- a/hw/net/can/xlnx-zynqmp-can.c
+++ b/hw/net/can/xlnx-zynqmp-can.c
@@ -1169,15 +1169,14 @@ static const VMStateDescription vmstate_can = {
}
};
-static Property xlnx_zynqmp_can_properties[] = {
+static const Property xlnx_zynqmp_can_properties[] = {
DEFINE_PROP_UINT32("ext_clk_freq", XlnxZynqMPCANState, cfg.ext_clk_freq,
CAN_DEFAULT_CLOCK),
DEFINE_PROP_LINK("canbus", XlnxZynqMPCANState, canbus, TYPE_CAN_BUS,
CanBusState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xlnx_zynqmp_can_class_init(ObjectClass *klass, void *data)
+static void xlnx_zynqmp_can_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index bf0652d..d490320 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -27,7 +27,7 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/timer.h"
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
#include "trace.h"
@@ -931,22 +931,21 @@ static const VMStateDescription vmstate_dp8393x = {
}
};
-static Property dp8393x_properties[] = {
+static const Property dp8393x_properties[] = {
DEFINE_NIC_PROPERTIES(dp8393xState, conf),
DEFINE_PROP_LINK("dma_mr", dp8393xState, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0),
DEFINE_PROP_BOOL("big_endian", dp8393xState, big_endian, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void dp8393x_class_init(ObjectClass *klass, void *data)
+static void dp8393x_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = dp8393x_realize;
- dc->reset = dp8393x_reset;
+ device_class_set_legacy_reset(dc, dp8393x_reset);
dc->vmsd = &vmstate_dp8393x;
device_class_set_props(dc, dp8393x_properties);
}
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 5012b96..a80a7b0 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -33,8 +33,8 @@
#include "net/eth.h"
#include "net/net.h"
#include "net/checksum.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
+#include "system/system.h"
+#include "system/dma.h"
#include "qemu/iov.h"
#include "qemu/module.h"
#include "qemu/range.h"
@@ -127,10 +127,8 @@ struct E1000State_st {
QEMUTimer *flush_queue_timer;
/* Compatibility flags for migration to/from qemu 1.3.0 and older */
-#define E1000_FLAG_MAC_BIT 2
#define E1000_FLAG_TSO_BIT 3
#define E1000_FLAG_VET_BIT 4
-#define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT)
#define E1000_FLAG_TSO (1 << E1000_FLAG_TSO_BIT)
#define E1000_FLAG_VET (1 << E1000_FLAG_VET_BIT)
@@ -1212,52 +1210,51 @@ enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 };
-#define markflag(x) ((E1000_FLAG_##x << 2) | MAC_ACCESS_FLAG_NEEDED)
/* In the array below the meaning of the bits is: [f|f|f|f|f|f|n|p]
* f - flag bits (up to 6 possible flags)
* n - flag needed
- * p - partially implenented */
+ * p - partially implemented */
static const uint8_t mac_reg_access[0x8000] = {
- [IPAV] = markflag(MAC), [WUC] = markflag(MAC),
- [IP6AT] = markflag(MAC), [IP4AT] = markflag(MAC),
- [FFVT] = markflag(MAC), [WUPM] = markflag(MAC),
- [ECOL] = markflag(MAC), [MCC] = markflag(MAC),
- [DC] = markflag(MAC), [TNCRS] = markflag(MAC),
- [RLEC] = markflag(MAC), [XONRXC] = markflag(MAC),
- [XOFFTXC] = markflag(MAC), [RFC] = markflag(MAC),
- [TSCTFC] = markflag(MAC), [MGTPRC] = markflag(MAC),
- [WUS] = markflag(MAC), [AIT] = markflag(MAC),
- [FFLT] = markflag(MAC), [FFMT] = markflag(MAC),
- [SCC] = markflag(MAC), [FCRUC] = markflag(MAC),
- [LATECOL] = markflag(MAC), [COLC] = markflag(MAC),
- [SEQEC] = markflag(MAC), [CEXTERR] = markflag(MAC),
- [XONTXC] = markflag(MAC), [XOFFRXC] = markflag(MAC),
- [RJC] = markflag(MAC), [RNBC] = markflag(MAC),
- [MGTPDC] = markflag(MAC), [MGTPTC] = markflag(MAC),
- [RUC] = markflag(MAC), [ROC] = markflag(MAC),
- [GORCL] = markflag(MAC), [GORCH] = markflag(MAC),
- [GOTCL] = markflag(MAC), [GOTCH] = markflag(MAC),
- [BPRC] = markflag(MAC), [MPRC] = markflag(MAC),
- [TSCTC] = markflag(MAC), [PRC64] = markflag(MAC),
- [PRC127] = markflag(MAC), [PRC255] = markflag(MAC),
- [PRC511] = markflag(MAC), [PRC1023] = markflag(MAC),
- [PRC1522] = markflag(MAC), [PTC64] = markflag(MAC),
- [PTC127] = markflag(MAC), [PTC255] = markflag(MAC),
- [PTC511] = markflag(MAC), [PTC1023] = markflag(MAC),
- [PTC1522] = markflag(MAC), [MPTC] = markflag(MAC),
- [BPTC] = markflag(MAC),
-
- [TDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [TDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [RDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
- [PBM] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [IPAV] = MAC_ACCESS_FLAG_NEEDED, [WUC] = MAC_ACCESS_FLAG_NEEDED,
+ [IP6AT] = MAC_ACCESS_FLAG_NEEDED, [IP4AT] = MAC_ACCESS_FLAG_NEEDED,
+ [FFVT] = MAC_ACCESS_FLAG_NEEDED, [WUPM] = MAC_ACCESS_FLAG_NEEDED,
+ [ECOL] = MAC_ACCESS_FLAG_NEEDED, [MCC] = MAC_ACCESS_FLAG_NEEDED,
+ [DC] = MAC_ACCESS_FLAG_NEEDED, [TNCRS] = MAC_ACCESS_FLAG_NEEDED,
+ [RLEC] = MAC_ACCESS_FLAG_NEEDED, [XONRXC] = MAC_ACCESS_FLAG_NEEDED,
+ [XOFFTXC] = MAC_ACCESS_FLAG_NEEDED, [RFC] = MAC_ACCESS_FLAG_NEEDED,
+ [TSCTFC] = MAC_ACCESS_FLAG_NEEDED, [MGTPRC] = MAC_ACCESS_FLAG_NEEDED,
+ [WUS] = MAC_ACCESS_FLAG_NEEDED, [AIT] = MAC_ACCESS_FLAG_NEEDED,
+ [FFLT] = MAC_ACCESS_FLAG_NEEDED, [FFMT] = MAC_ACCESS_FLAG_NEEDED,
+ [SCC] = MAC_ACCESS_FLAG_NEEDED, [FCRUC] = MAC_ACCESS_FLAG_NEEDED,
+ [LATECOL] = MAC_ACCESS_FLAG_NEEDED, [COLC] = MAC_ACCESS_FLAG_NEEDED,
+ [SEQEC] = MAC_ACCESS_FLAG_NEEDED, [CEXTERR] = MAC_ACCESS_FLAG_NEEDED,
+ [XONTXC] = MAC_ACCESS_FLAG_NEEDED, [XOFFRXC] = MAC_ACCESS_FLAG_NEEDED,
+ [RJC] = MAC_ACCESS_FLAG_NEEDED, [RNBC] = MAC_ACCESS_FLAG_NEEDED,
+ [MGTPDC] = MAC_ACCESS_FLAG_NEEDED, [MGTPTC] = MAC_ACCESS_FLAG_NEEDED,
+ [RUC] = MAC_ACCESS_FLAG_NEEDED, [ROC] = MAC_ACCESS_FLAG_NEEDED,
+ [GORCL] = MAC_ACCESS_FLAG_NEEDED, [GORCH] = MAC_ACCESS_FLAG_NEEDED,
+ [GOTCL] = MAC_ACCESS_FLAG_NEEDED, [GOTCH] = MAC_ACCESS_FLAG_NEEDED,
+ [BPRC] = MAC_ACCESS_FLAG_NEEDED, [MPRC] = MAC_ACCESS_FLAG_NEEDED,
+ [TSCTC] = MAC_ACCESS_FLAG_NEEDED, [PRC64] = MAC_ACCESS_FLAG_NEEDED,
+ [PRC127] = MAC_ACCESS_FLAG_NEEDED, [PRC255] = MAC_ACCESS_FLAG_NEEDED,
+ [PRC511] = MAC_ACCESS_FLAG_NEEDED, [PRC1023] = MAC_ACCESS_FLAG_NEEDED,
+ [PRC1522] = MAC_ACCESS_FLAG_NEEDED, [PTC64] = MAC_ACCESS_FLAG_NEEDED,
+ [PTC127] = MAC_ACCESS_FLAG_NEEDED, [PTC255] = MAC_ACCESS_FLAG_NEEDED,
+ [PTC511] = MAC_ACCESS_FLAG_NEEDED, [PTC1023] = MAC_ACCESS_FLAG_NEEDED,
+ [PTC1522] = MAC_ACCESS_FLAG_NEEDED, [MPTC] = MAC_ACCESS_FLAG_NEEDED,
+ [BPTC] = MAC_ACCESS_FLAG_NEEDED,
+
+ [TDFH] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [TDFT] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [TDFHS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [TDFTS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [TDFPC] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [RDFH] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [RDFT] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [RDFHS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [RDFTS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [RDFPC] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
+ [PBM] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL,
};
static void
@@ -1419,13 +1416,6 @@ static int e1000_tx_tso_post_load(void *opaque, int version_id)
return 0;
}
-static bool e1000_full_mac_needed(void *opaque)
-{
- E1000State *s = opaque;
-
- return chkflag(MAC);
-}
-
static bool e1000_tso_state_needed(void *opaque)
{
E1000State *s = opaque;
@@ -1451,7 +1441,6 @@ static const VMStateDescription vmstate_e1000_full_mac_state = {
.name = "e1000/full_mac_state",
.version_id = 1,
.minimum_version_id = 1,
- .needed = e1000_full_mac_needed,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(mac_reg, E1000State, 0x8000),
VMSTATE_END_OF_LIST()
@@ -1677,15 +1666,12 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp)
e1000_flush_queue_timer, d);
}
-static Property e1000_properties[] = {
+static const Property e1000_properties[] = {
DEFINE_NIC_PROPERTIES(E1000State, conf),
- DEFINE_PROP_BIT("extra_mac_registers", E1000State,
- compat_flags, E1000_FLAG_MAC_BIT, true),
DEFINE_PROP_BIT("migrate_tso_props", E1000State,
compat_flags, E1000_FLAG_TSO_BIT, true),
DEFINE_PROP_BIT("init-vet", E1000State,
compat_flags, E1000_FLAG_VET_BIT, true),
- DEFINE_PROP_END_OF_LIST(),
};
typedef struct E1000Info {
@@ -1695,7 +1681,7 @@ typedef struct E1000Info {
uint16_t phy_id2;
} E1000Info;
-static void e1000_class_init(ObjectClass *klass, void *data)
+static void e1000_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -1733,7 +1719,7 @@ static const TypeInfo e1000_base_info = {
.instance_init = e1000_instance_init,
.class_size = sizeof(E1000BaseClass),
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -1771,10 +1757,10 @@ static void e1000_register_types(void)
type_info.name = info->name;
type_info.parent = TYPE_E1000_BASE;
- type_info.class_data = (void *)info;
+ type_info.class_data = info;
type_info.class_init = e1000_class_init;
- type_register(&type_info);
+ type_register_static(&type_info);
}
}
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index 843892c..89e6d52 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -40,7 +40,7 @@
#include "net/tap.h"
#include "qemu/module.h"
#include "qemu/range.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/hw.h"
#include "hw/net/mii.h"
#include "hw/pci/msi.h"
@@ -372,8 +372,7 @@ static int
e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
{
Error *local_err = NULL;
- int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset,
- PCI_PM_SIZEOF, &local_err);
+ int ret = pci_pm_init(pdev, offset, &local_err);
if (local_err) {
error_report_err(local_err);
@@ -661,7 +660,7 @@ static PropertyInfo e1000e_prop_disable_vnet,
e1000e_prop_subsys_ven,
e1000e_prop_subsys;
-static Property e1000e_properties[] = {
+static const Property e1000e_properties[] = {
DEFINE_NIC_PROPERTIES(E1000EState, conf),
DEFINE_PROP_SIGNED("disable_vnet_hdr", E1000EState, disable_vnet, false,
e1000e_prop_disable_vnet, bool),
@@ -672,10 +671,9 @@ static Property e1000e_properties[] = {
e1000e_prop_subsys, uint16_t),
DEFINE_PROP_BOOL("init-vet", E1000EState, init_vet, true),
DEFINE_PROP_BOOL("migrate-timadj", E1000EState, timadj, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void e1000e_class_init(ObjectClass *class, void *data)
+static void e1000e_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
ResettableClass *rc = RESETTABLE_CLASS(class);
@@ -723,7 +721,7 @@ static const TypeInfo e1000e_info = {
.instance_size = sizeof(E1000EState),
.class_init = e1000e_class_init,
.instance_init = e1000e_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index 3ae2a18..2413858 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -40,7 +40,7 @@
#include "hw/net/mii.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "net_tx_pkt.h"
#include "net_rx_pkt.h"
@@ -561,8 +561,7 @@ e1000e_rss_calc_hash(E1000ECore *core,
type = NetPktRssIpV6Ex;
break;
default:
- assert(false);
- return 0;
+ g_assert_not_reached();
}
return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]);
@@ -841,7 +840,6 @@ e1000e_ring_free_descr_num(E1000ECore *core, const E1000ERingInfo *r)
}
g_assert_not_reached();
- return 0;
}
static inline bool
diff --git a/hw/net/e1000x_regs.h b/hw/net/e1000x_regs.h
index cd896fc..e9a74de 100644
--- a/hw/net/e1000x_regs.h
+++ b/hw/net/e1000x_regs.h
@@ -900,7 +900,7 @@ struct e1000_context_desc {
uint16_t tucse; /* TCP checksum end */
} tcp_fields;
} upper_setup;
- uint32_t cmd_and_length; /* */
+ uint32_t cmd_and_length;
union {
uint32_t data;
struct {
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index d9a70c4..d47df5a 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -6,10 +6,12 @@
* Portions of the code are copies from grub / etherboot eepro100.c
* and linux e100.c.
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
- * (at your option) version 3 or any later version.
+ * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -48,9 +50,9 @@
#include "net/net.h"
#include "net/eth.h"
#include "hw/nvram/eeprom93xx.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-#include "sysemu/reset.h"
+#include "system/system.h"
+#include "system/dma.h"
+#include "system/reset.h"
#include "qemu/bitops.h"
#include "qemu/module.h"
#include "qapi/error.h"
@@ -549,9 +551,7 @@ static void e100_pci_reset(EEPRO100State *s, Error **errp)
if (info->power_management) {
/* Power Management Capabilities */
int cfg_offset = 0xdc;
- int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
- cfg_offset, PCI_PM_SIZEOF,
- errp);
+ int r = pci_pm_init(&s->dev, cfg_offset, errp);
if (r < 0) {
return;
}
@@ -2056,12 +2056,11 @@ static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
}
-static Property e100_properties[] = {
+static const Property e100_properties[] = {
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void eepro100_class_init(ObjectClass *klass, void *data)
+static void eepro100_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -2095,12 +2094,12 @@ static void eepro100_register_types(void)
type_info.class_init = eepro100_class_init;
type_info.instance_size = sizeof(EEPRO100State);
type_info.instance_init = eepro100_instance_init;
- type_info.interfaces = (InterfaceInfo[]) {
+ type_info.interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
};
- type_register(&type_info);
+ type_register_static(&type_info);
}
}
diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c
deleted file mode 100644
index 5faf20c..0000000
--- a/hw/net/etraxfs_eth.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * QEMU ETRAX Ethernet Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/cris/etraxfs.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "trace.h"
-#include "qom/object.h"
-
-#define D(x)
-
-/* Advertisement control register. */
-#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
-#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
-#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
-
-/*
- * The MDIO extensions in the TDK PHY model were reversed engineered from the
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
- uint32_t regs[32];
-
- int link;
-
- unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
- void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
-};
-
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
-{
- int regnum;
- unsigned r = 0;
-
- regnum = req & 0x1f;
-
- switch (regnum) {
- case 1:
- if (!phy->link) {
- break;
- }
- /* MR1. */
- /* Speeds and modes. */
- r |= (1 << 13) | (1 << 14);
- r |= (1 << 11) | (1 << 12);
- r |= (1 << 5); /* Autoneg complete. */
- r |= (1 << 3); /* Autoneg able. */
- r |= (1 << 2); /* link. */
- break;
- case 5:
- /* Link partner ability.
- We are kind; always agree with whatever best mode
- the guest advertises. */
- r = 1 << 14; /* Success. */
- /* Copy advertised modes. */
- r |= phy->regs[4] & (15 << 5);
- /* Autoneg support. */
- r |= 1;
- break;
- case 18:
- {
- /* Diagnostics reg. */
- int duplex = 0;
- int speed_100 = 0;
-
- if (!phy->link) {
- break;
- }
-
- /* Are we advertising 100 half or 100 duplex ? */
- speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
- speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
- /* Are we advertising 10 duplex or 100 duplex ? */
- duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
- duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
- r = (speed_100 << 10) | (duplex << 11);
- }
- break;
-
- default:
- r = phy->regs[regnum];
- break;
- }
- trace_mdio_phy_read(regnum, r);
- return r;
-}
-
-static void
-tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
-{
- int regnum;
-
- regnum = req & 0x1f;
- trace_mdio_phy_write(regnum, data);
- switch (regnum) {
- default:
- phy->regs[regnum] = data;
- break;
- }
-}
-
-static void
-tdk_reset(struct qemu_phy *phy)
-{
- phy->regs[0] = 0x3100;
- /* PHY Id. */
- phy->regs[2] = 0x0300;
- phy->regs[3] = 0xe400;
- /* Autonegotiation advertisement reg. */
- phy->regs[4] = 0x01E1;
- phy->link = 1;
-}
-
-struct qemu_mdio
-{
- /* bus. */
- int mdc;
- int mdio;
-
- /* decoder. */
- enum {
- PREAMBLE,
- SOF,
- OPC,
- ADDR,
- REQ,
- TURNAROUND,
- DATA
- } state;
- unsigned int drive;
-
- unsigned int cnt;
- unsigned int addr;
- unsigned int opc;
- unsigned int req;
- unsigned int data;
-
- struct qemu_phy *devs[32];
-};
-
-static void
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static void mdio_read_req(struct qemu_mdio *bus)
-{
- struct qemu_phy *phy;
-
- phy = bus->devs[bus->addr];
- if (phy && phy->read) {
- bus->data = phy->read(phy, bus->req);
- } else {
- bus->data = 0xffff;
- }
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
- struct qemu_phy *phy;
-
- phy = bus->devs[bus->addr];
- if (phy && phy->write) {
- phy->write(phy, bus->req, bus->data);
- }
-}
-
-static void mdio_cycle(struct qemu_mdio *bus)
-{
- bus->cnt++;
-
- trace_mdio_bitbang(bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive);
-#if 0
- if (bus->mdc) {
- printf("%d", bus->mdio);
- }
-#endif
- switch (bus->state) {
- case PREAMBLE:
- if (bus->mdc) {
- if (bus->cnt >= (32 * 2) && !bus->mdio) {
- bus->cnt = 0;
- bus->state = SOF;
- bus->data = 0;
- }
- }
- break;
- case SOF:
- if (bus->mdc) {
- if (bus->mdio != 1) {
- printf("WARNING: no SOF\n");
- }
- if (bus->cnt == 1*2) {
- bus->cnt = 0;
- bus->opc = 0;
- bus->state = OPC;
- }
- }
- break;
- case OPC:
- if (bus->mdc) {
- bus->opc <<= 1;
- bus->opc |= bus->mdio & 1;
- if (bus->cnt == 2*2) {
- bus->cnt = 0;
- bus->addr = 0;
- bus->state = ADDR;
- }
- }
- break;
- case ADDR:
- if (bus->mdc) {
- bus->addr <<= 1;
- bus->addr |= bus->mdio & 1;
-
- if (bus->cnt == 5*2) {
- bus->cnt = 0;
- bus->req = 0;
- bus->state = REQ;
- }
- }
- break;
- case REQ:
- if (bus->mdc) {
- bus->req <<= 1;
- bus->req |= bus->mdio & 1;
- if (bus->cnt == 5*2) {
- bus->cnt = 0;
- bus->state = TURNAROUND;
- }
- }
- break;
- case TURNAROUND:
- if (bus->mdc && bus->cnt == 2*2) {
- bus->mdio = 0;
- bus->cnt = 0;
-
- if (bus->opc == 2) {
- bus->drive = 1;
- mdio_read_req(bus);
- bus->mdio = bus->data & 1;
- }
- bus->state = DATA;
- }
- break;
- case DATA:
- if (!bus->mdc) {
- if (bus->drive) {
- bus->mdio = !!(bus->data & (1 << 15));
- bus->data <<= 1;
- }
- } else {
- if (!bus->drive) {
- bus->data <<= 1;
- bus->data |= bus->mdio;
- }
- if (bus->cnt == 16 * 2) {
- bus->cnt = 0;
- bus->state = PREAMBLE;
- if (!bus->drive) {
- mdio_write_req(bus);
- }
- bus->drive = 0;
- }
- }
- break;
- default:
- break;
- }
-}
-
-/* ETRAX-FS Ethernet MAC block starts here. */
-
-#define RW_MA0_LO 0x00
-#define RW_MA0_HI 0x01
-#define RW_MA1_LO 0x02
-#define RW_MA1_HI 0x03
-#define RW_GA_LO 0x04
-#define RW_GA_HI 0x05
-#define RW_GEN_CTRL 0x06
-#define RW_REC_CTRL 0x07
-#define RW_TR_CTRL 0x08
-#define RW_CLR_ERR 0x09
-#define RW_MGM_CTRL 0x0a
-#define R_STAT 0x0b
-#define FS_ETH_MAX_REGS 0x17
-
-#define TYPE_ETRAX_FS_ETH "etraxfs-eth"
-OBJECT_DECLARE_SIMPLE_TYPE(ETRAXFSEthState, ETRAX_FS_ETH)
-
-struct ETRAXFSEthState {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- NICState *nic;
- NICConf conf;
-
- /* Two addrs in the filter. */
- uint8_t macaddr[2][6];
- uint32_t regs[FS_ETH_MAX_REGS];
-
- struct etraxfs_dma_client *dma_out;
- struct etraxfs_dma_client *dma_in;
-
- /* MDIO bus. */
- struct qemu_mdio mdio_bus;
- unsigned int phyaddr;
- int duplex_mismatch;
-
- /* PHY. */
- struct qemu_phy phy;
-};
-
-static void eth_validate_duplex(ETRAXFSEthState *eth)
-{
- struct qemu_phy *phy;
- unsigned int phy_duplex;
- unsigned int mac_duplex;
- int new_mm = 0;
-
- phy = eth->mdio_bus.devs[eth->phyaddr];
- phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
- mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
-
- if (mac_duplex != phy_duplex) {
- new_mm = 1;
- }
-
- if (eth->regs[RW_GEN_CTRL] & 1) {
- if (new_mm != eth->duplex_mismatch) {
- if (new_mm) {
- printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n",
- mac_duplex, phy_duplex);
- } else {
- printf("HW: ETH duplex ok.\n");
- }
- }
- eth->duplex_mismatch = new_mm;
- }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXFSEthState *eth = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
-
- switch (addr) {
- case R_STAT:
- r = eth->mdio_bus.mdio & 1;
- break;
- default:
- r = eth->regs[addr];
- D(printf("%s %x\n", __func__, addr * 4));
- break;
- }
- return r;
-}
-
-static void eth_update_ma(ETRAXFSEthState *eth, int ma)
-{
- int reg;
- int i = 0;
-
- ma &= 1;
-
- reg = RW_MA0_LO;
- if (ma) {
- reg = RW_MA1_LO;
- }
-
- eth->macaddr[ma][i++] = eth->regs[reg];
- eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
- eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
- eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
- eth->macaddr[ma][i++] = eth->regs[reg + 1];
- eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
-
- D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
- eth->macaddr[ma][0], eth->macaddr[ma][1],
- eth->macaddr[ma][2], eth->macaddr[ma][3],
- eth->macaddr[ma][4], eth->macaddr[ma][5]));
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXFSEthState *eth = opaque;
- uint32_t value = val64;
-
- addr >>= 2;
- switch (addr) {
- case RW_MA0_LO:
- case RW_MA0_HI:
- eth->regs[addr] = value;
- eth_update_ma(eth, 0);
- break;
- case RW_MA1_LO:
- case RW_MA1_HI:
- eth->regs[addr] = value;
- eth_update_ma(eth, 1);
- break;
-
- case RW_MGM_CTRL:
- /* Attach an MDIO/PHY abstraction. */
- if (value & 2) {
- eth->mdio_bus.mdio = value & 1;
- }
- if (eth->mdio_bus.mdc != (value & 4)) {
- mdio_cycle(&eth->mdio_bus);
- eth_validate_duplex(eth);
- }
- eth->mdio_bus.mdc = !!(value & 4);
- eth->regs[addr] = value;
- break;
-
- case RW_REC_CTRL:
- eth->regs[addr] = value;
- eth_validate_duplex(eth);
- break;
-
- default:
- eth->regs[addr] = value;
- D(printf("%s %x %x\n", __func__, addr, value));
- break;
- }
-}
-
-/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
- filter dropping group addresses we have not joined. The filter has 64
- bits (m). The has function is a simple nible xor of the group addr. */
-static int eth_match_groupaddr(ETRAXFSEthState *eth, const unsigned char *sa)
-{
- unsigned int hsh;
- int m_individual = eth->regs[RW_REC_CTRL] & 4;
- int match;
-
- /* First bit on the wire of a MAC address signals multicast or
- physical address. */
- if (!m_individual && !(sa[0] & 1)) {
- return 0;
- }
-
- /* Calculate the hash index for the GA registers. */
- hsh = 0;
- hsh ^= (*sa) & 0x3f;
- hsh ^= ((*sa) >> 6) & 0x03;
- ++sa;
- hsh ^= ((*sa) << 2) & 0x03c;
- hsh ^= ((*sa) >> 4) & 0xf;
- ++sa;
- hsh ^= ((*sa) << 4) & 0x30;
- hsh ^= ((*sa) >> 2) & 0x3f;
- ++sa;
- hsh ^= (*sa) & 0x3f;
- hsh ^= ((*sa) >> 6) & 0x03;
- ++sa;
- hsh ^= ((*sa) << 2) & 0x03c;
- hsh ^= ((*sa) >> 4) & 0xf;
- ++sa;
- hsh ^= ((*sa) << 4) & 0x30;
- hsh ^= ((*sa) >> 2) & 0x3f;
-
- hsh &= 63;
- if (hsh > 31) {
- match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
- } else {
- match = eth->regs[RW_GA_LO] & (1 << hsh);
- }
- D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
- eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
- return match;
-}
-
-static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
- int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
- int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
- int r_bcast = eth->regs[RW_REC_CTRL] & 8;
-
- if (size < 12) {
- return -1;
- }
-
- D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
- use_ma0, use_ma1, r_bcast));
-
- /* Does the frame get through the address filters? */
- if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
- && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
- && (!r_bcast || memcmp(buf, sa_bcast, 6))
- && !eth_match_groupaddr(eth, buf)) {
- return size;
- }
-
- /* FIXME: Find another way to pass on the fake csum. */
- etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
-
- return size;
-}
-
-static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
-{
- ETRAXFSEthState *eth = opaque;
-
- D(printf("%s buf=%p len=%d\n", __func__, buf, len));
- qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
- return len;
-}
-
-static void eth_set_link(NetClientState *nc)
-{
- ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
- D(printf("%s %d\n", __func__, nc->link_down));
- eth->phy.link = !nc->link_down;
-}
-
-static const MemoryRegionOps eth_ops = {
- .read = eth_read,
- .write = eth_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static NetClientInfo net_etraxfs_info = {
- .type = NET_CLIENT_DRIVER_NIC,
- .size = sizeof(NICState),
- .receive = eth_receive,
- .link_status_changed = eth_set_link,
-};
-
-static void etraxfs_eth_reset(DeviceState *dev)
-{
- ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
-
- memset(s->regs, 0, sizeof(s->regs));
- memset(s->macaddr, 0, sizeof(s->macaddr));
- s->duplex_mismatch = 0;
-
- s->mdio_bus.mdc = 0;
- s->mdio_bus.mdio = 0;
- s->mdio_bus.state = 0;
- s->mdio_bus.drive = 0;
- s->mdio_bus.cnt = 0;
- s->mdio_bus.addr = 0;
- s->mdio_bus.opc = 0;
- s->mdio_bus.req = 0;
- s->mdio_bus.data = 0;
-
- tdk_reset(&s->phy);
-}
-
-static void etraxfs_eth_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
-
- if (!s->dma_out || !s->dma_in) {
- error_setg(errp, "Unconnected ETRAX-FS Ethernet MAC");
- return;
- }
-
- s->dma_out->client.push = eth_tx_push;
- s->dma_out->client.opaque = s;
- s->dma_in->client.opaque = s;
- s->dma_in->client.pull = NULL;
-
- memory_region_init_io(&s->mmio, OBJECT(dev), &eth_ops, s,
- "etraxfs-eth", 0x5c);
- sysbus_init_mmio(sbd, &s->mmio);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
- object_get_typename(OBJECT(s)), dev->id,
- &dev->mem_reentrancy_guard, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- s->phy.read = tdk_read;
- s->phy.write = tdk_write;
- mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
-}
-
-static Property etraxfs_eth_properties[] = {
- DEFINE_PROP_UINT32("phyaddr", ETRAXFSEthState, phyaddr, 1),
- DEFINE_NIC_PROPERTIES(ETRAXFSEthState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = etraxfs_eth_realize;
- dc->reset = etraxfs_eth_reset;
- device_class_set_props(dc, etraxfs_eth_properties);
- /* Reason: dma_out, dma_in are not user settable */
- dc->user_creatable = false;
-}
-
-
-/* Instantiate an ETRAXFS Ethernet MAC. */
-DeviceState *
-etraxfs_eth_init(hwaddr base, int phyaddr,
- struct etraxfs_dma_client *dma_out,
- struct etraxfs_dma_client *dma_in)
-{
- DeviceState *dev;
-
- dev = qdev_new("etraxfs-eth");
- qemu_configure_nic_device(dev, true, "fseth");
- qdev_prop_set_uint32(dev, "phyaddr", phyaddr);
-
- /*
- * TODO: QOM design, define a QOM interface for "I am an etraxfs
- * DMA client" (which replaces the current 'struct
- * etraxfs_dma_client' ad-hoc interface), implement it on the
- * ethernet device, and then have QOM link properties on the DMA
- * controller device so that you can pass the interface
- * implementations to it.
- */
- ETRAX_FS_ETH(dev)->dma_out = dma_out;
- ETRAX_FS_ETH(dev)->dma_in = dma_in;
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static const TypeInfo etraxfs_eth_info = {
- .name = TYPE_ETRAX_FS_ETH,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXFSEthState),
- .class_init = etraxfs_eth_class_init,
-};
-
-static void etraxfs_eth_register_types(void)
-{
- type_register_static(&etraxfs_eth_info);
-}
-
-type_init(etraxfs_eth_register_types)
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 00315f3..846f6cb 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -36,7 +36,6 @@
#include "registers.h"
#include "qapi/error.h"
#include "qemu/log.h"
-#include "qemu/module.h"
/* #define HEX_DUMP */
/* #define DEBUG_REGISTER */
@@ -390,6 +389,7 @@ static void etsec_realize(DeviceState *dev, Error **errp)
{
eTSEC *etsec = ETSEC_COMMON(dev);
+ qemu_macaddr_default_if_unset(&etsec->conf.macaddr);
etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
object_get_typename(OBJECT(dev)), dev->id,
&dev->mem_reentrancy_guard, etsec);
@@ -415,33 +415,29 @@ static void etsec_instance_init(Object *obj)
sysbus_init_irq(sbd, &etsec->err_irq);
}
-static Property etsec_properties[] = {
+static const Property etsec_properties[] = {
DEFINE_NIC_PROPERTIES(eTSEC, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void etsec_class_init(ObjectClass *klass, void *data)
+static void etsec_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = etsec_realize;
- dc->reset = etsec_reset;
+ dc->desc = "Freescale Enhanced Three-Speed Ethernet Controller";
+ device_class_set_legacy_reset(dc, etsec_reset);
device_class_set_props(dc, etsec_properties);
- /* Supported by ppce500 machine */
- dc->user_creatable = true;
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
-static const TypeInfo etsec_info = {
- .name = TYPE_ETSEC_COMMON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(eTSEC),
- .class_init = etsec_class_init,
- .instance_init = etsec_instance_init,
+static const TypeInfo etsec_types[] = {
+ {
+ .name = TYPE_ETSEC_COMMON,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
+ .instance_size = sizeof(eTSEC),
+ .class_init = etsec_class_init,
+ .instance_init = etsec_instance_init,
+ },
};
-static void etsec_register_types(void)
-{
- type_register_static(&etsec_info);
-}
-
-type_init(etsec_register_types)
+DEFINE_TYPES(etsec_types)
diff --git a/hw/net/fsl_etsec/miim.c b/hw/net/fsl_etsec/miim.c
index b48d2cb..4e91699 100644
--- a/hw/net/fsl_etsec/miim.c
+++ b/hw/net/fsl_etsec/miim.c
@@ -29,13 +29,6 @@
/* #define DEBUG_MIIM */
-#define MIIM_CONTROL 0
-#define MIIM_STATUS 1
-#define MIIM_PHY_ID_1 2
-#define MIIM_PHY_ID_2 3
-#define MIIM_T2_STATUS 10
-#define MIIM_EXT_STATUS 15
-
static void miim_read_cycle(eTSEC *etsec)
{
uint8_t phy;
@@ -47,14 +40,14 @@ static void miim_read_cycle(eTSEC *etsec)
addr = etsec->regs[MIIMADD].value & 0x1F;
switch (addr) {
- case MIIM_CONTROL:
+ case MII_BMCR:
value = etsec->phy_control;
break;
- case MIIM_STATUS:
+ case MII_BMSR:
value = etsec->phy_status;
break;
- case MIIM_T2_STATUS:
- value = 0x1800; /* Local and remote receivers OK */
+ case MII_STAT1000:
+ value = MII_STAT1000_LOK | MII_STAT1000_ROK;
break;
default:
value = 0x0;
@@ -84,8 +77,8 @@ static void miim_write_cycle(eTSEC *etsec)
#endif
switch (addr) {
- case MIIM_CONTROL:
- etsec->phy_control = value & ~(0x8100);
+ case MII_BMCR:
+ etsec->phy_control = value & ~(MII_BMCR_RESET | MII_BMCR_FD);
break;
default:
break;
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 80f9cd5..c41ce88 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/net/ftgmac100.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -24,8 +24,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
/*
* FTGMAC100 registers
@@ -1255,19 +1254,18 @@ static const VMStateDescription vmstate_ftgmac100 = {
}
};
-static Property ftgmac100_properties[] = {
+static const Property ftgmac100_properties[] = {
DEFINE_PROP_BOOL("aspeed", FTGMAC100State, aspeed, false),
DEFINE_NIC_PROPERTIES(FTGMAC100State, conf),
DEFINE_PROP_BOOL("dma64", FTGMAC100State, dma64, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ftgmac100_class_init(ObjectClass *klass, void *data)
+static void ftgmac100_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_ftgmac100;
- dc->reset = ftgmac100_reset;
+ device_class_set_legacy_reset(dc, ftgmac100_reset);
device_class_set_props(dc, ftgmac100_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = ftgmac100_realize;
@@ -1416,18 +1414,17 @@ static const VMStateDescription vmstate_aspeed_mii = {
}
};
-static Property aspeed_mii_properties[] = {
+static const Property aspeed_mii_properties[] = {
DEFINE_PROP_LINK("nic", AspeedMiiState, nic, TYPE_FTGMAC100,
FTGMAC100State *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_mii_class_init(ObjectClass *klass, void *data)
+static void aspeed_mii_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_aspeed_mii;
- dc->reset = aspeed_mii_reset;
+ device_class_set_legacy_reset(dc, aspeed_mii_reset);
dc->realize = aspeed_mii_realize;
dc->desc = "Aspeed MII controller";
device_class_set_props(dc, aspeed_mii_properties);
diff --git a/hw/net/i82596.c b/hw/net/i82596.c
index 6cc8292..c1ff3e6 100644
--- a/hw/net/i82596.c
+++ b/hw/net/i82596.c
@@ -5,7 +5,7 @@
* This work is licensed under the GNU GPL license version 2 or later.
*
* This software was written to be compatible with the specification:
- * https://www.intel.com/assets/pdf/general/82596ca.pdf
+ * https://parisc.docs.kernel.org/en/latest/_downloads/96672be0650d9fc046bbcea40b92482f/82596CA.pdf
*/
#include "qemu/osdep.h"
@@ -15,11 +15,11 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qemu/module.h"
#include "trace.h"
#include "i82596.h"
-#include <zlib.h> /* For crc32 */
+#include <zlib.h> /* for crc32 */
#if defined(ENABLE_DEBUG)
#define DBG(x) x
@@ -177,6 +177,26 @@ static void set_individual_address(I82596State *s, uint32_t addr)
trace_i82596_new_mac(nc->info_str);
}
+static void i82596_configure(I82596State *s, uint32_t addr)
+{
+ uint8_t byte_cnt;
+ byte_cnt = get_byte(addr + 8) & 0x0f;
+
+ byte_cnt = MAX(byte_cnt, 4);
+ byte_cnt = MIN(byte_cnt, sizeof(s->config));
+ /* copy byte_cnt max. */
+ address_space_read(&address_space_memory, addr + 8,
+ MEMTXATTRS_UNSPECIFIED, s->config, byte_cnt);
+ /* config byte according to page 35ff */
+ s->config[2] &= 0x82; /* mask valid bits */
+ s->config[2] |= 0x40;
+ s->config[7] &= 0xf7; /* clear zero bit */
+ assert(I596_NOCRC_INS == 0); /* do CRC insertion */
+ s->config[10] = MAX(s->config[10], 5); /* min frame length */
+ s->config[12] &= 0x40; /* only full duplex field valid */
+ s->config[13] |= 0x3f; /* set ones in byte 13 */
+}
+
static void set_multicast_list(I82596State *s, uint32_t addr)
{
uint16_t mc_count, i;
@@ -234,7 +254,6 @@ static void command_loop(I82596State *s)
{
uint16_t cmd;
uint16_t status;
- uint8_t byte_cnt;
DBG(printf("STARTING COMMAND LOOP cmd_p=%08x\n", s->cmd_p));
@@ -254,20 +273,7 @@ static void command_loop(I82596State *s)
set_individual_address(s, s->cmd_p);
break;
case CmdConfigure:
- byte_cnt = get_byte(s->cmd_p + 8) & 0x0f;
- byte_cnt = MAX(byte_cnt, 4);
- byte_cnt = MIN(byte_cnt, sizeof(s->config));
- /* copy byte_cnt max. */
- address_space_read(&address_space_memory, s->cmd_p + 8,
- MEMTXATTRS_UNSPECIFIED, s->config, byte_cnt);
- /* config byte according to page 35ff */
- s->config[2] &= 0x82; /* mask valid bits */
- s->config[2] |= 0x40;
- s->config[7] &= 0xf7; /* clear zero bit */
- assert(I596_NOCRC_INS == 0); /* do CRC insertion */
- s->config[10] = MAX(s->config[10], 5); /* min frame length */
- s->config[12] &= 0x40; /* only full duplex field valid */
- s->config[13] |= 0x3f; /* set ones in byte 13 */
+ i82596_configure(s, s->cmd_p);
break;
case CmdTDR:
/* get signal LINK */
@@ -282,7 +288,7 @@ static void command_loop(I82596State *s)
case CmdDump:
case CmdDiagnose:
printf("FIXME Command %d !!\n", cmd & 7);
- assert(0);
+ g_assert_not_reached();
}
/* update status */
diff --git a/hw/net/i82596.h b/hw/net/i82596.h
index f0bbe81..dc1fa1a 100644
--- a/hw/net/i82596.h
+++ b/hw/net/i82596.h
@@ -3,8 +3,8 @@
#define I82596_IOPORT_SIZE 0x20
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
+#include "system/memory.h"
+#include "system/address-spaces.h"
#define PORT_RESET 0x00 /* reset 82596 */
#define PORT_SELFTEST 0x01 /* selftest */
diff --git a/hw/net/igb.c b/hw/net/igb.c
index b92bba4..e4c0236 100644
--- a/hw/net/igb.c
+++ b/hw/net/igb.c
@@ -44,7 +44,7 @@
#include "net/tap.h"
#include "qemu/module.h"
#include "qemu/range.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/hw.h"
#include "hw/net/mii.h"
#include "hw/pci/pci.h"
@@ -356,8 +356,7 @@ static int
igb_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
{
Error *local_err = NULL;
- int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset,
- PCI_PM_SIZEOF, &local_err);
+ int ret = pci_pm_init(pdev, offset, &local_err);
if (local_err) {
error_report_err(local_err);
@@ -446,9 +445,13 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
pcie_ari_init(pci_dev, 0x150);
- pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF,
- IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS,
- IGB_VF_OFFSET, IGB_VF_STRIDE);
+ if (!pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF,
+ IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS,
+ IGB_MAX_VF_FUNCTIONS, IGB_VF_OFFSET, IGB_VF_STRIDE,
+ errp)) {
+ igb_cleanup_msix(s);
+ return;
+ }
pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MMIO_BAR_IDX,
PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
@@ -591,13 +594,12 @@ static const VMStateDescription igb_vmstate = {
}
};
-static Property igb_properties[] = {
+static const Property igb_properties[] = {
DEFINE_NIC_PROPERTIES(IGBState, conf),
DEFINE_PROP_BOOL("x-pcie-flr-init", IGBState, has_flr, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void igb_class_init(ObjectClass *class, void *data)
+static void igb_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
ResettableClass *rc = RESETTABLE_CLASS(class);
@@ -633,7 +635,7 @@ static const TypeInfo igb_info = {
.instance_size = sizeof(IGBState),
.class_init = igb_class_init,
.instance_init = igb_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
index bcd5f6c..39e3ce1 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -44,7 +44,7 @@
#include "hw/net/mii.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "net_tx_pkt.h"
#include "net_rx_pkt.h"
@@ -397,8 +397,7 @@ igb_rss_calc_hash(IGBCore *core, struct NetRxPkt *pkt, E1000E_RSSInfo *info)
type = NetPktRssIpV6Udp;
break;
default:
- assert(false);
- return 0;
+ g_assert_not_reached();
}
return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]);
@@ -747,7 +746,6 @@ igb_ring_free_descr_num(IGBCore *core, const E1000ERingInfo *r)
}
g_assert_not_reached();
- return 0;
}
static inline bool
diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h
index e5a47ea..4dc4c31 100644
--- a/hw/net/igb_regs.h
+++ b/hw/net/igb_regs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* This is copied + edited from kernel header files in
* drivers/net/ethernet/intel/igb
diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c
index 21a97d4..31d72c4 100644
--- a/hw/net/igbvf.c
+++ b/hw/net/igbvf.c
@@ -299,7 +299,7 @@ static void igbvf_pci_uninit(PCIDevice *dev)
msix_uninit(dev, &s->msix, &s->msix);
}
-static void igbvf_class_init(ObjectClass *class, void *data)
+static void igbvf_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
@@ -325,7 +325,7 @@ static const TypeInfo igbvf_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(IgbVfState),
.class_init = igbvf_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 8c91d20..e5e34dd 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -26,15 +26,14 @@
#include "hw/net/imx_fec.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "net/checksum.h"
#include "net/eth.h"
#include "trace.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#define IMX_MAX_DESC 1024
@@ -204,17 +203,12 @@ static const VMStateDescription vmstate_imx_eth_txdescs = {
static const VMStateDescription vmstate_imx_eth = {
.name = TYPE_IMX_FEC,
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
VMSTATE_UINT32(rx_descriptor, IMXFECState),
VMSTATE_UINT32(tx_descriptor[0], IMXFECState),
- VMSTATE_UINT32(phy_status, IMXFECState),
- VMSTATE_UINT32(phy_control, IMXFECState),
- VMSTATE_UINT32(phy_advertise, IMXFECState),
- VMSTATE_UINT32(phy_int, IMXFECState),
- VMSTATE_UINT32(phy_int_mask, IMXFECState),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
@@ -223,14 +217,6 @@ static const VMStateDescription vmstate_imx_eth = {
},
};
-#define PHY_INT_ENERGYON (1 << 7)
-#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
-#define PHY_INT_FAULT (1 << 5)
-#define PHY_INT_DOWN (1 << 4)
-#define PHY_INT_AUTONEG_LP (1 << 3)
-#define PHY_INT_PARFAULT (1 << 2)
-#define PHY_INT_AUTONEG_PAGE (1 << 1)
-
static void imx_eth_update(IMXFECState *s);
/*
@@ -239,47 +225,19 @@ static void imx_eth_update(IMXFECState *s);
* For now we don't handle any GPIO/interrupt line, so the OS will
* have to poll for the PHY status.
*/
-static void imx_phy_update_irq(IMXFECState *s)
-{
- imx_eth_update(s);
-}
-
-static void imx_phy_update_link(IMXFECState *s)
+static void imx_phy_update_irq(void *opaque, int n, int level)
{
- /* Autonegotiation status mirrors link status. */
- if (qemu_get_queue(s->nic)->link_down) {
- trace_imx_phy_update_link("down");
- s->phy_status &= ~0x0024;
- s->phy_int |= PHY_INT_DOWN;
- } else {
- trace_imx_phy_update_link("up");
- s->phy_status |= 0x0024;
- s->phy_int |= PHY_INT_ENERGYON;
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
- }
- imx_phy_update_irq(s);
+ imx_eth_update(opaque);
}
static void imx_eth_set_link(NetClientState *nc)
{
- imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
-}
-
-static void imx_phy_reset(IMXFECState *s)
-{
- trace_imx_phy_reset();
-
- s->phy_status = 0x7809;
- s->phy_control = 0x3000;
- s->phy_advertise = 0x01e1;
- s->phy_int_mask = 0;
- s->phy_int = 0;
- imx_phy_update_link(s);
+ lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii,
+ nc->link_down);
}
static uint32_t imx_phy_read(IMXFECState *s, int reg)
{
- uint32_t val;
uint32_t phy = reg / 32;
if (!s->phy_connected) {
@@ -297,54 +255,7 @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
reg %= 32;
- switch (reg) {
- case 0: /* Basic Control */
- val = s->phy_control;
- break;
- case 1: /* Basic Status */
- val = s->phy_status;
- break;
- case 2: /* ID1 */
- val = 0x0007;
- break;
- case 3: /* ID2 */
- val = 0xc0d1;
- break;
- case 4: /* Auto-neg advertisement */
- val = s->phy_advertise;
- break;
- case 5: /* Auto-neg Link Partner Ability */
- val = 0x0f71;
- break;
- case 6: /* Auto-neg Expansion */
- val = 1;
- break;
- case 29: /* Interrupt source. */
- val = s->phy_int;
- s->phy_int = 0;
- imx_phy_update_irq(s);
- break;
- case 30: /* Interrupt mask */
- val = s->phy_int_mask;
- break;
- case 17:
- case 18:
- case 27:
- case 31:
- qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n",
- TYPE_IMX_FEC, __func__, reg);
- val = 0;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
- TYPE_IMX_FEC, __func__, reg);
- val = 0;
- break;
- }
-
- trace_imx_phy_read(val, phy, reg);
-
- return val;
+ return lan9118_phy_read(&s->mii, reg);
}
static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
@@ -366,39 +277,7 @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
reg %= 32;
- trace_imx_phy_write(val, phy, reg);
-
- switch (reg) {
- case 0: /* Basic Control */
- if (val & 0x8000) {
- imx_phy_reset(s);
- } else {
- s->phy_control = val & 0x7980;
- /* Complete autonegotiation immediately. */
- if (val & 0x1000) {
- s->phy_status |= 0x0020;
- }
- }
- break;
- case 4: /* Auto-neg advertisement */
- s->phy_advertise = (val & 0x2d7f) | 0x80;
- break;
- case 30: /* Interrupt mask */
- s->phy_int_mask = val & 0xff;
- imx_phy_update_irq(s);
- break;
- case 17:
- case 18:
- case 27:
- case 31:
- qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n",
- TYPE_IMX_FEC, __func__, reg);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
- TYPE_IMX_FEC, __func__, reg);
- break;
- }
+ lan9118_phy_write(&s->mii, reg, val);
}
static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
@@ -683,9 +562,6 @@ static void imx_eth_reset(DeviceState *d)
s->rx_descriptor = 0;
memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
-
- /* We also reset the PHY */
- imx_phy_reset(s);
}
static uint32_t imx_default_read(IMXFECState *s, uint32_t index)
@@ -792,7 +668,6 @@ static void imx_default_write(IMXFECState *s, uint32_t index, uint32_t value)
{
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
PRIx32 "\n", TYPE_IMX_FEC, __func__, index * 4);
- return;
}
static void imx_fec_write(IMXFECState *s, uint32_t index, uint32_t value)
@@ -1330,6 +1205,13 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq[0]);
sysbus_init_irq(sbd, &s->irq[1]);
+ qemu_init_irq(&s->mii_irq, imx_phy_update_irq, s, 0);
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
+
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
@@ -1339,22 +1221,21 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
}
-static Property imx_eth_properties[] = {
+static const Property imx_eth_properties[] = {
DEFINE_NIC_PROPERTIES(IMXFECState, conf),
DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1),
DEFINE_PROP_UINT32("phy-num", IMXFECState, phy_num, 0),
DEFINE_PROP_BOOL("phy-connected", IMXFECState, phy_connected, true),
DEFINE_PROP_LINK("phy-consumer", IMXFECState, phy_consumer, TYPE_IMX_FEC,
IMXFECState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void imx_eth_class_init(ObjectClass *klass, void *data)
+static void imx_eth_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_imx_eth;
- dc->reset = imx_eth_reset;
+ device_class_set_legacy_reset(dc, imx_eth_reset);
device_class_set_props(dc, imx_eth_properties);
dc->realize = imx_eth_realize;
dc->desc = "i.MX FEC/ENET Ethernet Controller";
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 91d81b4..6dda1e5 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -16,14 +16,14 @@
#include "net/net.h"
#include "net/eth.h"
#include "hw/irq.h"
+#include "hw/net/lan9118_phy.h"
#include "hw/net/lan9118.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
//#define DEBUG_LAN9118
@@ -140,14 +140,6 @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
#define MAC_CR_RXEN 0x00000004
#define MAC_CR_RESERVED 0x7f404213
-#define PHY_INT_ENERGYON 0x80
-#define PHY_INT_AUTONEG_COMPLETE 0x40
-#define PHY_INT_FAULT 0x20
-#define PHY_INT_DOWN 0x10
-#define PHY_INT_AUTONEG_LP 0x08
-#define PHY_INT_PARFAULT 0x04
-#define PHY_INT_AUTONEG_PAGE 0x02
-
#define GPT_TIMER_EN 0x20000000
/*
@@ -229,11 +221,8 @@ struct lan9118_state {
uint32_t mac_mii_data;
uint32_t mac_flow;
- uint32_t phy_status;
- uint32_t phy_control;
- uint32_t phy_advertise;
- uint32_t phy_int;
- uint32_t phy_int_mask;
+ Lan9118PhyState mii;
+ IRQState mii_irq;
int32_t eeprom_writable;
uint8_t eeprom[128];
@@ -275,8 +264,8 @@ struct lan9118_state {
static const VMStateDescription vmstate_lan9118 = {
.name = "lan9118",
- .version_id = 2,
- .minimum_version_id = 1,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_PTIMER(timer, lan9118_state),
VMSTATE_UINT32(irq_cfg, lan9118_state),
@@ -302,11 +291,6 @@ static const VMStateDescription vmstate_lan9118 = {
VMSTATE_UINT32(mac_mii_acc, lan9118_state),
VMSTATE_UINT32(mac_mii_data, lan9118_state),
VMSTATE_UINT32(mac_flow, lan9118_state),
- VMSTATE_UINT32(phy_status, lan9118_state),
- VMSTATE_UINT32(phy_control, lan9118_state),
- VMSTATE_UINT32(phy_advertise, lan9118_state),
- VMSTATE_UINT32(phy_int, lan9118_state),
- VMSTATE_UINT32(phy_int_mask, lan9118_state),
VMSTATE_INT32(eeprom_writable, lan9118_state),
VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
VMSTATE_INT32(tx_fifo_size, lan9118_state),
@@ -386,9 +370,11 @@ static void lan9118_reload_eeprom(lan9118_state *s)
lan9118_mac_changed(s);
}
-static void phy_update_irq(lan9118_state *s)
+static void lan9118_update_irq(void *opaque, int n, int level)
{
- if (s->phy_int & s->phy_int_mask) {
+ lan9118_state *s = opaque;
+
+ if (level) {
s->int_sts |= PHY_INT;
} else {
s->int_sts &= ~PHY_INT;
@@ -396,33 +382,10 @@ static void phy_update_irq(lan9118_state *s)
lan9118_update(s);
}
-static void phy_update_link(lan9118_state *s)
-{
- /* Autonegotiation status mirrors link status. */
- if (qemu_get_queue(s->nic)->link_down) {
- s->phy_status &= ~0x0024;
- s->phy_int |= PHY_INT_DOWN;
- } else {
- s->phy_status |= 0x0024;
- s->phy_int |= PHY_INT_ENERGYON;
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
- }
- phy_update_irq(s);
-}
-
static void lan9118_set_link(NetClientState *nc)
{
- phy_update_link(qemu_get_nic_opaque(nc));
-}
-
-static void phy_reset(lan9118_state *s)
-{
- s->phy_status = 0x7809;
- s->phy_control = 0x3000;
- s->phy_advertise = 0x01e1;
- s->phy_int_mask = 0;
- s->phy_int = 0;
- phy_update_link(s);
+ lan9118_phy_update_link(&LAN9118(qemu_get_nic_opaque(nc))->mii,
+ nc->link_down);
}
static void lan9118_reset(DeviceState *d)
@@ -479,8 +442,6 @@ static void lan9118_reset(DeviceState *d)
s->read_word_n = 0;
s->write_word_n = 0;
- phy_reset(s);
-
s->eeprom_writable = 0;
lan9118_reload_eeprom(s);
}
@@ -679,7 +640,7 @@ static void do_tx_packet(lan9118_state *s)
uint32_t status;
/* FIXME: Honor TX disable, and allow queueing of packets. */
- if (s->phy_control & 0x4000) {
+ if (s->mii.control & 0x4000) {
/* This assumes the receive routine doesn't touch the VLANClient. */
qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
} else {
@@ -835,68 +796,6 @@ static void tx_fifo_push(lan9118_state *s, uint32_t val)
}
}
-static uint32_t do_phy_read(lan9118_state *s, int reg)
-{
- uint32_t val;
-
- switch (reg) {
- case 0: /* Basic Control */
- return s->phy_control;
- case 1: /* Basic Status */
- return s->phy_status;
- case 2: /* ID1 */
- return 0x0007;
- case 3: /* ID2 */
- return 0xc0d1;
- case 4: /* Auto-neg advertisement */
- return s->phy_advertise;
- case 5: /* Auto-neg Link Partner Ability */
- return 0x0f71;
- case 6: /* Auto-neg Expansion */
- return 1;
- /* TODO 17, 18, 27, 29, 30, 31 */
- case 29: /* Interrupt source. */
- val = s->phy_int;
- s->phy_int = 0;
- phy_update_irq(s);
- return val;
- case 30: /* Interrupt mask */
- return s->phy_int_mask;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "do_phy_read: PHY read reg %d\n", reg);
- return 0;
- }
-}
-
-static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
-{
- switch (reg) {
- case 0: /* Basic Control */
- if (val & 0x8000) {
- phy_reset(s);
- break;
- }
- s->phy_control = val & 0x7980;
- /* Complete autonegotiation immediately. */
- if (val & 0x1000) {
- s->phy_status |= 0x0020;
- }
- break;
- case 4: /* Auto-neg advertisement */
- s->phy_advertise = (val & 0x2d7f) | 0x80;
- break;
- /* TODO 17, 18, 27, 31 */
- case 30: /* Interrupt mask */
- s->phy_int_mask = val & 0xff;
- phy_update_irq(s);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
- }
-}
-
static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
{
switch (reg) {
@@ -930,9 +829,9 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
if (val & 2) {
DPRINTF("PHY write %d = 0x%04x\n",
(val >> 6) & 0x1f, s->mac_mii_data);
- do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
+ lan9118_phy_write(&s->mii, (val >> 6) & 0x1f, s->mac_mii_data);
} else {
- s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
+ s->mac_mii_data = lan9118_phy_read(&s->mii, (val >> 6) & 0x1f);
DPRINTF("PHY read %d = 0x%04x\n",
(val >> 6) & 0x1f, s->mac_mii_data);
}
@@ -1127,7 +1026,7 @@ static void lan9118_writel(void *opaque, hwaddr offset,
break;
case CSR_PMT_CTRL:
if (val & 0x400) {
- phy_reset(s);
+ lan9118_phy_reset(&s->mii);
}
s->pmt_ctrl &= ~0x34e;
s->pmt_ctrl |= (val & 0x34e);
@@ -1374,6 +1273,13 @@ static void lan9118_realize(DeviceState *dev, Error **errp)
const MemoryRegionOps *mem_ops =
s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops;
+ qemu_init_irq(&s->mii_irq, lan9118_update_irq, s, 0);
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
+
memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s,
"lan9118-mmio", 0x100);
sysbus_init_mmio(sbd, &s->mmio);
@@ -1398,17 +1304,16 @@ static void lan9118_realize(DeviceState *dev, Error **errp)
ptimer_transaction_commit(s->timer);
}
-static Property lan9118_properties[] = {
+static const Property lan9118_properties[] = {
DEFINE_NIC_PROPERTIES(lan9118_state, conf),
DEFINE_PROP_UINT32("mode_16bit", lan9118_state, mode_16bit, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void lan9118_class_init(ObjectClass *klass, void *data)
+static void lan9118_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = lan9118_reset;
+ device_class_set_legacy_reset(dc, lan9118_reset);
device_class_set_props(dc, lan9118_properties);
dc->vmsd = &vmstate_lan9118;
dc->realize = lan9118_realize;
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
new file mode 100644
index 0000000..4c4e03d
--- /dev/null
+++ b/hw/net/lan9118_phy.c
@@ -0,0 +1,222 @@
+/*
+ * SMSC LAN9118 PHY emulation
+ *
+ * Copyright (c) 2009 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
+ *
+ * This code is licensed under the GNU GPL v2
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/net/lan9118_phy.h"
+#include "hw/net/mii.h"
+#include "hw/irq.h"
+#include "hw/resettable.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+#define PHY_INT_ENERGYON (1 << 7)
+#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
+#define PHY_INT_FAULT (1 << 5)
+#define PHY_INT_DOWN (1 << 4)
+#define PHY_INT_AUTONEG_LP (1 << 3)
+#define PHY_INT_PARFAULT (1 << 2)
+#define PHY_INT_AUTONEG_PAGE (1 << 1)
+
+static void lan9118_phy_update_irq(Lan9118PhyState *s)
+{
+ qemu_set_irq(s->irq, !!(s->ints & s->int_mask));
+}
+
+uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
+{
+ uint16_t val;
+
+ switch (reg) {
+ case MII_BMCR:
+ val = s->control;
+ break;
+ case MII_BMSR:
+ val = s->status;
+ break;
+ case MII_PHYID1:
+ val = SMSCLAN9118_PHYID1;
+ break;
+ case MII_PHYID2:
+ val = SMSCLAN9118_PHYID2;
+ break;
+ case MII_ANAR:
+ val = s->advertise;
+ break;
+ case MII_ANLPAR:
+ val = MII_ANLPAR_PAUSEASY | MII_ANLPAR_PAUSE | MII_ANLPAR_T4 |
+ MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD |
+ MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
+ break;
+ case MII_ANER:
+ val = MII_ANER_NWAY;
+ break;
+ case 29: /* Interrupt source. */
+ val = s->ints;
+ s->ints = 0;
+ lan9118_phy_update_irq(s);
+ break;
+ case 30: /* Interrupt mask */
+ val = s->int_mask;
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
+ __func__, reg);
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
+ __func__, reg);
+ val = 0;
+ break;
+ }
+
+ trace_lan9118_phy_read(val, reg);
+
+ return val;
+}
+
+void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
+{
+ trace_lan9118_phy_write(val, reg);
+
+ switch (reg) {
+ case MII_BMCR:
+ if (val & MII_BMCR_RESET) {
+ lan9118_phy_reset(s);
+ } else {
+ s->control = val & (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 |
+ MII_BMCR_AUTOEN | MII_BMCR_PDOWN | MII_BMCR_FD |
+ MII_BMCR_CTST);
+ /* Complete autonegotiation immediately. */
+ if (val & MII_BMCR_AUTOEN) {
+ s->status |= MII_BMSR_AN_COMP;
+ }
+ }
+ break;
+ case MII_ANAR:
+ s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM |
+ MII_ANAR_PAUSE | MII_ANAR_TXFD | MII_ANAR_10FD |
+ MII_ANAR_10 | MII_ANAR_SELECT))
+ | MII_ANAR_TX;
+ break;
+ case 30: /* Interrupt mask */
+ s->int_mask = val & 0xff;
+ lan9118_phy_update_irq(s);
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
+ __func__, reg);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
+ __func__, reg);
+ break;
+ }
+}
+
+void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
+{
+ s->link_down = link_down;
+
+ /* Autonegotiation status mirrors link status. */
+ if (link_down) {
+ trace_lan9118_phy_update_link("down");
+ s->status &= ~(MII_BMSR_AN_COMP | MII_BMSR_LINK_ST);
+ s->ints |= PHY_INT_DOWN;
+ } else {
+ trace_lan9118_phy_update_link("up");
+ s->status |= MII_BMSR_AN_COMP | MII_BMSR_LINK_ST;
+ s->ints |= PHY_INT_ENERGYON;
+ s->ints |= PHY_INT_AUTONEG_COMPLETE;
+ }
+ lan9118_phy_update_irq(s);
+}
+
+void lan9118_phy_reset(Lan9118PhyState *s)
+{
+ trace_lan9118_phy_reset();
+
+ s->control = MII_BMCR_AUTOEN | MII_BMCR_SPEED100;
+ s->status = MII_BMSR_100TX_FD
+ | MII_BMSR_100TX_HD
+ | MII_BMSR_10T_FD
+ | MII_BMSR_10T_HD
+ | MII_BMSR_AUTONEG
+ | MII_BMSR_EXTCAP;
+ s->advertise = MII_ANAR_TXFD
+ | MII_ANAR_TX
+ | MII_ANAR_10FD
+ | MII_ANAR_10
+ | MII_ANAR_CSMACD;
+ s->int_mask = 0;
+ s->ints = 0;
+ lan9118_phy_update_link(s, s->link_down);
+}
+
+static void lan9118_phy_reset_hold(Object *obj, ResetType type)
+{
+ Lan9118PhyState *s = LAN9118_PHY(obj);
+
+ lan9118_phy_reset(s);
+}
+
+static void lan9118_phy_init(Object *obj)
+{
+ Lan9118PhyState *s = LAN9118_PHY(obj);
+
+ qdev_init_gpio_out(DEVICE(s), &s->irq, 1);
+}
+
+static const VMStateDescription vmstate_lan9118_phy = {
+ .name = "lan9118-phy",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT16(status, Lan9118PhyState),
+ VMSTATE_UINT16(control, Lan9118PhyState),
+ VMSTATE_UINT16(advertise, Lan9118PhyState),
+ VMSTATE_UINT16(ints, Lan9118PhyState),
+ VMSTATE_UINT16(int_mask, Lan9118PhyState),
+ VMSTATE_BOOL(link_down, Lan9118PhyState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void lan9118_phy_class_init(ObjectClass *klass, const void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ rc->phases.hold = lan9118_phy_reset_hold;
+ dc->vmsd = &vmstate_lan9118_phy;
+}
+
+static const TypeInfo types[] = {
+ {
+ .name = TYPE_LAN9118_PHY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Lan9118PhyState),
+ .instance_init = lan9118_phy_init,
+ .class_init = lan9118_phy_class_init,
+ }
+};
+
+DEFINE_TYPES(types)
diff --git a/hw/net/lance.c b/hw/net/lance.c
index e1ed24c..dfb855c 100644
--- a/hw/net/lance.c
+++ b/hw/net/lance.c
@@ -43,7 +43,7 @@
#include "hw/net/lance.h"
#include "hw/qdev-properties.h"
#include "trace.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static void parent_lance_reset(void *opaque, int irq, int level)
@@ -137,21 +137,20 @@ static void lance_instance_init(Object *obj)
DEVICE(obj));
}
-static Property lance_properties[] = {
+static const Property lance_properties[] = {
DEFINE_PROP_LINK("dma", SysBusPCNetState, state.dma_opaque,
TYPE_DEVICE, DeviceState *),
DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void lance_class_init(ObjectClass *klass, void *data)
+static void lance_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = lance_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->fw_name = "ethernet";
- dc->reset = lance_reset;
+ device_class_set_legacy_reset(dc, lance_reset);
dc->vmsd = &vmstate_lance;
device_class_set_props(dc, lance_properties);
}
diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c
index fcf7fae..9e1dd21 100644
--- a/hw/net/lasi_i82596.c
+++ b/hw/net/lasi_i82596.c
@@ -14,7 +14,7 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "net/eth.h"
#include "hw/net/lasi_82596.h"
#include "hw/net/i82596.h"
@@ -158,19 +158,18 @@ static void lasi_82596_instance_init(Object *obj)
DEVICE(obj));
}
-static Property lasi_82596_properties[] = {
+static const Property lasi_82596_properties[] = {
DEFINE_NIC_PROPERTIES(SysBusI82596State, state.conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void lasi_82596_class_init(ObjectClass *klass, void *data)
+static void lasi_82596_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = lasi_82596_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->fw_name = "ethernet";
- dc->reset = lasi_82596_reset;
+ device_class_set_legacy_reset(dc, lasi_82596_reset);
dc->vmsd = &vmstate_lasi_82596;
dc->user_creatable = false;
device_class_set_props(dc, lasi_82596_properties);
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index e690271..ae128fa 100644
--- a/hw/net/mcf_fec.c
+++ b/hw/net/mcf_fec.c
@@ -16,8 +16,7 @@
#include "hw/net/mii.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
//#define DEBUG_FEC 1
@@ -661,19 +660,18 @@ static void mcf_fec_instance_init(Object *obj)
}
}
-static Property mcf_fec_properties[] = {
+static const Property mcf_fec_properties[] = {
DEFINE_NIC_PROPERTIES(mcf_fec_state, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mcf_fec_class_init(ObjectClass *oc, void *data)
+static void mcf_fec_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = mcf_fec_realize;
dc->desc = "MCF Fast Ethernet Controller network device";
- dc->reset = mcf_fec_reset;
+ device_class_set_legacy_reset(dc, mcf_fec_reset);
device_class_set_props(dc, mcf_fec_properties);
}
diff --git a/hw/net/meson.build b/hw/net/meson.build
index b742687..e6759e2 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -19,6 +19,7 @@ system_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('vmxnet3.c'))
system_ss.add(when: 'CONFIG_SMC91C111', if_true: files('smc91c111.c'))
system_ss.add(when: 'CONFIG_LAN9118', if_true: files('lan9118.c'))
+system_ss.add(when: 'CONFIG_LAN9118_PHY', if_true: files('lan9118_phy.c'))
system_ss.add(when: 'CONFIG_NE2000_ISA', if_true: files('ne2000-isa.c'))
system_ss.add(when: 'CONFIG_OPENCORES_ETH', if_true: files('opencores_eth.c'))
system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c'))
@@ -39,8 +40,8 @@ system_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c'))
system_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c'))
system_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c', 'npcm_gmac.c'))
+system_ss.add(when: 'CONFIG_NPCM8XX', if_true: files('npcm_pcs.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c'))
system_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c'))
diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c
index df5101a..583aa1c 100644
--- a/hw/net/mipsnet.c
+++ b/hw/net/mipsnet.c
@@ -266,19 +266,18 @@ static void mipsnet_sysbus_reset(DeviceState *dev)
mipsnet_reset(s);
}
-static Property mipsnet_properties[] = {
+static const Property mipsnet_properties[] = {
DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mipsnet_class_init(ObjectClass *klass, void *data)
+static void mipsnet_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mipsnet_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "MIPS Simulator network device";
- dc->reset = mipsnet_sysbus_reset;
+ device_class_set_legacy_reset(dc, mipsnet_sysbus_reset);
dc->vmsd = &vmstate_mipsnet;
device_class_set_props(dc, mipsnet_properties);
}
diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c
index c1fc10d..5904597 100644
--- a/hw/net/msf2-emac.c
+++ b/hw/net/msf2-emac.c
@@ -546,11 +546,10 @@ static void msf2_emac_init(Object *obj)
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
-static Property msf2_emac_properties[] = {
+static const Property msf2_emac_properties[] = {
DEFINE_PROP_LINK("ahb-bus", MSF2EmacState, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_NIC_PROPERTIES(MSF2EmacState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_msf2_emac = {
@@ -566,12 +565,12 @@ static const VMStateDescription vmstate_msf2_emac = {
}
};
-static void msf2_emac_class_init(ObjectClass *klass, void *data)
+static void msf2_emac_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = msf2_emac_realize;
- dc->reset = msf2_emac_reset;
+ device_class_set_legacy_reset(dc, msf2_emac_reset);
dc->vmsd = &vmstate_msf2_emac;
device_class_set_props(dc, msf2_emac_properties);
}
diff --git a/hw/net/mv88w8618_eth.c b/hw/net/mv88w8618_eth.c
index 96c65f4..6f08846 100644
--- a/hw/net/mv88w8618_eth.c
+++ b/hw/net/mv88w8618_eth.c
@@ -12,7 +12,7 @@
#include "hw/irq.h"
#include "hw/net/mv88w8618_eth.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "net/net.h"
#define MP_ETH_SIZE 0x00001000
@@ -371,14 +371,13 @@ static const VMStateDescription mv88w8618_eth_vmsd = {
}
};
-static Property mv88w8618_eth_properties[] = {
+static const Property mv88w8618_eth_properties[] = {
DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
DEFINE_PROP_LINK("dma-memory", mv88w8618_eth_state, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
+static void mv88w8618_eth_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c
index 26980e0..673c785 100644
--- a/hw/net/ne2000-isa.c
+++ b/hw/net/ne2000-isa.c
@@ -27,7 +27,7 @@
#include "hw/net/ne2000-isa.h"
#include "migration/vmstate.h"
#include "ne2000.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/module.h"
@@ -79,14 +79,13 @@ static void isa_ne2000_realizefn(DeviceState *dev, Error **errp)
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
}
-static Property ne2000_isa_properties[] = {
+static const Property ne2000_isa_properties[] = {
DEFINE_PROP_UINT32("iobase", ISANE2000State, iobase, 0x300),
DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9),
DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
};
-static void isa_ne2000_class_initfn(ObjectClass *klass, void *data)
+static void isa_ne2000_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c
index 7477306..ce937e1 100644
--- a/hw/net/ne2000-pci.c
+++ b/hw/net/ne2000-pci.c
@@ -28,7 +28,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "ne2000.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
typedef struct PCINE2000State {
PCIDevice dev;
@@ -96,12 +96,11 @@ static void ne2000_instance_init(Object *obj)
&pci_dev->qdev);
}
-static Property ne2000_properties[] = {
+static const Property ne2000_properties[] = {
DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ne2000_class_init(ObjectClass *klass, void *data)
+static void ne2000_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -123,7 +122,7 @@ static const TypeInfo ne2000_info = {
.instance_size = sizeof(PCINE2000State),
.class_init = ne2000_class_init,
.instance_init = ne2000_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index b482c5f..b1923c8 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "net/eth.h"
#include "qemu/module.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "ne2000.h"
diff --git a/hw/net/net_rx_pkt.c b/hw/net/net_rx_pkt.c
index 32e5f3f..f87b6f0 100644
--- a/hw/net/net_rx_pkt.c
+++ b/hw/net/net_rx_pkt.c
@@ -209,12 +209,6 @@ void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
*l4hdr_proto = pkt->l4hdr_info.proto;
}
-size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt)
-{
- assert(pkt);
- return pkt->l3hdr_off;
-}
-
size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt)
{
assert(pkt);
@@ -375,8 +369,7 @@ net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt,
_net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
break;
default:
- assert(false);
- break;
+ g_assert_not_reached();
}
net_toeplitz_key_init(&key_data, key);
@@ -427,13 +420,6 @@ struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt)
return pkt->vec;
}
-uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->vec_len;
-}
-
void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt,
struct virtio_net_hdr *vhdr)
{
diff --git a/hw/net/net_rx_pkt.h b/hw/net/net_rx_pkt.h
index 55ec67a..ea077f5 100644
--- a/hw/net/net_rx_pkt.h
+++ b/hw/net/net_rx_pkt.h
@@ -78,14 +78,6 @@ void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
EthL4HdrProto *l4hdr_proto);
/**
-* fetches L3 header offset
-*
-* @pkt: packet
-*
-*/
-size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt);
-
-/**
* fetches L4 header offset
*
* @pkt: packet
@@ -268,15 +260,6 @@ net_rx_pkt_attach_data(struct NetRxPkt *pkt, const void *data,
struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt);
/**
-* returns io vector length that holds the attached data
-*
-* @pkt: packet
-* @ret: IOVec length
-*
-*/
-uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt);
-
-/**
* prints rx packet data if debug is enabled
*
* @pkt: packet
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index 1f79b82..903238d 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -141,10 +141,6 @@ bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt)
uint32_t csum = 0;
struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG;
- if (iov_size(pl_start_frag, pkt->payload_frags) < 8 + sizeof(csum)) {
- return false;
- }
-
if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) {
return false;
}
diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c
index d1583b6..9ba35e2 100644
--- a/hw/net/npcm7xx_emc.c
+++ b/hw/net/npcm7xx_emc.c
@@ -29,8 +29,7 @@
#include "qemu/osdep.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "hw/irq.h"
#include "hw/qdev-clock.h"
@@ -43,7 +42,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/units.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "trace.h"
#define CRC_LENGTH 4
@@ -846,12 +845,11 @@ static const VMStateDescription vmstate_npcm7xx_emc = {
},
};
-static Property npcm7xx_emc_properties[] = {
+static const Property npcm7xx_emc_properties[] = {
DEFINE_NIC_PROPERTIES(NPCM7xxEMCState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void npcm7xx_emc_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_emc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -859,7 +857,7 @@ static void npcm7xx_emc_class_init(ObjectClass *klass, void *data)
dc->desc = "NPCM7xx EMC Controller";
dc->realize = npcm7xx_emc_realize;
dc->unrealize = npcm7xx_emc_unrealize;
- dc->reset = npcm7xx_emc_reset;
+ device_class_set_legacy_reset(dc, npcm7xx_emc_reset);
dc->vmsd = &vmstate_npcm7xx_emc;
device_class_set_props(dc, npcm7xx_emc_properties);
}
diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c
index 1b71e25..a434112 100644
--- a/hw/net/npcm_gmac.c
+++ b/hw/net/npcm_gmac.c
@@ -33,7 +33,7 @@
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qemu/units.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "trace.h"
REG32(NPCM_DMA_BUS_MODE, 0x1000)
@@ -546,9 +546,8 @@ static void gmac_try_send_next_packet(NPCMGMACState *gmac)
/* 1 = DMA Owned, 0 = Software Owned */
if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "TX Descriptor @ 0x%x is owned by software\n",
- desc_addr);
+ trace_npcm_gmac_tx_desc_owner(DEVICE(gmac)->canonical_path,
+ desc_addr);
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU;
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_TX_SUSPENDED_STATE);
@@ -913,12 +912,11 @@ static const VMStateDescription vmstate_npcm_gmac = {
},
};
-static Property npcm_gmac_properties[] = {
+static const Property npcm_gmac_properties[] = {
DEFINE_NIC_PROPERTIES(NPCMGMACState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void npcm_gmac_class_init(ObjectClass *klass, void *data)
+static void npcm_gmac_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -926,7 +924,7 @@ static void npcm_gmac_class_init(ObjectClass *klass, void *data)
dc->desc = "NPCM GMAC Controller";
dc->realize = npcm_gmac_realize;
dc->unrealize = npcm_gmac_unrealize;
- dc->reset = npcm_gmac_reset;
+ device_class_set_legacy_reset(dc, npcm_gmac_reset);
dc->vmsd = &vmstate_npcm_gmac;
device_class_set_props(dc, npcm_gmac_properties);
}
diff --git a/hw/net/npcm_pcs.c b/hw/net/npcm_pcs.c
new file mode 100644
index 0000000..6aec105
--- /dev/null
+++ b/hw/net/npcm_pcs.c
@@ -0,0 +1,410 @@
+/*
+ * Nuvoton NPCM8xx PCS Module
+ *
+ * Copyright 2022 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/*
+ * Disclaimer:
+ * Currently we only implemented the default values of the registers and
+ * the soft reset feature. These are required to boot up the GMAC module
+ * in Linux kernel for NPCM845 boards. Other functionalities are not modeled.
+ */
+
+#include "qemu/osdep.h"
+
+#include "exec/hwaddr.h"
+#include "hw/registerfields.h"
+#include "hw/net/npcm_pcs.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/units.h"
+#include "trace.h"
+
+#define NPCM_PCS_IND_AC_BA 0x1fe
+#define NPCM_PCS_IND_SR_CTL 0x1e00
+#define NPCM_PCS_IND_SR_MII 0x1f00
+#define NPCM_PCS_IND_SR_TIM 0x1f07
+#define NPCM_PCS_IND_VR_MII 0x1f80
+
+REG16(NPCM_PCS_SR_CTL_ID1, 0x08)
+REG16(NPCM_PCS_SR_CTL_ID2, 0x0a)
+REG16(NPCM_PCS_SR_CTL_STS, 0x10)
+
+REG16(NPCM_PCS_SR_MII_CTRL, 0x00)
+REG16(NPCM_PCS_SR_MII_STS, 0x02)
+REG16(NPCM_PCS_SR_MII_DEV_ID1, 0x04)
+REG16(NPCM_PCS_SR_MII_DEV_ID2, 0x06)
+REG16(NPCM_PCS_SR_MII_AN_ADV, 0x08)
+REG16(NPCM_PCS_SR_MII_LP_BABL, 0x0a)
+REG16(NPCM_PCS_SR_MII_AN_EXPN, 0x0c)
+REG16(NPCM_PCS_SR_MII_EXT_STS, 0x1e)
+
+REG16(NPCM_PCS_SR_TIM_SYNC_ABL, 0x10)
+REG16(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR, 0x12)
+REG16(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR, 0x14)
+REG16(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR, 0x16)
+REG16(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR, 0x18)
+REG16(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR, 0x1a)
+REG16(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR, 0x1c)
+REG16(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR, 0x1e)
+REG16(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR, 0x20)
+
+REG16(NPCM_PCS_VR_MII_MMD_DIG_CTRL1, 0x000)
+REG16(NPCM_PCS_VR_MII_AN_CTRL, 0x002)
+REG16(NPCM_PCS_VR_MII_AN_INTR_STS, 0x004)
+REG16(NPCM_PCS_VR_MII_TC, 0x006)
+REG16(NPCM_PCS_VR_MII_DBG_CTRL, 0x00a)
+REG16(NPCM_PCS_VR_MII_EEE_MCTRL0, 0x00c)
+REG16(NPCM_PCS_VR_MII_EEE_TXTIMER, 0x010)
+REG16(NPCM_PCS_VR_MII_EEE_RXTIMER, 0x012)
+REG16(NPCM_PCS_VR_MII_LINK_TIMER_CTRL, 0x014)
+REG16(NPCM_PCS_VR_MII_EEE_MCTRL1, 0x016)
+REG16(NPCM_PCS_VR_MII_DIG_STS, 0x020)
+REG16(NPCM_PCS_VR_MII_ICG_ERRCNT1, 0x022)
+REG16(NPCM_PCS_VR_MII_MISC_STS, 0x030)
+REG16(NPCM_PCS_VR_MII_RX_LSTS, 0x040)
+REG16(NPCM_PCS_VR_MII_MP_TX_BSTCTRL0, 0x070)
+REG16(NPCM_PCS_VR_MII_MP_TX_LVLCTRL0, 0x074)
+REG16(NPCM_PCS_VR_MII_MP_TX_GENCTRL0, 0x07a)
+REG16(NPCM_PCS_VR_MII_MP_TX_GENCTRL1, 0x07c)
+REG16(NPCM_PCS_VR_MII_MP_TX_STS, 0x090)
+REG16(NPCM_PCS_VR_MII_MP_RX_GENCTRL0, 0x0b0)
+REG16(NPCM_PCS_VR_MII_MP_RX_GENCTRL1, 0x0b2)
+REG16(NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0, 0x0ba)
+REG16(NPCM_PCS_VR_MII_MP_MPLL_CTRL0, 0x0f0)
+REG16(NPCM_PCS_VR_MII_MP_MPLL_CTRL1, 0x0f2)
+REG16(NPCM_PCS_VR_MII_MP_MPLL_STS, 0x110)
+REG16(NPCM_PCS_VR_MII_MP_MISC_CTRL2, 0x126)
+REG16(NPCM_PCS_VR_MII_MP_LVL_CTRL, 0x130)
+REG16(NPCM_PCS_VR_MII_MP_MISC_CTRL0, 0x132)
+REG16(NPCM_PCS_VR_MII_MP_MISC_CTRL1, 0x134)
+REG16(NPCM_PCS_VR_MII_DIG_CTRL2, 0x1c2)
+REG16(NPCM_PCS_VR_MII_DIG_ERRCNT_SEL, 0x1c4)
+
+/* Register Fields */
+#define NPCM_PCS_SR_MII_CTRL_RST BIT(15)
+
+static const uint16_t npcm_pcs_sr_ctl_cold_reset_values[NPCM_PCS_NR_SR_CTLS] = {
+ [R_NPCM_PCS_SR_CTL_ID1] = 0x699e,
+ [R_NPCM_PCS_SR_CTL_STS] = 0x8000,
+};
+
+static const uint16_t npcm_pcs_sr_mii_cold_reset_values[NPCM_PCS_NR_SR_MIIS] = {
+ [R_NPCM_PCS_SR_MII_CTRL] = 0x1140,
+ [R_NPCM_PCS_SR_MII_STS] = 0x0109,
+ [R_NPCM_PCS_SR_MII_DEV_ID1] = 0x699e,
+ [R_NPCM_PCS_SR_MII_DEV_ID2] = 0xced0,
+ [R_NPCM_PCS_SR_MII_AN_ADV] = 0x0020,
+ [R_NPCM_PCS_SR_MII_EXT_STS] = 0xc000,
+};
+
+static const uint16_t npcm_pcs_sr_tim_cold_reset_values[NPCM_PCS_NR_SR_TIMS] = {
+ [R_NPCM_PCS_SR_TIM_SYNC_ABL] = 0x0003,
+ [R_NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR] = 0x0038,
+ [R_NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR] = 0x0038,
+ [R_NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR] = 0x0058,
+ [R_NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR] = 0x0048,
+};
+
+static const uint16_t npcm_pcs_vr_mii_cold_reset_values[NPCM_PCS_NR_VR_MIIS] = {
+ [R_NPCM_PCS_VR_MII_MMD_DIG_CTRL1] = 0x2400,
+ [R_NPCM_PCS_VR_MII_AN_INTR_STS] = 0x000a,
+ [R_NPCM_PCS_VR_MII_EEE_MCTRL0] = 0x899c,
+ [R_NPCM_PCS_VR_MII_DIG_STS] = 0x0010,
+ [R_NPCM_PCS_VR_MII_MP_TX_BSTCTRL0] = 0x000a,
+ [R_NPCM_PCS_VR_MII_MP_TX_LVLCTRL0] = 0x007f,
+ [R_NPCM_PCS_VR_MII_MP_TX_GENCTRL0] = 0x0001,
+ [R_NPCM_PCS_VR_MII_MP_RX_GENCTRL0] = 0x0100,
+ [R_NPCM_PCS_VR_MII_MP_RX_GENCTRL1] = 0x1100,
+ [R_NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0] = 0x000e,
+ [R_NPCM_PCS_VR_MII_MP_MPLL_CTRL0] = 0x0100,
+ [R_NPCM_PCS_VR_MII_MP_MPLL_CTRL1] = 0x0032,
+ [R_NPCM_PCS_VR_MII_MP_MPLL_STS] = 0x0001,
+ [R_NPCM_PCS_VR_MII_MP_LVL_CTRL] = 0x0019,
+};
+
+static void npcm_pcs_soft_reset(NPCMPCSState *s)
+{
+ memcpy(s->sr_ctl, npcm_pcs_sr_ctl_cold_reset_values,
+ NPCM_PCS_NR_SR_CTLS * sizeof(uint16_t));
+ memcpy(s->sr_mii, npcm_pcs_sr_mii_cold_reset_values,
+ NPCM_PCS_NR_SR_MIIS * sizeof(uint16_t));
+ memcpy(s->sr_tim, npcm_pcs_sr_tim_cold_reset_values,
+ NPCM_PCS_NR_SR_TIMS * sizeof(uint16_t));
+ memcpy(s->vr_mii, npcm_pcs_vr_mii_cold_reset_values,
+ NPCM_PCS_NR_VR_MIIS * sizeof(uint16_t));
+}
+
+static uint16_t npcm_pcs_read_sr_ctl(NPCMPCSState *s, hwaddr offset)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_SR_CTLS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SR_CTL read offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return 0;
+ }
+
+ return s->sr_ctl[regno];
+}
+
+static uint16_t npcm_pcs_read_sr_mii(NPCMPCSState *s, hwaddr offset)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_SR_MIIS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SR_MII read offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return 0;
+ }
+
+ return s->sr_mii[regno];
+}
+
+static uint16_t npcm_pcs_read_sr_tim(NPCMPCSState *s, hwaddr offset)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_SR_TIMS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SR_TIM read offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return 0;
+ }
+
+ return s->sr_tim[regno];
+}
+
+static uint16_t npcm_pcs_read_vr_mii(NPCMPCSState *s, hwaddr offset)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_VR_MIIS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: VR_MII read offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return 0;
+ }
+
+ return s->vr_mii[regno];
+}
+
+static void npcm_pcs_write_sr_ctl(NPCMPCSState *s, hwaddr offset, uint16_t v)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_SR_CTLS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SR_CTL write offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return;
+ }
+
+ s->sr_ctl[regno] = v;
+}
+
+static void npcm_pcs_write_sr_mii(NPCMPCSState *s, hwaddr offset, uint16_t v)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_SR_MIIS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SR_MII write offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return;
+ }
+
+ s->sr_mii[regno] = v;
+
+ if ((offset == A_NPCM_PCS_SR_MII_CTRL) && (v & NPCM_PCS_SR_MII_CTRL_RST)) {
+ /* Trigger a soft reset */
+ npcm_pcs_soft_reset(s);
+ }
+}
+
+static void npcm_pcs_write_sr_tim(NPCMPCSState *s, hwaddr offset, uint16_t v)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_SR_TIMS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SR_TIM write offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return;
+ }
+
+ s->sr_tim[regno] = v;
+}
+
+static void npcm_pcs_write_vr_mii(NPCMPCSState *s, hwaddr offset, uint16_t v)
+{
+ hwaddr regno = offset / sizeof(uint16_t);
+
+ if (regno >= NPCM_PCS_NR_VR_MIIS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: VR_MII write offset 0x%04" HWADDR_PRIx
+ " is out of range.\n",
+ DEVICE(s)->canonical_path, offset);
+ return;
+ }
+
+ s->vr_mii[regno] = v;
+}
+
+static uint64_t npcm_pcs_read(void *opaque, hwaddr offset, unsigned size)
+{
+ NPCMPCSState *s = opaque;
+ uint16_t v = 0;
+
+ if (offset == NPCM_PCS_IND_AC_BA) {
+ v = s->indirect_access_base;
+ } else {
+ switch (s->indirect_access_base) {
+ case NPCM_PCS_IND_SR_CTL:
+ v = npcm_pcs_read_sr_ctl(s, offset);
+ break;
+
+ case NPCM_PCS_IND_SR_MII:
+ v = npcm_pcs_read_sr_mii(s, offset);
+ break;
+
+ case NPCM_PCS_IND_SR_TIM:
+ v = npcm_pcs_read_sr_tim(s, offset);
+ break;
+
+ case NPCM_PCS_IND_VR_MII:
+ v = npcm_pcs_read_vr_mii(s, offset);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Read with invalid indirect address base: 0x%"
+ PRIx16 "\n", DEVICE(s)->canonical_path,
+ s->indirect_access_base);
+ }
+ }
+
+ trace_npcm_pcs_reg_read(DEVICE(s)->canonical_path, s->indirect_access_base,
+ offset, v);
+ return v;
+}
+
+static void npcm_pcs_write(void *opaque, hwaddr offset,
+ uint64_t v, unsigned size)
+{
+ NPCMPCSState *s = opaque;
+
+ trace_npcm_pcs_reg_write(DEVICE(s)->canonical_path, s->indirect_access_base,
+ offset, v);
+ if (offset == NPCM_PCS_IND_AC_BA) {
+ s->indirect_access_base = v;
+ } else {
+ switch (s->indirect_access_base) {
+ case NPCM_PCS_IND_SR_CTL:
+ npcm_pcs_write_sr_ctl(s, offset, v);
+ break;
+
+ case NPCM_PCS_IND_SR_MII:
+ npcm_pcs_write_sr_mii(s, offset, v);
+ break;
+
+ case NPCM_PCS_IND_SR_TIM:
+ npcm_pcs_write_sr_tim(s, offset, v);
+ break;
+
+ case NPCM_PCS_IND_VR_MII:
+ npcm_pcs_write_vr_mii(s, offset, v);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Write with invalid indirect address base: 0x%02"
+ PRIx16 "\n", DEVICE(s)->canonical_path,
+ s->indirect_access_base);
+ }
+ }
+}
+
+static void npcm_pcs_enter_reset(Object *obj, ResetType type)
+{
+ NPCMPCSState *s = NPCM_PCS(obj);
+
+ npcm_pcs_soft_reset(s);
+}
+
+static const struct MemoryRegionOps npcm_pcs_ops = {
+ .read = npcm_pcs_read,
+ .write = npcm_pcs_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 2,
+ .max_access_size = 2,
+ .unaligned = false,
+ },
+};
+
+static void npcm_pcs_realize(DeviceState *dev, Error **errp)
+{
+ NPCMPCSState *pcs = NPCM_PCS(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&pcs->iomem, OBJECT(pcs), &npcm_pcs_ops, pcs,
+ TYPE_NPCM_PCS, 8 * KiB);
+ sysbus_init_mmio(sbd, &pcs->iomem);
+}
+
+static const VMStateDescription vmstate_npcm_pcs = {
+ .name = TYPE_NPCM_PCS,
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(indirect_access_base, NPCMPCSState),
+ VMSTATE_UINT16_ARRAY(sr_ctl, NPCMPCSState, NPCM_PCS_NR_SR_CTLS),
+ VMSTATE_UINT16_ARRAY(sr_mii, NPCMPCSState, NPCM_PCS_NR_SR_MIIS),
+ VMSTATE_UINT16_ARRAY(sr_tim, NPCMPCSState, NPCM_PCS_NR_SR_TIMS),
+ VMSTATE_UINT16_ARRAY(vr_mii, NPCMPCSState, NPCM_PCS_NR_VR_MIIS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static void npcm_pcs_class_init(ObjectClass *klass, const void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->desc = "NPCM PCS Controller";
+ dc->realize = npcm_pcs_realize;
+ dc->vmsd = &vmstate_npcm_pcs;
+ rc->phases.enter = npcm_pcs_enter_reset;
+}
+
+static const TypeInfo npcm_pcs_types[] = {
+ {
+ .name = TYPE_NPCM_PCS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMPCSState),
+ .class_init = npcm_pcs_class_init,
+ },
+};
+DEFINE_TYPES(npcm_pcs_types)
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
index f96d6ea..7e955c0 100644
--- a/hw/net/opencores_eth.c
+++ b/hw/net/opencores_eth.c
@@ -743,19 +743,18 @@ static void qdev_open_eth_reset(DeviceState *dev)
open_eth_reset(d);
}
-static Property open_eth_properties[] = {
+static const Property open_eth_properties[] = {
DEFINE_NIC_PROPERTIES(OpenEthState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void open_eth_class_init(ObjectClass *klass, void *data)
+static void open_eth_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sysbus_open_eth_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "Opencores 10/100 Mbit Ethernet";
- dc->reset = qdev_open_eth_reset;
+ device_class_set_legacy_reset(dc, qdev_open_eth_reset);
device_class_set_props(dc, open_eth_properties);
}
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
index fe1a845..0ca5bc2 100644
--- a/hw/net/pcnet-pci.c
+++ b/hw/net/pcnet-pci.c
@@ -35,8 +35,8 @@
#include "net/net.h"
#include "qemu/module.h"
#include "qemu/timer.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
+#include "system/dma.h"
+#include "system/system.h"
#include "trace.h"
#include "pcnet.h"
@@ -252,12 +252,11 @@ static void pcnet_instance_init(Object *obj)
DEVICE(obj));
}
-static Property pcnet_properties[] = {
+static const Property pcnet_properties[] = {
DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pcnet_class_init(ObjectClass *klass, void *data)
+static void pcnet_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -269,7 +268,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_AMD_LANCE;
k->revision = 0x10;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- dc->reset = pci_reset;
+ device_class_set_legacy_reset(dc, pci_reset);
dc->vmsd = &vmstate_pci_pcnet;
device_class_set_props(dc, pcnet_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
@@ -281,7 +280,7 @@ static const TypeInfo pcnet_info = {
.instance_size = sizeof(PCIPCNetState),
.class_init = pcnet_class_init,
.instance_init = pcnet_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h
index eb7f46a..a94356e 100644
--- a/hw/net/pcnet.h
+++ b/hw/net/pcnet.h
@@ -7,7 +7,7 @@
#define PCNET_LOOPTEST_CRC 1
#define PCNET_LOOPTEST_NOCRC 2
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/irq.h"
/* BUS CONFIGURATION REGISTERS */
diff --git a/hw/net/rocker/rocker-hmp-cmds.c b/hw/net/rocker/rocker-hmp-cmds.c
index 197c6e2..df40991 100644
--- a/hw/net/rocker/rocker-hmp-cmds.c
+++ b/hw/net/rocker/rocker-hmp-cmds.c
@@ -18,7 +18,7 @@
#include "monitor/monitor.h"
#include "net/eth.h"
#include "qapi/qapi-commands-rocker.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
void hmp_rocker(Monitor *mon, const QDict *qdict)
{
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index 7ea8eb6..cc49701 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -134,11 +134,6 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
return list;
}
-uint32_t rocker_fp_ports(Rocker *r)
-{
- return r->fp_ports;
-}
-
static uint32_t rocker_get_pport_by_tx_ring(Rocker *r,
DescRing *ring)
{
@@ -1464,7 +1459,7 @@ static void rocker_reset(DeviceState *dev)
DPRINTF("Reset done\n");
}
-static Property rocker_properties[] = {
+static const Property rocker_properties[] = {
DEFINE_PROP_STRING("name", Rocker, name),
DEFINE_PROP_STRING("world", Rocker, world_name),
DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
@@ -1473,7 +1468,6 @@ static Property rocker_properties[] = {
switch_id, 0),
DEFINE_PROP_ARRAY("ports", Rocker, fp_ports,
fp_ports_peers, qdev_prop_netdev, NICPeers),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription rocker_vmsd = {
@@ -1481,7 +1475,7 @@ static const VMStateDescription rocker_vmsd = {
.unmigratable = 1,
};
-static void rocker_class_init(ObjectClass *klass, void *data)
+static void rocker_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1494,7 +1488,7 @@ static void rocker_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_NETWORK_OTHER;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "Rocker Switch";
- dc->reset = rocker_reset;
+ device_class_set_legacy_reset(dc, rocker_reset);
device_class_set_props(dc, rocker_properties);
dc->vmsd = &rocker_vmsd;
}
@@ -1504,7 +1498,7 @@ static const TypeInfo rocker_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(Rocker),
.class_init = rocker_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/rocker/rocker.h b/hw/net/rocker/rocker.h
index f85354d..ae06c1c 100644
--- a/hw/net/rocker/rocker.h
+++ b/hw/net/rocker/rocker.h
@@ -36,15 +36,7 @@ static inline G_GNUC_PRINTF(1, 2) int DPRINTF(const char *fmt, ...)
}
#endif
-#define __le16 uint16_t
-#define __le32 uint32_t
-#define __le64 uint64_t
-
-#define __be16 uint16_t
-#define __be32 uint32_t
-#define __be64 uint64_t
-
-static inline bool ipv4_addr_is_multicast(__be32 addr)
+static inline bool ipv4_addr_is_multicast(uint32_t addr)
{
return (addr & htonl(0xf0000000)) == htonl(0xe0000000);
}
@@ -52,8 +44,8 @@ static inline bool ipv4_addr_is_multicast(__be32 addr)
typedef struct ipv6_addr {
union {
uint8_t addr8[16];
- __be16 addr16[8];
- __be32 addr32[4];
+ uint16_t addr16[8];
+ uint32_t addr32[4];
};
} Ipv6Addr;
@@ -72,7 +64,6 @@ DECLARE_INSTANCE_CHECKER(Rocker, ROCKER,
TYPE_ROCKER)
Rocker *rocker_find(const char *name);
-uint32_t rocker_fp_ports(Rocker *r);
int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up);
int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
uint16_t vlan_id);
diff --git a/hw/net/rocker/rocker_hw.h b/hw/net/rocker/rocker_hw.h
index 1786323..7ec6bfb 100644
--- a/hw/net/rocker/rocker_hw.h
+++ b/hw/net/rocker/rocker_hw.h
@@ -9,10 +9,6 @@
#ifndef ROCKER_HW_H
#define ROCKER_HW_H
-#define __le16 uint16_t
-#define __le32 uint32_t
-#define __le64 uint64_t
-
/*
* Return codes
*/
@@ -124,12 +120,12 @@ enum {
*/
typedef struct rocker_desc {
- __le64 buf_addr;
+ uint64_t buf_addr;
uint64_t cookie;
- __le16 buf_size;
- __le16 tlv_size;
- __le16 rsvd[5]; /* pad to 32 bytes */
- __le16 comp_err;
+ uint16_t buf_size;
+ uint16_t tlv_size;
+ uint16_t rsvd[5]; /* pad to 32 bytes */
+ uint16_t comp_err;
} __attribute__((packed, aligned(8))) RockerDesc;
/*
@@ -137,9 +133,9 @@ typedef struct rocker_desc {
*/
typedef struct rocker_tlv {
- __le32 type;
- __le16 len;
- __le16 rsvd;
+ uint32_t type;
+ uint16_t len;
+ uint16_t rsvd;
} __attribute__((packed, aligned(8))) RockerTlv;
/* cmd msg */
diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c
index 5e16056..4aed178 100644
--- a/hw/net/rocker/rocker_of_dpa.c
+++ b/hw/net/rocker/rocker_of_dpa.c
@@ -52,10 +52,10 @@ typedef struct of_dpa_flow_key {
uint32_t tunnel_id; /* overlay tunnel id */
uint32_t tbl_id; /* table id */
struct {
- __be16 vlan_id; /* 0 if no VLAN */
+ uint16_t vlan_id; /* 0 if no VLAN */
MACAddr src; /* ethernet source address */
MACAddr dst; /* ethernet destination address */
- __be16 type; /* ethernet frame type */
+ uint16_t type; /* ethernet frame type */
} eth;
struct {
uint8_t proto; /* IP protocol or ARP opcode */
@@ -66,14 +66,14 @@ typedef struct of_dpa_flow_key {
union {
struct {
struct {
- __be32 src; /* IP source address */
- __be32 dst; /* IP destination address */
+ uint32_t src; /* IP source address */
+ uint32_t dst; /* IP destination address */
} addr;
union {
struct {
- __be16 src; /* TCP/UDP/SCTP source port */
- __be16 dst; /* TCP/UDP/SCTP destination port */
- __be16 flags; /* TCP flags */
+ uint16_t src; /* TCP/UDP/SCTP source port */
+ uint16_t dst; /* TCP/UDP/SCTP destination port */
+ uint16_t flags; /* TCP flags */
} tp;
struct {
MACAddr sha; /* ARP source hardware address */
@@ -86,11 +86,11 @@ typedef struct of_dpa_flow_key {
Ipv6Addr src; /* IPv6 source address */
Ipv6Addr dst; /* IPv6 destination address */
} addr;
- __be32 label; /* IPv6 flow label */
+ uint32_t label; /* IPv6 flow label */
struct {
- __be16 src; /* TCP/UDP/SCTP source port */
- __be16 dst; /* TCP/UDP/SCTP destination port */
- __be16 flags; /* TCP flags */
+ uint16_t src; /* TCP/UDP/SCTP source port */
+ uint16_t dst; /* TCP/UDP/SCTP destination port */
+ uint16_t flags; /* TCP flags */
} tp;
struct {
Ipv6Addr target; /* ND target address */
@@ -112,13 +112,13 @@ typedef struct of_dpa_flow_action {
struct {
uint32_t group_id;
uint32_t tun_log_lport;
- __be16 vlan_id;
+ uint16_t vlan_id;
} write;
struct {
- __be16 new_vlan_id;
+ uint16_t new_vlan_id;
uint32_t out_pport;
uint8_t copy_to_cpu;
- __be16 vlan_id;
+ uint16_t vlan_id;
} apply;
} OfDpaFlowAction;
@@ -143,7 +143,7 @@ typedef struct of_dpa_flow {
typedef struct of_dpa_flow_pkt_fields {
uint32_t tunnel_id;
struct eth_header *ethhdr;
- __be16 *h_proto;
+ uint16_t *h_proto;
struct vlan_header *vlanhdr;
struct ip_header *ipv4hdr;
struct ip6_header *ipv6hdr;
@@ -180,7 +180,7 @@ typedef struct of_dpa_group {
uint32_t group_id;
MACAddr src_mac;
MACAddr dst_mac;
- __be16 vlan_id;
+ uint16_t vlan_id;
} l2_rewrite;
struct {
uint16_t group_count;
@@ -190,13 +190,13 @@ typedef struct of_dpa_group {
uint32_t group_id;
MACAddr src_mac;
MACAddr dst_mac;
- __be16 vlan_id;
+ uint16_t vlan_id;
uint8_t ttl_check;
} l3_unicast;
};
} OfDpaGroup;
-static int of_dpa_mask2prefix(__be32 mask)
+static int of_dpa_mask2prefix(uint32_t mask)
{
int i;
int count = 32;
@@ -451,7 +451,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
fc->iovcnt = iovcnt + 2;
}
-static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, __be16 vlan_id)
+static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, uint16_t vlan_id)
{
OfDpaFlowPktFields *fields = &fc->fields;
uint16_t h_proto = fields->ethhdr->h_proto;
@@ -486,7 +486,7 @@ static void of_dpa_flow_pkt_strip_vlan(OfDpaFlowContext *fc)
static void of_dpa_flow_pkt_hdr_rewrite(OfDpaFlowContext *fc,
uint8_t *src_mac, uint8_t *dst_mac,
- __be16 vlan_id)
+ uint16_t vlan_id)
{
OfDpaFlowPktFields *fields = &fc->fields;
@@ -1635,8 +1635,8 @@ static int of_dpa_cmd_add_multicast_routing(OfDpaFlow *flow,
return ROCKER_OK;
}
-static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
- RockerTlv **flow_tlvs)
+static void of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
+ RockerTlv **flow_tlvs)
{
key->width = FLOW_KEY_WIDTH(ip.tos);
@@ -1669,8 +1669,6 @@ static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
mask->ip.tos |=
rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) << 6;
}
-
- return ROCKER_OK;
}
static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
@@ -1689,7 +1687,6 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
ACL_MODE_ANY_VLAN,
ACL_MODE_ANY_TENANT,
} mode = ACL_MODE_UNKNOWN;
- int err = ROCKER_OK;
if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) {
@@ -1776,14 +1773,10 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
switch (ntohs(key->eth.type)) {
case 0x0800:
case 0x86dd:
- err = of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs);
+ of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs);
break;
}
- if (err) {
- return err;
- }
-
if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
action->write.group_id =
rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 03a204e..654a087 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -48,20 +48,18 @@
* 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading
*/
-/* For crc32 */
-
#include "qemu/osdep.h"
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "net/net.h"
#include "net/eth.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qom/object.h"
/* debug RTL8139 card */
@@ -1818,7 +1816,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
PCIDevice *d = PCI_DEVICE(s);
int txsize = s->TxStatus[descriptor] & 0x1fff;
- uint8_t txbuffer[0x2000];
+ QEMU_UNINITIALIZED uint8_t txbuffer[0x2000];
DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
txsize, s->TxAddr[descriptor]);
@@ -3412,12 +3410,11 @@ static void rtl8139_instance_init(Object *obj)
DEVICE(obj));
}
-static Property rtl8139_properties[] = {
+static const Property rtl8139_properties[] = {
DEFINE_NIC_PROPERTIES(RTL8139State, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void rtl8139_class_init(ObjectClass *klass, void *data)
+static void rtl8139_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -3429,7 +3426,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_REALTEK_8139;
k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- dc->reset = rtl8139_reset;
+ device_class_set_legacy_reset(dc, rtl8139_reset);
dc->vmsd = &vmstate_rtl8139;
device_class_set_props(dc, rtl8139_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
@@ -3441,7 +3438,7 @@ static const TypeInfo rtl8139_info = {
.instance_size = sizeof(RTL8139State),
.class_init = rtl8139_class_init,
.instance_init = rtl8139_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
index 702d0e8..5cd78e3 100644
--- a/hw/net/smc91c111.c
+++ b/hw/net/smc91c111.c
@@ -13,16 +13,23 @@
#include "net/net.h"
#include "hw/irq.h"
#include "hw/net/smc91c111.h"
+#include "hw/registerfields.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
/* Number of 2k memory pages available. */
#define NUM_PACKETS 4
+/*
+ * Maximum size of a data frame, including the leading status word
+ * and byte count fields and the trailing CRC, last data byte
+ * and control byte (per figure 8-1 in the Microchip Technology
+ * LAN91C111 datasheet).
+ */
+#define MAX_PACKET_SIZE 2048
#define TYPE_SMC91C111 "smc91c111"
OBJECT_DECLARE_SIMPLE_TYPE(smc91c111_state, SMC91C111)
@@ -52,7 +59,7 @@ struct smc91c111_state {
int tx_fifo_done_len;
int tx_fifo_done[NUM_PACKETS];
/* Packet buffer memory. */
- uint8_t data[NUM_PACKETS][2048];
+ uint8_t data[NUM_PACKETS][MAX_PACKET_SIZE];
uint8_t int_level;
uint8_t int_mask;
MemoryRegion mmio;
@@ -80,7 +87,8 @@ static const VMStateDescription vmstate_smc91c111 = {
VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
- VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
+ VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0,
+ NUM_PACKETS * MAX_PACKET_SIZE),
VMSTATE_UINT8(int_level, smc91c111_state),
VMSTATE_UINT8(int_mask, smc91c111_state),
VMSTATE_END_OF_LIST()
@@ -119,6 +127,18 @@ static const VMStateDescription vmstate_smc91c111 = {
#define RS_TOOSHORT 0x0400
#define RS_MULTICAST 0x0001
+FIELD(PTR, PTR, 0, 11)
+FIELD(PTR, NOT_EMPTY, 11, 1)
+FIELD(PTR, RESERVED, 12, 1)
+FIELD(PTR, READ, 13, 1)
+FIELD(PTR, AUTOINCR, 14, 1)
+FIELD(PTR, RCV, 15, 1)
+
+static inline bool packetnum_valid(int packet_num)
+{
+ return packet_num >= 0 && packet_num < NUM_PACKETS;
+}
+
/* Update interrupt status. */
static void smc91c111_update(smc91c111_state *s)
{
@@ -183,6 +203,15 @@ static void smc91c111_pop_rx_fifo(smc91c111_state *s)
{
int i;
+ if (s->rx_fifo_len == 0) {
+ /*
+ * The datasheet doesn't document what the behaviour is if the
+ * guest tries to pop an empty RX FIFO, and there's no obvious
+ * error status register to report it. Just ignore the attempt.
+ */
+ return;
+ }
+
s->rx_fifo_len--;
if (s->rx_fifo_len) {
for (i = 0; i < s->rx_fifo_len; i++)
@@ -210,12 +239,33 @@ static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
/* Release the memory allocated to a packet. */
static void smc91c111_release_packet(smc91c111_state *s, int packet)
{
+ if (!packetnum_valid(packet)) {
+ /*
+ * Data sheet doesn't document behaviour in this guest error
+ * case, and there is no error status register to report it.
+ * Log and ignore the attempt.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "smc91c111: attempt to release invalid packet %d\n",
+ packet);
+ return;
+ }
s->allocated &= ~(1 << packet);
if (s->tx_alloc == 0x80)
smc91c111_tx_alloc(s);
smc91c111_flush_queued_packets(s);
}
+static void smc91c111_complete_tx_packet(smc91c111_state *s, int packetnum)
+{
+ if (s->ctr & CTR_AUTO_RELEASE) {
+ /* Race? */
+ smc91c111_release_packet(s, packetnum);
+ } else if (s->tx_fifo_done_len < NUM_PACKETS) {
+ s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
+ }
+}
+
/* Flush the TX FIFO. */
static void smc91c111_do_tx(smc91c111_state *s)
{
@@ -231,12 +281,25 @@ static void smc91c111_do_tx(smc91c111_state *s)
return;
for (i = 0; i < s->tx_fifo_len; i++) {
packetnum = s->tx_fifo[i];
+ /* queue_tx checked the packet number was valid */
+ assert(packetnum_valid(packetnum));
p = &s->data[packetnum][0];
/* Set status word. */
*(p++) = 0x01;
*(p++) = 0x40;
len = *(p++);
len |= ((int)*(p++)) << 8;
+ if (len > MAX_PACKET_SIZE) {
+ /*
+ * Datasheet doesn't say what to do here, and there is no
+ * relevant tx error condition listed. Log, and drop the packet.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "smc91c111: tx packet with bad length %d, dropping\n",
+ len);
+ smc91c111_complete_tx_packet(s, packetnum);
+ continue;
+ }
len -= 6;
control = p[len + 1];
if (control & 0x20)
@@ -265,11 +328,7 @@ static void smc91c111_do_tx(smc91c111_state *s)
}
}
#endif
- if (s->ctr & CTR_AUTO_RELEASE)
- /* Race? */
- smc91c111_release_packet(s, packetnum);
- else if (s->tx_fifo_done_len < NUM_PACKETS)
- s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
+ smc91c111_complete_tx_packet(s, packetnum);
qemu_send_packet(qemu_get_queue(s->nic), p, len);
}
s->tx_fifo_len = 0;
@@ -279,6 +338,17 @@ static void smc91c111_do_tx(smc91c111_state *s)
/* Add a packet to the TX FIFO. */
static void smc91c111_queue_tx(smc91c111_state *s, int packet)
{
+ if (!packetnum_valid(packet)) {
+ /*
+ * Datasheet doesn't document behaviour in this error case, and
+ * there's no error status register we could report it in.
+ * Log and ignore.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "smc91c111: attempt to queue invalid packet %d\n",
+ packet);
+ return;
+ }
if (s->tx_fifo_len == NUM_PACKETS)
return;
s->tx_fifo[s->tx_fifo_len++] = packet;
@@ -310,6 +380,49 @@ static void smc91c111_reset(DeviceState *dev)
#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
+/*
+ * The pointer register's pointer is an 11 bit value (so it exactly
+ * indexes a 2048-byte data frame). Add the specified offset to it,
+ * wrapping around at the 2048 byte mark, and return the resulting
+ * wrapped value. There are flag bits in the top part of the register,
+ * but we can ignore them here as the mask will mask them out.
+ */
+static int ptr_reg_add(smc91c111_state *s, int offset)
+{
+ return (s->ptr + offset) & R_PTR_PTR_MASK;
+}
+
+/*
+ * For an access to the Data Register at @offset, return the
+ * required offset into the packet's data frame. This will
+ * perform the pointer register autoincrement if required, and
+ * guarantees to return an in-bounds offset.
+ */
+static int data_reg_ptr(smc91c111_state *s, int offset)
+{
+ int p;
+
+ if (s->ptr & R_PTR_AUTOINCR_MASK) {
+ /*
+ * Autoincrement: use the current pointer value, and
+ * increment the pointer register's pointer field.
+ */
+ p = FIELD_EX32(s->ptr, PTR, PTR);
+ s->ptr = FIELD_DP32(s->ptr, PTR, PTR, ptr_reg_add(s, 1));
+ } else {
+ /*
+ * No autoincrement: register offset determines which
+ * byte we're addressing. Setting the pointer to the top
+ * of the data buffer and then using the pointer wrapping
+ * to read the bottom byte of the buffer is not something
+ * sensible guest software will do, but the datasheet
+ * doesn't say what the behaviour is, so we don't forbid it.
+ */
+ p = ptr_reg_add(s, offset & 3);
+ }
+ return p;
+}
+
static void smc91c111_writeb(void *opaque, hwaddr offset,
uint32_t value)
{
@@ -449,12 +562,14 @@ static void smc91c111_writeb(void *opaque, hwaddr offset,
n = s->rx_fifo[0];
else
n = s->packet_num;
- p = s->ptr & 0x07ff;
- if (s->ptr & 0x4000) {
- s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
- } else {
- p += (offset & 3);
+ if (!packetnum_valid(n)) {
+ /* Datasheet doesn't document what to do here */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "smc91c111: attempt to write data to invalid packet %d\n",
+ n);
+ return;
}
+ p = data_reg_ptr(s, offset);
s->data[n][p] = value;
}
return;
@@ -597,12 +712,14 @@ static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
n = s->rx_fifo[0];
else
n = s->packet_num;
- p = s->ptr & 0x07ff;
- if (s->ptr & 0x4000) {
- s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
- } else {
- p += (offset & 3);
+ if (!packetnum_valid(n)) {
+ /* Datasheet doesn't document what to do here */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "smc91c111: attempt to read data from invalid packet %d\n",
+ n);
+ return 0;
}
+ p = data_reg_ptr(s, offset);
return s->data[n][p];
}
case 12: /* Interrupt status. */
@@ -698,13 +815,16 @@ static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t
if (crc)
packetsize += 4;
/* TODO: Flag overrun and receive errors. */
- if (packetsize > 2048)
+ if (packetsize > MAX_PACKET_SIZE) {
return -1;
+ }
packetnum = smc91c111_allocate_packet(s);
if (packetnum == 0x80)
return -1;
s->rx_fifo[s->rx_fifo_len++] = packetnum;
+ /* allocate_packet() will not hand us back an invalid packet number */
+ assert(packetnum_valid(packetnum));
p = &s->data[packetnum][0];
/* ??? Multicast packets? */
status = 0;
@@ -789,17 +909,16 @@ static void smc91c111_realize(DeviceState *dev, Error **errp)
/* ??? Save/restore. */
}
-static Property smc91c111_properties[] = {
+static const Property smc91c111_properties[] = {
DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void smc91c111_class_init(ObjectClass *klass, void *data)
+static void smc91c111_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = smc91c111_realize;
- dc->reset = smc91c111_reset;
+ device_class_set_legacy_reset(dc, smc91c111_reset);
dc->vmsd = &vmstate_smc91c111;
device_class_set_props(dc, smc91c111_properties);
}
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 8af33d9..f6f217d 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -33,7 +33,7 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "hw/qdev-properties.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "trace.h"
#include <libfdt.h>
@@ -786,12 +786,11 @@ static target_ulong h_change_logical_lan_mac(PowerPCCPU *cpu,
return H_SUCCESS;
}
-static Property spapr_vlan_properties[] = {
+static const Property spapr_vlan_properties[] = {
DEFINE_SPAPR_PROPERTIES(SpaprVioVlan, sdev),
DEFINE_NIC_PROPERTIES(SpaprVioVlan, nicconf),
DEFINE_PROP_BIT("use-rx-buffer-pools", SpaprVioVlan,
compat_flags, SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT, true),
- DEFINE_PROP_END_OF_LIST(),
};
static bool spapr_vlan_rx_buffer_pools_needed(void *opaque)
@@ -849,7 +848,7 @@ static const VMStateDescription vmstate_spapr_llan = {
}
};
-static void spapr_vlan_class_init(ObjectClass *klass, void *data)
+static void spapr_vlan_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c
index db95766..2fc51e1 100644
--- a/hw/net/stellaris_enet.c
+++ b/hw/net/stellaris_enet.c
@@ -15,7 +15,7 @@
#include "net/net.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
//#define DEBUG_STELLARIS_ENET 1
@@ -497,17 +497,16 @@ static void stellaris_enet_realize(DeviceState *dev, Error **errp)
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
}
-static Property stellaris_enet_properties[] = {
+static const Property stellaris_enet_properties[] = {
DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void stellaris_enet_class_init(ObjectClass *klass, void *data)
+static void stellaris_enet_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = stellaris_enet_realize;
- dc->reset = stellaris_enet_reset;
+ device_class_set_legacy_reset(dc, stellaris_enet_reset);
device_class_set_props(dc, stellaris_enet_properties);
dc->vmsd = &vmstate_stellaris_enet;
}
diff --git a/hw/net/sungem.c b/hw/net/sungem.c
index dd1b4a1..b405eb8 100644
--- a/hw/net/sungem.c
+++ b/hw/net/sungem.c
@@ -17,7 +17,7 @@
#include "net/eth.h"
#include "net/checksum.h"
#include "hw/net/mii.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "trace.h"
#include "qom/object.h"
@@ -1420,14 +1420,13 @@ static void sungem_instance_init(Object *obj)
DEVICE(obj));
}
-static Property sungem_properties[] = {
+static const Property sungem_properties[] = {
DEFINE_NIC_PROPERTIES(SunGEMState, conf),
/* Phy address should be 0 for most Apple machines except
* for K2 in which case it's 1. Will be set by a machine
* override.
*/
DEFINE_PROP_UINT32("phy_addr", SunGEMState, phy_addr, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_sungem = {
@@ -1455,7 +1454,7 @@ static const VMStateDescription vmstate_sungem = {
}
};
-static void sungem_class_init(ObjectClass *klass, void *data)
+static void sungem_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1467,7 +1466,7 @@ static void sungem_class_init(ObjectClass *klass, void *data)
k->revision = 0x01;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->vmsd = &vmstate_sungem;
- dc->reset = sungem_reset;
+ device_class_set_legacy_reset(dc, sungem_reset);
device_class_set_props(dc, sungem_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
@@ -1478,7 +1477,7 @@ static const TypeInfo sungem_info = {
.instance_size = sizeof(SunGEMState),
.class_init = sungem_class_init,
.instance_init = sungem_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c
index ae8452e..c2f7a84 100644
--- a/hw/net/sunhme.c
+++ b/hw/net/sunhme.c
@@ -31,7 +31,7 @@
#include "qemu/module.h"
#include "net/checksum.h"
#include "net/eth.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "trace.h"
#include "qom/object.h"
@@ -177,9 +177,8 @@ struct SunHMEState {
uint16_t miiregs[HME_MII_REGS_SIZE];
};
-static Property sunhme_properties[] = {
+static const Property sunhme_properties[] = {
DEFINE_NIC_PROPERTIES(SunHMEState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
static void sunhme_reset_tx(SunHMEState *s)
@@ -938,7 +937,7 @@ static const VMStateDescription vmstate_hme = {
}
};
-static void sunhme_class_init(ObjectClass *klass, void *data)
+static void sunhme_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -948,7 +947,7 @@ static void sunhme_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_SUN_HME;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->vmsd = &vmstate_hme;
- dc->reset = sunhme_reset;
+ device_class_set_legacy_reset(dc, sunhme_reset);
device_class_set_props(dc, sunhme_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
@@ -959,7 +958,7 @@ static const TypeInfo sunhme_info = {
.class_init = sunhme_class_init,
.instance_size = sizeof(SunHMEState),
.instance_init = sunhme_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 78efa2e..72b69c4 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -10,10 +10,11 @@ allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u"
allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64
allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64
-# etraxfs_eth.c
-mdio_phy_read(int regnum, uint16_t value) "read phy_reg:%d value:0x%04x"
-mdio_phy_write(int regnum, uint16_t value) "write phy_reg:%d value:0x%04x"
-mdio_bitbang(bool mdc, bool mdio, int state, uint16_t cnt, unsigned int drive) "bitbang mdc=%u mdio=%u state=%d cnt=%u drv=%d"
+# lan9118_phy.c
+lan9118_phy_read(uint16_t val, int reg) "[0x%02x] -> 0x%04" PRIx16
+lan9118_phy_write(uint16_t val, int reg) "[0x%02x] <- 0x%04" PRIx16
+lan9118_phy_update_link(const char *s) "%s"
+lan9118_phy_reset(void) ""
# lance.c
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x"
@@ -399,9 +400,11 @@ virtio_net_announce_notify(void) ""
virtio_net_announce_timer(int round) "%d"
virtio_net_handle_announce(int round) "%d"
virtio_net_post_load_device(void)
-virtio_net_rss_disable(void)
-virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x"
-virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d"
+virtio_net_rss_load(void *nic, size_t nfds, void *fds) "nic=%p nfds=%zu fds=%p"
+virtio_net_rss_attach_ebpf(void *nic, int prog_fd) "nic=%p prog-fd=%d"
+virtio_net_rss_disable(void *nic) "nic=%p"
+virtio_net_rss_error(void *nic, const char *msg, uint32_t value) "nic=%p msg=%s, value 0x%08x"
+virtio_net_rss_enable(void *nic, uint32_t p1, uint16_t p2, uint8_t p3) "nic=%p hashes 0x%x, table of %d, key of %d"
# tulip.c
tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64
@@ -431,12 +434,8 @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries"
i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
# imx_fec.c
-imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]"
imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)"
-imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]"
imx_phy_write_num(int phy, int configured) "write request to unconfigured phy %d (configured %d)"
-imx_phy_update_link(const char *s) "%s"
-imx_phy_reset(void) ""
imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x"
imx_enet_read_bd(uint64_t addr, int flags, int len, int data, int options, int status) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x option 0x%04x status 0x%04x"
imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit"
@@ -481,10 +480,11 @@ npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finishe
npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16
npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32
npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
+npcm_gmac_tx_desc_owner(const char* name, uint32_t desc_addr) "%s: TX Descriptor @0x%04" PRIX32 " is owned by software"
# npcm_pcs.c
-npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
-npcm_pcs_reg_write(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
+npcm_pcs_reg_read(const char *name, uint16_t indirect_access_base, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
+npcm_pcs_reg_write(const char *name, uint16_t indirect_access_base, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
# dp8398x.c
dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x"
@@ -513,3 +513,7 @@ xen_netdev_connect(int dev, unsigned int tx, unsigned int rx, int port) "vif%u t
xen_netdev_frontend_changed(const char *dev, int state) "vif%s state %d"
xen_netdev_tx(int dev, int ref, int off, int len, unsigned int flags, const char *c, const char *d, const char *m, const char *e) "vif%u ref %u off %u len %u flags 0x%x%s%s%s%s"
xen_netdev_rx(int dev, int idx, int status, int flags) "vif%u idx %d status %d flags 0x%x"
+
+# xilinx_ethlite.c
+ethlite_pkt_lost(uint32_t rx_ctrl) "rx_ctrl:0x%" PRIx32
+ethlite_pkt_size_too_big(uint64_t size) "size:0x%" PRIx64
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
index 1f2ef20..319af90 100644
--- a/hw/net/tulip.c
+++ b/hw/net/tulip.c
@@ -13,7 +13,7 @@
#include "hw/qdev-properties.h"
#include "hw/nvram/eeprom93xx.h"
#include "migration/vmstate.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "tulip.h"
#include "trace.h"
#include "net/eth.h"
@@ -629,7 +629,7 @@ static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n)
static void tulip_setup_frame(TULIPState *s,
struct tulip_descriptor *desc)
{
- uint8_t buf[4096];
+ QEMU_UNINITIALIZED uint8_t buf[4096];
int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
int i;
@@ -1007,12 +1007,11 @@ static void tulip_instance_init(Object *obj)
&pci_dev->qdev);
}
-static Property tulip_properties[] = {
+static const Property tulip_properties[] = {
DEFINE_NIC_PROPERTIES(TULIPState, c),
- DEFINE_PROP_END_OF_LIST(),
};
-static void tulip_class_init(ObjectClass *klass, void *data)
+static void tulip_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1026,7 +1025,7 @@ static void tulip_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->vmsd = &vmstate_pci_tulip;
device_class_set_props(dc, tulip_properties);
- dc->reset = tulip_qdev_reset;
+ device_class_set_legacy_reset(dc, tulip_qdev_reset);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
@@ -1036,7 +1035,7 @@ static const TypeInfo tulip_info = {
.instance_size = sizeof(TULIPState),
.class_init = tulip_class_init,
.instance_init = tulip_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index dedf9ad..891f235 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -162,6 +162,148 @@ void vhost_net_save_acked_features(NetClientState *nc)
#endif
}
+static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev,
+ NetClientState *ncs, int data_queue_pairs, int nvhosts)
+{
+ VirtIONet *n = VIRTIO_NET(dev);
+ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
+ struct vhost_net *net;
+ struct vhost_dev *hdev;
+ int r, i, j;
+ NetClientState *peer;
+
+ /*
+ * Batch all the host notifiers in a single transaction to avoid
+ * quadratic time complexity in address_space_update_ioeventfds().
+ */
+ memory_region_transaction_begin();
+
+ for (i = 0; i < nvhosts; i++) {
+ if (i < data_queue_pairs) {
+ peer = qemu_get_peer(ncs, i);
+ } else {
+ peer = qemu_get_peer(ncs, n->max_queue_pairs);
+ }
+
+ net = get_vhost_net(peer);
+ hdev = &net->dev;
+ for (j = 0; j < hdev->nvqs; j++) {
+ r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
+ hdev->vq_index + j,
+ false);
+ if (r < 0) {
+ error_report("vhost %d VQ %d notifier cleanup failed: %d",
+ i, j, -r);
+ }
+ assert(r >= 0);
+ }
+ }
+ /*
+ * The transaction expects the ioeventfds to be open when it
+ * commits. Do it now, before the cleanup loop.
+ */
+ memory_region_transaction_commit();
+
+ for (i = 0; i < nvhosts; i++) {
+ if (i < data_queue_pairs) {
+ peer = qemu_get_peer(ncs, i);
+ } else {
+ peer = qemu_get_peer(ncs, n->max_queue_pairs);
+ }
+
+ net = get_vhost_net(peer);
+ hdev = &net->dev;
+ for (j = 0; j < hdev->nvqs; j++) {
+ virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus),
+ hdev->vq_index + j);
+ }
+ virtio_device_release_ioeventfd(dev);
+ }
+}
+
+static int vhost_net_enable_notifiers(VirtIODevice *dev,
+ NetClientState *ncs, int data_queue_pairs, int cvq)
+{
+ VirtIONet *n = VIRTIO_NET(dev);
+ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
+ int nvhosts = data_queue_pairs + cvq;
+ struct vhost_net *net;
+ struct vhost_dev *hdev;
+ int r, i, j, k;
+ NetClientState *peer;
+
+ /*
+ * We will pass the notifiers to the kernel, make sure that QEMU
+ * doesn't interfere.
+ */
+ for (i = 0; i < nvhosts; i++) {
+ r = virtio_device_grab_ioeventfd(dev);
+ if (r < 0) {
+ error_report("vhost %d binding does not support host notifiers", i);
+ for (k = 0; k < i; k++) {
+ virtio_device_release_ioeventfd(dev);
+ }
+ return r;
+ }
+ }
+
+ /*
+ * Batch all the host notifiers in a single transaction to avoid
+ * quadratic time complexity in address_space_update_ioeventfds().
+ */
+ memory_region_transaction_begin();
+
+ for (i = 0; i < nvhosts; i++) {
+ if (i < data_queue_pairs) {
+ peer = qemu_get_peer(ncs, i);
+ } else {
+ peer = qemu_get_peer(ncs, n->max_queue_pairs);
+ }
+
+ net = get_vhost_net(peer);
+ hdev = &net->dev;
+
+ for (j = 0; j < hdev->nvqs; j++) {
+ r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
+ hdev->vq_index + j,
+ true);
+ if (r < 0) {
+ error_report("vhost %d VQ %d notifier binding failed: %d",
+ i, j, -r);
+ memory_region_transaction_commit();
+ vhost_dev_disable_notifiers_nvqs(hdev, dev, j);
+ goto fail_nvhosts;
+ }
+ }
+ }
+
+ memory_region_transaction_commit();
+
+ return 0;
+fail_nvhosts:
+ vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i);
+ /*
+ * This for loop starts from i+1, not i, because the i-th ioeventfd
+ * has already been released in vhost_dev_disable_notifiers_nvqs().
+ */
+ for (k = i + 1; k < nvhosts; k++) {
+ virtio_device_release_ioeventfd(dev);
+ }
+
+ return r;
+}
+
+/*
+ * Stop processing guest IO notifications in qemu.
+ * Start processing them in vhost in kernel.
+ */
+static void vhost_net_disable_notifiers(VirtIODevice *dev,
+ NetClientState *ncs, int data_queue_pairs, int cvq)
+{
+ vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs,
+ data_queue_pairs + cvq);
+}
+
static int vhost_net_get_fd(NetClientState *backend)
{
switch (backend->info->type) {
@@ -272,11 +414,6 @@ static int vhost_net_start_one(struct vhost_net *net,
}
}
- r = vhost_dev_enable_notifiers(&net->dev, dev);
- if (r < 0) {
- goto fail_notifiers;
- }
-
r = vhost_dev_start(&net->dev, dev, false);
if (r < 0) {
goto fail_start;
@@ -328,8 +465,6 @@ fail:
}
vhost_dev_stop(&net->dev, dev, false);
fail_start:
- vhost_dev_disable_notifiers(&net->dev, dev);
-fail_notifiers:
return r;
}
@@ -351,7 +486,6 @@ static void vhost_net_stop_one(struct vhost_net *net,
if (net->nc->info->stop) {
net->nc->info->stop(net->nc);
}
- vhost_dev_disable_notifiers(&net->dev, dev);
}
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
@@ -396,10 +530,16 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
}
}
+ r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq);
+ if (r < 0) {
+ error_report("Error enabling host notifiers: %d", -r);
+ goto err;
+ }
+
r = k->set_guest_notifiers(qbus->parent, total_notifiers, true);
if (r < 0) {
error_report("Error binding guest notifier: %d", -r);
- goto err;
+ goto err_host_notifiers;
}
for (i = 0; i < nvhosts; i++) {
@@ -414,19 +554,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
r = vhost_set_vring_enable(peer, peer->vring_enable);
if (r < 0) {
- goto err_start;
+ goto err_guest_notifiers;
}
}
r = vhost_net_start_one(get_vhost_net(peer), dev);
if (r < 0) {
- goto err_start;
+ goto err_guest_notifiers;
}
}
return 0;
-err_start:
+err_guest_notifiers:
while (--i >= 0) {
peer = qemu_get_peer(ncs, i < data_queue_pairs ?
i : n->max_queue_pairs);
@@ -437,6 +577,8 @@ err_start:
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
fflush(stderr);
}
+err_host_notifiers:
+ vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
err:
return r;
}
@@ -468,6 +610,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
fflush(stderr);
}
assert(r >= 0);
+
+ vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
}
void vhost_net_cleanup(struct vhost_net *net)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index ed33a32..eb93607 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -26,7 +26,7 @@
#include "qemu/option.h"
#include "qemu/option_int.h"
#include "qemu/config-file.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "hw/virtio/virtio-net.h"
#include "net/vhost_net.h"
#include "net/announce.h"
@@ -39,15 +39,15 @@
#include "hw/virtio/virtio-access.h"
#include "migration/misc.h"
#include "standard-headers/linux/ethtool.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/replay.h"
+#include "system/system.h"
+#include "system/replay.h"
#include "trace.h"
#include "monitor/qdev.h"
#include "monitor/monitor.h"
#include "hw/pci/pci_device.h"
#include "net_rx_pkt.h"
#include "hw/virtio/vhost.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#define VIRTIO_NET_VM_VERSION 11
@@ -382,7 +382,7 @@ static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq)
}
}
-static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+static int virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
VirtIONet *n = VIRTIO_NET(vdev);
VirtIONetQueue *q;
@@ -437,6 +437,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
}
}
}
+ return 0;
}
static void virtio_net_set_link_status(NetClientState *nc)
@@ -1241,6 +1242,7 @@ static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd)
return false;
}
+ trace_virtio_net_rss_attach_ebpf(nic, prog_fd);
return nc->info->set_steering_ebpf(nc, prog_fd);
}
@@ -1254,7 +1256,7 @@ static void rss_data_to_rss_config(struct VirtioNetRssData *data,
config->default_queue = data->default_queue;
}
-static bool virtio_net_attach_epbf_rss(VirtIONet *n)
+static bool virtio_net_attach_ebpf_rss(VirtIONet *n)
{
struct EBPFRSSConfig config = {};
@@ -1265,7 +1267,8 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n)
rss_data_to_rss_config(&n->rss_data, &config);
if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
- n->rss_data.indirections_table, n->rss_data.key)) {
+ n->rss_data.indirections_table, n->rss_data.key,
+ NULL)) {
return false;
}
@@ -1276,7 +1279,7 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n)
return true;
}
-static void virtio_net_detach_epbf_rss(VirtIONet *n)
+static void virtio_net_detach_ebpf_rss(VirtIONet *n)
{
virtio_net_attach_ebpf_to_backend(n->nic, -1);
}
@@ -1286,8 +1289,8 @@ static void virtio_net_commit_rss_config(VirtIONet *n)
if (n->rss_data.enabled) {
n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
if (n->rss_data.populate_hash) {
- virtio_net_detach_epbf_rss(n);
- } else if (!virtio_net_attach_epbf_rss(n)) {
+ virtio_net_detach_ebpf_rss(n);
+ } else if (!virtio_net_attach_ebpf_rss(n)) {
if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
warn_report("Can't load eBPF RSS for vhost");
} else {
@@ -1296,12 +1299,13 @@ static void virtio_net_commit_rss_config(VirtIONet *n)
}
}
- trace_virtio_net_rss_enable(n->rss_data.hash_types,
+ trace_virtio_net_rss_enable(n,
+ n->rss_data.hash_types,
n->rss_data.indirections_len,
sizeof(n->rss_data.key));
} else {
- virtio_net_detach_epbf_rss(n);
- trace_virtio_net_rss_disable();
+ virtio_net_detach_ebpf_rss(n);
+ trace_virtio_net_rss_disable(n);
}
}
@@ -1315,28 +1319,27 @@ static void virtio_net_disable_rss(VirtIONet *n)
virtio_net_commit_rss_config(n);
}
-static bool virtio_net_load_ebpf_fds(VirtIONet *n)
+static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp)
{
int fds[EBPF_RSS_MAX_FDS] = { [0 ... EBPF_RSS_MAX_FDS - 1] = -1};
int ret = true;
int i = 0;
if (n->nr_ebpf_rss_fds != EBPF_RSS_MAX_FDS) {
- warn_report("Expected %d file descriptors but got %d",
- EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds);
- return false;
- }
+ error_setg(errp, "Expected %d file descriptors but got %d",
+ EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds);
+ return false;
+ }
for (i = 0; i < n->nr_ebpf_rss_fds; i++) {
- fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i],
- &error_warn);
+ fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i], errp);
if (fds[i] < 0) {
ret = false;
goto exit;
}
}
- ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+ ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3], errp);
exit:
if (!ret) {
@@ -1348,17 +1351,27 @@ exit:
return ret;
}
-static bool virtio_net_load_ebpf(VirtIONet *n)
+static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
{
- bool ret = false;
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+ return true;
+ }
- if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
- if (!(n->ebpf_rss_fds && virtio_net_load_ebpf_fds(n))) {
- ret = ebpf_rss_load(&n->ebpf_rss);
- }
+ trace_virtio_net_rss_load(n, n->nr_ebpf_rss_fds, n->ebpf_rss_fds);
+
+ /*
+ * If user explicitly gave QEMU RSS FDs to use, then
+ * failing to use them must be considered a fatal
+ * error. If no RSS FDs were provided, QEMU is trying
+ * eBPF on a "best effort" basis only, so report a
+ * warning and allow fallback to software RSS.
+ */
+ if (n->ebpf_rss_fds) {
+ return virtio_net_load_ebpf_fds(n, errp);
}
- return ret;
+ ebpf_rss_load(&n->ebpf_rss, &error_warn);
+ return true;
}
static void virtio_net_unload_ebpf(VirtIONet *n)
@@ -1401,17 +1414,17 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types);
n->rss_data.indirections_len =
virtio_lduw_p(vdev, &cfg.indirection_table_mask);
- n->rss_data.indirections_len++;
if (!do_rss) {
- n->rss_data.indirections_len = 1;
+ n->rss_data.indirections_len = 0;
}
- if (!is_power_of_2(n->rss_data.indirections_len)) {
- err_msg = "Invalid size of indirection table";
+ if (n->rss_data.indirections_len >= VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+ err_msg = "Too large indirection table";
err_value = n->rss_data.indirections_len;
goto error;
}
- if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
- err_msg = "Too large indirection table";
+ n->rss_data.indirections_len++;
+ if (!is_power_of_2(n->rss_data.indirections_len)) {
+ err_msg = "Invalid size of indirection table";
err_value = n->rss_data.indirections_len;
goto error;
}
@@ -1482,7 +1495,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
virtio_net_commit_rss_config(n);
return queue_pairs;
error:
- trace_virtio_net_rss_error(err_msg, err_value);
+ trace_virtio_net_rss_error(n, err_msg, err_value);
virtio_net_disable_rss(n);
return 0;
}
@@ -1692,8 +1705,11 @@ static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr)
static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
uint8_t *buf, size_t size)
{
+ size_t csum_size = ETH_HLEN + sizeof(struct ip_header) +
+ sizeof(struct udp_header);
+
if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
- (size > 27 && size < 1500) && /* normal sized MTU */
+ (size >= csum_size && size < 1500) && /* normal sized MTU */
(buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
(buf[23] == 17) && /* ip.protocol == UDP */
(buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
@@ -1890,32 +1906,34 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
}
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
- size_t size, bool no_rss)
+ size_t size)
{
VirtIONet *n = qemu_get_nic_opaque(nc);
- VirtIONetQueue *q = virtio_net_get_subqueue(nc);
+ VirtIONetQueue *q;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
- VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE];
- size_t lens[VIRTQUEUE_MAX_SIZE];
- struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
+ QEMU_UNINITIALIZED VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE];
+ QEMU_UNINITIALIZED size_t lens[VIRTQUEUE_MAX_SIZE];
+ QEMU_UNINITIALIZED struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
struct virtio_net_hdr_v1_hash extra_hdr;
unsigned mhdr_cnt = 0;
size_t offset, i, guest_offset, j;
ssize_t err;
- if (!virtio_net_can_receive(nc)) {
- return -1;
- }
+ memset(&extra_hdr, 0, sizeof(extra_hdr));
- if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) {
+ if (n->rss_data.enabled && n->rss_data.enabled_software_rss) {
int index = virtio_net_process_rss(nc, buf, size, &extra_hdr);
if (index >= 0) {
- NetClientState *nc2 =
- qemu_get_subqueue(n->nic, index % n->curr_queue_pairs);
- return virtio_net_receive_rcu(nc2, buf, size, true);
+ nc = qemu_get_subqueue(n->nic, index % n->curr_queue_pairs);
}
}
+ if (!virtio_net_can_receive(nc)) {
+ return -1;
+ }
+
+ q = virtio_net_get_subqueue(nc);
+
/* hdr_len refers to the header we supply to the guest */
if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
return 0;
@@ -1971,6 +1989,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
sg, elem->in_num,
offsetof(typeof(extra_hdr), hdr.num_buffers),
sizeof(extra_hdr.hdr.num_buffers));
+ } else {
+ extra_hdr.hdr.num_buffers = cpu_to_le16(1);
}
receive_header(n, sg, elem->in_num, buf, size);
@@ -2041,7 +2061,22 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf,
{
RCU_READ_LOCK_GUARD();
- return virtio_net_receive_rcu(nc, buf, size, false);
+ return virtio_net_receive_rcu(nc, buf, size);
+}
+
+/*
+ * Accessors to read and write the IP packet data length field. This
+ * is a potentially unaligned network-byte-order 16 bit unsigned integer
+ * pointed to by unit->ip_len.
+ */
+static uint16_t read_unit_ip_len(VirtioNetRscUnit *unit)
+{
+ return lduw_be_p(unit->ip_plen);
+}
+
+static void write_unit_ip_len(VirtioNetRscUnit *unit, uint16_t l)
+{
+ stw_be_p(unit->ip_plen, l);
}
static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
@@ -2058,7 +2093,7 @@ static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
unit->ip_plen = &ip->ip_len;
unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen);
unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
- unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen;
+ unit->payload = read_unit_ip_len(unit) - ip_hdrlen - unit->tcp_hdrlen;
}
static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain,
@@ -2077,7 +2112,7 @@ static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain,
/* There is a difference between payload length in ipv4 and v6,
ip header is excluded in ipv6 */
- unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
+ unit->payload = read_unit_ip_len(unit) - unit->tcp_hdrlen;
}
static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain,
@@ -2226,7 +2261,7 @@ static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain,
VirtioNetRscUnit *o_unit;
o_unit = &seg->unit;
- o_ip_len = htons(*o_unit->ip_plen);
+ o_ip_len = read_unit_ip_len(o_unit);
nseq = htonl(n_unit->tcp->th_seq);
oseq = htonl(o_unit->tcp->th_seq);
@@ -2262,7 +2297,7 @@ coalesce:
o_unit->payload += n_unit->payload; /* update new data len */
/* update field in ip header */
- *o_unit->ip_plen = htons(o_ip_len + n_unit->payload);
+ write_unit_ip_len(o_unit, o_ip_len + n_unit->payload);
/* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced
for windows guest, while this may change the behavior for linux
@@ -3032,6 +3067,15 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
virtio_net_set_queue_pairs(n);
}
+static int virtio_net_pre_load_queues(VirtIODevice *vdev)
+{
+ virtio_net_set_multiqueue(VIRTIO_NET(vdev),
+ virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_RSS) ||
+ virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MQ));
+
+ return 0;
+}
+
static int virtio_net_post_load_device(void *opaque, int version_id)
{
VirtIONet *n = opaque;
@@ -3296,6 +3340,117 @@ static const VMStateDescription vmstate_virtio_net_rss = {
},
};
+static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
+{
+ VirtIONet *n = VIRTIO_NET(vdev);
+ NetClientState *nc;
+ struct vhost_net *net;
+
+ if (!n->nic) {
+ return NULL;
+ }
+
+ nc = qemu_get_queue(n->nic);
+ if (!nc) {
+ return NULL;
+ }
+
+ net = get_vhost_net(nc->peer);
+ if (!net) {
+ return NULL;
+ }
+
+ return &net->dev;
+}
+
+static int vhost_user_net_save_state(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field,
+ JSONWriter *vmdesc)
+{
+ VirtIONet *n = pv;
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ struct vhost_dev *vhdev;
+ Error *local_error = NULL;
+ int ret;
+
+ vhdev = virtio_net_get_vhost(vdev);
+ if (vhdev == NULL) {
+ error_reportf_err(local_error,
+ "Error getting vhost back-end of %s device %s: ",
+ vdev->name, vdev->parent_obj.canonical_path);
+ return -1;
+ }
+
+ ret = vhost_save_backend_state(vhdev, f, &local_error);
+ if (ret < 0) {
+ error_reportf_err(local_error,
+ "Error saving back-end state of %s device %s: ",
+ vdev->name, vdev->parent_obj.canonical_path);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int vhost_user_net_load_state(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field)
+{
+ VirtIONet *n = pv;
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ struct vhost_dev *vhdev;
+ Error *local_error = NULL;
+ int ret;
+
+ vhdev = virtio_net_get_vhost(vdev);
+ if (vhdev == NULL) {
+ error_reportf_err(local_error,
+ "Error getting vhost back-end of %s device %s: ",
+ vdev->name, vdev->parent_obj.canonical_path);
+ return -1;
+ }
+
+ ret = vhost_load_backend_state(vhdev, f, &local_error);
+ if (ret < 0) {
+ error_reportf_err(local_error,
+ "Error loading back-end state of %s device %s: ",
+ vdev->name, vdev->parent_obj.canonical_path);
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool vhost_user_net_is_internal_migration(void *opaque)
+{
+ VirtIONet *n = opaque;
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ struct vhost_dev *vhdev;
+
+ vhdev = virtio_net_get_vhost(vdev);
+ if (vhdev == NULL) {
+ return false;
+ }
+
+ return vhost_supports_device_state(vhdev);
+}
+
+static const VMStateDescription vhost_user_net_backend_state = {
+ .name = "virtio-net-device/backend",
+ .version_id = 0,
+ .needed = vhost_user_net_is_internal_migration,
+ .fields = (const VMStateField[]) {
+ {
+ .name = "backend",
+ .info = &(const VMStateInfo) {
+ .name = "virtio-net vhost-user backend state",
+ .get = vhost_user_net_load_state,
+ .put = vhost_user_net_save_state,
+ },
+ },
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_virtio_net_device = {
.name = "virtio-net-device",
.version_id = VIRTIO_NET_VM_VERSION,
@@ -3348,6 +3503,7 @@ static const VMStateDescription vmstate_virtio_net_device = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_virtio_net_rss,
+ &vhost_user_net_backend_state,
NULL
}
};
@@ -3760,7 +3916,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
net_rx_pkt_init(&n->rx_pkt);
if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
- virtio_net_load_ebpf(n);
+ virtio_net_load_ebpf(n, errp);
}
}
@@ -3893,14 +4049,6 @@ static bool dev_unplug_pending(void *opaque)
return vdc->primary_unplug_pending(dev);
}
-static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- NetClientState *nc = qemu_get_queue(n->nic);
- struct vhost_net *net = get_vhost_net(nc->peer);
- return &net->dev;
-}
-
static const VMStateDescription vmstate_virtio_net = {
.name = "virtio-net",
.minimum_version_id = VIRTIO_NET_VM_VERSION,
@@ -3913,7 +4061,7 @@ static const VMStateDescription vmstate_virtio_net = {
.dev_unplug_pending = dev_unplug_pending,
};
-static Property virtio_net_properties[] = {
+static const Property virtio_net_properties[] = {
DEFINE_PROP_BIT64("csum", VirtIONet, host_features,
VIRTIO_NET_F_CSUM, true),
DEFINE_PROP_BIT64("guest_csum", VirtIONet, host_features,
@@ -3985,10 +4133,9 @@ static Property virtio_net_properties[] = {
VIRTIO_NET_F_GUEST_USO6, true),
DEFINE_PROP_BIT64("host_uso", VirtIONet, host_features,
VIRTIO_NET_F_HOST_USO, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_net_class_init(ObjectClass *klass, void *data)
+static void virtio_net_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -4010,6 +4157,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO);
+ vdc->pre_load_queues = virtio_net_pre_load_queues;
vdc->post_load = virtio_net_post_load_virtio;
vdc->vmsd = &vmstate_virtio_net_device;
vdc->primary_unplug_pending = primary_unplug_pending;
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 63a9187..7c0ca56 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -21,7 +21,7 @@
#include "hw/qdev-properties.h"
#include "net/tap.h"
#include "net/checksum.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/bswap.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -41,19 +41,9 @@
#define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
#define VMXNET3_MSIX_BAR_SIZE 0x2000
-/* Compatibility flags for migration */
-#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT 0
-#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS \
- (1 << VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT)
-#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT 1
-#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE \
- (1 << VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT)
-
#define VMXNET3_EXP_EP_OFFSET (0x48)
-#define VMXNET3_MSI_OFFSET(s) \
- ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x50 : 0x84)
-#define VMXNET3_MSIX_OFFSET(s) \
- ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0 : 0x9c)
+#define VMXNET3_MSI_OFFSET (0x84)
+#define VMXNET3_MSIX_OFFSET (0x9c)
#define VMXNET3_DSN_OFFSET (0x100)
#define VMXNET3_BAR0_IDX (0)
@@ -61,8 +51,7 @@
#define VMXNET3_MSIX_BAR_IDX (2)
#define VMXNET3_OFF_MSIX_TABLE (0x000)
-#define VMXNET3_OFF_MSIX_PBA(s) \
- ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x800 : 0x1000)
+#define VMXNET3_OFF_MSIX_PBA (0x1000)
/* Link speed in Mbps should be shifted by 16 */
#define VMXNET3_LINK_SPEED (1000 << 16)
@@ -456,7 +445,6 @@ vmxnet3_setup_tx_offloads(VMXNET3State *s)
default:
g_assert_not_reached();
- return false;
}
return true;
@@ -933,7 +921,6 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt,
nocsum:
rxcd->cnc = 1;
- return;
}
static void
@@ -2124,8 +2111,8 @@ vmxnet3_init_msix(VMXNET3State *s)
&s->msix_bar,
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
&s->msix_bar,
- VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
- VMXNET3_MSIX_OFFSET(s), NULL);
+ VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA,
+ VMXNET3_MSIX_OFFSET, NULL);
if (0 > res) {
VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
@@ -2223,7 +2210,7 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
/* Interrupt pin A */
pci_dev->config[PCI_INTERRUPT_PIN] = 0x01;
- ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
+ ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET, VMXNET3_MAX_NMSIX_INTRS,
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, NULL);
/* Any error other than -ENOTSUP(board's MSI support is broken)
* is a programming error. Fall back to INTx silently on -ENOTSUP */
@@ -2251,6 +2238,7 @@ static void vmxnet3_instance_init(Object *obj)
device_add_bootindex_property(obj, &s->conf.bootindex,
"bootindex", "/ethernet-phy@0",
DEVICE(obj));
+ PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
static void vmxnet3_pci_uninit(PCIDevice *pci_dev)
@@ -2472,33 +2460,14 @@ static const VMStateDescription vmstate_vmxnet3 = {
}
};
-static Property vmxnet3_properties[] = {
+static const Property vmxnet3_properties[] = {
DEFINE_NIC_PROPERTIES(VMXNET3State, conf),
- DEFINE_PROP_BIT("x-old-msi-offsets", VMXNET3State, compat_flags,
- VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT, false),
- DEFINE_PROP_BIT("x-disable-pcie", VMXNET3State, compat_flags,
- VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vmxnet3_realize(DeviceState *qdev, Error **errp)
-{
- VMXNET3Class *vc = VMXNET3_DEVICE_GET_CLASS(qdev);
- PCIDevice *pci_dev = PCI_DEVICE(qdev);
- VMXNET3State *s = VMXNET3(qdev);
-
- if (!(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE)) {
- pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
- }
-
- vc->parent_dc_realize(qdev, errp);
-}
-
-static void vmxnet3_class_init(ObjectClass *class, void *data)
+static void vmxnet3_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
- VMXNET3Class *vc = VMXNET3_DEVICE_CLASS(class);
c->realize = vmxnet3_pci_realize;
c->exit = vmxnet3_pci_uninit;
@@ -2509,10 +2478,8 @@ static void vmxnet3_class_init(ObjectClass *class, void *data)
c->class_id = PCI_CLASS_NETWORK_ETHERNET;
c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
- device_class_set_parent_realize(dc, vmxnet3_realize,
- &vc->parent_dc_realize);
dc->desc = "VMWare Paravirtualized Ethernet v3";
- dc->reset = vmxnet3_qdev_reset;
+ device_class_set_legacy_reset(dc, vmxnet3_qdev_reset);
dc->vmsd = &vmstate_vmxnet3;
device_class_set_props(dc, vmxnet3_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
@@ -2525,7 +2492,7 @@ static const TypeInfo vmxnet3_info = {
.instance_size = sizeof(VMXNET3State),
.class_init = vmxnet3_class_init,
.instance_init = vmxnet3_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
diff --git a/hw/net/vmxnet3.h b/hw/net/vmxnet3.h
index f9283f9..dbc69d5 100644
--- a/hw/net/vmxnet3.h
+++ b/hw/net/vmxnet3.h
@@ -63,8 +63,8 @@
* details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * along with this program; if not, see
+ * <https://www.gnu.org/licenses/>.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index 89487b4..34c6a1d 100644
--- a/hw/net/xen_nic.c
+++ b/hw/net/xen_nic.c
@@ -24,7 +24,7 @@
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qemu/qemu-print.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/error.h"
#include <sys/socket.h>
@@ -510,23 +510,22 @@ static char *xen_netdev_get_name(XenDevice *xendev, Error **errp)
if (netdev->dev == -1) {
XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
- char fe_path[XENSTORE_ABS_PATH_MAX + 1];
int idx = (xen_mode == XEN_EMULATE) ? 0 : 1;
+ Error *local_err = NULL;
char *value;
/* Theoretically we could go up to INT_MAX here but that's overkill */
while (idx < 100) {
- snprintf(fe_path, sizeof(fe_path),
- "/local/domain/%u/device/vif/%u",
- xendev->frontend_id, idx);
- value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL);
+ value = xs_node_read(xenbus->xsh, XBT_NULL, NULL, &local_err,
+ "/local/domain/%u/device/vif/%u",
+ xendev->frontend_id, idx);
if (!value) {
if (errno == ENOENT) {
netdev->dev = idx;
+ error_free(local_err);
goto found;
}
- error_setg(errp, "cannot read %s: %s", fe_path,
- strerror(errno));
+ error_propagate(errp, local_err);
return NULL;
}
free(value);
@@ -555,13 +554,12 @@ static void xen_netdev_unrealize(XenDevice *xendev)
/* ------------------------------------------------------------- */
-static Property xen_netdev_properties[] = {
+static const Property xen_netdev_properties[] = {
DEFINE_NIC_PROPERTIES(XenNetDev, conf),
DEFINE_PROP_INT32("idx", XenNetDev, dev, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xen_netdev_class_init(ObjectClass *class, void *data)
+static void xen_netdev_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c
index ffe3fc8..d45f872 100644
--- a/hw/net/xgmac.c
+++ b/hw/net/xgmac.c
@@ -207,7 +207,7 @@ static void xgmac_enet_send(XgmacState *s)
struct desc bd;
int frame_size;
int len;
- uint8_t frame[8192];
+ QEMU_UNINITIALIZED uint8_t frame[8192];
uint8_t *ptr;
ptr = frame;
@@ -414,12 +414,11 @@ static void xgmac_enet_realize(DeviceState *dev, Error **errp)
s->conf.macaddr.a[0];
}
-static Property xgmac_properties[] = {
+static const Property xgmac_properties[] = {
DEFINE_NIC_PROPERTIES(XgmacState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xgmac_enet_class_init(ObjectClass *klass, void *data)
+static void xgmac_enet_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index 05d41bd..1f5c748 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -996,7 +996,7 @@ static void xilinx_enet_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property xilinx_enet_properties[] = {
+static const Property xilinx_enet_properties[] = {
DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7),
DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
@@ -1005,27 +1005,27 @@ static Property xilinx_enet_properties[] = {
tx_data_dev, TYPE_STREAM_SINK, StreamSink *),
DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIEnet,
tx_control_dev, TYPE_STREAM_SINK, StreamSink *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xilinx_enet_class_init(ObjectClass *klass, void *data)
+static void xilinx_enet_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = xilinx_enet_realize;
device_class_set_props(dc, xilinx_enet_properties);
- dc->reset = xilinx_axienet_reset;
+ device_class_set_legacy_reset(dc, xilinx_axienet_reset);
}
static void xilinx_enet_control_stream_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
ssc->push = xilinx_axienet_control_stream_push;
}
-static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data)
+static void xilinx_enet_data_stream_class_init(ObjectClass *klass,
+ const void *data)
{
StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
@@ -1045,7 +1045,7 @@ static const TypeInfo xilinx_enet_data_stream_info = {
.parent = TYPE_OBJECT,
.instance_size = sizeof(XilinxAXIEnetStreamSink),
.class_init = xilinx_enet_data_stream_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_STREAM_SINK },
{ }
}
@@ -1056,7 +1056,7 @@ static const TypeInfo xilinx_enet_control_stream_info = {
.parent = TYPE_OBJECT,
.instance_size = sizeof(XilinxAXIEnetStreamSink),
.class_init = xilinx_enet_control_stream_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_STREAM_SINK },
{ }
}
diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
index 989afaf..42b19d0 100644
--- a/hw/net/xilinx_ethlite.c
+++ b/hw/net/xilinx_ethlite.c
@@ -2,6 +2,10 @@
* QEMU model of the Xilinx Ethernet Lite MAC.
*
* Copyright (c) 2009 Edgar E. Iglesias.
+ * Copyright (c) 2024 Linaro, Ltd
+ *
+ * DS580: https://docs.amd.com/v/u/en-US/xps_ethernetlite
+ * LogiCORE IP XPS Ethernet Lite Media Access Controller
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,27 +28,35 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
+#include "qemu/bitops.h"
#include "qom/object.h"
-#include "exec/tswap.h"
+#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/misc/unimp.h"
#include "net/net.h"
+#include "trace.h"
+
+#define BUFSZ_MAX 0x07e4
+#define A_MDIO_BASE 0x07e4
+#define A_TX_BASE0 0x07f4
+#define A_TX_BASE1 0x0ff4
+#define A_RX_BASE0 0x17fc
+#define A_RX_BASE1 0x1ffc
+
+enum {
+ TX_LEN = 0,
+ TX_GIE = 1,
+ TX_CTRL = 2,
+ TX_MAX
+};
-#define D(x)
-#define R_TX_BUF0 0
-#define R_TX_LEN0 (0x07f4 / 4)
-#define R_TX_GIE0 (0x07f8 / 4)
-#define R_TX_CTRL0 (0x07fc / 4)
-#define R_TX_BUF1 (0x0800 / 4)
-#define R_TX_LEN1 (0x0ff4 / 4)
-#define R_TX_CTRL1 (0x0ffc / 4)
-
-#define R_RX_BUF0 (0x1000 / 4)
-#define R_RX_CTRL0 (0x17fc / 4)
-#define R_RX_BUF1 (0x1800 / 4)
-#define R_RX_CTRL1 (0x1ffc / 4)
-#define R_MAX (0x2000 / 4)
+enum {
+ RX_CTRL = 0,
+ RX_MAX
+};
#define GIE_GIE 0x80000000
@@ -52,174 +64,238 @@
#define CTRL_P 0x2
#define CTRL_S 0x1
+typedef struct XlnxXpsEthLitePort {
+ MemoryRegion txio;
+ MemoryRegion rxio;
+ MemoryRegion txbuf;
+ MemoryRegion rxbuf;
+
+ struct {
+ uint32_t tx_len;
+ uint32_t tx_gie;
+ uint32_t tx_ctrl;
+
+ uint32_t rx_ctrl;
+ } reg;
+} XlnxXpsEthLitePort;
+
#define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite"
-DECLARE_INSTANCE_CHECKER(struct xlx_ethlite, XILINX_ETHLITE,
- TYPE_XILINX_ETHLITE)
+OBJECT_DECLARE_SIMPLE_TYPE(XlnxXpsEthLite, XILINX_ETHLITE)
-struct xlx_ethlite
+struct XlnxXpsEthLite
{
SysBusDevice parent_obj;
- MemoryRegion mmio;
+ EndianMode model_endianness;
+ MemoryRegion container;
qemu_irq irq;
NICState *nic;
NICConf conf;
uint32_t c_tx_pingpong;
uint32_t c_rx_pingpong;
- unsigned int txbuf;
- unsigned int rxbuf;
+ unsigned int port_index; /* dual port RAM index */
- uint32_t regs[R_MAX];
+ UnimplementedDeviceState rsvd;
+ UnimplementedDeviceState mdio;
+ XlnxXpsEthLitePort port[2];
};
-static inline void eth_pulse_irq(struct xlx_ethlite *s)
+static inline void eth_pulse_irq(XlnxXpsEthLite *s)
{
/* Only the first gie reg is active. */
- if (s->regs[R_TX_GIE0] & GIE_GIE) {
+ if (s->port[0].reg.tx_gie & GIE_GIE) {
qemu_irq_pulse(s->irq);
}
}
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
+static unsigned addr_to_port_index(hwaddr addr)
{
- struct xlx_ethlite *s = opaque;
- uint32_t r = 0;
+ return extract64(addr, 11, 1);
+}
- addr >>= 2;
+static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
+{
+ return memory_region_get_ram_ptr(&s->port[port_index].txbuf);
+}
- switch (addr)
- {
- case R_TX_GIE0:
- case R_TX_LEN0:
- case R_TX_LEN1:
- case R_TX_CTRL1:
- case R_TX_CTRL0:
- case R_RX_CTRL1:
- case R_RX_CTRL0:
- r = s->regs[addr];
- D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr * 4, r));
- break;
-
- default:
- r = tswap32(s->regs[addr]);
- break;
+static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
+{
+ return memory_region_get_ram_ptr(&s->port[port_index].rxbuf);
+}
+
+static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ XlnxXpsEthLite *s = opaque;
+ unsigned port_index = addr_to_port_index(addr);
+ uint32_t r = 0;
+
+ switch (addr >> 2) {
+ case TX_LEN:
+ r = s->port[port_index].reg.tx_len;
+ break;
+ case TX_GIE:
+ r = s->port[port_index].reg.tx_gie;
+ break;
+ case TX_CTRL:
+ r = s->port[port_index].reg.tx_ctrl;
+ break;
+ default:
+ g_assert_not_reached();
}
+
return r;
}
-static void
-eth_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
+static void port_tx_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned int size)
{
- struct xlx_ethlite *s = opaque;
- unsigned int base = 0;
- uint32_t value = val64;
-
- addr >>= 2;
- switch (addr)
- {
- case R_TX_CTRL0:
- case R_TX_CTRL1:
- if (addr == R_TX_CTRL1)
- base = 0x800 / 4;
-
- D(qemu_log("%s addr=" HWADDR_FMT_plx " val=%x\n",
- __func__, addr * 4, value));
- if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
- qemu_send_packet(qemu_get_queue(s->nic),
- (void *) &s->regs[base],
- s->regs[base + R_TX_LEN0]);
- D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
- if (s->regs[base + R_TX_CTRL0] & CTRL_I)
- eth_pulse_irq(s);
- } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
- memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
- if (s->regs[base + R_TX_CTRL0] & CTRL_I)
- eth_pulse_irq(s);
+ XlnxXpsEthLite *s = opaque;
+ unsigned port_index = addr_to_port_index(addr);
+
+ switch (addr >> 2) {
+ case TX_LEN:
+ s->port[port_index].reg.tx_len = value;
+ break;
+ case TX_GIE:
+ s->port[port_index].reg.tx_gie = value;
+ break;
+ case TX_CTRL:
+ if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
+ qemu_send_packet(qemu_get_queue(s->nic),
+ txbuf_ptr(s, port_index),
+ s->port[port_index].reg.tx_len);
+ if (s->port[port_index].reg.tx_ctrl & CTRL_I) {
+ eth_pulse_irq(s);
+ }
+ } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
+ memcpy(&s->conf.macaddr.a[0], txbuf_ptr(s, port_index), 6);
+ if (s->port[port_index].reg.tx_ctrl & CTRL_I) {
+ eth_pulse_irq(s);
}
+ }
+ /*
+ * We are fast and get ready pretty much immediately
+ * so we actually never flip the S nor P bits to one.
+ */
+ s->port[port_index].reg.tx_ctrl = value & ~(CTRL_P | CTRL_S);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
- /* We are fast and get ready pretty much immediately so
- we actually never flip the S nor P bits to one. */
- s->regs[addr] = value & ~(CTRL_P | CTRL_S);
- break;
+static const MemoryRegionOps eth_porttx_ops[2] = {
+ [0 ... 1] = {
+ .read = port_tx_read,
+ .write = port_tx_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ },
+ [0].endianness = DEVICE_LITTLE_ENDIAN,
+ [1].endianness = DEVICE_BIG_ENDIAN,
+};
- /* Keep these native. */
- case R_RX_CTRL0:
- case R_RX_CTRL1:
- if (!(value & CTRL_S)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- /* fall through */
- case R_TX_LEN0:
- case R_TX_LEN1:
- case R_TX_GIE0:
- D(qemu_log("%s addr=" HWADDR_FMT_plx " val=%x\n",
- __func__, addr * 4, value));
- s->regs[addr] = value;
- break;
-
- default:
- s->regs[addr] = tswap32(value);
- break;
+static uint64_t port_rx_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ XlnxXpsEthLite *s = opaque;
+ unsigned port_index = addr_to_port_index(addr);
+ uint32_t r = 0;
+
+ switch (addr >> 2) {
+ case RX_CTRL:
+ r = s->port[port_index].reg.rx_ctrl;
+ break;
+ default:
+ g_assert_not_reached();
}
+
+ return r;
}
-static const MemoryRegionOps eth_ops = {
- .read = eth_read,
- .write = eth_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
+static void port_rx_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned int size)
+{
+ XlnxXpsEthLite *s = opaque;
+ unsigned port_index = addr_to_port_index(addr);
+
+ switch (addr >> 2) {
+ case RX_CTRL:
+ if (!(value & CTRL_S)) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+ s->port[port_index].reg.rx_ctrl = value;
+ break;
+ default:
+ g_assert_not_reached();
}
+}
+
+static const MemoryRegionOps eth_portrx_ops[2] = {
+ [0 ... 1] = {
+ .read = port_rx_read,
+ .write = port_rx_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ },
+ [0].endianness = DEVICE_LITTLE_ENDIAN,
+ [1].endianness = DEVICE_BIG_ENDIAN,
};
static bool eth_can_rx(NetClientState *nc)
{
- struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
- unsigned int rxbase = s->rxbuf * (0x800 / 4);
+ XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
- return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
+ return !(s->port[s->port_index].reg.rx_ctrl & CTRL_S);
}
static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
{
- struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
- unsigned int rxbase = s->rxbuf * (0x800 / 4);
+ XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
+ unsigned int port_index = s->port_index;
/* DA filter. */
if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
return size;
- if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
- D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
+ if (s->port[port_index].reg.rx_ctrl & CTRL_S) {
+ trace_ethlite_pkt_lost(s->port[port_index].reg.rx_ctrl);
return -1;
}
- D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase));
- if (size > (R_MAX - R_RX_BUF0 - rxbase) * 4) {
- D(qemu_log("ethlite packet is too big, size=%x\n", size));
+ if (size >= BUFSZ_MAX) {
+ trace_ethlite_pkt_size_too_big(size);
return -1;
}
- memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
+ memcpy(rxbuf_ptr(s, port_index), buf, size);
- s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
- if (s->regs[R_RX_CTRL0] & CTRL_I) {
+ s->port[port_index].reg.rx_ctrl |= CTRL_S;
+ if (s->port[port_index].reg.rx_ctrl & CTRL_I) {
eth_pulse_irq(s);
}
/* If c_rx_pingpong was set flip buffers. */
- s->rxbuf ^= s->c_rx_pingpong;
+ s->port_index ^= s->c_rx_pingpong;
return size;
}
static void xilinx_ethlite_reset(DeviceState *dev)
{
- struct xlx_ethlite *s = XILINX_ETHLITE(dev);
+ XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
- s->rxbuf = 0;
+ s->port_index = 0;
}
static NetClientInfo net_xilinx_ethlite_info = {
@@ -231,7 +307,61 @@ static NetClientInfo net_xilinx_ethlite_info = {
static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
{
- struct xlx_ethlite *s = XILINX_ETHLITE(dev);
+ XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
+ unsigned ops_index;
+
+ if (s->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
+ error_setg(errp, TYPE_XILINX_ETHLITE " property 'endianness'"
+ " must be set to 'big' or 'little'");
+ return;
+ }
+ ops_index = s->model_endianness == ENDIAN_MODE_BIG ? 1 : 0;
+
+ memory_region_init(&s->container, OBJECT(dev),
+ "xlnx.xps-ethernetlite", 0x2000);
+
+ object_initialize_child(OBJECT(dev), "ethlite.reserved", &s->rsvd,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ qdev_prop_set_string(DEVICE(&s->rsvd), "name", "ethlite.reserved");
+ qdev_prop_set_uint64(DEVICE(&s->rsvd), "size",
+ memory_region_size(&s->container));
+ sysbus_realize(SYS_BUS_DEVICE(&s->rsvd), &error_fatal);
+ memory_region_add_subregion_overlap(&s->container, 0,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rsvd), 0),
+ -1);
+
+ object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio,
+ TYPE_UNIMPLEMENTED_DEVICE);
+ qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio");
+ qdev_prop_set_uint64(DEVICE(&s->mdio), "size", 4 * 4);
+ sysbus_realize(SYS_BUS_DEVICE(&s->mdio), &error_fatal);
+ memory_region_add_subregion(&s->container, A_MDIO_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0));
+
+ for (unsigned i = 0; i < 2; i++) {
+ memory_region_init_ram(&s->port[i].txbuf, OBJECT(dev),
+ i ? "ethlite.tx[1]buf" : "ethlite.tx[0]buf",
+ BUFSZ_MAX, &error_abort);
+ memory_region_add_subregion(&s->container, 0x0800 * i, &s->port[i].txbuf);
+ memory_region_init_io(&s->port[i].txio, OBJECT(dev),
+ &eth_porttx_ops[ops_index], s,
+ i ? "ethlite.tx[1]io" : "ethlite.tx[0]io",
+ 4 * TX_MAX);
+ memory_region_add_subregion(&s->container, i ? A_TX_BASE1 : A_TX_BASE0,
+ &s->port[i].txio);
+
+ memory_region_init_ram(&s->port[i].rxbuf, OBJECT(dev),
+ i ? "ethlite.rx[1]buf" : "ethlite.rx[0]buf",
+ BUFSZ_MAX, &error_abort);
+ memory_region_add_subregion(&s->container, 0x1000 + 0x0800 * i,
+ &s->port[i].rxbuf);
+ memory_region_init_io(&s->port[i].rxio, OBJECT(dev),
+ &eth_portrx_ops[ops_index], s,
+ i ? "ethlite.rx[1]io" : "ethlite.rx[0]io",
+ 4 * RX_MAX);
+ memory_region_add_subregion(&s->container, i ? A_RX_BASE1 : A_RX_BASE0,
+ &s->port[i].rxio);
+ }
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
@@ -242,42 +372,36 @@ static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
static void xilinx_ethlite_init(Object *obj)
{
- struct xlx_ethlite *s = XILINX_ETHLITE(obj);
+ XlnxXpsEthLite *s = XILINX_ETHLITE(obj);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
-
- memory_region_init_io(&s->mmio, obj, &eth_ops, s,
- "xlnx.xps-ethernetlite", R_MAX * 4);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container);
}
-static Property xilinx_ethlite_properties[] = {
- DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1),
- DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1),
- DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
- DEFINE_PROP_END_OF_LIST(),
+static const Property xilinx_ethlite_properties[] = {
+ DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XlnxXpsEthLite, model_endianness),
+ DEFINE_PROP_UINT32("tx-ping-pong", XlnxXpsEthLite, c_tx_pingpong, 1),
+ DEFINE_PROP_UINT32("rx-ping-pong", XlnxXpsEthLite, c_rx_pingpong, 1),
+ DEFINE_NIC_PROPERTIES(XlnxXpsEthLite, conf),
};
-static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
+static void xilinx_ethlite_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = xilinx_ethlite_realize;
- dc->reset = xilinx_ethlite_reset;
+ device_class_set_legacy_reset(dc, xilinx_ethlite_reset);
device_class_set_props(dc, xilinx_ethlite_properties);
}
-static const TypeInfo xilinx_ethlite_info = {
- .name = TYPE_XILINX_ETHLITE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct xlx_ethlite),
- .instance_init = xilinx_ethlite_init,
- .class_init = xilinx_ethlite_class_init,
+static const TypeInfo xilinx_ethlite_types[] = {
+ {
+ .name = TYPE_XILINX_ETHLITE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XlnxXpsEthLite),
+ .instance_init = xilinx_ethlite_init,
+ .class_init = xilinx_ethlite_class_init,
+ },
};
-static void xilinx_ethlite_register_types(void)
-{
- type_register_static(&xilinx_ethlite_info);
-}
-
-type_init(xilinx_ethlite_register_types)
+DEFINE_TYPES(xilinx_ethlite_types)
diff --git a/hw/nubus/mac-nubus-bridge.c b/hw/nubus/mac-nubus-bridge.c
index a0da5a8..0dac8d1 100644
--- a/hw/nubus/mac-nubus-bridge.c
+++ b/hw/nubus/mac-nubus-bridge.c
@@ -40,7 +40,7 @@ static void mac_nubus_bridge_init(Object *obj)
sysbus_init_mmio(sbd, &s->slot_alias);
}
-static void mac_nubus_bridge_class_init(ObjectClass *klass, void *data)
+static void mac_nubus_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/nubus/nubus-bridge.c b/hw/nubus/nubus-bridge.c
index a42c860..fb14402 100644
--- a/hw/nubus/nubus-bridge.c
+++ b/hw/nubus/nubus-bridge.c
@@ -23,13 +23,12 @@ static void nubus_bridge_init(Object *obj)
qdev_init_gpio_out(DEVICE(s), bus->irqs, NUBUS_IRQS);
}
-static Property nubus_bridge_properties[] = {
+static const Property nubus_bridge_properties[] = {
DEFINE_PROP_UINT16("slot-available-mask", NubusBridge,
bus.slot_available_mask, 0xffff),
- DEFINE_PROP_END_OF_LIST()
};
-static void nubus_bridge_class_init(ObjectClass *klass, void *data)
+static void nubus_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/nubus/nubus-bus.c b/hw/nubus/nubus-bus.c
index 07c279b..44820f1 100644
--- a/hw/nubus/nubus-bus.c
+++ b/hw/nubus/nubus-bus.c
@@ -162,7 +162,7 @@ static bool nubus_check_address(BusState *bus, DeviceState *dev, Error **errp)
return true;
}
-static void nubus_class_init(ObjectClass *oc, void *data)
+static void nubus_class_init(ObjectClass *oc, const void *data)
{
BusClass *bc = BUS_CLASS(oc);
diff --git a/hw/nubus/nubus-device.c b/hw/nubus/nubus-device.c
index be4cb24..7797e61 100644
--- a/hw/nubus/nubus-device.c
+++ b/hw/nubus/nubus-device.c
@@ -35,6 +35,13 @@ static void nubus_device_realize(DeviceState *dev, Error **errp)
uint8_t *rom_ptr;
int ret;
+ if (nd->slot < 0 || nd->slot >= NUBUS_SLOT_NB) {
+ error_setg(errp,
+ "'slot' value %d out of range (must be between 0 and %d)",
+ nd->slot, NUBUS_SLOT_NB - 1);
+ return;
+ }
+
/* Super */
slot_offset = nd->slot * NUBUS_SUPER_SLOT_SIZE;
@@ -100,13 +107,12 @@ static void nubus_device_realize(DeviceState *dev, Error **errp)
}
}
-static Property nubus_device_properties[] = {
+static const Property nubus_device_properties[] = {
DEFINE_PROP_INT32("slot", NubusDevice, slot, -1),
DEFINE_PROP_STRING("romfile", NubusDevice, romfile),
- DEFINE_PROP_END_OF_LIST()
};
-static void nubus_device_class_init(ObjectClass *oc, void *data)
+static void nubus_device_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/nubus/nubus-virtio-mmio.c b/hw/nubus/nubus-virtio-mmio.c
index 7a98731..63aeca5 100644
--- a/hw/nubus/nubus-virtio-mmio.c
+++ b/hw/nubus/nubus-virtio-mmio.c
@@ -81,7 +81,7 @@ static void nubus_virtio_mmio_init(Object *obj)
"pic-input-irq", 1);
}
-static void nubus_virtio_mmio_class_init(ObjectClass *oc, void *data)
+static void nubus_virtio_mmio_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
NubusVirtioMMIODeviceClass *nvmdc = NUBUS_VIRTIO_MMIO_CLASS(oc);
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 9f277b8..2200028 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -40,6 +40,9 @@
* sriov_vi_flexible=<N[optional]> \
* sriov_max_vi_per_vf=<N[optional]> \
* sriov_max_vq_per_vf=<N[optional]> \
+ * atomic.dn=<on|off[optional]>, \
+ * atomic.awun<N[optional]>, \
+ * atomic.awupf<N[optional]>, \
* subsys=<subsys_id>
* -device nvme-ns,drive=<drive_id>,bus=<bus_name>,nsid=<nsid>,\
* zoned=<true|false[optional]>, \
@@ -198,12 +201,12 @@
#include "qemu/range.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/hostmem.h"
+#include "system/system.h"
+#include "system/block-backend.h"
+#include "system/hostmem.h"
#include "hw/pci/msix.h"
#include "hw/pci/pcie_sriov.h"
-#include "sysemu/spdm-socket.h"
+#include "system/spdm-socket.h"
#include "migration/vmstate.h"
#include "nvme.h"
@@ -254,6 +257,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
[NVME_ERROR_RECOVERY] = NVME_FEAT_CAP_CHANGE | NVME_FEAT_CAP_NS,
[NVME_VOLATILE_WRITE_CACHE] = NVME_FEAT_CAP_CHANGE,
[NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE,
+ [NVME_WRITE_ATOMICITY] = NVME_FEAT_CAP_CHANGE,
[NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE,
[NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE,
[NVME_HOST_BEHAVIOR_SUPPORT] = NVME_FEAT_CAP_CHANGE,
@@ -262,7 +266,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
[NVME_FDP_EVENTS] = NVME_FEAT_CAP_CHANGE | NVME_FEAT_CAP_NS,
};
-static const uint32_t nvme_cse_acs[256] = {
+static const uint32_t nvme_cse_acs_default[256] = {
[NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_GET_LOG_PAGE] = NVME_CMD_EFF_CSUPP,
@@ -273,17 +277,14 @@ static const uint32_t nvme_cse_acs[256] = {
[NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP,
- [NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC,
- [NVME_ADM_CMD_VIRT_MNGMT] = NVME_CMD_EFF_CSUPP,
- [NVME_ADM_CMD_DBBUF_CONFIG] = NVME_CMD_EFF_CSUPP,
+ [NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC |
+ NVME_CMD_EFF_CCC,
[NVME_ADM_CMD_FORMAT_NVM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_ADM_CMD_DIRECTIVE_RECV] = NVME_CMD_EFF_CSUPP,
[NVME_ADM_CMD_DIRECTIVE_SEND] = NVME_CMD_EFF_CSUPP,
};
-static const uint32_t nvme_cse_iocs_none[256];
-
-static const uint32_t nvme_cse_iocs_nvm[256] = {
+static const uint32_t nvme_cse_iocs_nvm_default[256] = {
[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
@@ -296,7 +297,7 @@ static const uint32_t nvme_cse_iocs_nvm[256] = {
[NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
};
-static const uint32_t nvme_cse_iocs_zoned[256] = {
+static const uint32_t nvme_cse_iocs_zoned_default[256] = {
[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
@@ -305,6 +306,9 @@ static const uint32_t nvme_cse_iocs_zoned[256] = {
[NVME_CMD_VERIFY] = NVME_CMD_EFF_CSUPP,
[NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP,
+ [NVME_CMD_IO_MGMT_RECV] = NVME_CMD_EFF_CSUPP,
+ [NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
+
[NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_ZONE_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
[NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP,
@@ -652,6 +656,12 @@ static void nvme_irq_check(NvmeCtrl *n)
if (msix_enabled(pci)) {
return;
}
+
+ /* vfs does not implement intx */
+ if (pci_is_vf(pci)) {
+ return;
+ }
+
if (~intms & n->irq_status) {
pci_irq_assert(pci);
} else {
@@ -1047,7 +1057,8 @@ static uint16_t nvme_map_sgl(NvmeCtrl *n, NvmeSg *sg, NvmeSglDescriptor sgl,
*/
#define SEG_CHUNK_SIZE 256
- NvmeSglDescriptor segment[SEG_CHUNK_SIZE], *sgld, *last_sgld;
+ QEMU_UNINITIALIZED NvmeSglDescriptor segment[SEG_CHUNK_SIZE];
+ NvmeSglDescriptor *sgld, *last_sgld;
uint64_t nsgld;
uint32_t seg_len;
uint16_t status;
@@ -1516,9 +1527,16 @@ static void nvme_post_cqes(void *opaque)
stl_le_p(&n->bar.csts, NVME_CSTS_FAILED);
break;
}
+
QTAILQ_REMOVE(&cq->req_list, req, entry);
+
nvme_inc_cq_tail(cq);
nvme_sg_unmap(&req->sg);
+
+ if (QTAILQ_EMPTY(&sq->req_list) && !nvme_sq_empty(sq)) {
+ qemu_bh_schedule(sq->bh);
+ }
+
QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
}
if (cq->tail != cq->head) {
@@ -1649,9 +1667,16 @@ static void nvme_smart_event(NvmeCtrl *n, uint8_t event)
static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type)
{
+ NvmeAsyncEvent *event, *next;
+
n->aer_mask &= ~(1 << event_type);
- if (!QTAILQ_EMPTY(&n->aer_queue)) {
- nvme_process_aers(n);
+
+ QTAILQ_FOREACH_SAFE(event, &n->aer_queue, entry, next) {
+ if (event->result.event_type == event_type) {
+ QTAILQ_REMOVE(&n->aer_queue, event, entry);
+ n->aer_queued--;
+ g_free(event);
+ }
}
}
@@ -1738,47 +1763,6 @@ static uint16_t nvme_check_dulbe(NvmeNamespace *ns, uint64_t slba,
return NVME_SUCCESS;
}
-static void nvme_aio_err(NvmeRequest *req, int ret)
-{
- uint16_t status = NVME_SUCCESS;
- Error *local_err = NULL;
-
- switch (req->cmd.opcode) {
- case NVME_CMD_READ:
- status = NVME_UNRECOVERED_READ;
- break;
- case NVME_CMD_FLUSH:
- case NVME_CMD_WRITE:
- case NVME_CMD_WRITE_ZEROES:
- case NVME_CMD_ZONE_APPEND:
- case NVME_CMD_COPY:
- status = NVME_WRITE_FAULT;
- break;
- default:
- status = NVME_INTERNAL_DEV_ERROR;
- break;
- }
-
- if (ret == -ECANCELED) {
- status = NVME_CMD_ABORT_REQ;
- }
-
- trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), status);
-
- error_setg_errno(&local_err, -ret, "aio failed");
- error_report_err(local_err);
-
- /*
- * Set the command status code to the first encountered error but allow a
- * subsequent Internal Device Error to trump it.
- */
- if (req->status && status != NVME_INTERNAL_DEV_ERROR) {
- return;
- }
-
- req->status = status;
-}
-
static inline uint32_t nvme_zone_idx(NvmeNamespace *ns, uint64_t slba)
{
return ns->zone_size_log2 > 0 ? slba >> ns->zone_size_log2 :
@@ -1816,7 +1800,7 @@ static uint16_t nvme_check_zone_state_for_write(NvmeZone *zone)
trace_pci_nvme_err_zone_is_read_only(zslba);
return NVME_ZONE_READ_ONLY;
default:
- assert(false);
+ g_assert_not_reached();
}
return NVME_INTERNAL_DEV_ERROR;
@@ -1870,7 +1854,7 @@ static uint16_t nvme_check_zone_state_for_read(NvmeZone *zone)
trace_pci_nvme_err_zone_is_offline(zone->d.zslba);
return NVME_ZONE_OFFLINE;
default:
- assert(false);
+ g_assert_not_reached();
}
return NVME_INTERNAL_DEV_ERROR;
@@ -2137,11 +2121,16 @@ static inline bool nvme_is_write(NvmeRequest *req)
static void nvme_misc_cb(void *opaque, int ret)
{
NvmeRequest *req = opaque;
+ uint16_t cid = nvme_cid(req);
- trace_pci_nvme_misc_cb(nvme_cid(req));
+ trace_pci_nvme_misc_cb(cid);
if (ret) {
- nvme_aio_err(req, ret);
+ if (!req->status) {
+ req->status = NVME_INTERNAL_DEV_ERROR;
+ }
+
+ trace_pci_nvme_err_aio(cid, strerror(-ret), req->status);
}
nvme_enqueue_req_completion(nvme_cq(req), req);
@@ -2158,8 +2147,30 @@ void nvme_rw_complete_cb(void *opaque, int ret)
trace_pci_nvme_rw_complete_cb(nvme_cid(req), blk_name(blk));
if (ret) {
+ Error *err = NULL;
+
block_acct_failed(stats, acct);
- nvme_aio_err(req, ret);
+
+ switch (req->cmd.opcode) {
+ case NVME_CMD_READ:
+ req->status = NVME_UNRECOVERED_READ;
+ break;
+
+ case NVME_CMD_WRITE:
+ case NVME_CMD_WRITE_ZEROES:
+ case NVME_CMD_ZONE_APPEND:
+ req->status = NVME_WRITE_FAULT;
+ break;
+
+ default:
+ req->status = NVME_INTERNAL_DEV_ERROR;
+ break;
+ }
+
+ trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
+
+ error_setg_errno(&err, -ret, "aio failed");
+ error_report_err(err);
} else {
block_acct_done(stats, acct);
}
@@ -2244,7 +2255,10 @@ static void nvme_verify_cb(void *opaque, int ret)
if (ret) {
block_acct_failed(stats, acct);
- nvme_aio_err(req, ret);
+ req->status = NVME_UNRECOVERED_READ;
+
+ trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
+
goto out;
}
@@ -2343,7 +2357,10 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
if (ret) {
block_acct_failed(stats, acct);
- nvme_aio_err(req, ret);
+ req->status = NVME_UNRECOVERED_READ;
+
+ trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
+
goto out;
}
@@ -2425,7 +2442,10 @@ static void nvme_compare_data_cb(void *opaque, int ret)
if (ret) {
block_acct_failed(stats, acct);
- nvme_aio_err(req, ret);
+ req->status = NVME_UNRECOVERED_READ;
+
+ trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
+
goto out;
}
@@ -2646,6 +2666,7 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req)
uint64_t slba = le64_to_cpu(rw->slba);
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
size_t len = nvme_l2b(ns, nlb);
+ size_t data_len = len;
int64_t offset = nvme_l2b(ns, slba);
uint8_t prinfo = NVME_RW_PRINFO(le16_to_cpu(rw->control));
uint32_t reftag = le32_to_cpu(rw->reftag);
@@ -2665,7 +2686,11 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req)
}
}
- if (len > n->page_size << n->params.vsl) {
+ if (nvme_ns_ext(ns) && !(NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt))) {
+ data_len += nvme_m2b(ns, nlb);
+ }
+
+ if (data_len > (n->page_size << n->params.vsl)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
@@ -2899,6 +2924,7 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
if (ret < 0) {
iocb->ret = ret;
+ req->status = NVME_WRITE_FAULT;
goto out;
} else if (iocb->ret < 0) {
goto out;
@@ -2963,6 +2989,7 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
if (ret < 0) {
iocb->ret = ret;
+ req->status = NVME_UNRECOVERED_READ;
goto out;
} else if (iocb->ret < 0) {
goto out;
@@ -3406,7 +3433,11 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req)
len += nvme_m2b(ns, nlb);
}
- status = nvme_check_mdts(n, len);
+ if (NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt)) {
+ status = nvme_check_mdts(n, data_len);
+ } else {
+ status = nvme_check_mdts(n, len);
+ }
if (status) {
return status;
}
@@ -3481,6 +3512,7 @@ static void nvme_flush_ns_cb(void *opaque, int ret)
if (ret < 0) {
iocb->ret = ret;
+ iocb->req->status = NVME_WRITE_FAULT;
goto out;
} else if (iocb->ret < 0) {
goto out;
@@ -3583,7 +3615,7 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req)
BlockBackend *blk = ns->blkconf.blk;
uint16_t status;
- if (nvme_ns_ext(ns)) {
+ if (nvme_ns_ext(ns) && !(NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt))) {
mapped_size += nvme_m2b(ns, nlb);
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
@@ -3695,7 +3727,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append,
BlockBackend *blk = ns->blkconf.blk;
uint16_t status;
- if (nvme_ns_ext(ns)) {
+ if (nvme_ns_ext(ns) && !(NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt))) {
mapped_size += nvme_m2b(ns, nlb);
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
@@ -4572,6 +4604,61 @@ static uint16_t nvme_io_mgmt_send(NvmeCtrl *n, NvmeRequest *req)
};
}
+static uint16_t __nvme_io_cmd_nvm(NvmeCtrl *n, NvmeRequest *req)
+{
+ switch (req->cmd.opcode) {
+ case NVME_CMD_WRITE:
+ return nvme_write(n, req);
+ case NVME_CMD_READ:
+ return nvme_read(n, req);
+ case NVME_CMD_COMPARE:
+ return nvme_compare(n, req);
+ case NVME_CMD_WRITE_ZEROES:
+ return nvme_write_zeroes(n, req);
+ case NVME_CMD_DSM:
+ return nvme_dsm(n, req);
+ case NVME_CMD_VERIFY:
+ return nvme_verify(n, req);
+ case NVME_CMD_COPY:
+ return nvme_copy(n, req);
+ case NVME_CMD_IO_MGMT_RECV:
+ return nvme_io_mgmt_recv(n, req);
+ case NVME_CMD_IO_MGMT_SEND:
+ return nvme_io_mgmt_send(n, req);
+ }
+
+ g_assert_not_reached();
+}
+
+static uint16_t nvme_io_cmd_nvm(NvmeCtrl *n, NvmeRequest *req)
+{
+ if (!(n->cse.iocs.nvm[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
+ trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
+ return NVME_INVALID_OPCODE | NVME_DNR;
+ }
+
+ return __nvme_io_cmd_nvm(n, req);
+}
+
+static uint16_t nvme_io_cmd_zoned(NvmeCtrl *n, NvmeRequest *req)
+{
+ if (!(n->cse.iocs.zoned[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
+ trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
+ return NVME_INVALID_OPCODE | NVME_DNR;
+ }
+
+ switch (req->cmd.opcode) {
+ case NVME_CMD_ZONE_APPEND:
+ return nvme_zone_append(n, req);
+ case NVME_CMD_ZONE_MGMT_SEND:
+ return nvme_zone_mgmt_send(n, req);
+ case NVME_CMD_ZONE_MGMT_RECV:
+ return nvme_zone_mgmt_recv(n, req);
+ }
+
+ return __nvme_io_cmd_nvm(n, req);
+}
+
static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
{
NvmeNamespace *ns;
@@ -4613,11 +4700,6 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
return NVME_INVALID_FIELD | NVME_DNR;
}
- if (!(ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
- trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
- return NVME_INVALID_OPCODE | NVME_DNR;
- }
-
if (ns->status) {
return ns->status;
}
@@ -4628,36 +4710,14 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
req->ns = ns;
- switch (req->cmd.opcode) {
- case NVME_CMD_WRITE_ZEROES:
- return nvme_write_zeroes(n, req);
- case NVME_CMD_ZONE_APPEND:
- return nvme_zone_append(n, req);
- case NVME_CMD_WRITE:
- return nvme_write(n, req);
- case NVME_CMD_READ:
- return nvme_read(n, req);
- case NVME_CMD_COMPARE:
- return nvme_compare(n, req);
- case NVME_CMD_DSM:
- return nvme_dsm(n, req);
- case NVME_CMD_VERIFY:
- return nvme_verify(n, req);
- case NVME_CMD_COPY:
- return nvme_copy(n, req);
- case NVME_CMD_ZONE_MGMT_SEND:
- return nvme_zone_mgmt_send(n, req);
- case NVME_CMD_ZONE_MGMT_RECV:
- return nvme_zone_mgmt_recv(n, req);
- case NVME_CMD_IO_MGMT_RECV:
- return nvme_io_mgmt_recv(n, req);
- case NVME_CMD_IO_MGMT_SEND:
- return nvme_io_mgmt_send(n, req);
- default:
- assert(false);
+ switch (ns->csi) {
+ case NVME_CSI_NVM:
+ return nvme_io_cmd_nvm(n, req);
+ case NVME_CSI_ZONED:
+ return nvme_io_cmd_zoned(n, req);
}
- return NVME_INVALID_OPCODE | NVME_DNR;
+ g_assert_not_reached();
}
static void nvme_cq_notifier(EventNotifier *e)
@@ -4766,6 +4826,7 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeRequest *req)
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
r = QTAILQ_FIRST(&sq->out_req_list);
assert(r->aiocb);
+ r->status = NVME_CMD_ABORT_SQ_DEL;
blk_aio_cancel(r->aiocb);
}
@@ -4884,6 +4945,45 @@ static void nvme_set_blk_stats(NvmeNamespace *ns, struct nvme_stats *stats)
stats->write_commands += s->nr_ops[BLOCK_ACCT_WRITE];
}
+static uint16_t nvme_ocp_extended_smart_info(NvmeCtrl *n, uint8_t rae,
+ uint32_t buf_len, uint64_t off,
+ NvmeRequest *req)
+{
+ NvmeNamespace *ns = NULL;
+ NvmeSmartLogExtended smart_l = { 0 };
+ struct nvme_stats stats = { 0 };
+ uint32_t trans_len;
+
+ if (off >= sizeof(smart_l)) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ /* accumulate all stats from all namespaces */
+ for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) {
+ ns = nvme_ns(n, i);
+ if (ns) {
+ nvme_set_blk_stats(ns, &stats);
+ }
+ }
+
+ smart_l.physical_media_units_written[0] = cpu_to_le64(stats.units_written);
+ smart_l.physical_media_units_read[0] = cpu_to_le64(stats.units_read);
+ smart_l.log_page_version = 0x0005;
+
+ static const uint8_t guid[16] = {
+ 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4,
+ 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF
+ };
+ memcpy(smart_l.log_page_guid, guid, sizeof(smart_l.log_page_guid));
+
+ if (!rae) {
+ nvme_clear_events(n, NVME_AER_TYPE_SMART);
+ }
+
+ trans_len = MIN(sizeof(smart_l) - off, buf_len);
+ return nvme_c2h(n, (uint8_t *) &smart_l + off, trans_len, req);
+}
+
static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
uint64_t off, NvmeRequest *req)
{
@@ -5029,7 +5129,7 @@ static uint16_t nvme_error_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
uint64_t off, NvmeRequest *req)
{
- uint32_t nslist[1024];
+ uint32_t nslist[1024] = {};
uint32_t trans_len;
int i = 0;
uint32_t nsid;
@@ -5039,7 +5139,6 @@ static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
return NVME_INVALID_FIELD | NVME_DNR;
}
- memset(nslist, 0x0, sizeof(nslist));
trans_len = MIN(sizeof(nslist) - off, buf_len);
while ((nsid = find_first_bit(n->changed_nsids, NVME_CHANGED_NSID_SIZE)) !=
@@ -5077,7 +5176,7 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
uint64_t off, NvmeRequest *req)
{
NvmeEffectsLog log = {};
- const uint32_t *src_iocs = NULL;
+ const uint32_t *iocs = NULL;
uint32_t trans_len;
if (off >= sizeof(log)) {
@@ -5087,25 +5186,26 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
switch (NVME_CC_CSS(ldl_le_p(&n->bar.cc))) {
case NVME_CC_CSS_NVM:
- src_iocs = nvme_cse_iocs_nvm;
- /* fall through */
- case NVME_CC_CSS_ADMIN_ONLY:
+ iocs = n->cse.iocs.nvm;
break;
- case NVME_CC_CSS_CSI:
+
+ case NVME_CC_CSS_ALL:
switch (csi) {
case NVME_CSI_NVM:
- src_iocs = nvme_cse_iocs_nvm;
+ iocs = n->cse.iocs.nvm;
break;
case NVME_CSI_ZONED:
- src_iocs = nvme_cse_iocs_zoned;
+ iocs = n->cse.iocs.zoned;
break;
}
+
+ break;
}
- memcpy(log.acs, nvme_cse_acs, sizeof(nvme_cse_acs));
+ memcpy(log.acs, n->cse.acs, sizeof(log.acs));
- if (src_iocs) {
- memcpy(log.iocs, src_iocs, sizeof(log.iocs));
+ if (iocs) {
+ memcpy(log.iocs, iocs, sizeof(log.iocs));
}
trans_len = MIN(sizeof(log) - off, buf_len);
@@ -5113,6 +5213,23 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
return nvme_c2h(n, ((uint8_t *)&log) + off, trans_len, req);
}
+static uint16_t nvme_vendor_specific_log(NvmeCtrl *n, uint8_t rae,
+ uint32_t buf_len, uint64_t off,
+ NvmeRequest *req, uint8_t lid)
+{
+ switch (lid) {
+ case NVME_OCP_EXTENDED_SMART_INFO:
+ if (n->params.ocp) {
+ return nvme_ocp_extended_smart_info(n, rae, buf_len, off, req);
+ }
+ break;
+ /* add a case for each additional vendor specific log id */
+ }
+
+ trace_pci_nvme_err_invalid_log_page(nvme_cid(req), lid);
+ return NVME_INVALID_FIELD | NVME_DNR;
+}
+
static size_t sizeof_fdp_conf_descr(size_t nruh, size_t vss)
{
size_t entry_siz = sizeof(NvmeFdpDescrHdr) + nruh * sizeof(NvmeRuhDescr)
@@ -5363,6 +5480,8 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req)
return nvme_smart_info(n, rae, len, off, req);
case NVME_LOG_FW_SLOT_INFO:
return nvme_fw_log_info(n, len, off, req);
+ case NVME_LOG_VENDOR_START...NVME_LOG_VENDOR_END:
+ return nvme_vendor_specific_log(n, rae, len, off, req, lid);
case NVME_LOG_CHANGED_NSLIST:
return nvme_changed_nslist(n, rae, len, off, req);
case NVME_LOG_CMD_EFFECTS:
@@ -5396,7 +5515,7 @@ static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n)
event_notifier_set_handler(&cq->notifier, NULL);
event_notifier_cleanup(&cq->notifier);
}
- if (msix_enabled(pci)) {
+ if (msix_enabled(pci) && cq->irq_enabled) {
msix_vector_unuse(pci, cq->vector);
}
if (cq->cqid) {
@@ -5437,9 +5556,10 @@ static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr,
{
PCIDevice *pci = PCI_DEVICE(n);
- if (msix_enabled(pci)) {
+ if (msix_enabled(pci) && irq_enabled) {
msix_vector_use(pci, vector);
}
+
cq->ctrl = n;
cq->cqid = cqid;
cq->size = size;
@@ -5549,7 +5669,9 @@ static uint16_t nvme_identify_ctrl_csi(NvmeCtrl *n, NvmeRequest *req)
switch (c->csi) {
case NVME_CSI_NVM:
id_nvm->vsl = n->params.vsl;
+ id_nvm->dmrl = NVME_ID_CTRL_NVM_DMRL_MAX;
id_nvm->dmrsl = cpu_to_le32(n->dmrsl);
+ id_nvm->dmsl = NVME_ID_CTRL_NVM_DMRL_MAX * n->dmrsl;
break;
case NVME_CSI_ZONED:
@@ -5591,7 +5713,7 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeRequest *req, bool active)
return nvme_c2h(n, (uint8_t *)&ns->id_ns, sizeof(NvmeIdNs), req);
}
- return NVME_INVALID_CMD_SET | NVME_DNR;
+ return NVME_INVALID_IOCS | NVME_DNR;
}
static uint16_t nvme_identify_ctrl_list(NvmeCtrl *n, NvmeRequest *req,
@@ -5672,6 +5794,33 @@ static uint16_t nvme_identify_sec_ctrl_list(NvmeCtrl *n, NvmeRequest *req)
return nvme_c2h(n, (uint8_t *)&list, sizeof(list), req);
}
+static uint16_t nvme_identify_ns_ind(NvmeCtrl *n, NvmeRequest *req, bool alloc)
+{
+ NvmeNamespace *ns;
+ NvmeIdentify *c = (NvmeIdentify *)&req->cmd;
+ uint32_t nsid = le32_to_cpu(c->nsid);
+
+ trace_pci_nvme_identify_ns_ind(nsid);
+
+ if (!nvme_nsid_valid(n, nsid) || nsid == NVME_NSID_BROADCAST) {
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+
+ ns = nvme_ns(n, nsid);
+ if (unlikely(!ns)) {
+ if (alloc) {
+ ns = nvme_subsys_ns(n->subsys, nsid);
+ if (!ns) {
+ return nvme_rpt_empty_id_struct(n, req);
+ }
+ } else {
+ return nvme_rpt_empty_id_struct(n, req);
+ }
+ }
+
+ return nvme_c2h(n, (uint8_t *)&ns->id_ns_ind, sizeof(NvmeIdNsInd), req);
+}
+
static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeRequest *req,
bool active)
{
@@ -5926,6 +6075,10 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeRequest *req)
return nvme_identify_sec_ctrl_list(n, req);
case NVME_ID_CNS_CS_NS:
return nvme_identify_ns_csi(n, req, true);
+ case NVME_ID_CNS_CS_IND_NS:
+ return nvme_identify_ns_ind(n, req, false);
+ case NVME_ID_CNS_CS_IND_NS_ALLOCATED:
+ return nvme_identify_ns_ind(n, req, true);
case NVME_ID_CNS_CS_NS_PRESENT:
return nvme_identify_ns_csi(n, req, false);
case NVME_ID_CNS_CTRL:
@@ -5983,6 +6136,7 @@ static uint16_t nvme_abort(NvmeCtrl *n, NvmeRequest *req)
QTAILQ_FOREACH_SAFE(r, &sq->out_req_list, entry, next) {
if (r->cqe.cid == cid) {
if (r->aiocb) {
+ r->status = NVME_CMD_ABORT_REQ;
blk_aio_cancel_async(r->aiocb);
}
break;
@@ -6293,8 +6447,10 @@ defaults:
if (ret) {
return ret;
}
- goto out;
+ break;
+ case NVME_WRITE_ATOMICITY:
+ result = n->dn;
break;
default:
result = nvme_feature_default[fid];
@@ -6378,6 +6534,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
uint8_t save = NVME_SETFEAT_SAVE(dw10);
uint16_t status;
int i;
+ NvmeIdCtrl *id = &n->id_ctrl;
+ NvmeAtomic *atomic = &n->atomic;
trace_pci_nvme_setfeat(nvme_cid(req), nsid, fid, save, dw11);
@@ -6522,7 +6680,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
case NVME_COMMAND_SET_PROFILE:
if (dw11 & 0x1ff) {
trace_pci_nvme_err_invalid_iocsci(dw11 & 0x1ff);
- return NVME_CMD_SET_CMB_REJECTED | NVME_DNR;
+ return NVME_IOCS_COMBINATION_REJECTED | NVME_DNR;
}
break;
case NVME_FDP_MODE:
@@ -6530,6 +6688,22 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
return NVME_CMD_SEQ_ERROR | NVME_DNR;
case NVME_FDP_EVENTS:
return nvme_set_feature_fdp_events(n, ns, req);
+ case NVME_WRITE_ATOMICITY:
+
+ n->dn = 0x1 & dw11;
+
+ if (n->dn) {
+ atomic->atomic_max_write_size = le16_to_cpu(id->awupf) + 1;
+ } else {
+ atomic->atomic_max_write_size = le16_to_cpu(id->awun) + 1;
+ }
+
+ if (atomic->atomic_max_write_size == 1) {
+ atomic->atomic_writes = 0;
+ } else {
+ atomic->atomic_writes = 1;
+ }
+ break;
default:
return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
}
@@ -6555,40 +6729,49 @@ static uint16_t nvme_aer(NvmeCtrl *n, NvmeRequest *req)
return NVME_NO_COMPLETE;
}
-static void nvme_update_dmrsl(NvmeCtrl *n)
+static void nvme_update_dsm_limits(NvmeCtrl *n, NvmeNamespace *ns)
{
- int nsid;
+ if (ns) {
+ n->dmrsl =
+ MIN_NON_ZERO(n->dmrsl, BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1));
+
+ return;
+ }
- for (nsid = 1; nsid <= NVME_MAX_NAMESPACES; nsid++) {
- NvmeNamespace *ns = nvme_ns(n, nsid);
+ for (uint32_t nsid = 1; nsid <= NVME_MAX_NAMESPACES; nsid++) {
+ ns = nvme_ns(n, nsid);
if (!ns) {
continue;
}
- n->dmrsl = MIN_NON_ZERO(n->dmrsl,
- BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1));
+ n->dmrsl =
+ MIN_NON_ZERO(n->dmrsl, BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1));
}
}
-static void nvme_select_iocs_ns(NvmeCtrl *n, NvmeNamespace *ns)
+static bool nvme_csi_supported(NvmeCtrl *n, uint8_t csi)
{
- uint32_t cc = ldl_le_p(&n->bar.cc);
+ uint32_t cc;
- ns->iocs = nvme_cse_iocs_none;
- switch (ns->csi) {
+ switch (csi) {
case NVME_CSI_NVM:
- if (NVME_CC_CSS(cc) != NVME_CC_CSS_ADMIN_ONLY) {
- ns->iocs = nvme_cse_iocs_nvm;
- }
- break;
+ return true;
+
case NVME_CSI_ZONED:
- if (NVME_CC_CSS(cc) == NVME_CC_CSS_CSI) {
- ns->iocs = nvme_cse_iocs_zoned;
- } else if (NVME_CC_CSS(cc) == NVME_CC_CSS_NVM) {
- ns->iocs = nvme_cse_iocs_nvm;
- }
- break;
+ cc = ldl_le_p(&n->bar.cc);
+
+ return NVME_CC_CSS(cc) == NVME_CC_CSS_ALL;
}
+
+ g_assert_not_reached();
+}
+
+static void nvme_detach_ns(NvmeCtrl *n, NvmeNamespace *ns)
+{
+ assert(ns->attached > 0);
+
+ n->namespaces[ns->params.nsid] = NULL;
+ ns->attached--;
}
static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
@@ -6633,7 +6816,7 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
switch (sel) {
case NVME_NS_ATTACHMENT_ATTACH:
- if (nvme_ns(ctrl, nsid)) {
+ if (nvme_ns(n, nsid)) {
return NVME_NS_ALREADY_ATTACHED | NVME_DNR;
}
@@ -6641,20 +6824,18 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
return NVME_NS_PRIVATE | NVME_DNR;
}
+ if (!nvme_csi_supported(n, ns->csi)) {
+ return NVME_IOCS_NOT_SUPPORTED | NVME_DNR;
+ }
+
nvme_attach_ns(ctrl, ns);
- nvme_select_iocs_ns(ctrl, ns);
+ nvme_update_dsm_limits(ctrl, ns);
break;
case NVME_NS_ATTACHMENT_DETACH:
- if (!nvme_ns(ctrl, nsid)) {
- return NVME_NS_NOT_ATTACHED | NVME_DNR;
- }
-
- ctrl->namespaces[nsid] = NULL;
- ns->attached--;
-
- nvme_update_dmrsl(ctrl);
+ nvme_detach_ns(ctrl, ns);
+ nvme_update_dsm_limits(ctrl, NULL);
break;
@@ -7157,7 +7338,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode,
nvme_adm_opc_str(req->cmd.opcode));
- if (!(nvme_cse_acs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
+ if (!(n->cse.acs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
trace_pci_nvme_err_invalid_admin_opc(req->cmd.opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
}
@@ -7205,7 +7386,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
case NVME_ADM_CMD_DIRECTIVE_RECV:
return nvme_directive_receive(n, req);
default:
- assert(false);
+ g_assert_not_reached();
}
return NVME_INVALID_OPCODE | NVME_DNR;
@@ -7227,6 +7408,81 @@ static void nvme_update_sq_tail(NvmeSQueue *sq)
trace_pci_nvme_update_sq_tail(sq->sqid, sq->tail);
}
+#define NVME_ATOMIC_NO_START 0
+#define NVME_ATOMIC_START_ATOMIC 1
+#define NVME_ATOMIC_START_NONATOMIC 2
+
+static int nvme_atomic_write_check(NvmeCtrl *n, NvmeCmd *cmd,
+ NvmeAtomic *atomic)
+{
+ NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
+ uint64_t slba = le64_to_cpu(rw->slba);
+ uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb);
+ uint64_t elba = slba + nlb;
+ bool cmd_atomic_wr = true;
+ int i;
+
+ if ((cmd->opcode == NVME_CMD_READ) || ((cmd->opcode == NVME_CMD_WRITE) &&
+ ((rw->nlb + 1) > atomic->atomic_max_write_size))) {
+ cmd_atomic_wr = false;
+ }
+
+ /*
+ * Walk the queues to see if there are any atomic conflicts.
+ */
+ for (i = 1; i < n->params.max_ioqpairs + 1; i++) {
+ NvmeSQueue *sq;
+ NvmeRequest *req;
+ NvmeRwCmd *req_rw;
+ uint64_t req_slba;
+ uint32_t req_nlb;
+ uint64_t req_elba;
+
+ sq = n->sq[i];
+ if (!sq) {
+ continue;
+ }
+
+ /*
+ * Walk all the requests on a given queue.
+ */
+ QTAILQ_FOREACH(req, &sq->out_req_list, entry) {
+ req_rw = (NvmeRwCmd *)&req->cmd;
+
+ if (((req_rw->opcode == NVME_CMD_WRITE) ||
+ (req_rw->opcode == NVME_CMD_READ)) &&
+ (cmd->nsid == req->ns->params.nsid)) {
+ req_slba = le64_to_cpu(req_rw->slba);
+ req_nlb = (uint32_t)le16_to_cpu(req_rw->nlb);
+ req_elba = req_slba + req_nlb;
+
+ if (cmd_atomic_wr) {
+ if ((elba >= req_slba) && (slba <= req_elba)) {
+ return NVME_ATOMIC_NO_START;
+ }
+ } else {
+ if (req->atomic_write && ((elba >= req_slba) &&
+ (slba <= req_elba))) {
+ return NVME_ATOMIC_NO_START;
+ }
+ }
+ }
+ }
+ }
+ if (cmd_atomic_wr) {
+ return NVME_ATOMIC_START_ATOMIC;
+ }
+ return NVME_ATOMIC_START_NONATOMIC;
+}
+
+static NvmeAtomic *nvme_get_atomic(NvmeCtrl *n, NvmeCmd *cmd)
+{
+ if (n->atomic.atomic_writes) {
+ return &n->atomic;
+ }
+ return NULL;
+}
+
static void nvme_process_sq(void *opaque)
{
NvmeSQueue *sq = opaque;
@@ -7243,6 +7499,9 @@ static void nvme_process_sq(void *opaque)
}
while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) {
+ NvmeAtomic *atomic;
+ bool cmd_is_atomic;
+
addr = sq->dma_addr + (sq->head << NVME_SQES);
if (nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd))) {
trace_pci_nvme_err_addr_read(addr);
@@ -7250,6 +7509,26 @@ static void nvme_process_sq(void *opaque)
stl_le_p(&n->bar.csts, NVME_CSTS_FAILED);
break;
}
+
+ atomic = nvme_get_atomic(n, &cmd);
+
+ cmd_is_atomic = false;
+ if (sq->sqid && atomic) {
+ int ret;
+
+ ret = nvme_atomic_write_check(n, &cmd, atomic);
+ switch (ret) {
+ case NVME_ATOMIC_NO_START:
+ qemu_bh_schedule(sq->bh);
+ return;
+ case NVME_ATOMIC_START_ATOMIC:
+ cmd_is_atomic = true;
+ break;
+ case NVME_ATOMIC_START_NONATOMIC:
+ default:
+ break;
+ }
+ }
nvme_inc_sq_head(sq);
req = QTAILQ_FIRST(&sq->req_list);
@@ -7259,6 +7538,10 @@ static void nvme_process_sq(void *opaque)
req->cqe.cid = cmd.cid;
memcpy(&req->cmd, &cmd, sizeof(NvmeCmd));
+ if (sq->sqid && atomic) {
+ req->atomic_write = cmd_is_atomic;
+ }
+
status = sq->sqid ? nvme_io_cmd(n, req) :
nvme_admin_cmd(n, req);
if (status != NVME_NO_COMPLETE) {
@@ -7362,6 +7645,8 @@ static void nvme_ctrl_reset(NvmeCtrl *n, NvmeResetType rst)
n->outstanding_aers = 0;
n->qs_created = false;
+ n->dn = n->params.atomic_dn; /* Set Disable Normal */
+
nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize);
if (pci_is_vf(pci_dev)) {
@@ -7400,21 +7685,6 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n)
}
}
-static void nvme_select_iocs(NvmeCtrl *n)
-{
- NvmeNamespace *ns;
- int i;
-
- for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
- ns = nvme_ns(n, i);
- if (!ns) {
- continue;
- }
-
- nvme_select_iocs_ns(n, ns);
- }
-}
-
static int nvme_start_ctrl(NvmeCtrl *n)
{
uint64_t cap = ldq_le_p(&n->bar.cap);
@@ -7481,7 +7751,22 @@ static int nvme_start_ctrl(NvmeCtrl *n)
nvme_set_timestamp(n, 0ULL);
- nvme_select_iocs(n);
+ /* verify that the command sets of attached namespaces are supported */
+ for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) {
+ NvmeNamespace *ns = nvme_subsys_ns(n->subsys, i);
+
+ if (!ns || (!ns->params.shared && ns->ctrl != n)) {
+ continue;
+ }
+
+ if (nvme_csi_supported(n, ns->csi) && !ns->params.detached) {
+ if (!ns->attached || ns->params.shared) {
+ nvme_attach_ns(n, ns);
+ }
+ }
+ }
+
+ nvme_update_dsm_limits(n, NULL);
return 0;
}
@@ -7806,7 +8091,6 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
/* Completion queue doorbell write */
uint16_t new_head = val & 0xffff;
- int start_sqs;
NvmeCQueue *cq;
qid = (addr - (0x1000 + (1 << 2))) >> 3;
@@ -7857,18 +8141,15 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
trace_pci_nvme_mmio_doorbell_cq(cq->cqid, new_head);
- start_sqs = nvme_cq_full(cq) ? 1 : 0;
+ /* scheduled deferred cqe posting if queue was previously full */
+ if (nvme_cq_full(cq)) {
+ qemu_bh_schedule(cq->bh);
+ }
+
cq->head = new_head;
if (!qid && n->dbbuf_enabled) {
stl_le_pci_dma(pci, cq->db_addr, cq->head, MEMTXATTRS_UNSPECIFIED);
}
- if (start_sqs) {
- NvmeSQueue *sq;
- QTAILQ_FOREACH(sq, &cq->sq_list, entry) {
- qemu_bh_schedule(sq->bh);
- }
- qemu_bh_schedule(cq->bh);
- }
if (cq->tail == cq->head) {
if (cq->irq_enabled) {
@@ -8138,6 +8419,8 @@ static void nvme_init_state(NvmeCtrl *n)
NvmeSecCtrlEntry *list = n->sec_ctrl_list;
NvmeSecCtrlEntry *sctrl;
PCIDevice *pci = PCI_DEVICE(n);
+ NvmeAtomic *atomic = &n->atomic;
+ NvmeIdCtrl *id = &n->id_ctrl;
uint8_t max_vfs;
int i;
@@ -8195,6 +8478,29 @@ static void nvme_init_state(NvmeCtrl *n)
cpu_to_le16(n->params.sriov_max_vi_per_vf) :
cap->vifrt / MAX(max_vfs, 1);
}
+
+ /* Atomic Write */
+ id->awun = cpu_to_le16(n->params.atomic_awun);
+ id->awupf = cpu_to_le16(n->params.atomic_awupf);
+ n->dn = n->params.atomic_dn;
+
+ if (id->awun || id->awupf) {
+ if (id->awupf > id->awun) {
+ id->awupf = 0;
+ }
+
+ if (n->dn) {
+ atomic->atomic_max_write_size = id->awupf + 1;
+ } else {
+ atomic->atomic_max_write_size = id->awun + 1;
+ }
+
+ if (atomic->atomic_max_write_size == 1) {
+ atomic->atomic_writes = 0;
+ } else {
+ atomic->atomic_writes = 1;
+ }
+ }
}
static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev)
@@ -8271,7 +8577,8 @@ out:
return pow2ceil(bar_size);
}
-static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset)
+static bool nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset,
+ Error **errp)
{
uint16_t vf_dev_id = n->params.use_intel_id ?
PCI_DEVICE_ID_INTEL_NVME : PCI_DEVICE_ID_REDHAT_NVME;
@@ -8280,12 +8587,16 @@ static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset)
le16_to_cpu(cap->vifrsm),
NULL, NULL);
- pcie_sriov_pf_init(pci_dev, offset, "nvme", vf_dev_id,
- n->params.sriov_max_vfs, n->params.sriov_max_vfs,
- NVME_VF_OFFSET, NVME_VF_STRIDE);
+ if (!pcie_sriov_pf_init(pci_dev, offset, "nvme", vf_dev_id,
+ n->params.sriov_max_vfs, n->params.sriov_max_vfs,
+ NVME_VF_OFFSET, NVME_VF_STRIDE, errp)) {
+ return false;
+ }
pcie_sriov_pf_init_vf_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_TYPE_64, bar_size);
+
+ return true;
}
static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
@@ -8293,8 +8604,7 @@ static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
Error *err = NULL;
int ret;
- ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, offset,
- PCI_PM_SIZEOF, &err);
+ ret = pci_pm_init(pci_dev, offset, &err);
if (err) {
error_report_err(err);
return ret;
@@ -8340,7 +8650,7 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
unsigned nr_vectors;
int ret;
- pci_conf[PCI_INTERRUPT_PIN] = 1;
+ pci_conf[PCI_INTERRUPT_PIN] = pci_is_vf(pci_dev) ? 0 : 1;
pci_config_set_prog_interface(pci_conf, 0x2);
if (n->params.use_intel_id) {
@@ -8410,6 +8720,11 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
return false;
}
+ if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs &&
+ !nvme_init_sriov(n, pci_dev, 0x120, errp)) {
+ return false;
+ }
+
nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize);
pcie_cap_deverr_init(pci_dev);
@@ -8439,10 +8754,6 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
nvme_init_pmr(n, pci_dev);
}
- if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs) {
- nvme_init_sriov(n, pci_dev, 0x120);
- }
-
return true;
}
@@ -8466,6 +8777,12 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
uint64_t cap = ldq_le_p(&n->bar.cap);
NvmeSecCtrlEntry *sctrl = nvme_sctrl(n);
uint32_t ctratt;
+ uint16_t oacs;
+
+ memcpy(n->cse.acs, nvme_cse_acs_default, sizeof(n->cse.acs));
+ memcpy(n->cse.iocs.nvm, nvme_cse_iocs_nvm_default, sizeof(n->cse.iocs.nvm));
+ memcpy(n->cse.iocs.zoned, nvme_cse_iocs_zoned_default,
+ sizeof(n->cse.iocs.zoned));
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
@@ -8476,7 +8793,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->cntlid = cpu_to_le16(n->cntlid);
id->oaes = cpu_to_le32(NVME_OAES_NS_ATTR);
+
ctratt = NVME_CTRATT_ELBAS;
+ if (n->params.ctratt.mem) {
+ ctratt |= NVME_CTRATT_MEM;
+ }
id->rab = 6;
@@ -8492,9 +8813,23 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->mdts = n->params.mdts;
id->ver = cpu_to_le32(NVME_SPEC_VER);
- id->oacs =
- cpu_to_le16(NVME_OACS_NS_MGMT | NVME_OACS_FORMAT | NVME_OACS_DBBUF |
- NVME_OACS_DIRECTIVES);
+
+ oacs = NVME_OACS_NMS | NVME_OACS_FORMAT | NVME_OACS_DIRECTIVES;
+
+ if (n->params.dbcs) {
+ oacs |= NVME_OACS_DBCS;
+
+ n->cse.acs[NVME_ADM_CMD_DBBUF_CONFIG] = NVME_CMD_EFF_CSUPP;
+ }
+
+ if (n->params.sriov_max_vfs) {
+ oacs |= NVME_OACS_VMS;
+
+ n->cse.acs[NVME_ADM_CMD_VIRT_MNGMT] = NVME_CMD_EFF_CSUPP;
+ }
+
+ id->oacs = cpu_to_le16(oacs);
+
id->cntrltype = 0x1;
/*
@@ -8536,7 +8871,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1 |
NVME_OCFS_COPY_FORMAT_2 | NVME_OCFS_COPY_FORMAT_3);
- id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN);
+ id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN |
+ NVME_CTRL_SGLS_MPTR_SGL);
nvme_init_subnqn(n);
@@ -8544,15 +8880,13 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->psd[0].enlat = cpu_to_le32(0x10);
id->psd[0].exlat = cpu_to_le32(0x4);
- if (n->subsys) {
- id->cmic |= NVME_CMIC_MULTI_CTRL;
- ctratt |= NVME_CTRATT_ENDGRPS;
+ id->cmic |= NVME_CMIC_MULTI_CTRL;
+ ctratt |= NVME_CTRATT_ENDGRPS;
- id->endgidmax = cpu_to_le16(0x1);
+ id->endgidmax = cpu_to_le16(0x1);
- if (n->subsys->endgrp.fdp.enabled) {
- ctratt |= NVME_CTRATT_FDPS;
- }
+ if (n->subsys->endgrp.fdp.enabled) {
+ ctratt |= NVME_CTRATT_FDPS;
}
id->ctratt = cpu_to_le32(ctratt);
@@ -8560,9 +8894,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
NVME_CAP_SET_MQES(cap, n->params.mqes);
NVME_CAP_SET_CQR(cap, 1);
NVME_CAP_SET_TO(cap, 0xf);
- NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_NVM);
- NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_CSI_SUPP);
- NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_ADMIN_ONLY);
+ NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_NCSS);
+ NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_IOCSS);
NVME_CAP_SET_MPSMAX(cap, 4);
NVME_CAP_SET_CMBS(cap, n->params.cmb_size_mb ? 1 : 0);
NVME_CAP_SET_PMRS(cap, n->pmr.dev ? 1 : 0);
@@ -8581,7 +8914,15 @@ static int nvme_init_subsys(NvmeCtrl *n, Error **errp)
int cntlid;
if (!n->subsys) {
- return 0;
+ DeviceState *dev = qdev_new(TYPE_NVME_SUBSYS);
+
+ qdev_prop_set_string(dev, "nqn", n->params.serial);
+
+ if (!qdev_realize(dev, NULL, errp)) {
+ return -1;
+ }
+
+ n->subsys = NVME_SUBSYS(dev);
}
cntlid = nvme_subsys_register_ctrl(n, errp);
@@ -8601,9 +8942,6 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns)
n->namespaces[nsid] = ns;
ns->attached++;
-
- n->dmrsl = MIN_NON_ZERO(n->dmrsl,
- BDRV_REQUEST_MAX_BYTES / nvme_l2b(ns, 1));
}
static void nvme_realize(PCIDevice *pci_dev, Error **errp)
@@ -8626,6 +8964,13 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
*/
n->params.serial = g_strdup(pn->params.serial);
n->subsys = pn->subsys;
+
+ /*
+ * Assigning this link (strong link) causes an `object_unref` later in
+ * `object_release_link_property`. Increment the refcount to balance
+ * this out.
+ */
+ object_ref(OBJECT(pn->subsys));
}
if (!nvme_check_params(n, errp)) {
@@ -8647,12 +8992,13 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
if (n->namespace.blkconf.blk) {
ns = &n->namespace;
ns->params.nsid = 1;
+ ns->ctrl = n;
if (nvme_ns_setup(ns, errp)) {
return;
}
- nvme_attach_ns(n, ns);
+ n->subsys->namespaces[ns->params.nsid] = ns;
}
}
@@ -8664,17 +9010,15 @@ static void nvme_exit(PCIDevice *pci_dev)
nvme_ctrl_reset(n, NVME_RESET_FUNCTION);
- if (n->subsys) {
- for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
- ns = nvme_ns(n, i);
- if (ns) {
- ns->attached--;
- }
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
+ ns = nvme_ns(n, i);
+ if (ns) {
+ ns->attached--;
}
-
- nvme_subsys_unregister_ctrl(n->subsys, n);
}
+ nvme_subsys_unregister_ctrl(n->subsys, n);
+
g_free(n->cq);
g_free(n->sq);
g_free(n->aer_reqs);
@@ -8696,11 +9040,16 @@ static void nvme_exit(PCIDevice *pci_dev)
pcie_sriov_pf_exit(pci_dev);
}
- msix_uninit(pci_dev, &n->bar0, &n->bar0);
+ if (n->params.msix_exclusive_bar && !pci_is_vf(pci_dev)) {
+ msix_uninit_exclusive_bar(pci_dev);
+ } else {
+ msix_uninit(pci_dev, &n->bar0, &n->bar0);
+ }
+
memory_region_del_subregion(&n->bar0, &n->iomem);
}
-static Property nvme_props[] = {
+static const Property nvme_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, namespace.blkconf),
DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmr.dev, TYPE_MEMORY_BACKEND,
HostMemoryBackend *),
@@ -8718,6 +9067,7 @@ static Property nvme_props[] = {
DEFINE_PROP_BOOL("use-intel-id", NvmeCtrl, params.use_intel_id, false),
DEFINE_PROP_BOOL("legacy-cmb", NvmeCtrl, params.legacy_cmb, false),
DEFINE_PROP_BOOL("ioeventfd", NvmeCtrl, params.ioeventfd, false),
+ DEFINE_PROP_BOOL("dbcs", NvmeCtrl, params.dbcs, true),
DEFINE_PROP_UINT8("zoned.zasl", NvmeCtrl, params.zasl, 0),
DEFINE_PROP_BOOL("zoned.auto_transition", NvmeCtrl,
params.auto_transition_zones, true),
@@ -8734,7 +9084,11 @@ static Property nvme_props[] = {
false),
DEFINE_PROP_UINT16("mqes", NvmeCtrl, params.mqes, 0x7ff),
DEFINE_PROP_UINT16("spdm_port", PCIDevice, spdm_port, 0),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("ctratt.mem", NvmeCtrl, params.ctratt.mem, false),
+ DEFINE_PROP_BOOL("atomic.dn", NvmeCtrl, params.atomic_dn, 0),
+ DEFINE_PROP_UINT16("atomic.awun", NvmeCtrl, params.atomic_awun, 0),
+ DEFINE_PROP_UINT16("atomic.awupf", NvmeCtrl, params.atomic_awupf, 0),
+ DEFINE_PROP_BOOL("ocp", NvmeCtrl, params.ocp, false),
};
static void nvme_get_smart_warning(Object *obj, Visitor *v, const char *name,
@@ -8829,7 +9183,7 @@ static const VMStateDescription nvme_vmstate = {
.unmigratable = 1,
};
-static void nvme_class_init(ObjectClass *oc, void *data)
+static void nvme_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
@@ -8845,7 +9199,7 @@ static void nvme_class_init(ObjectClass *oc, void *data)
dc->desc = "Non-Volatile Memory Express";
device_class_set_props(dc, nvme_props);
dc->vmsd = &nvme_vmstate;
- dc->reset = nvme_pci_reset;
+ device_class_set_legacy_reset(dc, nvme_pci_reset);
}
static void nvme_instance_init(Object *obj)
@@ -8867,7 +9221,7 @@ static const TypeInfo nvme_info = {
.instance_size = sizeof(NvmeCtrl),
.instance_init = nvme_instance_init,
.class_init = nvme_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/nvme/dif.c b/hw/nvme/dif.c
index 01b19c3..4e7874f 100644
--- a/hw/nvme/dif.c
+++ b/hw/nvme/dif.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "nvme.h"
#include "dif.h"
@@ -575,11 +575,6 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req)
uint8_t *mbuf, *end;
int16_t pil = ns->lbaf.ms - nvme_pi_tuple_size(ns);
- status = nvme_check_prinfo(ns, prinfo, slba, reftag);
- if (status) {
- goto err;
- }
-
flags = 0;
ctx->mdata.bounce = g_malloc0(mlen);
diff --git a/hw/nvme/nguid.c b/hw/nvme/nguid.c
index 829832b..4cd6fad 100644
--- a/hw/nvme/nguid.c
+++ b/hw/nvme/nguid.c
@@ -149,7 +149,7 @@ static void nvme_nguid_stringify(const NvmeNGUID *nguid, char *out)
static void get_nguid(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
NvmeNGUID *nguid = object_field_prop_ptr(obj, prop);
char buffer[NGUID_STR_LEN];
char *p = buffer;
@@ -162,7 +162,7 @@ static void get_nguid(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_nguid(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
NvmeNGUID *nguid = object_field_prop_ptr(obj, prop);
char *str;
@@ -179,7 +179,7 @@ static void set_nguid(Object *obj, Visitor *v, const char *name, void *opaque,
}
const PropertyInfo qdev_prop_nguid = {
- .name = "str",
+ .type = "str",
.description =
"NGUID or \"" NGUID_VALUE_AUTO "\" for random value",
.get = get_nguid,
diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index ea8db17..6df2e8e 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -18,8 +18,8 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qemu/bitops.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
+#include "system/system.h"
+#include "system/block-backend.h"
#include "nvme.h"
#include "trace.h"
@@ -30,6 +30,7 @@
void nvme_ns_init_format(NvmeNamespace *ns)
{
NvmeIdNs *id_ns = &ns->id_ns;
+ NvmeIdNsNvm *id_ns_nvm = &ns->id_ns_nvm;
BlockDriverInfo bdi;
int npdg, ret;
int64_t nlbas;
@@ -55,6 +56,8 @@ void nvme_ns_init_format(NvmeNamespace *ns)
}
id_ns->npda = id_ns->npdg = npdg - 1;
+ id_ns_nvm->npdal = npdg;
+ id_ns_nvm->npdgl = npdg;
}
static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
@@ -62,6 +65,7 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
static uint64_t ns_count;
NvmeIdNs *id_ns = &ns->id_ns;
NvmeIdNsNvm *id_ns_nvm = &ns->id_ns_nvm;
+ NvmeIdNsInd *id_ns_ind = &ns->id_ns_ind;
uint8_t ds;
uint16_t ms;
int i;
@@ -72,10 +76,12 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
ns->id_ns.dlfeat = 0x1;
/* support DULBE and I/O optimization fields */
- id_ns->nsfeat |= (0x4 | 0x10);
+ id_ns->nsfeat |= (NVME_ID_NS_NSFEAT_DAE | NVME_ID_NS_NSFEAT_OPTPERF_ALL);
if (ns->params.shared) {
- id_ns->nmic |= NVME_NMIC_NS_SHARED;
+ id_ns->nmic |= NVME_ID_NS_IND_NMIC_SHRNS;
+ id_ns_ind->nmic = NVME_ID_NS_IND_NMIC_SHRNS;
+ id_ns_ind->nstat = NVME_ID_NS_IND_NSTAT_NRDY;
}
/* Substitute a missing EUI-64 by an autogenerated one */
@@ -721,25 +727,14 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
uint32_t nsid = ns->params.nsid;
int i;
- if (!n->subsys) {
- /* If no subsys, the ns cannot be attached to more than one ctrl. */
- ns->params.shared = false;
- if (ns->params.detached) {
- error_setg(errp, "detached requires that the nvme device is "
- "linked to an nvme-subsys device");
- return;
- }
- } else {
- /*
- * If this namespace belongs to a subsystem (through a link on the
- * controller device), reparent the device.
- */
- if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) {
- return;
- }
- ns->subsys = subsys;
- ns->endgrp = &subsys->endgrp;
+ assert(subsys);
+
+ /* reparent to subsystem bus */
+ if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) {
+ return;
}
+ ns->subsys = subsys;
+ ns->endgrp = &subsys->endgrp;
if (nvme_ns_setup(ns, errp)) {
return;
@@ -747,7 +742,7 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
if (!nsid) {
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
- if (nvme_ns(n, i) || nvme_subsys_ns(subsys, i)) {
+ if (nvme_subsys_ns(subsys, i)) {
continue;
}
@@ -759,40 +754,22 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
error_setg(errp, "no free namespace id");
return;
}
- } else {
- if (nvme_ns(n, nsid) || nvme_subsys_ns(subsys, nsid)) {
- error_setg(errp, "namespace id '%d' already allocated", nsid);
- return;
- }
+ } else if (nvme_subsys_ns(subsys, nsid)) {
+ error_setg(errp, "namespace id '%d' already allocated", nsid);
+ return;
}
- if (subsys) {
- subsys->namespaces[nsid] = ns;
+ subsys->namespaces[nsid] = ns;
- ns->id_ns.endgid = cpu_to_le16(0x1);
-
- if (ns->params.detached) {
- return;
- }
-
- if (ns->params.shared) {
- for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
- NvmeCtrl *ctrl = subsys->ctrls[i];
-
- if (ctrl && ctrl != SUBSYS_SLOT_RSVD) {
- nvme_attach_ns(ctrl, ns);
- }
- }
-
- return;
- }
+ ns->id_ns.endgid = cpu_to_le16(0x1);
+ ns->id_ns_ind.endgrpid = cpu_to_le16(0x1);
+ if (!ns->params.shared) {
+ ns->ctrl = n;
}
-
- nvme_attach_ns(n, ns);
}
-static Property nvme_ns_props[] = {
+static const Property nvme_ns_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false),
DEFINE_PROP_BOOL("shared", NvmeNamespace, params.shared, true),
@@ -827,10 +804,9 @@ static Property nvme_ns_props[] = {
DEFINE_PROP_BOOL("eui64-default", NvmeNamespace, params.eui64_default,
false),
DEFINE_PROP_STRING("fdp.ruhs", NvmeNamespace, params.fdp.ruhs),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nvme_ns_class_init(ObjectClass *oc, void *data)
+static void nvme_ns_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index 7819857..b5c9378 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -220,6 +220,11 @@ typedef struct NvmeNamespaceParams {
} fdp;
} NvmeNamespaceParams;
+typedef struct NvmeAtomic {
+ uint32_t atomic_max_write_size;
+ bool atomic_writes;
+} NvmeAtomic;
+
typedef struct NvmeNamespace {
DeviceState parent_obj;
BlockConf blkconf;
@@ -228,10 +233,10 @@ typedef struct NvmeNamespace {
int64_t moff;
NvmeIdNs id_ns;
NvmeIdNsNvm id_ns_nvm;
+ NvmeIdNsInd id_ns_ind;
NvmeLBAF lbaf;
unsigned int nlbaf;
size_t lbasz;
- const uint32_t *iocs;
uint8_t csi;
uint16_t status;
int attached;
@@ -263,6 +268,9 @@ typedef struct NvmeNamespace {
NvmeSubsystem *subsys;
NvmeEnduranceGroup *endgrp;
+ /* NULL for shared namespaces; set to specific controller if private */
+ NvmeCtrl *ctrl;
+
struct {
uint32_t err_rec;
} features;
@@ -421,6 +429,7 @@ typedef struct NvmeRequest {
NvmeCmd cmd;
BlockAcctCookie acct;
NvmeSg sg;
+ bool atomic_write;
QTAILQ_ENTRY(NvmeRequest)entry;
} NvmeRequest;
@@ -532,12 +541,22 @@ typedef struct NvmeParams {
bool auto_transition_zones;
bool legacy_cmb;
bool ioeventfd;
+ bool dbcs;
uint16_t sriov_max_vfs;
uint16_t sriov_vq_flexible;
uint16_t sriov_vi_flexible;
uint32_t sriov_max_vq_per_vf;
uint32_t sriov_max_vi_per_vf;
bool msix_exclusive_bar;
+ bool ocp;
+
+ struct {
+ bool mem;
+ } ctratt;
+
+ uint16_t atomic_awun;
+ uint16_t atomic_awupf;
+ bool atomic_dn;
} NvmeParams;
typedef struct NvmeCtrl {
@@ -569,6 +588,14 @@ typedef struct NvmeCtrl {
bool dbbuf_enabled;
struct {
+ uint32_t acs[256];
+ struct {
+ uint32_t nvm[256];
+ uint32_t zoned[256];
+ } iocs;
+ } cse;
+
+ struct {
MemoryRegion mem;
uint8_t *buf;
bool cmse;
@@ -619,6 +646,8 @@ typedef struct NvmeCtrl {
uint16_t vqrfap;
uint16_t virfap;
} next_pri_ctrl_cap; /* These override pri_ctrl_cap after reset */
+ uint32_t dn; /* Disable Normal */
+ NvmeAtomic atomic;
} NvmeCtrl;
typedef enum NvmeResetType {
diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c
index 77deaf2..777e1c6 100644
--- a/hw/nvme/subsys.c
+++ b/hw/nvme/subsys.c
@@ -56,7 +56,7 @@ int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
{
NvmeSubsystem *subsys = n->subsys;
NvmeSecCtrlEntry *sctrl = nvme_sctrl(n);
- int cntlid, nsid, num_rsvd, num_vfs = n->params.sriov_max_vfs;
+ int cntlid, num_rsvd, num_vfs = n->params.sriov_max_vfs;
if (pci_is_vf(&n->parent_obj)) {
cntlid = le16_to_cpu(sctrl->scid);
@@ -92,13 +92,6 @@ int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
subsys->ctrls[cntlid] = n;
- for (nsid = 1; nsid < ARRAY_SIZE(subsys->namespaces); nsid++) {
- NvmeNamespace *ns = subsys->namespaces[nsid];
- if (ns && ns->params.shared && !ns->params.detached) {
- nvme_attach_ns(n, ns);
- }
- }
-
return cntlid;
}
@@ -216,17 +209,16 @@ static void nvme_subsys_realize(DeviceState *dev, Error **errp)
nvme_subsys_setup(subsys, errp);
}
-static Property nvme_subsystem_props[] = {
+static const Property nvme_subsystem_props[] = {
DEFINE_PROP_STRING("nqn", NvmeSubsystem, params.nqn),
DEFINE_PROP_BOOL("fdp", NvmeSubsystem, params.fdp.enabled, false),
DEFINE_PROP_SIZE("fdp.runs", NvmeSubsystem, params.fdp.runs,
NVME_DEFAULT_RU_SIZE),
DEFINE_PROP_UINT32("fdp.nrg", NvmeSubsystem, params.fdp.nrg, 1),
DEFINE_PROP_UINT16("fdp.nruh", NvmeSubsystem, params.fdp.nruh, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nvme_subsys_class_init(ObjectClass *oc, void *data)
+static void nvme_subsys_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -234,7 +226,6 @@ static void nvme_subsys_class_init(ObjectClass *oc, void *data)
dc->realize = nvme_subsys_realize;
dc->desc = "Virtual NVMe subsystem";
- dc->hotpluggable = false;
device_class_set_props(dc, nvme_subsystem_props);
}
diff --git a/hw/nvme/trace-events b/hw/nvme/trace-events
index 3a67680..6be0bfa 100644
--- a/hw/nvme/trace-events
+++ b/hw/nvme/trace-events
@@ -56,6 +56,7 @@ pci_nvme_identify(uint16_t cid, uint8_t cns, uint16_t ctrlid, uint8_t csi) "cid
pci_nvme_identify_ctrl(void) "identify controller"
pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8""
pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
+pci_nvme_identify_ns_ind(uint32_t nsid) "nsid %"PRIu32""
pci_nvme_identify_ctrl_list(uint8_t cns, uint16_t cntid) "cns 0x%"PRIx8" cntid %"PRIu16""
pci_nvme_identify_pri_ctrl_cap(uint16_t cntlid) "identify primary controller capabilities cntlid=%"PRIu16""
pci_nvme_identify_sec_ctrl_list(uint16_t cntlid, uint8_t numcntl) "identify secondary controller list cntlid=%"PRIu16" numcntl=%"PRIu8""
diff --git a/hw/nvram/bcm2835_otp.c b/hw/nvram/bcm2835_otp.c
index c4aed28..6816b53 100644
--- a/hw/nvram/bcm2835_otp.c
+++ b/hw/nvram/bcm2835_otp.c
@@ -164,7 +164,7 @@ static const VMStateDescription vmstate_bcm2835_otp = {
}
};
-static void bcm2835_otp_class_init(ObjectClass *klass, void *data)
+static void bcm2835_otp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/nvram/chrp_nvram.c b/hw/nvram/chrp_nvram.c
index d4d10a7..0b204e3 100644
--- a/hw/nvram/chrp_nvram.c
+++ b/hw/nvram/chrp_nvram.c
@@ -23,7 +23,7 @@
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "hw/nvram/chrp_nvram.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str,
int max_len)
diff --git a/hw/nvram/ds1225y.c b/hw/nvram/ds1225y.c
index 6d510dc..dbfd0d2 100644
--- a/hw/nvram/ds1225y.c
+++ b/hw/nvram/ds1225y.c
@@ -142,13 +142,12 @@ static void nvram_sysbus_realize(DeviceState *dev, Error **errp)
nvram_post_load(s, 0);
}
-static Property nvram_sysbus_properties[] = {
+static const Property nvram_sysbus_properties[] = {
DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
+static void nvram_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
index 3272068..82ea97e 100644
--- a/hw/nvram/eeprom_at24c.c
+++ b/hw/nvram/eeprom_at24c.c
@@ -10,12 +10,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "qemu/module.h"
#include "hw/i2c/i2c.h"
#include "hw/nvram/eeprom_at24c.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qom/object.h"
/* #define DEBUG_AT24C */
@@ -26,13 +27,8 @@
#define DPRINTK(FMT, ...) do {} while (0)
#endif
-#define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \
- ## __VA_ARGS__)
-
#define TYPE_AT24C_EE "at24c-eeprom"
-typedef struct EEPROMState EEPROMState;
-DECLARE_INSTANCE_CHECKER(EEPROMState, AT24C_EE,
- TYPE_AT24C_EE)
+OBJECT_DECLARE_SIMPLE_TYPE(EEPROMState, AT24C_EE)
struct EEPROMState {
I2CSlave parent_obj;
@@ -77,8 +73,7 @@ int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
if (ee->blk && ee->changed) {
int ret = blk_pwrite(ee->blk, 0, ee->rsize, ee->mem, 0);
if (ret < 0) {
- ERR(TYPE_AT24C_EE
- " : failed to write backing file\n");
+ error_report("%s: failed to write backing file", __func__);
}
DPRINTK("Wrote to backing file\n");
}
@@ -195,20 +190,18 @@ static void at24c_eeprom_realize(DeviceState *dev, Error **errp)
}
ee->mem = g_malloc0(ee->rsize);
- memset(ee->mem, 0, ee->rsize);
-
- if (ee->init_rom) {
- memcpy(ee->mem, ee->init_rom, MIN(ee->init_rom_size, ee->rsize));
- }
if (ee->blk) {
int ret = blk_pread(ee->blk, 0, ee->rsize, ee->mem, 0);
if (ret < 0) {
- ERR(TYPE_AT24C_EE
- " : Failed initial sync with backing file\n");
+ error_setg(errp, "%s: Failed initial sync with backing file",
+ TYPE_AT24C_EE);
+ return;
}
DPRINTK("Reset read backing file\n");
+ } else if (ee->init_rom) {
+ memcpy(ee->mem, ee->init_rom, MIN(ee->init_rom_size, ee->rsize));
}
/*
@@ -234,16 +227,15 @@ void at24c_eeprom_reset(DeviceState *state)
ee->haveaddr = 0;
}
-static Property at24c_eeprom_props[] = {
+static const Property at24c_eeprom_props[] = {
DEFINE_PROP_UINT32("rom-size", EEPROMState, rsize, 0),
DEFINE_PROP_UINT8("address-size", EEPROMState, asize, 0),
DEFINE_PROP_BOOL("writable", EEPROMState, writable, true),
DEFINE_PROP_DRIVE("drive", EEPROMState, blk),
- DEFINE_PROP_END_OF_LIST()
};
static
-void at24c_eeprom_class_init(ObjectClass *klass, void *data)
+void at24c_eeprom_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -254,7 +246,7 @@ void at24c_eeprom_class_init(ObjectClass *klass, void *data)
k->send = &at24c_eeprom_send;
device_class_set_props(dc, at24c_eeprom_props);
- dc->reset = at24c_eeprom_reset;
+ device_class_set_legacy_reset(dc, at24c_eeprom_reset);
}
static
diff --git a/hw/nvram/fw_cfg-acpi.c b/hw/nvram/fw_cfg-acpi.c
index 58cdcd3..2e6ef89 100644
--- a/hw/nvram/fw_cfg-acpi.c
+++ b/hw/nvram/fw_cfg-acpi.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Add fw_cfg device in DSDT
*
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index fc0263f..aa24050 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -24,10 +24,10 @@
#include "qemu/osdep.h"
#include "qemu/datadir.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-#include "sysemu/reset.h"
-#include "exec/address-spaces.h"
+#include "system/system.h"
+#include "system/dma.h"
+#include "system/reset.h"
+#include "system/address-spaces.h"
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/qdev-properties.h"
@@ -41,7 +41,6 @@
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "hw/acpi/aml-build.h"
-#include "hw/pci/pci_bus.h"
#include "hw/loader.h"
#define FW_CFG_FILE_SLOTS_DFLT 0x20
@@ -730,7 +729,6 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
ptr = s->entries[arch][key].data;
s->entries[arch][key].data = data;
s->entries[arch][key].len = len;
- s->entries[arch][key].callback_opaque = NULL;
s->entries[arch][key].allow_write = false;
return ptr;
@@ -819,62 +817,6 @@ void fw_cfg_modify_i64(FWCfgState *s, uint16_t key, uint64_t value)
g_free(old);
}
-void fw_cfg_set_order_override(FWCfgState *s, int order)
-{
- assert(s->fw_cfg_order_override == 0);
- s->fw_cfg_order_override = order;
-}
-
-void fw_cfg_reset_order_override(FWCfgState *s)
-{
- assert(s->fw_cfg_order_override != 0);
- s->fw_cfg_order_override = 0;
-}
-
-/*
- * This is the legacy order list. For legacy systems, files are in
- * the fw_cfg in the order defined below, by the "order" value. Note
- * that some entries (VGA ROMs, NIC option ROMS, etc.) go into a
- * specific area, but there may be more than one and they occur in the
- * order that the user specifies them on the command line. Those are
- * handled in a special manner, using the order override above.
- *
- * For non-legacy, the files are sorted by filename to avoid this kind
- * of complexity in the future.
- *
- * This is only for x86, other arches don't implement versioning so
- * they won't set legacy mode.
- */
-static struct {
- const char *name;
- int order;
-} fw_cfg_order[] = {
- { "etc/boot-menu-wait", 10 },
- { "bootsplash.jpg", 11 },
- { "bootsplash.bmp", 12 },
- { "etc/boot-fail-wait", 15 },
- { "etc/smbios/smbios-tables", 20 },
- { "etc/smbios/smbios-anchor", 30 },
- { "etc/e820", 40 },
- { "etc/reserved-memory-end", 50 },
- { "genroms/kvmvapic.bin", 55 },
- { "genroms/linuxboot.bin", 60 },
- { }, /* VGA ROMs from pc_vga_init come here, 70. */
- { }, /* NIC option ROMs from pc_nic_init come here, 80. */
- { "etc/system-states", 90 },
- { }, /* User ROMs come here, 100. */
- { }, /* Device FW comes here, 110. */
- { "etc/extra-pci-roots", 120 },
- { "etc/acpi/tables", 130 },
- { "etc/table-loader", 140 },
- { "etc/tpm/log", 150 },
- { "etc/acpi/rsdp", 160 },
- { "bootorder", 170 },
- { "etc/msr_feature_control", 180 },
-
-#define FW_CFG_ORDER_OVERRIDE_LAST 200
-};
-
/*
* Any sub-page size update to these table MRs will be lost during migration,
* as we use aligned size in ram_load_precopy() -> qemu_ram_resize() path.
@@ -892,29 +834,6 @@ static void fw_cfg_acpi_mr_save(FWCfgState *s, const char *filename, size_t len)
}
}
-static int get_fw_cfg_order(FWCfgState *s, const char *name)
-{
- int i;
-
- if (s->fw_cfg_order_override > 0) {
- return s->fw_cfg_order_override;
- }
-
- for (i = 0; i < ARRAY_SIZE(fw_cfg_order); i++) {
- if (fw_cfg_order[i].name == NULL) {
- continue;
- }
-
- if (strcmp(name, fw_cfg_order[i].name) == 0) {
- return fw_cfg_order[i].order;
- }
- }
-
- /* Stick unknown stuff at the end. */
- warn_report("Unknown firmware file in legacy mode: %s", name);
- return FW_CFG_ORDER_OVERRIDE_LAST;
-}
-
void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
FWCfgCallback select_cb,
FWCfgWriteCallback write_cb,
@@ -923,7 +842,6 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
{
int i, index, count;
size_t dsize;
- MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
int order = 0;
if (!s->files) {
@@ -935,22 +853,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
count = be32_to_cpu(s->files->count);
assert(count < fw_cfg_file_slots(s));
- /* Find the insertion point. */
- if (mc->legacy_fw_cfg_order) {
- /*
- * Sort by order. For files with the same order, we keep them
- * in the sequence in which they were added.
- */
- order = get_fw_cfg_order(s, filename);
- for (index = count;
- index > 0 && order < s->entry_order[index - 1];
- index--);
- } else {
- /* Sort by file name. */
- for (index = count;
- index > 0 && strcmp(filename, s->files->f[index - 1].name) < 0;
- index--);
- }
+ /* Find the insertion point, sorting by file name. */
+ for (index = count;
+ index > 0 && strcmp(filename, s->files->f[index - 1].name) < 0;
+ index--)
+ ;
/*
* Move all the entries from the index point and after down one
@@ -1027,27 +934,29 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
return NULL;
}
-bool fw_cfg_add_from_generator(FWCfgState *s, const char *filename,
- const char *gen_id, Error **errp)
+bool fw_cfg_add_file_from_generator(FWCfgState *s,
+ Object *parent, const char *part,
+ const char *filename, Error **errp)
{
+ ERRP_GUARD();
FWCfgDataGeneratorClass *klass;
GByteArray *array;
Object *obj;
gsize size;
- obj = object_resolve_path_component(object_get_objects_root(), gen_id);
+ obj = object_resolve_path_component(parent, part);
if (!obj) {
- error_setg(errp, "Cannot find object ID '%s'", gen_id);
+ error_setg(errp, "Cannot find object ID '%s'", part);
return false;
}
if (!object_dynamic_cast(obj, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)) {
error_setg(errp, "Object ID '%s' is not a '%s' subclass",
- gen_id, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE);
+ part, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE);
return false;
}
klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj);
array = klass->get_data(obj, errp);
- if (!array) {
+ if (*errp || !array) {
return false;
}
size = array->len;
@@ -1056,31 +965,8 @@ bool fw_cfg_add_from_generator(FWCfgState *s, const char *filename,
return true;
}
-void fw_cfg_add_extra_pci_roots(PCIBus *bus, FWCfgState *s)
-{
- int extra_hosts = 0;
-
- if (!bus) {
- return;
- }
-
- QLIST_FOREACH(bus, &bus->child, sibling) {
- /* look for expander root buses */
- if (pci_bus_is_root(bus)) {
- extra_hosts++;
- }
- }
-
- if (extra_hosts && s) {
- uint64_t *val = g_malloc(sizeof(*val));
- *val = cpu_to_le64(extra_hosts);
- fw_cfg_add_file(s, "etc/extra-pci-roots", val, sizeof(*val));
- }
-}
-
static void fw_cfg_machine_reset(void *opaque)
{
- MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
FWCfgState *s = opaque;
void *ptr;
size_t len;
@@ -1090,11 +976,9 @@ static void fw_cfg_machine_reset(void *opaque)
ptr = fw_cfg_modify_file(s, "bootorder", (uint8_t *)buf, len);
g_free(ptr);
- if (!mc->legacy_fw_cfg_order) {
- buf = get_boot_devices_lchs_list(&len);
- ptr = fw_cfg_modify_file(s, "bios-geometry", (uint8_t *)buf, len);
- g_free(ptr);
- }
+ buf = get_boot_devices_lchs_list(&len);
+ ptr = fw_cfg_modify_file(s, "bios-geometry", (uint8_t *)buf, len);
+ g_free(ptr);
}
static void fw_cfg_machine_ready(struct Notifier *n, void *data)
@@ -1103,9 +987,8 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
qemu_register_reset(fw_cfg_machine_reset, s);
}
-static Property fw_cfg_properties[] = {
+static const Property fw_cfg_properties[] = {
DEFINE_PROP_BOOL("acpi-mr-restore", FWCfgState, acpi_mr_restore, true),
- DEFINE_PROP_END_OF_LIST(),
};
static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
@@ -1171,11 +1054,6 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
return s;
}
-FWCfgState *fw_cfg_init_io(uint32_t iobase)
-{
- return fw_cfg_init_io_dma(iobase, 0, NULL);
-}
-
FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
hwaddr data_addr, uint32_t data_width,
hwaddr dma_addr, AddressSpace *dma_as)
@@ -1256,11 +1134,11 @@ void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
-static void fw_cfg_class_init(ObjectClass *klass, void *data)
+static void fw_cfg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = fw_cfg_reset;
+ device_class_set_legacy_reset(dc, fw_cfg_reset);
dc->vmsd = &vmstate_fw_cfg;
device_class_set_props(dc, fw_cfg_properties);
@@ -1299,12 +1177,11 @@ static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp)
s->entry_order = g_new0(int, fw_cfg_max_entry(s));
}
-static Property fw_cfg_io_properties[] = {
+static const Property fw_cfg_io_properties[] = {
DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
true),
DEFINE_PROP_UINT16("x-file-slots", FWCfgIoState, parent_obj.file_slots,
FW_CFG_FILE_SLOTS_DFLT),
- DEFINE_PROP_END_OF_LIST(),
};
static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
@@ -1332,7 +1209,7 @@ static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
fw_cfg_common_realize(dev, errp);
}
-static void fw_cfg_io_class_init(ObjectClass *klass, void *data)
+static void fw_cfg_io_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1348,13 +1225,12 @@ static const TypeInfo fw_cfg_io_info = {
};
-static Property fw_cfg_mem_properties[] = {
+static const Property fw_cfg_mem_properties[] = {
DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
true),
DEFINE_PROP_UINT16("x-file-slots", FWCfgMemState, parent_obj.file_slots,
FW_CFG_FILE_SLOTS_DFLT),
- DEFINE_PROP_END_OF_LIST(),
};
static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
@@ -1394,7 +1270,7 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
fw_cfg_common_realize(dev, errp);
}
-static void fw_cfg_mem_class_init(ObjectClass *klass, void *data)
+static void fw_cfg_mem_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
index fe9df9f..66526a2 100644
--- a/hw/nvram/mac_nvram.c
+++ b/hw/nvram/mac_nvram.c
@@ -29,13 +29,13 @@
#include "hw/nvram/mac_nvram.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "migration/vmstate.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "trace.h"
-#include <zlib.h>
+#include <zlib.h> /* for adler32 */
#define DEF_SYSTEM_SIZE 0xc10
@@ -134,20 +134,19 @@ static void macio_nvram_unrealizefn(DeviceState *dev)
g_free(s->data);
}
-static Property macio_nvram_properties[] = {
+static const Property macio_nvram_properties[] = {
DEFINE_PROP_UINT32("size", MacIONVRAMState, size, 0),
DEFINE_PROP_UINT32("it_shift", MacIONVRAMState, it_shift, 0),
DEFINE_PROP_DRIVE("drive", MacIONVRAMState, blk),
- DEFINE_PROP_END_OF_LIST()
};
-static void macio_nvram_class_init(ObjectClass *oc, void *data)
+static void macio_nvram_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = macio_nvram_realizefn;
dc->unrealize = macio_nvram_unrealizefn;
- dc->reset = macio_nvram_reset;
+ device_class_set_legacy_reset(dc, macio_nvram_reset);
dc->vmsd = &vmstate_macio_nvram;
device_class_set_props(dc, macio_nvram_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
diff --git a/hw/nvram/npcm7xx_otp.c b/hw/nvram/npcm7xx_otp.c
index f00ebfa..1fb752b 100644
--- a/hw/nvram/npcm7xx_otp.c
+++ b/hw/nvram/npcm7xx_otp.c
@@ -391,7 +391,7 @@ static const VMStateDescription vmstate_npcm7xx_otp = {
},
};
-static void npcm7xx_otp_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_otp_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -403,14 +403,14 @@ static void npcm7xx_otp_class_init(ObjectClass *klass, void *data)
rc->phases.enter = npcm7xx_otp_enter_reset;
}
-static void npcm7xx_key_storage_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_key_storage_class_init(ObjectClass *klass, const void *data)
{
NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
oc->mmio_ops = &npcm7xx_key_storage_ops;
}
-static void npcm7xx_fuse_array_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_fuse_array_class_init(ObjectClass *klass, const void *data)
{
NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
diff --git a/hw/nvram/nrf51_nvm.c b/hw/nvram/nrf51_nvm.c
index 73564f7..23cc9fe 100644
--- a/hw/nvram/nrf51_nvm.c
+++ b/hw/nvram/nrf51_nvm.c
@@ -354,9 +354,8 @@ static void nrf51_nvm_reset(DeviceState *dev)
memset(s->uicr_content, 0xFF, sizeof(s->uicr_content));
}
-static Property nrf51_nvm_properties[] = {
+static const Property nrf51_nvm_properties[] = {
DEFINE_PROP_UINT32("flash-size", NRF51NVMState, flash_size, 0x40000),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_nvm = {
@@ -371,14 +370,14 @@ static const VMStateDescription vmstate_nvm = {
}
};
-static void nrf51_nvm_class_init(ObjectClass *klass, void *data)
+static void nrf51_nvm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, nrf51_nvm_properties);
dc->vmsd = &vmstate_nvm;
dc->realize = nrf51_nvm_realize;
- dc->reset = nrf51_nvm_reset;
+ device_class_set_legacy_reset(dc, nrf51_nvm_reset);
}
static const TypeInfo nrf51_nvm_info = {
diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c
index bfd8aa3..d0ac4e57 100644
--- a/hw/nvram/spapr_nvram.c
+++ b/hw/nvram/spapr_nvram.c
@@ -28,10 +28,10 @@
#include "qapi/error.h"
#include <libfdt.h>
-#include "sysemu/block-backend.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/block-backend.h"
+#include "system/device_tree.h"
+#include "system/system.h"
+#include "system/runstate.h"
#include "migration/vmstate.h"
#include "hw/nvram/chrp_nvram.h"
#include "hw/ppc/spapr.h"
@@ -252,13 +252,12 @@ static const VMStateDescription vmstate_spapr_nvram = {
},
};
-static Property spapr_nvram_properties[] = {
+static const Property spapr_nvram_properties[] = {
DEFINE_SPAPR_PROPERTIES(SpaprNvram, sdev),
DEFINE_PROP_DRIVE("drive", SpaprNvram, blk),
- DEFINE_PROP_END_OF_LIST(),
};
-static void spapr_nvram_class_init(ObjectClass *klass, void *data)
+static void spapr_nvram_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c
index 09575a7..5702bb3 100644
--- a/hw/nvram/xlnx-bbram.c
+++ b/hw/nvram/xlnx-bbram.c
@@ -29,7 +29,7 @@
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qapi/error.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
@@ -456,9 +456,8 @@ static void bbram_ctrl_init(Object *obj)
{
XlnxBBRam *s = XLNX_BBRAM(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), bbram_ctrl_regs_info,
ARRAY_SIZE(bbram_ctrl_regs_info),
s->regs_info, s->regs,
@@ -466,10 +465,17 @@ static void bbram_ctrl_init(Object *obj)
XLNX_BBRAM_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq_bbram);
}
+static void bbram_ctrl_finalize(Object *obj)
+{
+ XlnxBBRam *s = XLNX_BBRAM(obj);
+
+ register_finalize_block(s->reg_array);
+}
+
static void bbram_prop_set_drive(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -496,7 +502,7 @@ static void bbram_prop_release_drive(Object *obj, const char *name,
}
static const PropertyInfo bbram_prop_drive = {
- .name = "str",
+ .type = "str",
.description = "Node name or ID of a block device to use as BBRAM backend",
.realized_set_allowed = true,
.get = bbram_prop_get_drive,
@@ -514,13 +520,12 @@ static const VMStateDescription vmstate_bbram_ctrl = {
}
};
-static Property bbram_ctrl_props[] = {
+static const Property bbram_ctrl_props[] = {
DEFINE_PROP("drive", XlnxBBRam, blk, bbram_prop_drive, BlockBackend *),
DEFINE_PROP_UINT32("crc-zpads", XlnxBBRam, crc_zpads, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void bbram_ctrl_class_init(ObjectClass *klass, void *data)
+static void bbram_ctrl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -537,6 +542,7 @@ static const TypeInfo bbram_ctrl_info = {
.instance_size = sizeof(XlnxBBRam),
.class_init = bbram_ctrl_class_init,
.instance_init = bbram_ctrl_init,
+ .instance_finalize = bbram_ctrl_finalize,
};
static void bbram_ctrl_register_types(void)
diff --git a/hw/nvram/xlnx-efuse.c b/hw/nvram/xlnx-efuse.c
index f7b849f..4c23f8b 100644
--- a/hw/nvram/xlnx-efuse.c
+++ b/hw/nvram/xlnx-efuse.c
@@ -30,7 +30,7 @@
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qapi/error.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
@@ -257,7 +257,7 @@ static void efuse_prop_release_drive(Object *obj, const char *name,
}
static const PropertyInfo efuse_prop_drive = {
- .name = "str",
+ .type = "str",
.description = "Node name or ID of a block device to use as eFUSE backend",
.realized_set_allowed = true,
.get = efuse_prop_get_drive,
@@ -265,22 +265,23 @@ static const PropertyInfo efuse_prop_drive = {
.release = efuse_prop_release_drive,
};
-static Property efuse_properties[] = {
+static const Property efuse_properties[] = {
DEFINE_PROP("drive", XlnxEFuse, blk, efuse_prop_drive, BlockBackend *),
DEFINE_PROP_UINT8("efuse-nr", XlnxEFuse, efuse_nr, 3),
DEFINE_PROP_UINT32("efuse-size", XlnxEFuse, efuse_size, 64 * 32),
DEFINE_PROP_BOOL("init-factory-tbits", XlnxEFuse, init_tbits, true),
DEFINE_PROP_ARRAY("read-only", XlnxEFuse, ro_bits_cnt, ro_bits,
qdev_prop_uint32, uint32_t),
- DEFINE_PROP_END_OF_LIST(),
};
-static void efuse_class_init(ObjectClass *klass, void *data)
+static void efuse_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = efuse_realize;
device_class_set_props(dc, efuse_properties);
+ /* Reason: Part of Xilinx SoC */
+ dc->user_creatable = false;
}
static const TypeInfo efuse_info = {
diff --git a/hw/nvram/xlnx-versal-efuse-cache.c b/hw/nvram/xlnx-versal-efuse-cache.c
index eaec64d..d4ec96a 100644
--- a/hw/nvram/xlnx-versal-efuse-cache.c
+++ b/hw/nvram/xlnx-versal-efuse-cache.c
@@ -83,15 +83,13 @@ static void efuse_cache_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property efuse_cache_props[] = {
+static const Property efuse_cache_props[] = {
DEFINE_PROP_LINK("efuse",
XlnxVersalEFuseCache, efuse,
TYPE_XLNX_EFUSE, XlnxEFuse *),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void efuse_cache_class_init(ObjectClass *klass, void *data)
+static void efuse_cache_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/nvram/xlnx-versal-efuse-ctrl.c b/hw/nvram/xlnx-versal-efuse-ctrl.c
index def6fe33..9096219 100644
--- a/hw/nvram/xlnx-versal-efuse-ctrl.c
+++ b/hw/nvram/xlnx-versal-efuse-ctrl.c
@@ -494,7 +494,6 @@ static void efuse_rd_addr_postw(RegisterInfo *reg, uint64_t val64)
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_DONE, 1);
efuse_imr_update_irq(s);
- return;
}
static uint64_t efuse_cache_load_prew(RegisterInfo *reg, uint64_t val64)
@@ -712,9 +711,8 @@ static void efuse_ctrl_init(Object *obj)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), efuse_ctrl_regs_info,
ARRAY_SIZE(efuse_ctrl_regs_info),
s->regs_info, s->regs,
@@ -722,7 +720,7 @@ static void efuse_ctrl_init(Object *obj)
XLNX_VERSAL_EFUSE_CTRL_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq_efuse_imr);
}
@@ -730,6 +728,7 @@ static void efuse_ctrl_finalize(Object *obj)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj);
+ register_finalize_block(s->reg_array);
g_free(s->extra_pg0_lock_spec);
}
@@ -743,18 +742,16 @@ static const VMStateDescription vmstate_efuse_ctrl = {
}
};
-static Property efuse_ctrl_props[] = {
+static const Property efuse_ctrl_props[] = {
DEFINE_PROP_LINK("efuse",
XlnxVersalEFuseCtrl, efuse,
TYPE_XLNX_EFUSE, XlnxEFuse *),
DEFINE_PROP_ARRAY("pg0-lock",
XlnxVersalEFuseCtrl, extra_pg0_lock_n16,
extra_pg0_lock_spec, qdev_prop_uint16, uint16_t),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void efuse_ctrl_class_init(ObjectClass *klass, void *data)
+static void efuse_ctrl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/nvram/xlnx-zynqmp-efuse.c b/hw/nvram/xlnx-zynqmp-efuse.c
index 2d465f0..5a218c3 100644
--- a/hw/nvram/xlnx-zynqmp-efuse.c
+++ b/hw/nvram/xlnx-zynqmp-efuse.c
@@ -803,9 +803,8 @@ static void zynqmp_efuse_init(Object *obj)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), zynqmp_efuse_regs_info,
ARRAY_SIZE(zynqmp_efuse_regs_info),
s->regs_info, s->regs,
@@ -813,10 +812,17 @@ static void zynqmp_efuse_init(Object *obj)
ZYNQMP_EFUSE_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq);
}
+static void zynqmp_efuse_finalize(Object *obj)
+{
+ XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj);
+
+ register_finalize_block(s->reg_array);
+}
+
static const VMStateDescription vmstate_efuse = {
.name = TYPE_XLNX_ZYNQMP_EFUSE,
.version_id = 1,
@@ -827,15 +833,13 @@ static const VMStateDescription vmstate_efuse = {
}
};
-static Property zynqmp_efuse_props[] = {
+static const Property zynqmp_efuse_props[] = {
DEFINE_PROP_LINK("efuse",
XlnxZynqMPEFuse, efuse,
TYPE_XLNX_EFUSE, XlnxEFuse *),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void zynqmp_efuse_class_init(ObjectClass *klass, void *data)
+static void zynqmp_efuse_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -853,6 +857,7 @@ static const TypeInfo efuse_info = {
.instance_size = sizeof(XlnxZynqMPEFuse),
.class_init = zynqmp_efuse_class_init,
.instance_init = zynqmp_efuse_init,
+ .instance_finalize = zynqmp_efuse_finalize,
};
static void efuse_register_types(void)
diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig
index 76b953c..0702f62 100644
--- a/hw/openrisc/Kconfig
+++ b/hw/openrisc/Kconfig
@@ -3,7 +3,7 @@ config OR1K_SIM
default y
depends on OPENRISC
select DEVICE_TREE
- select SERIAL
+ select SERIAL_MM
select OPENCORES_ETH
select OMPIC
select SPLIT_IRQ
@@ -19,6 +19,6 @@ config OR1K_VIRT
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
select GOLDFISH_RTC
- select SERIAL
+ select SERIAL_MM
select SIFIVE_TEST
select VIRTIO_MMIO
diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c
index 55475aa..c81efe8 100644
--- a/hw/openrisc/boot.c
+++ b/hw/openrisc/boot.c
@@ -9,12 +9,13 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/cpu-defs.h"
+#include "exec/target_page.h"
#include "elf.h"
#include "hw/loader.h"
#include "hw/openrisc/boot.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
+#include "system/device_tree.h"
+#include "system/qtest.h"
+#include "system/reset.h"
#include "qemu/error-report.h"
#include <libfdt.h>
@@ -32,7 +33,7 @@ hwaddr openrisc_load_kernel(ram_addr_t ram_size,
if (kernel_filename && !qtest_enabled()) {
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
- &elf_entry, NULL, &high_addr, NULL, 1,
+ &elf_entry, NULL, &high_addr, NULL, ELFDATA2MSB,
EM_OPENRISC, 1, 0);
entry = elf_entry;
if (kernel_size < 0) {
@@ -90,8 +91,8 @@ hwaddr openrisc_load_initrd(void *fdt, const char *filename,
return start + size;
}
-uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
- uint64_t mem_size)
+uint32_t openrisc_load_fdt(MachineState *ms, void *fdt,
+ hwaddr load_start, uint64_t mem_size)
{
uint32_t fdt_addr;
int ret;
@@ -109,7 +110,9 @@ uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
/* Should only fail if we've built a corrupted tree */
g_assert(ret == 0);
/* copy in the device tree */
- qemu_fdt_dumpdtb(fdt, fdtsize);
+
+ /* Save FDT for dumpdtb monitor command */
+ ms->fdt = fdt;
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
&address_space_memory);
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
index 835986c..6331997 100644
--- a/hw/openrisc/cputimer.c
+++ b/hw/openrisc/cputimer.c
@@ -22,14 +22,15 @@
#include "cpu.h"
#include "migration/vmstate.h"
#include "qemu/timer.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */
/* Tick Timer global state to allow all cores to be in sync */
typedef struct OR1KTimerState {
uint32_t ttcr;
- uint64_t last_clk;
+ uint32_t ttcr_offset;
+ uint64_t clk_offset;
} OR1KTimerState;
static OR1KTimerState *or1k_timer;
@@ -37,6 +38,8 @@ static OR1KTimerState *or1k_timer;
void cpu_openrisc_count_set(OpenRISCCPU *cpu, uint32_t val)
{
or1k_timer->ttcr = val;
+ or1k_timer->ttcr_offset = val;
+ or1k_timer->clk_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu)
@@ -53,9 +56,8 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu)
return;
}
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- or1k_timer->ttcr += (uint32_t)((now - or1k_timer->last_clk)
- / TIMER_PERIOD);
- or1k_timer->last_clk = now;
+ or1k_timer->ttcr = or1k_timer->ttcr_offset +
+ DIV_ROUND_UP(now - or1k_timer->clk_offset, TIMER_PERIOD);
}
/* Update the next timeout time as difference between ttmr and ttcr */
@@ -69,7 +71,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
}
cpu_openrisc_count_update(cpu);
- now = or1k_timer->last_clk;
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if ((cpu->env.ttmr & TTMR_TP) <= (or1k_timer->ttcr & TTMR_TP)) {
wait = TTMR_TP - (or1k_timer->ttcr & TTMR_TP) + 1;
@@ -110,7 +112,8 @@ static void openrisc_timer_cb(void *opaque)
case TIMER_NONE:
break;
case TIMER_INTR:
- or1k_timer->ttcr = 0;
+ /* Zero the count by applying a negative offset to the counter */
+ or1k_timer->ttcr_offset -= (cpu->env.ttmr & TTMR_TP);
break;
case TIMER_SHOT:
cpu_openrisc_count_stop(cpu);
@@ -137,17 +140,18 @@ static void openrisc_count_reset(void *opaque)
/* Reset the global timer state. */
static void openrisc_timer_reset(void *opaque)
{
- or1k_timer->ttcr = 0x00000000;
- or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ OpenRISCCPU *cpu = opaque;
+ cpu_openrisc_count_set(cpu, 0);
}
static const VMStateDescription vmstate_or1k_timer = {
.name = "or1k_timer",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(ttcr, OR1KTimerState),
- VMSTATE_UINT64(last_clk, OR1KTimerState),
+ VMSTATE_UINT32(ttcr_offset, OR1KTimerState),
+ VMSTATE_UINT64(clk_offset, OR1KTimerState),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
index bffd6f7..880c8eb 100644
--- a/hw/openrisc/openrisc_sim.c
+++ b/hw/openrisc/openrisc_sim.c
@@ -24,16 +24,16 @@
#include "cpu.h"
#include "hw/irq.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
#include "hw/openrisc/boot.h"
#include "hw/qdev-properties.h"
-#include "exec/address-spaces.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
+#include "system/address-spaces.h"
+#include "system/device_tree.h"
+#include "system/system.h"
#include "hw/sysbus.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
+#include "system/qtest.h"
+#include "system/reset.h"
#include "hw/core/split-irq.h"
#include <libfdt.h>
@@ -250,7 +250,7 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base,
void *fdt = state->fdt;
char *nodename;
qemu_irq serial_irq;
- char alias[sizeof("uart0")];
+ char alias[sizeof("serial0")];
int i;
if (num_cpus > 1) {
@@ -265,8 +265,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base,
serial_irq = get_cpu_irq(cpus, 0, irq_pin);
}
serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200,
- serial_hd(OR1KSIM_UART_COUNT - uart_idx - 1),
- DEVICE_NATIVE_ENDIAN);
+ serial_hd(uart_idx),
+ DEVICE_BIG_ENDIAN);
/* Add device tree node for serial. */
nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base);
@@ -277,10 +277,13 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base,
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", OR1KSIM_CLK_MHZ);
qemu_fdt_setprop(fdt, nodename, "big-endian", NULL, 0);
- /* The /chosen node is created during fdt creation. */
- qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
- snprintf(alias, sizeof(alias), "uart%d", uart_idx);
+ if (uart_idx == 0) {
+ /* The /chosen node is created during fdt creation. */
+ qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
+ }
+ snprintf(alias, sizeof(alias), "serial%d", uart_idx);
qemu_fdt_setprop_string(fdt, "/aliases", alias, nodename);
+
g_free(nodename);
}
@@ -303,8 +306,6 @@ static void openrisc_sim_init(MachineState *machine)
exit(1);
}
- cpu_openrisc_clock_init(cpus[n]);
-
qemu_register_reset(main_cpu_reset, cpus[n]);
}
@@ -326,11 +327,22 @@ static void openrisc_sim_init(MachineState *machine)
smp_cpus, cpus, OR1KSIM_OMPIC_IRQ);
}
- for (n = 0; n < OR1KSIM_UART_COUNT; ++n)
+ /*
+ * We create the UART nodes starting with the highest address and
+ * working downwards, because in QEMU the DTB nodes end up in the
+ * DTB in reverse order of creation. Correctly-written guest software
+ * will not care about the node order (it will look at stdout-path
+ * or the alias nodes), but for the benefit of guest software which
+ * just looks for the first UART node in the DTB, make sure the
+ * lowest-address UART (which is QEMU's first serial port) appears
+ * first in the DTB.
+ */
+ for (n = OR1KSIM_UART_COUNT - 1; n >= 0; n--) {
openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base +
or1ksim_memmap[OR1KSIM_UART].size * n,
or1ksim_memmap[OR1KSIM_UART].size,
smp_cpus, cpus, OR1KSIM_UART_IRQ, n);
+ }
load_addr = openrisc_load_kernel(ram_size, kernel_filename,
&boot_info.bootstrap_pc);
@@ -340,12 +352,12 @@ static void openrisc_sim_init(MachineState *machine)
machine->initrd_filename,
load_addr, machine->ram_size);
}
- boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
+ boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
machine->ram_size);
}
}
-static void openrisc_sim_machine_init(ObjectClass *oc, void *data)
+static void openrisc_sim_machine_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
index f8a68a6..a98071c 100644
--- a/hw/openrisc/virt.c
+++ b/hw/openrisc/virt.c
@@ -11,10 +11,10 @@
#include "qemu/guest-random.h"
#include "qapi/error.h"
#include "cpu.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/irq.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/core/split-irq.h"
#include "hw/openrisc/boot.h"
#include "hw/misc/sifive_test.h"
@@ -24,10 +24,10 @@
#include "hw/rtc/goldfish_rtc.h"
#include "hw/sysbus.h"
#include "hw/virtio/virtio-mmio.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
+#include "system/device_tree.h"
+#include "system/system.h"
+#include "system/qtest.h"
+#include "system/reset.h"
#include <libfdt.h>
@@ -236,7 +236,7 @@ static void openrisc_virt_serial_init(OR1KVirtState *state, hwaddr base,
qemu_irq serial_irq = get_per_cpu_irq(cpus, num_cpus, irq_pin);
serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200,
- serial_hd(0), DEVICE_NATIVE_ENDIAN);
+ serial_hd(0), DEVICE_BIG_ENDIAN);
/* Add device tree node for serial. */
nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base);
@@ -318,7 +318,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
{
int pin, dev;
uint32_t irq_map_stride = 0;
- uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {};
+ uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 6] = {};
uint32_t *irq_map = full_irq_map;
/*
@@ -330,11 +330,11 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
* possible slot) seeing the interrupt-map-mask will allow the table
* to wrap to any number of devices.
*/
- for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+ for (dev = 0; dev < PCI_NUM_PINS; dev++) {
int devfn = dev << 3;
- for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
- int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+ for (pin = 0; pin < PCI_NUM_PINS; pin++) {
+ int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
int i = 0;
/* Fill PCI address cells */
@@ -357,7 +357,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base,
}
qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
- GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ PCI_NUM_PINS * PCI_NUM_PINS *
irq_map_stride * sizeof(uint32_t));
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -409,7 +409,7 @@ static void openrisc_virt_pcie_init(OR1KVirtState *state,
memory_region_add_subregion(get_system_memory(), pio_base, alias);
/* Connect IRQ lines. */
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
pcie_irq = get_per_cpu_irq(cpus, num_cpus, irq_base + i);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq);
@@ -487,8 +487,6 @@ static void openrisc_virt_init(MachineState *machine)
exit(1);
}
- cpu_openrisc_clock_init(cpus[n]);
-
qemu_register_reset(main_cpu_reset, cpus[n]);
}
@@ -540,12 +538,12 @@ static void openrisc_virt_init(MachineState *machine)
machine->initrd_filename,
load_addr, machine->ram_size);
}
- boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
+ boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
machine->ram_size);
}
}
-static void openrisc_virt_machine_init(ObjectClass *oc, void *data)
+static void openrisc_virt_machine_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/pci-bridge/Kconfig b/hw/pci-bridge/Kconfig
index 6707736..449ec98 100644
--- a/hw/pci-bridge/Kconfig
+++ b/hw/pci-bridge/Kconfig
@@ -1,3 +1,8 @@
+config PCI_BRIDGE
+ bool
+ default y if PCI_DEVICES
+ depends on PCI
+
config PCIE_PORT
bool
default y if PCI_DEVICES
diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index 742da07..1065245 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -13,6 +13,8 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_port.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/cxl/cxl.h"
#include "qapi/error.h"
@@ -210,24 +212,19 @@ static void cxl_dsp_exitfn(PCIDevice *d)
pci_bridge_exitfn(d);
}
-static void cxl_dsp_instance_post_init(Object *obj)
-{
- PCIESlot *s = PCIE_SLOT(obj);
-
- if (!s->speed) {
- s->speed = QEMU_PCI_EXP_LNK_2_5GT;
- }
-
- if (!s->width) {
- s->width = QEMU_PCI_EXP_LNK_X1;
- }
-}
+static const Property cxl_dsp_props[] = {
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
+ speed, PCIE_LINK_SPEED_64),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
+ width, PCIE_LINK_WIDTH_16),
+};
-static void cxl_dsp_class_init(ObjectClass *oc, void *data)
+static void cxl_dsp_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
+ device_class_set_props(dc, cxl_dsp_props);
k->config_write = cxl_dsp_config_write;
k->realize = cxl_dsp_realize;
k->exit = cxl_dsp_exitfn;
@@ -236,16 +233,15 @@ static void cxl_dsp_class_init(ObjectClass *oc, void *data)
k->revision = 0;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "CXL Switch Downstream Port";
- dc->reset = cxl_dsp_reset;
+ device_class_set_legacy_reset(dc, cxl_dsp_reset);
}
static const TypeInfo cxl_dsp_info = {
.name = TYPE_CXL_DSP,
.instance_size = sizeof(CXLDownstreamPort),
.parent = TYPE_PCIE_SLOT,
- .instance_post_init = cxl_dsp_instance_post_init,
.class_init = cxl_dsp_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CXL_DEVICE },
{ }
diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index 2dd1023..e6a4035 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -24,6 +24,7 @@
#include "hw/pci/pcie_port.h"
#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
#include "hw/cxl/cxl.h"
@@ -198,7 +199,7 @@ static void cxl_rp_reset_hold(Object *obj, ResetType type)
latch_registers(crp);
}
-static Property gen_rp_props[] = {
+static const Property gen_rp_props[] = {
DEFINE_PROP_UINT32("bus-reserve", CXLRootPort, res_reserve.bus, -1),
DEFINE_PROP_SIZE("io-reserve", CXLRootPort, res_reserve.io, -1),
DEFINE_PROP_SIZE("mem-reserve", CXLRootPort, res_reserve.mem_non_pref, -1),
@@ -206,7 +207,10 @@ static Property gen_rp_props[] = {
-1),
DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64,
-1),
- DEFINE_PROP_END_OF_LIST()
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
+ speed, PCIE_LINK_SPEED_64),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
+ width, PCIE_LINK_WIDTH_32),
};
static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr,
@@ -258,7 +262,7 @@ static void cxl_rp_write_config(PCIDevice *d, uint32_t address, uint32_t val,
cxl_rp_dvsec_write_config(d, address, val, len);
}
-static void cxl_root_port_class_init(ObjectClass *oc, void *data)
+static void cxl_root_port_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
@@ -290,7 +294,7 @@ static const TypeInfo cxl_root_port_info = {
.parent = TYPE_PCIE_ROOT_PORT,
.instance_size = sizeof(CXLRootPort),
.class_init = cxl_root_port_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CXL_DEVICE },
{ }
},
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index e51221a..208e0c6 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -11,6 +11,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_port.h"
@@ -100,6 +101,7 @@ static void cxl_usp_reset(DeviceState *qdev)
pci_bridge_reset(qdev);
pcie_cap_deverr_reset(d);
+ pcie_cap_fill_link_ep_usp(d, usp->width, usp->speed);
latch_registers(usp);
}
@@ -234,7 +236,7 @@ static int build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
.type = CDAT_TYPE_SSLBIS,
.length = sslbis_size,
},
- .data_type = HMATLB_DATA_TYPE_ACCESS_LATENCY,
+ .data_type = HMAT_LB_DATA_TYPE_ACCESS_LATENCY,
.entry_base_unit = 10000,
},
};
@@ -254,7 +256,7 @@ static int build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
.type = CDAT_TYPE_SSLBIS,
.length = sslbis_size,
},
- .data_type = HMATLB_DATA_TYPE_ACCESS_BANDWIDTH,
+ .data_type = HMAT_LB_DATA_TYPE_ACCESS_BANDWIDTH,
.entry_base_unit = 1024,
},
};
@@ -360,13 +362,16 @@ static void cxl_usp_exitfn(PCIDevice *d)
pci_bridge_exitfn(d);
}
-static Property cxl_upstream_props[] = {
+static const Property cxl_upstream_props[] = {
DEFINE_PROP_UINT64("sn", CXLUpstreamPort, sn, UI64_NULL),
DEFINE_PROP_STRING("cdat", CXLUpstreamPort, cxl_cstate.cdat.filename),
- DEFINE_PROP_END_OF_LIST()
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLUpstreamPort,
+ speed, PCIE_LINK_SPEED_32),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLUpstreamPort,
+ width, PCIE_LINK_WIDTH_16),
};
-static void cxl_upstream_class_init(ObjectClass *oc, void *data)
+static void cxl_upstream_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
@@ -380,7 +385,7 @@ static void cxl_upstream_class_init(ObjectClass *oc, void *data)
k->revision = 0;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "CXL Switch Upstream Port";
- dc->reset = cxl_usp_reset;
+ device_class_set_legacy_reset(dc, cxl_usp_reset);
device_class_set_props(dc, cxl_upstream_props);
}
@@ -389,7 +394,7 @@ static const TypeInfo cxl_usp_info = {
.parent = TYPE_PCIE_PORT,
.instance_size = sizeof(CXLUpstreamPort),
.class_init = cxl_upstream_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CXL_DEVICE },
{ }
diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
index 784507c..d9078e7 100644
--- a/hw/pci-bridge/gen_pcie_root_port.c
+++ b/hw/pci-bridge/gen_pcie_root_port.c
@@ -128,7 +128,7 @@ static const VMStateDescription vmstate_rp_dev = {
}
};
-static Property gen_rp_props[] = {
+static const Property gen_rp_props[] = {
DEFINE_PROP_BOOL("x-migrate-msix", GenPCIERootPort,
migrate_msix, true),
DEFINE_PROP_UINT32("bus-reserve", GenPCIERootPort,
@@ -145,10 +145,9 @@ static Property gen_rp_props[] = {
speed, PCIE_LINK_SPEED_16),
DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
width, PCIE_LINK_WIDTH_32),
- DEFINE_PROP_END_OF_LIST()
};
-static void gen_rp_dev_class_init(ObjectClass *klass, void *data)
+static void gen_rp_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c
index c140919..1d73c14 100644
--- a/hw/pci-bridge/i82801b11.c
+++ b/hw/pci-bridge/i82801b11.c
@@ -87,7 +87,7 @@ static const VMStateDescription i82801b11_bridge_dev_vmstate = {
}
};
-static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
+static void i82801b11_bridge_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -98,7 +98,7 @@ static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
k->realize = i82801b11_bridge_realize;
k->config_write = pci_bridge_write_config;
dc->vmsd = &i82801b11_bridge_dev_vmstate;
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
@@ -107,7 +107,7 @@ static const TypeInfo i82801b11_bridge_info = {
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(I82801b11Bridge),
.class_init = i82801b11_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c
index be752a4..bba640f 100644
--- a/hw/pci-bridge/ioh3420.c
+++ b/hw/pci-bridge/ioh3420.c
@@ -96,7 +96,7 @@ static const VMStateDescription vmstate_ioh3420 = {
}
};
-static void ioh3420_class_init(ObjectClass *klass, void *data)
+static void ioh3420_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/pci-bridge/meson.build b/hw/pci-bridge/meson.build
index f2a6043..2e0eb0d 100644
--- a/hw/pci-bridge/meson.build
+++ b/hw/pci-bridge/meson.build
@@ -1,5 +1,5 @@
pci_ss = ss.source_set()
-pci_ss.add(files('pci_bridge_dev.c'))
+pci_ss.add(when: 'CONFIG_PCI_BRIDGE', if_true: files('pci_bridge_dev.c'))
pci_ss.add(when: 'CONFIG_I82801B11', if_true: files('i82801b11.c'))
pci_ss.add(when: 'CONFIG_IOH3420', if_true: files('ioh3420.c'))
pci_ss.add(when: 'CONFIG_PCIE_PORT', if_true: files('pcie_root_port.c', 'gen_pcie_root_port.c'))
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 089f91e..b328e50 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -28,7 +28,7 @@
#include "hw/pci/shpc.h"
#include "hw/pci/slotid_cap.h"
#include "hw/qdev-properties.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/pci/pci_bus.h"
#include "hw/hotplug.h"
#include "qom/object.h"
@@ -168,7 +168,7 @@ static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
}
}
-static Property pci_bridge_dev_properties[] = {
+static const Property pci_bridge_dev_properties[] = {
/* Note: 0 is not a legal chassis number. */
DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr,
0),
@@ -186,7 +186,6 @@ static Property pci_bridge_dev_properties[] = {
res_reserve.mem_pref_32, -1),
DEFINE_PROP_SIZE("pref64-reserve", PCIBridgeDev,
res_reserve.mem_pref_64, -1),
- DEFINE_PROP_END_OF_LIST(),
};
static bool pci_device_shpc_present(void *opaque, int version_id)
@@ -241,7 +240,7 @@ void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
shpc_device_unplug_request_cb(hotplug_dev, dev, errp);
}
-static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
+static void pci_bridge_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -254,7 +253,7 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
k->class_id = PCI_CLASS_BRIDGE_PCI;
dc->desc = "Standard PCI Bridge";
- dc->reset = qdev_pci_bridge_dev_reset;
+ device_class_set_legacy_reset(dc, qdev_pci_bridge_dev_reset);
device_class_set_props(dc, pci_bridge_dev_properties);
dc->vmsd = &pci_bridge_dev_vmstate;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
@@ -269,7 +268,7 @@ static const TypeInfo pci_bridge_dev_info = {
.instance_size = sizeof(PCIBridgeDev),
.class_init = pci_bridge_dev_class_init,
.instance_finalize = pci_bridge_dev_instance_finalize,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
@@ -281,7 +280,7 @@ static const TypeInfo pci_bridge_dev_info = {
* different pci id, so we can match it easily in the guest for
* automagic multiseat configuration. See docs/multiseat.txt for more.
*/
-static void pci_bridge_dev_seat_class_init(ObjectClass *klass, void *data)
+static void pci_bridge_dev_seat_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 0411ad3..3a29dfe 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -23,7 +23,7 @@
#include "qemu/range.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#include "hw/boards.h"
#include "qom/object.h"
@@ -38,7 +38,6 @@ DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS,
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS,
TYPE_PXB_PCIE_BUS)
-#define TYPE_PXB_CXL_BUS "pxb-cxl-bus"
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS,
TYPE_PXB_CXL_BUS)
@@ -85,12 +84,25 @@ static uint16_t pxb_bus_numa_node(PCIBus *bus)
return pxb->numa_node;
}
-static void pxb_bus_class_init(ObjectClass *class, void *data)
+static void prop_pxb_uid_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint32_t uid = pci_bus_num(PCI_BUS(obj));
+
+ visit_type_uint32(v, name, &uid, errp);
+}
+
+static void pxb_bus_class_init(ObjectClass *class, const void *data)
{
PCIBusClass *pbc = PCI_BUS_CLASS(class);
pbc->bus_num = pxb_bus_num;
pbc->numa_node = pxb_bus_numa_node;
+
+ object_class_property_add(class, "acpi_uid", "uint32",
+ prop_pxb_uid_get, NULL, NULL, NULL);
+ object_class_property_set_description(class, "acpi_uid",
+ "ACPI Unique ID used to distinguish this PCI Host Bridge / ACPI00016");
}
static const TypeInfo pxb_bus_info = {
@@ -157,7 +169,7 @@ static char *pxb_host_ofw_unit_address(const SysBusDevice *dev)
return NULL;
}
-static void pxb_host_class_init(ObjectClass *class, void *data)
+static void pxb_host_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class);
@@ -212,7 +224,7 @@ void pxb_cxl_hook_up_registers(CXLState *cxl_state, PCIBus *bus, Error **errp)
cxl_state->next_mr_idx++;
}
-static void pxb_cxl_host_class_init(ObjectClass *class, void *data)
+static void pxb_cxl_host_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
@@ -318,7 +330,7 @@ static gint pxb_compare(gconstpointer a, gconstpointer b)
0;
}
-static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
+static bool pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
Error **errp)
{
PXBDev *pxb = PXB_DEV(dev);
@@ -330,13 +342,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
if (ms->numa_state == NULL) {
error_setg(errp, "NUMA is not supported by this machine-type");
- return;
+ return false;
}
if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
pxb->numa_node >= ms->numa_state->num_nodes) {
error_setg(errp, "Illegal numa node %d", pxb->numa_node);
- return;
+ return false;
}
if (dev->qdev.id && *dev->qdev.id) {
@@ -382,12 +394,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
- return;
+ return true;
err_register_bus:
object_unref(OBJECT(bds));
object_unparent(OBJECT(bus));
object_unref(OBJECT(ds));
+ return false;
}
static void pxb_dev_realize(PCIDevice *dev, Error **errp)
@@ -407,15 +420,14 @@ static void pxb_dev_exitfn(PCIDevice *pci_dev)
pxb_dev_list = g_list_remove(pxb_dev_list, pxb);
}
-static Property pxb_dev_properties[] = {
+static const Property pxb_dev_properties[] = {
/* Note: 0 is not a legal PXB bus number. */
DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED),
DEFINE_PROP_BOOL("bypass_iommu", PXBDev, bypass_iommu, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pxb_dev_class_init(ObjectClass *klass, void *data)
+static void pxb_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -437,7 +449,7 @@ static const TypeInfo pxb_dev_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PXBDev),
.class_init = pxb_dev_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -453,7 +465,7 @@ static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp)
pxb_dev_realize_common(dev, PCIE, errp);
}
-static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
+static void pxb_pcie_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -474,7 +486,7 @@ static const TypeInfo pxb_pcie_dev_info = {
.parent = TYPE_PXB_DEV,
.instance_size = sizeof(PXBPCIEDev),
.class_init = pxb_pcie_dev_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -488,16 +500,17 @@ static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp)
return;
}
- pxb_dev_realize_common(dev, CXL, errp);
+ if (!pxb_dev_realize_common(dev, CXL, errp)) {
+ return;
+ }
pxb_cxl_dev_reset(DEVICE(dev));
}
-static Property pxb_cxl_dev_properties[] = {
+static const Property pxb_cxl_dev_properties[] = {
DEFINE_PROP_BOOL("hdm_for_passthrough", PXBCXLDev, hdm_for_passthrough, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data)
+static void pxb_cxl_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -515,7 +528,7 @@ static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data)
/* Host bridges aren't hotpluggable. FIXME: spec reference */
dc->hotpluggable = false;
- dc->reset = pxb_cxl_dev_reset;
+ device_class_set_legacy_reset(dc, pxb_cxl_dev_reset);
}
static const TypeInfo pxb_cxl_dev_info = {
@@ -524,7 +537,7 @@ static const TypeInfo pxb_cxl_dev_info = {
.instance_size = sizeof(PXBCXLDev),
.class_init = pxb_cxl_dev_class_init,
.interfaces =
- (InterfaceInfo[]){
+ (const InterfaceInfo[]){
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{},
},
diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c
index 7646ac2..fce292a 100644
--- a/hw/pci-bridge/pcie_pci_bridge.c
+++ b/hw/pci-bridge/pcie_pci_bridge.c
@@ -52,11 +52,10 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
goto cap_error;
}
- pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF, errp);
+ pos = pci_pm_init(d, 0, errp);
if (pos < 0) {
goto pm_error;
}
- d->exp.pm_cap = pos;
pci_set_word(d->config + pos + PCI_PM_PMC, 0x3);
pcie_cap_arifwd_init(d);
@@ -124,9 +123,8 @@ static void pcie_pci_bridge_write_config(PCIDevice *d,
shpc_cap_write_config(d, address, val, len);
}
-static Property pcie_pci_bridge_dev_properties[] = {
+static const Property pcie_pci_bridge_dev_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_AUTO),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription pcie_pci_bridge_dev_vmstate = {
@@ -139,7 +137,7 @@ static const VMStateDescription pcie_pci_bridge_dev_vmstate = {
}
};
-static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
+static void pcie_pci_bridge_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -152,7 +150,7 @@ static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
k->config_write = pcie_pci_bridge_write_config;
dc->vmsd = &pcie_pci_bridge_dev_vmstate;
device_class_set_props(dc, pcie_pci_bridge_dev_properties);
- dc->reset = &pcie_pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pcie_pci_bridge_reset);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = pci_bridge_dev_plug_cb;
hc->unplug = pci_bridge_dev_unplug_cb;
@@ -164,7 +162,7 @@ static const TypeInfo pcie_pci_bridge_info = {
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(PCIEPCIBridge),
.class_init = pcie_pci_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ INTERFACE_PCIE_DEVICE },
{ },
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index 09a3478..22c2fdb 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -148,11 +148,10 @@ static void rp_exit(PCIDevice *d)
pci_bridge_exitfn(d);
}
-static Property rp_props[] = {
+static const Property rp_props[] = {
DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
QEMU_PCIE_SLTCAP_PCP_BITNR, true),
DEFINE_PROP_BOOL("disable-acs", PCIESlot, disable_acs, false),
- DEFINE_PROP_END_OF_LIST()
};
static void rp_instance_post_init(Object *obj)
@@ -168,7 +167,7 @@ static void rp_instance_post_init(Object *obj)
}
}
-static void rp_class_init(ObjectClass *klass, void *data)
+static void rp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -189,7 +188,7 @@ static const TypeInfo rp_info = {
.class_init = rp_class_init,
.abstract = true,
.class_size = sizeof(PCIERootPortClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/pci-bridge/simba.c b/hw/pci-bridge/simba.c
index 17aa0d7..bbae594 100644
--- a/hw/pci-bridge/simba.c
+++ b/hw/pci-bridge/simba.c
@@ -66,7 +66,7 @@ static void simba_pci_bridge_realize(PCIDevice *dev, Error **errp)
pci_bridge_update_mappings(PCI_BRIDGE(br));
}
-static void simba_pci_bridge_class_init(ObjectClass *klass, void *data)
+static void simba_pci_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -78,7 +78,7 @@ static void simba_pci_bridge_class_init(ObjectClass *klass, void *data)
k->revision = 0x11;
k->config_write = pci_bridge_write_config;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
dc->vmsd = &vmstate_pci_device;
}
@@ -87,7 +87,7 @@ static const TypeInfo simba_pci_bridge_info = {
.parent = TYPE_PCI_BRIDGE,
.class_init = simba_pci_bridge_class_init,
.instance_size = sizeof(SimbaPCIBridge),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index 907d510..dc7d1aa 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -134,10 +134,9 @@ static void xio3130_downstream_exitfn(PCIDevice *d)
pci_bridge_exitfn(d);
}
-static Property xio3130_downstream_props[] = {
+static const Property xio3130_downstream_props[] = {
DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
QEMU_PCIE_SLTCAP_PCP_BITNR, true),
- DEFINE_PROP_END_OF_LIST()
};
static const VMStateDescription vmstate_xio3130_downstream = {
@@ -154,7 +153,7 @@ static const VMStateDescription vmstate_xio3130_downstream = {
}
};
-static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
+static void xio3130_downstream_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -167,7 +166,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
k->revision = XIO3130_REVISION;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
- dc->reset = xio3130_downstream_reset;
+ device_class_set_legacy_reset(dc, xio3130_downstream_reset);
dc->vmsd = &vmstate_xio3130_downstream;
device_class_set_props(dc, xio3130_downstream_props);
}
@@ -176,7 +175,7 @@ static const TypeInfo xio3130_downstream_info = {
.name = TYPE_XIO3130_DOWNSTREAM,
.parent = TYPE_PCIE_SLOT,
.class_init = xio3130_downstream_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index 2a6cff6..40057b7 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -123,7 +123,7 @@ static const VMStateDescription vmstate_xio3130_upstream = {
}
};
-static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
+static void xio3130_upstream_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -136,7 +136,7 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
k->revision = XIO3130_REVISION;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
- dc->reset = xio3130_upstream_reset;
+ device_class_set_legacy_reset(dc, xio3130_upstream_reset);
dc->vmsd = &vmstate_xio3130_upstream;
}
@@ -144,7 +144,7 @@ static const TypeInfo xio3130_upstream_info = {
.name = "x3130-upstream",
.parent = TYPE_PCIE_PORT,
.class_init = xio3130_upstream_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index c91880b..35c0415 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -99,6 +99,9 @@ config ASTRO
bool
select PCI
+config PCI_EXPRESS_FSL_IMX8M_PHY
+ bool
+
config GT64120
bool
select PCI
diff --git a/hw/pci-host/articia.c b/hw/pci-host/articia.c
index f3fcc49..cc65aac 100644
--- a/hw/pci-host/articia.c
+++ b/hw/pci-host/articia.c
@@ -195,7 +195,7 @@ static void articia_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq));
}
-static void articia_class_init(ObjectClass *klass, void *data)
+static void articia_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -228,7 +228,7 @@ static void articia_pci_host_cfg_write(PCIDevice *d, uint32_t addr,
}
}
-static void articia_pci_host_class_init(ObjectClass *klass, void *data)
+static void articia_pci_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -246,7 +246,7 @@ static void articia_pci_host_class_init(ObjectClass *klass, void *data)
/* TYPE_ARTICIA_PCI_BRIDGE */
-static void articia_pci_bridge_class_init(ObjectClass *klass, void *data)
+static void articia_pci_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -273,7 +273,7 @@ static const TypeInfo articia_types[] = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(ArticiaHostState),
.class_init = articia_pci_host_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -283,7 +283,7 @@ static const TypeInfo articia_types[] = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = articia_pci_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c
index e3e589c..859e308 100644
--- a/hw/pci-host/astro.c
+++ b/hw/pci-host/astro.c
@@ -35,6 +35,7 @@
#include "target/hppa/cpu.h"
#include "trace.h"
#include "qom/object.h"
+#include "exec/target_page.h"
/*
* Helper functions
@@ -461,10 +462,6 @@ static void elroy_pcihost_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), elroy_set_irq, ELROY_IRQS);
}
-static Property elroy_pcihost_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
static const VMStateDescription vmstate_elroy = {
.name = "Elroy",
.version_id = 1,
@@ -485,12 +482,11 @@ static const VMStateDescription vmstate_elroy = {
}
};
-static void elroy_pcihost_class_init(ObjectClass *klass, void *data)
+static void elroy_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = elroy_reset;
- device_class_set_props(dc, elroy_pcihost_properties);
+ device_class_set_legacy_reset(dc, elroy_reset);
dc->vmsd = &vmstate_elroy;
dc->user_creatable = false;
}
@@ -526,6 +522,53 @@ static ElroyState *elroy_init(int num)
* Astro Runway chip.
*/
+static void adjust_LMMIO_DIRECT_mapping(AstroState *s, unsigned int reg_index)
+{
+ MemoryRegion *lmmio_alias;
+ unsigned int lmmio_index, map_route;
+ hwaddr map_addr;
+ uint32_t map_size;
+ struct ElroyState *elroy;
+
+ /* pointer to LMMIO_DIRECT entry */
+ lmmio_index = reg_index / 3;
+ lmmio_alias = &s->lmmio_direct[lmmio_index];
+
+ map_addr = s->ioc_ranges[3 * lmmio_index + 0];
+ map_size = s->ioc_ranges[3 * lmmio_index + 1];
+ map_route = s->ioc_ranges[3 * lmmio_index + 2];
+
+ /* find elroy to which this address is routed */
+ map_route &= (ELROY_NUM - 1);
+ elroy = s->elroy[map_route];
+
+ if (lmmio_alias->enabled) {
+ memory_region_set_enabled(lmmio_alias, false);
+ }
+
+ map_addr = F_EXTEND(map_addr);
+ map_addr &= TARGET_PAGE_MASK;
+ map_size = (~map_size) + 1;
+ map_size &= TARGET_PAGE_MASK;
+
+ /* exit if disabled or zero map size */
+ if (!(map_addr & 1) || !map_size) {
+ return;
+ }
+
+ if (!memory_region_size(lmmio_alias)) {
+ memory_region_init_alias(lmmio_alias, OBJECT(elroy),
+ "pci-lmmmio-alias", &elroy->pci_mmio,
+ (uint32_t) map_addr, map_size);
+ memory_region_add_subregion(get_system_memory(), map_addr,
+ lmmio_alias);
+ } else {
+ memory_region_set_alias_offset(lmmio_alias, map_addr);
+ memory_region_set_size(lmmio_alias, map_size);
+ memory_region_set_enabled(lmmio_alias, true);
+ }
+}
+
static MemTxResult astro_chip_read_with_attrs(void *opaque, hwaddr addr,
uint64_t *data, unsigned size,
MemTxAttrs attrs)
@@ -633,6 +676,11 @@ static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr,
break;
case 0x0300 ... 0x03d8 - 1: /* LMMIO_DIRECT0_BASE... */
put_val_in_arrary(s->ioc_ranges, 0x300, addr, size, val);
+ unsigned int index = (addr - 0x300) / 8;
+ /* check if one of the 4 LMMIO_DIRECT regs, each using 3 entries. */
+ if (index < LMMIO_DIRECT_RANGES * 3) {
+ adjust_LMMIO_DIRECT_mapping(s, index);
+ }
break;
case 0x10200:
case 0x10220:
@@ -861,11 +909,11 @@ static void astro_realize(DeviceState *obj, Error **errp)
}
}
-static void astro_class_init(ObjectClass *klass, void *data)
+static void astro_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = astro_reset;
+ device_class_set_legacy_reset(dc, astro_reset);
dc->vmsd = &vmstate_astro;
dc->realize = astro_realize;
/*
@@ -884,7 +932,7 @@ static const TypeInfo astro_chip_info = {
};
static void astro_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c
index 1516d00..7d6251a 100644
--- a/hw/pci-host/bonito.c
+++ b/hw/pci-host/bonito.c
@@ -48,7 +48,7 @@
#include "hw/pci-host/bonito.h"
#include "hw/pci/pci_host.h"
#include "migration/vmstate.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/misc/unimp.h"
#include "hw/registerfields.h"
#include "qom/object.h"
@@ -757,7 +757,7 @@ PCIBus *bonito_init(qemu_irq *pic)
return phb->bus;
}
-static void bonito_pci_class_init(ObjectClass *klass, void *data)
+static void bonito_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -783,13 +783,13 @@ static const TypeInfo bonito_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBonitoState),
.class_init = bonito_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void bonito_host_class_init(ObjectClass *klass, void *data)
+static void bonito_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
index c25d50f..f6e49ce 100644
--- a/hw/pci-host/designware.c
+++ b/hw/pci-host/designware.c
@@ -20,8 +20,8 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu/module.h"
#include "qemu/log.h"
+#include "qemu/bitops.h"
#include "hw/pci/msi.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
@@ -55,7 +55,17 @@
#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
-#define DESIGNWARE_PCIE_IRQ_MSI 3
+static void designware_pcie_root_bus_class_init(ObjectClass *klass,
+ const void *data)
+{
+ BusClass *k = BUS_CLASS(klass);
+
+ /*
+ * Designware has only a single root complex. Enforce the limit on the
+ * parent bus
+ */
+ k->max_dev = 1;
+}
static DesignwarePCIEHost *
designware_pcie_root_to_host(DesignwarePCIERoot *root)
@@ -90,7 +100,7 @@ static void designware_pcie_root_msi_write(void *opaque, hwaddr addr,
root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
- qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
+ qemu_set_irq(host->pci.msi, 1);
}
}
@@ -153,11 +163,9 @@ designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len)
break;
case DESIGNWARE_PCIE_MSI_ADDR_LO:
- val = root->msi.base;
- break;
-
case DESIGNWARE_PCIE_MSI_ADDR_HI:
- val = root->msi.base >> 32;
+ val = extract64(root->msi.base,
+ address == DESIGNWARE_PCIE_MSI_ADDR_LO ? 0 : 32, 32);
break;
case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
@@ -181,19 +189,16 @@ designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len)
break;
case DESIGNWARE_PCIE_ATU_LOWER_BASE:
- val = viewport->base;
- break;
-
case DESIGNWARE_PCIE_ATU_UPPER_BASE:
- val = viewport->base >> 32;
+ val = extract64(viewport->base,
+ address == DESIGNWARE_PCIE_ATU_LOWER_BASE ? 0 : 32, 32);
break;
case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
- val = viewport->target;
- break;
-
case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
- val = viewport->target >> 32;
+ val = extract64(viewport->target,
+ address == DESIGNWARE_PCIE_ATU_LOWER_TARGET ? 0 : 32,
+ 32);
break;
case DESIGNWARE_PCIE_ATU_LIMIT:
@@ -312,14 +317,10 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
break;
case DESIGNWARE_PCIE_MSI_ADDR_LO:
- root->msi.base &= 0xFFFFFFFF00000000ULL;
- root->msi.base |= val;
- designware_pcie_root_update_msi_mapping(root);
- break;
-
case DESIGNWARE_PCIE_MSI_ADDR_HI:
- root->msi.base &= 0x00000000FFFFFFFFULL;
- root->msi.base |= (uint64_t)val << 32;
+ root->msi.base = deposit64(root->msi.base,
+ address == DESIGNWARE_PCIE_MSI_ADDR_LO
+ ? 0 : 32, 32, val);
designware_pcie_root_update_msi_mapping(root);
break;
@@ -335,7 +336,7 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
root->msi.intr[0].status ^= val;
if (!root->msi.intr[0].status) {
- qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
+ qemu_set_irq(host->pci.msi, 0);
}
break;
@@ -346,23 +347,17 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
break;
case DESIGNWARE_PCIE_ATU_LOWER_BASE:
- viewport->base &= 0xFFFFFFFF00000000ULL;
- viewport->base |= val;
- break;
-
case DESIGNWARE_PCIE_ATU_UPPER_BASE:
- viewport->base &= 0x00000000FFFFFFFFULL;
- viewport->base |= (uint64_t)val << 32;
+ viewport->base = deposit64(viewport->base,
+ address == DESIGNWARE_PCIE_ATU_LOWER_BASE
+ ? 0 : 32, 32, val);
break;
case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
- viewport->target &= 0xFFFFFFFF00000000ULL;
- viewport->target |= val;
- break;
-
case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
- viewport->target &= 0x00000000FFFFFFFFULL;
- viewport->target |= val;
+ viewport->target = deposit64(viewport->target,
+ address == DESIGNWARE_PCIE_ATU_LOWER_TARGET
+ ? 0 : 32, 32, val);
break;
case DESIGNWARE_PCIE_ATU_LIMIT:
@@ -395,6 +390,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
{
DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(dev);
DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
+ MemoryRegion *host_mem = get_system_memory();
MemoryRegion *address_space = &host->pci.memory;
PCIBridge *br = PCI_BRIDGE(dev);
DesignwarePCIEViewport *viewport;
@@ -435,7 +431,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM;
source = &host->pci.address_space_root;
- destination = get_system_memory();
+ destination = host_mem;
direction = "Inbound";
/*
@@ -460,7 +456,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
destination = &host->pci.memory;
direction = "Outbound";
- source = get_system_memory();
+ source = host_mem;
/*
* Configure MemoryRegion implementing CPU -> PCI memory
@@ -591,7 +587,8 @@ static const VMStateDescription vmstate_designware_pcie_root = {
}
};
-static void designware_pcie_root_class_init(ObjectClass *klass, void *data)
+static void designware_pcie_root_class_init(ObjectClass *klass,
+ const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -607,7 +604,7 @@ static void designware_pcie_root_class_init(ObjectClass *klass, void *data)
k->config_read = designware_pcie_root_config_read;
k->config_write = designware_pcie_root_config_write;
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
/*
* PCI-facing part of the host bridge, not usable without the
* host-facing part, which can't be device_add'ed, yet.
@@ -679,6 +676,7 @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
for (i = 0; i < ARRAY_SIZE(s->pci.irqs); i++) {
sysbus_init_irq(sbd, &s->pci.irqs[i]);
}
+ sysbus_init_irq(sbd, &s->pci.msi);
memory_region_init_io(&s->mmio,
OBJECT(s),
@@ -699,7 +697,7 @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
&s->pci.memory,
&s->pci.io,
0, 4,
- TYPE_PCIE_BUS);
+ TYPE_DESIGNWARE_PCIE_ROOT_BUS);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
memory_region_init(&s->pci.address_space_root,
@@ -730,7 +728,8 @@ static const VMStateDescription vmstate_designware_pcie_host = {
}
};
-static void designware_pcie_host_class_init(ObjectClass *klass, void *data)
+static void designware_pcie_host_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
@@ -752,28 +751,28 @@ static void designware_pcie_host_init(Object *obj)
qdev_prop_set_bit(DEVICE(root), "multifunction", false);
}
-static const TypeInfo designware_pcie_root_info = {
- .name = TYPE_DESIGNWARE_PCIE_ROOT,
- .parent = TYPE_PCI_BRIDGE,
- .instance_size = sizeof(DesignwarePCIERoot),
- .class_init = designware_pcie_root_class_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { }
+static const TypeInfo designware_pcie_types[] = {
+ {
+ .name = TYPE_DESIGNWARE_PCIE_ROOT_BUS,
+ .parent = TYPE_PCIE_BUS,
+ .instance_size = sizeof(DesignwarePCIERootBus),
+ .class_init = designware_pcie_root_bus_class_init,
+ }, {
+ .name = TYPE_DESIGNWARE_PCIE_HOST,
+ .parent = TYPE_PCI_HOST_BRIDGE,
+ .instance_size = sizeof(DesignwarePCIEHost),
+ .instance_init = designware_pcie_host_init,
+ .class_init = designware_pcie_host_class_init,
+ }, {
+ .name = TYPE_DESIGNWARE_PCIE_ROOT,
+ .parent = TYPE_PCI_BRIDGE,
+ .instance_size = sizeof(DesignwarePCIERoot),
+ .class_init = designware_pcie_root_class_init,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { }
+ },
},
};
-static const TypeInfo designware_pcie_host_info = {
- .name = TYPE_DESIGNWARE_PCIE_HOST,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(DesignwarePCIEHost),
- .instance_init = designware_pcie_host_init,
- .class_init = designware_pcie_host_class_init,
-};
-
-static void designware_pcie_register(void)
-{
- type_register_static(&designware_pcie_root_info);
- type_register_static(&designware_pcie_host_info);
-}
-type_init(designware_pcie_register)
+DEFINE_TYPES(designware_pcie_types)
diff --git a/hw/pci-host/dino.c b/hw/pci-host/dino.c
index d992c4b..11b353b 100644
--- a/hw/pci-host/dino.c
+++ b/hw/pci-host/dino.c
@@ -492,17 +492,16 @@ static void dino_pcihost_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), dino_set_irq, DINO_IRQS);
}
-static Property dino_pcihost_properties[] = {
+static const Property dino_pcihost_properties[] = {
DEFINE_PROP_LINK("memory-as", DinoState, memory_as, TYPE_MEMORY_REGION,
MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void dino_pcihost_class_init(ObjectClass *klass, void *data)
+static void dino_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = dino_pcihost_reset;
+ device_class_set_legacy_reset(dc, dino_pcihost_reset);
dc->realize = dino_pcihost_realize;
dc->unrealize = dino_pcihost_unrealize;
device_class_set_props(dc, dino_pcihost_properties);
diff --git a/hw/pci-host/fsl_imx8m_phy.c b/hw/pci-host/fsl_imx8m_phy.c
new file mode 100644
index 0000000..04da3f9
--- /dev/null
+++ b/hw/pci-host/fsl_imx8m_phy.c
@@ -0,0 +1,98 @@
+/*
+ * i.MX8 PCIe PHY emulation
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci-host/fsl_imx8m_phy.h"
+#include "hw/resettable.h"
+#include "migration/vmstate.h"
+
+#define CMN_REG075 0x1d4
+#define ANA_PLL_LOCK_DONE BIT(1)
+#define ANA_PLL_AFC_DONE BIT(0)
+
+static uint64_t fsl_imx8m_pcie_phy_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ FslImx8mPciePhyState *s = opaque;
+
+ if (offset == CMN_REG075) {
+ return s->data[offset] | ANA_PLL_LOCK_DONE | ANA_PLL_AFC_DONE;
+ }
+
+ return s->data[offset];
+}
+
+static void fsl_imx8m_pcie_phy_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ FslImx8mPciePhyState *s = opaque;
+
+ s->data[offset] = value;
+}
+
+static const MemoryRegionOps fsl_imx8m_pcie_phy_ops = {
+ .read = fsl_imx8m_pcie_phy_read,
+ .write = fsl_imx8m_pcie_phy_write,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void fsl_imx8m_pcie_phy_realize(DeviceState *dev, Error **errp)
+{
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &fsl_imx8m_pcie_phy_ops, s,
+ TYPE_FSL_IMX8M_PCIE_PHY, ARRAY_SIZE(s->data));
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+}
+
+static void fsl_imx8m_pcie_phy_reset_hold(Object *obj, ResetType type)
+{
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(obj);
+
+ memset(s->data, 0, sizeof(s->data));
+}
+
+static const VMStateDescription fsl_imx8m_pcie_phy_vmstate = {
+ .name = "fsl-imx8m-pcie-phy",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(data, FslImx8mPciePhyState,
+ FSL_IMX8M_PCIE_PHY_DATA_SIZE),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void fsl_imx8m_pcie_phy_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = fsl_imx8m_pcie_phy_realize;
+ dc->vmsd = &fsl_imx8m_pcie_phy_vmstate;
+ rc->phases.hold = fsl_imx8m_pcie_phy_reset_hold;
+}
+
+static const TypeInfo fsl_imx8m_pcie_phy_types[] = {
+ {
+ .name = TYPE_FSL_IMX8M_PCIE_PHY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FslImx8mPciePhyState),
+ .class_init = fsl_imx8m_pcie_phy_class_init,
+ }
+};
+
+DEFINE_TYPES(fsl_imx8m_pcie_phy_types)
diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c
index 391fabb..0aba47c 100644
--- a/hw/pci-host/gpex-acpi.c
+++ b/hw/pci-host/gpex-acpi.c
@@ -141,6 +141,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
QLIST_FOREACH(bus, &bus->child, sibling) {
uint8_t bus_num = pci_bus_num(bus);
uint8_t numa_node = pci_bus_numa_node(bus);
+ uint32_t uid;
bool is_cxl = pci_bus_is_cxl(bus);
if (!pci_bus_is_root(bus)) {
@@ -156,6 +157,8 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
nr_pcie_buses = bus_num;
}
+ uid = object_property_get_uint(OBJECT(bus), "acpi_uid",
+ &error_fatal);
dev = aml_device("PC%.02X", bus_num);
if (is_cxl) {
struct Aml *pkg = aml_package(2);
@@ -168,7 +171,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03")));
}
aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
- aml_append(dev, aml_name_decl("_UID", aml_int(bus_num)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
aml_append(dev, aml_name_decl("_STR", aml_unicode("pxb Device")));
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
if (numa_node != NUMA_NODE_UNASSIGNED) {
@@ -179,7 +182,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
/*
* Resources defined for PXBs are composed of the following parts:
- * 1. The resources the pci-brige/pcie-root-port need.
+ * 1. The resources the pci-bridge/pcie-root-port need.
* 2. The resources the devices behind pxb need.
*/
crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), &crs_range_set,
diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
index e9cf455..b806a22 100644
--- a/hw/pci-host/gpex.c
+++ b/hw/pci-host/gpex.c
@@ -32,6 +32,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/irq.h"
+#include "hw/pci/pci_bus.h"
#include "hw/pci-host/gpex.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -41,20 +42,25 @@
* GPEX host
*/
+struct GPEXIrq {
+ qemu_irq irq;
+ int irq_num;
+};
+
static void gpex_set_irq(void *opaque, int irq_num, int level)
{
GPEXHost *s = opaque;
- qemu_set_irq(s->irq[irq_num], level);
+ qemu_set_irq(s->irq[irq_num].irq, level);
}
int gpex_set_irq_num(GPEXHost *s, int index, int gsi)
{
- if (index >= GPEX_NUM_IRQS) {
+ if (index >= s->num_irqs) {
return -EINVAL;
}
- s->irq_num[index] = gsi;
+ s->irq[index].irq_num = gsi;
return 0;
}
@@ -62,7 +68,7 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin)
{
PCIINTxRoute route;
GPEXHost *s = opaque;
- int gsi = s->irq_num[pin];
+ int gsi = s->irq[pin].irq_num;
route.irq = gsi;
if (gsi < 0) {
@@ -74,6 +80,13 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin)
return route;
}
+static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
+{
+ PCIBus *bus = pci_device_root_bus(pci_dev);
+
+ return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq;
+}
+
static void gpex_host_realize(DeviceState *dev, Error **errp)
{
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
@@ -82,6 +95,8 @@ static void gpex_host_realize(DeviceState *dev, Error **errp)
PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
int i;
+ s->irq = g_malloc0_n(s->num_irqs, sizeof(*s->irq));
+
pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
sysbus_init_mmio(sbd, &pex->mmio);
@@ -128,26 +143,34 @@ static void gpex_host_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->io_ioport);
}
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
- sysbus_init_irq(sbd, &s->irq[i]);
- s->irq_num[i] = -1;
+ for (i = 0; i < s->num_irqs; i++) {
+ sysbus_init_irq(sbd, &s->irq[i].irq);
+ s->irq[i].irq_num = -1;
}
pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq,
- pci_swizzle_map_irq_fn, s, &s->io_mmio,
- &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
+ gpex_swizzle_map_irq_fn,
+ s, &s->io_mmio, &s->io_ioport, 0,
+ s->num_irqs, TYPE_PCIE_BUS);
pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq);
qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal);
}
+static void gpex_host_unrealize(DeviceState *dev)
+{
+ GPEXHost *s = GPEX_HOST(dev);
+
+ g_free(s->irq);
+}
+
static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
return "0000:00";
}
-static Property gpex_host_properties[] = {
+static const Property gpex_host_properties[] = {
/*
* Permit CPU accesses to unmapped areas of the PIO and MMIO windows
* (discarding writes and returning -1 for reads) rather than aborting.
@@ -166,16 +189,17 @@ static Property gpex_host_properties[] = {
gpex_cfg.mmio64.base, 0),
DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost,
gpex_cfg.mmio64.size, 0),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_UINT8("num-irqs", GPEXHost, num_irqs, PCI_NUM_PINS),
};
-static void gpex_host_class_init(ObjectClass *klass, void *data)
+static void gpex_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
hc->root_bus_path = gpex_host_root_bus_path;
dc->realize = gpex_host_realize;
+ dc->unrealize = gpex_host_unrealize;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "pci";
device_class_set_props(dc, gpex_host_properties);
@@ -213,7 +237,7 @@ static const VMStateDescription vmstate_gpex_root = {
}
};
-static void gpex_root_class_init(ObjectClass *klass, void *data)
+static void gpex_root_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -237,7 +261,7 @@ static const TypeInfo gpex_root_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(GPEXRootState),
.class_init = gpex_root_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c
index 8e589ff..f9da5a9 100644
--- a/hw/pci-host/grackle.c
+++ b/hw/pci-host/grackle.c
@@ -94,7 +94,7 @@ static void grackle_pci_realize(PCIDevice *d, Error **errp)
d->config[PCI_CLASS_PROG] = 0x01;
}
-static void grackle_pci_class_init(ObjectClass *klass, void *data)
+static void grackle_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -116,7 +116,7 @@ static const TypeInfo grackle_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = grackle_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -129,12 +129,11 @@ static char *grackle_ofw_unit_address(const SysBusDevice *dev)
return g_strdup_printf("%x", s->ofw_addr);
}
-static Property grackle_properties[] = {
+static const Property grackle_properties[] = {
DEFINE_PROP_UINT32("ofw-addr", GrackleState, ofw_addr, -1),
- DEFINE_PROP_END_OF_LIST()
};
-static void grackle_class_init(ObjectClass *klass, void *data)
+static void grackle_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c
index 33607df..b12a256 100644
--- a/hw/pci-host/gt64120.c
+++ b/hw/pci-host/gt64120.c
@@ -320,38 +320,6 @@ static void gt64120_isd_mapping(GT64120State *s)
memory_region_transaction_commit();
}
-static void gt64120_update_pci_cfgdata_mapping(GT64120State *s)
-{
- /* Indexed on MByteSwap bit, see Table 158: PCI_0 Command, Offset: 0xc00 */
- static const MemoryRegionOps *pci_host_data_ops[] = {
- &pci_host_data_be_ops, &pci_host_data_le_ops
- };
- PCIHostState *phb = PCI_HOST_BRIDGE(s);
-
- memory_region_transaction_begin();
-
- /*
- * The setting of the MByteSwap bit and MWordSwap bit in the PCI Internal
- * Command Register determines how data transactions from the CPU to/from
- * PCI are handled along with the setting of the Endianness bit in the CPU
- * Configuration Register. See:
- * - Table 16: 32-bit PCI Transaction Endianness
- * - Table 158: PCI_0 Command, Offset: 0xc00
- */
-
- if (memory_region_is_mapped(&phb->data_mem)) {
- memory_region_del_subregion(&s->ISD_mem, &phb->data_mem);
- object_unparent(OBJECT(&phb->data_mem));
- }
- memory_region_init_io(&phb->data_mem, OBJECT(phb),
- pci_host_data_ops[s->regs[GT_PCI0_CMD] & 1],
- s, "pci-conf-data", 4);
- memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
- &phb->data_mem, 1);
-
- memory_region_transaction_commit();
-}
-
static void gt64120_pci_mapping(GT64120State *s)
{
memory_region_transaction_begin();
@@ -645,7 +613,6 @@ static void gt64120_writel(void *opaque, hwaddr addr,
case GT_PCI0_CMD:
case GT_PCI1_CMD:
s->regs[saddr] = val & 0x0401fc0f;
- gt64120_update_pci_cfgdata_mapping(s);
break;
case GT_PCI0_TOR:
case GT_PCI0_BS_SCS10:
@@ -689,7 +656,6 @@ static void gt64120_writel(void *opaque, hwaddr addr,
case GT_PCI0_CFGDATA:
/* Mapped via in gt64120_pci_mapping() */
g_assert_not_reached();
- break;
/* Interrupts */
case GT_INTRCAUSE:
@@ -933,7 +899,6 @@ static uint64_t gt64120_readl(void *opaque,
case GT_PCI0_CFGDATA:
/* Mapped via in gt64120_pci_mapping() */
g_assert_not_reached();
- break;
case GT_PCI0_CMD:
case GT_PCI0_TOR:
@@ -1026,6 +991,48 @@ static const MemoryRegionOps isd_mem_ops = {
},
};
+static bool bswap(const GT64120State *s)
+{
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
+ /*check for bus == 0 && device == 0, Bits 11:15 = Device , Bits 16:23 = Bus*/
+ bool is_phb_dev0 = extract32(phb->config_reg, 11, 13) == 0;
+ bool le_mode = FIELD_EX32(s->regs[GT_PCI0_CMD], GT_PCI0_CMD, MByteSwap);
+ /* Only swap for non-bridge devices in big-endian mode */
+ return !le_mode && !is_phb_dev0;
+}
+
+static uint64_t gt64120_pci_data_read(void *opaque, hwaddr addr, unsigned size)
+{
+ GT64120State *s = opaque;
+ uint32_t val = pci_host_data_le_ops.read(opaque, addr, size);
+
+ if (bswap(s)) {
+ val = bswap32(val);
+ }
+ return val;
+}
+
+static void gt64120_pci_data_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ GT64120State *s = opaque;
+
+ if (bswap(s)) {
+ val = bswap32(val);
+ }
+ pci_host_data_le_ops.write(opaque, addr, val, size);
+}
+
+static const MemoryRegionOps gt64120_pci_data_ops = {
+ .read = gt64120_pci_data_read,
+ .write = gt64120_pci_data_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
static void gt64120_reset(DeviceState *dev)
{
GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev);
@@ -1180,7 +1187,6 @@ static void gt64120_reset(DeviceState *dev)
gt64120_isd_mapping(s);
gt64120_pci_mapping(s);
- gt64120_update_pci_cfgdata_mapping(s);
}
static void gt64120_realize(DeviceState *dev, Error **errp)
@@ -1204,6 +1210,12 @@ static void gt64120_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2,
&phb->conf_mem, 1);
+ memory_region_init_io(&phb->data_mem, OBJECT(phb),
+ &gt64120_pci_data_ops,
+ s, "pci-conf-data", 4);
+ memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
+ &phb->data_mem, 1);
+
/*
* The whole address space decoded by the GT-64120A doesn't generate
@@ -1246,7 +1258,7 @@ static void gt64120_pci_reset_hold(Object *obj, ResetType type)
pci_set_byte(d->config + 0x3d, 0x01);
}
-static void gt64120_pci_class_init(ObjectClass *klass, void *data)
+static void gt64120_pci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1270,26 +1282,25 @@ static const TypeInfo gt64120_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = gt64120_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static Property gt64120_properties[] = {
+static const Property gt64120_properties[] = {
DEFINE_PROP_BOOL("cpu-little-endian", GT64120State,
cpu_little_endian, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void gt64120_class_init(ObjectClass *klass, void *data)
+static void gt64120_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
device_class_set_props(dc, gt64120_properties);
dc->realize = gt64120_realize;
- dc->reset = gt64120_reset;
+ device_class_set_legacy_reset(dc, gt64120_reset);
dc->vmsd = &vmstate_gt64120;
}
diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c
index 4f0a043..e13bb1b 100644
--- a/hw/pci-host/i440fx.c
+++ b/hw/pci-host/i440fx.c
@@ -315,7 +315,7 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp)
i440fx_update_memory_mappings(f);
}
-static void i440fx_class_init(ObjectClass *klass, void *data)
+static void i440fx_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -341,7 +341,7 @@ static const TypeInfo i440fx_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCII440FXState),
.class_init = i440fx_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -353,7 +353,7 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
return "0000:00";
}
-static Property i440fx_props[] = {
+static const Property i440fx_props[] = {
DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState,
pci_hole64_size, I440FX_PCI_HOST_HOLE64_SIZE_DEFAULT),
DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MEM_SIZE, I440FXState,
@@ -362,10 +362,9 @@ static Property i440fx_props[] = {
above_4g_mem_size, 0),
DEFINE_PROP_BOOL("x-pci-hole64-fix", I440FXState, pci_hole64_fix, true),
DEFINE_PROP_STRING(I440FX_HOST_PROP_PCI_TYPE, I440FXState, pci_type),
- DEFINE_PROP_END_OF_LIST(),
};
-static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
+static void i440fx_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index 3001e93..937a0f7 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -28,6 +28,7 @@ pci_ss.add(when: 'CONFIG_ARTICIA', if_true: files('articia.c'))
pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c'))
# ARM devices
+pci_ss.add(when: 'CONFIG_PCI_EXPRESS_FSL_IMX8M_PHY', if_true: files('fsl_imx8m_phy.c'))
pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c'))
# HPPA devices
diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c
index 01bd8c8..e05b677 100644
--- a/hw/pci-host/mv64361.c
+++ b/hw/pci-host/mv64361.c
@@ -17,7 +17,7 @@
#include "hw/irq.h"
#include "hw/intc/i8259.h"
#include "hw/qdev-properties.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "trace.h"
@@ -26,7 +26,7 @@
#define TYPE_MV64361_PCI_BRIDGE "mv64361-pcibridge"
-static void mv64361_pcibridge_class_init(ObjectClass *klass, void *data)
+static void mv64361_pcibridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -46,7 +46,7 @@ static const TypeInfo mv64361_pcibridge_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = mv64361_pcibridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -95,14 +95,14 @@ static void mv64361_pcihost_realize(DeviceState *dev, Error **errp)
&s->mem, &s->io, 0, 4, TYPE_PCI_BUS);
g_free(name);
pci_create_simple(h->bus, 0, TYPE_MV64361_PCI_BRIDGE);
+ qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq));
}
-static Property mv64361_pcihost_props[] = {
+static const Property mv64361_pcihost_props[] = {
DEFINE_PROP_UINT8("index", MV64361PCIState, index, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void mv64361_pcihost_class_init(ObjectClass *klass, void *data)
+static void mv64361_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -923,12 +923,12 @@ static void mv64361_reset(DeviceState *dev)
set_mem_windows(s, 0xfbfff);
}
-static void mv64361_class_init(ObjectClass *klass, void *data)
+static void mv64361_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mv64361_realize;
- dc->reset = mv64361_reset;
+ device_class_set_legacy_reset(dc, mv64361_reset);
}
static const TypeInfo mv64361_type_info = {
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index d4c118d..4b0ced7 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -17,7 +17,7 @@
#include "hw/ppc/pnv.h"
#include "hw/qdev-properties.h"
#include "qom/object.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
/*
@@ -183,7 +183,7 @@ static const char *pnv_phb_root_bus_path(PCIHostState *host_bridge,
return phb->bus_path;
}
-static Property pnv_phb_properties[] = {
+static const Property pnv_phb_properties[] = {
DEFINE_PROP_UINT32("index", PnvPHB, phb_id, 0),
DEFINE_PROP_UINT32("chip-id", PnvPHB, chip_id, 0),
DEFINE_PROP_UINT32("version", PnvPHB, version, 0),
@@ -192,11 +192,9 @@ static Property pnv_phb_properties[] = {
DEFINE_PROP_LINK("pec", PnvPHB, pec, TYPE_PNV_PHB4_PEC,
PnvPhb4PecState *),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_phb_class_init(ObjectClass *klass, void *data)
+static void pnv_phb_class_init(ObjectClass *klass, const void *data)
{
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -302,13 +300,11 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
pci_config_set_interrupt_pin(pci->config, 0);
}
-static Property pnv_phb_root_port_properties[] = {
+static const Property pnv_phb_root_port_properties[] = {
DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0),
-
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data)
+static void pnv_phb_root_port_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index 2a74dbe..a4335f4 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -20,7 +20,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qom/object.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#define phb3_error(phb, fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "phb3[%d:%d]: " fmt "\n", \
@@ -888,7 +888,7 @@ DECLARE_INSTANCE_CHECKER(IOMMUMemoryRegion, PNV_PHB3_IOMMU_MEMORY_REGION,
TYPE_PNV_PHB3_IOMMU_MEMORY_REGION)
static void pnv_phb3_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
@@ -1090,15 +1090,14 @@ void pnv_phb3_update_regions(PnvPHB3 *phb)
pnv_phb3_check_all_m64s(phb);
}
-static Property pnv_phb3_properties[] = {
+static const Property pnv_phb3_properties[] = {
DEFINE_PROP_UINT32("index", PnvPHB3, phb_id, 0),
DEFINE_PROP_UINT32("chip-id", PnvPHB3, chip_id, 0),
DEFINE_PROP_LINK("chip", PnvPHB3, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_LINK("phb-base", PnvPHB3, phb_base, TYPE_PNV_PHB, PnvPHB *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_phb3_class_init(ObjectClass *klass, void *data)
+static void pnv_phb3_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1150,7 +1149,7 @@ static void pnv_phb3_root_bus_set_prop(Object *obj, Visitor *v,
}
}
-static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data)
+static void pnv_phb3_root_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
diff --git a/hw/pci-host/pnv_phb3_msi.c b/hw/pci-host/pnv_phb3_msi.c
index 77d673d..3a83311 100644
--- a/hw/pci-host/pnv_phb3_msi.c
+++ b/hw/pci-host/pnv_phb3_msi.c
@@ -15,7 +15,7 @@
#include "hw/pci/msi.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
static uint64_t phb3_msi_ive_addr(PnvPHB3 *phb, int srcno)
{
@@ -284,7 +284,7 @@ static void phb3_msi_instance_init(Object *obj)
ics->offset = 0;
}
-static void phb3_msi_class_init(ObjectClass *klass, void *data)
+static void phb3_msi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_CLASS(klass);
diff --git a/hw/pci-host/pnv_phb3_pbcq.c b/hw/pci-host/pnv_phb3_pbcq.c
index 82f70ef..1f7a149 100644
--- a/hw/pci-host/pnv_phb3_pbcq.c
+++ b/hw/pci-host/pnv_phb3_pbcq.c
@@ -337,7 +337,7 @@ static void phb3_pbcq_instance_init(Object *obj)
OBJ_PROP_LINK_STRONG);
}
-static void pnv_pbcq_class_init(ObjectClass *klass, void *data)
+static void pnv_pbcq_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -354,7 +354,7 @@ static const TypeInfo pnv_pbcq_type_info = {
.instance_size = sizeof(PnvPBCQState),
.instance_init = phb3_pbcq_instance_init,
.class_init = pnv_pbcq_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 9999100..77ea352 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -1362,7 +1362,7 @@ DECLARE_INSTANCE_CHECKER(IOMMUMemoryRegion, PNV_PHB4_IOMMU_MEMORY_REGION,
TYPE_PNV_PHB4_IOMMU_MEMORY_REGION)
static void pnv_phb4_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
@@ -1688,16 +1688,15 @@ static void pnv_phb4_xive_notify(XiveNotifier *xf, uint32_t srcno,
}
}
-static Property pnv_phb4_properties[] = {
+static const Property pnv_phb4_properties[] = {
DEFINE_PROP_UINT32("index", PnvPHB4, phb_id, 0),
DEFINE_PROP_UINT32("chip-id", PnvPHB4, chip_id, 0),
DEFINE_PROP_LINK("pec", PnvPHB4, pec, TYPE_PNV_PHB4_PEC,
PnvPhb4PecState *),
DEFINE_PROP_LINK("phb-base", PnvPHB4, phb_base, TYPE_PNV_PHB, PnvPHB *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_phb4_class_init(ObjectClass *klass, void *data)
+static void pnv_phb4_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
@@ -1715,7 +1714,7 @@ static const TypeInfo pnv_phb4_type_info = {
.instance_init = pnv_phb4_instance_init,
.instance_size = sizeof(PnvPHB4),
.class_init = pnv_phb4_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_NOTIFIER },
{ },
}
@@ -1762,7 +1761,7 @@ static void pnv_phb4_root_bus_set_prop(Object *obj, Visitor *v,
}
}
-static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data)
+static void pnv_phb4_root_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index ce8e228..5bac1c4 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -19,7 +19,7 @@
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_chip.h"
#include "hw/qdev-properties.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include <libfdt.h>
@@ -197,6 +197,9 @@ static PnvPHB *pnv_pec_default_phb_realize(PnvPhb4PecState *pec,
return phb;
}
+#define XPEC_P9_PCI_LANE_CFG PPC_BITMASK(10, 11)
+#define XPEC_P10_PCI_LANE_CFG PPC_BITMASK(0, 1)
+
static void pnv_pec_realize(DeviceState *dev, Error **errp)
{
PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
@@ -211,6 +214,43 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp)
pec->num_phbs = pecc->num_phbs[pec->index];
+ /* Pervasive chiplet */
+ object_initialize_child(OBJECT(pec), "nest-pervasive-common",
+ &pec->nest_pervasive,
+ TYPE_PNV_NEST_CHIPLET_PERVASIVE);
+ if (!qdev_realize(DEVICE(&pec->nest_pervasive), NULL, errp)) {
+ return;
+ }
+
+ /* Set up pervasive chiplet registers */
+ /*
+ * Most registers are not set up, this just sets the PCI CONF1 link-width
+ * field because skiboot probes it.
+ */
+ if (pecc->version == PNV_PHB4_VERSION) {
+ /*
+ * On P9, PEC2 has configurable 1/2/3-furcation).
+ * Make it trifurcated (x8, x4, x4) to match pnv_pec_num_phbs.
+ */
+ if (pec->index == 2) {
+ pec->nest_pervasive.control_regs.cplt_cfg1 =
+ SETFIELD(XPEC_P9_PCI_LANE_CFG,
+ pec->nest_pervasive.control_regs.cplt_cfg1,
+ 0b10);
+ }
+ } else if (pecc->version == PNV_PHB5_VERSION) {
+ /*
+ * On P10, both PECs are configurable 1/2/3-furcation).
+ * Both are trifurcated to match pnv_phb5_pec_num_stacks.
+ */
+ pec->nest_pervasive.control_regs.cplt_cfg1 =
+ SETFIELD(XPEC_P10_PCI_LANE_CFG,
+ pec->nest_pervasive.control_regs.cplt_cfg1,
+ 0b10);
+ } else {
+ g_assert_not_reached();
+ }
+
/* Create PHBs if running with defaults */
if (defaults_enabled()) {
g_assert(pec->num_phbs <= MAX_PHBS_PER_PEC);
@@ -283,17 +323,23 @@ static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
return 0;
}
-static Property pnv_pec_properties[] = {
+static const Property pnv_pec_properties[] = {
DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0),
DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0),
DEFINE_PROP_LINK("chip", PnvPhb4PecState, chip, TYPE_PNV_CHIP,
PnvChip *),
- DEFINE_PROP_END_OF_LIST(),
};
+#define XPEC_PCI_CPLT_OFFSET 0x1000000ULL
+
+static uint32_t pnv_pec_xscom_cplt_base(PnvPhb4PecState *pec)
+{
+ return PNV9_XSCOM_PEC_NEST_CPLT_BASE + XPEC_PCI_CPLT_OFFSET * pec->index;
+}
+
static uint32_t pnv_pec_xscom_pci_base(PnvPhb4PecState *pec)
{
- return PNV9_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
+ return PNV9_XSCOM_PEC_PCI_BASE + XPEC_PCI_CPLT_OFFSET * pec->index;
}
static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec)
@@ -308,7 +354,7 @@ static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec)
*/
static const uint32_t pnv_pec_num_phbs[] = { 1, 2, 3 };
-static void pnv_pec_class_init(ObjectClass *klass, void *data)
+static void pnv_pec_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -322,6 +368,7 @@ static void pnv_pec_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, pnv_pec_properties);
dc->user_creatable = false;
+ pecc->xscom_cplt_base = pnv_pec_xscom_cplt_base;
pecc->xscom_nest_base = pnv_pec_xscom_nest_base;
pecc->xscom_pci_base = pnv_pec_xscom_pci_base;
pecc->xscom_nest_size = PNV9_XSCOM_PEC_NEST_SIZE;
@@ -341,7 +388,7 @@ static const TypeInfo pnv_pec_type_info = {
.instance_size = sizeof(PnvPhb4PecState),
.class_init = pnv_pec_class_init,
.class_size = sizeof(PnvPhb4PecClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
@@ -350,6 +397,10 @@ static const TypeInfo pnv_pec_type_info = {
/*
* POWER10 definitions
*/
+static uint32_t pnv_phb5_pec_xscom_cplt_base(PnvPhb4PecState *pec)
+{
+ return PNV10_XSCOM_PEC_NEST_CPLT_BASE + XPEC_PCI_CPLT_OFFSET * pec->index;
+}
static uint32_t pnv_phb5_pec_xscom_pci_base(PnvPhb4PecState *pec)
{
@@ -368,12 +419,13 @@ static uint32_t pnv_phb5_pec_xscom_nest_base(PnvPhb4PecState *pec)
*/
static const uint32_t pnv_phb5_pec_num_stacks[] = { 3, 3 };
-static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data)
+static void pnv_phb5_pec_class_init(ObjectClass *klass, const void *data)
{
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
static const char compat[] = "ibm,power10-pbcq";
static const char stk_compat[] = "ibm,power10-phb-stack";
+ pecc->xscom_cplt_base = pnv_phb5_pec_xscom_cplt_base;
pecc->xscom_nest_base = pnv_phb5_pec_xscom_nest_base;
pecc->xscom_pci_base = pnv_phb5_pec_xscom_pci_base;
pecc->xscom_nest_size = PNV10_XSCOM_PEC_NEST_SIZE;
@@ -393,7 +445,7 @@ static const TypeInfo pnv_phb5_pec_type_info = {
.instance_size = sizeof(PnvPhb4PecState),
.class_init = pnv_phb5_pec_class_init,
.class_size = sizeof(PnvPhb4PecClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/pci-host/ppc440_pcix.c b/hw/pci-host/ppc440_pcix.c
index ef212d9..744b85e 100644
--- a/hw/pci-host/ppc440_pcix.c
+++ b/hw/pci-host/ppc440_pcix.c
@@ -519,12 +519,12 @@ static void ppc440_pcix_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
+static void ppc440_pcix_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ppc440_pcix_realize;
- dc->reset = ppc440_pcix_reset;
+ device_class_set_legacy_reset(dc, ppc440_pcix_reset);
}
static const TypeInfo ppc440_pcix_info = {
diff --git a/hw/pci-host/ppc4xx_pci.c b/hw/pci-host/ppc4xx_pci.c
index b6c6c89..2547817 100644
--- a/hw/pci-host/ppc4xx_pci.c
+++ b/hw/pci-host/ppc4xx_pci.c
@@ -27,7 +27,7 @@
#include "hw/pci-host/ppc4xx.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/pci/pci_device.h"
#include "hw/pci/pci_host.h"
#include "trace.h"
@@ -349,7 +349,7 @@ static void ppc4xx_pcihost_realize(DeviceState *dev, Error **errp)
qemu_register_reset(ppc4xx_pci_reset, s);
}
-static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
+static void ppc4xx_host_bridge_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -370,13 +370,13 @@ static const TypeInfo ppc4xx_host_bridge_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = ppc4xx_host_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
+static void ppc4xx_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index 95b983b..52269b0 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -16,13 +16,11 @@
#include "qemu/osdep.h"
#include "hw/irq.h"
-#include "hw/ppc/e500-ccsr.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "hw/pci/pci_device.h"
#include "hw/pci/pci_host.h"
#include "qemu/bswap.h"
-#include "qemu/module.h"
#include "hw/pci-host/ppce500.h"
#include "qom/object.h"
@@ -419,11 +417,12 @@ static const VMStateDescription vmstate_ppce500_pci = {
static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
{
PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
- PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
- "/e500-ccsr"));
+ SysBusDevice *ccsr = SYS_BUS_DEVICE(
+ object_resolve_path_component(qdev_get_machine(), "e500-ccsr"));
+ MemoryRegion *ccsr_space = sysbus_mmio_get_region(ccsr, 0);
- memory_region_init_alias(&b->bar0, OBJECT(ccsr), "e500-pci-bar0", &ccsr->ccsr_space,
- 0, int128_get64(ccsr->ccsr_space.size));
+ memory_region_init_alias(&b->bar0, OBJECT(ccsr), "e500-pci-bar0",
+ ccsr_space, 0, int128_get64(ccsr_space->size));
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
}
@@ -475,7 +474,7 @@ static void e500_pcihost_realize(DeviceState *dev, Error **errp)
address_space_init(&s->bm_as, &s->bm, "pci-bm");
pci_setup_iommu(b, &ppce500_iommu_ops, s);
- pci_create_simple(b, 0, "e500-host-bridge");
+ pci_create_simple(b, 0, TYPE_PPC_E500_PCI_BRIDGE);
memory_region_init(&s->container, OBJECT(h), "pci-container", PCIE500_ALL_SIZE);
memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_be_ops, h,
@@ -491,7 +490,7 @@ static void e500_pcihost_realize(DeviceState *dev, Error **errp)
pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq);
}
-static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
+static void e500_host_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -508,24 +507,12 @@ static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
dc->user_creatable = false;
}
-static const TypeInfo e500_host_bridge_info = {
- .name = TYPE_PPC_E500_PCI_BRIDGE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PPCE500PCIBridgeState),
- .class_init = e500_host_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- { },
- },
-};
-
-static Property pcihost_properties[] = {
+static const Property pcihost_properties[] = {
DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11),
DEFINE_PROP_UINT32("first_pin_irq", PPCE500PCIState, first_pin_irq, 0x1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void e500_pcihost_class_init(ObjectClass *klass, void *data)
+static void e500_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -535,17 +522,23 @@ static void e500_pcihost_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_ppce500_pci;
}
-static const TypeInfo e500_pcihost_info = {
- .name = TYPE_PPC_E500_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(PPCE500PCIState),
- .class_init = e500_pcihost_class_init,
+static const TypeInfo e500_pci_types[] = {
+ {
+ .name = TYPE_PPC_E500_PCI_BRIDGE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PPCE500PCIBridgeState),
+ .class_init = e500_host_bridge_class_init,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+ },
+ {
+ .name = TYPE_PPC_E500_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
+ .instance_size = sizeof(PPCE500PCIState),
+ .class_init = e500_pcihost_class_init,
+ },
};
-static void e500_pci_register_types(void)
-{
- type_register_static(&e500_pcihost_info);
- type_register_static(&e500_host_bridge_info);
-}
-
-type_init(e500_pci_register_types)
+DEFINE_TYPES(e500_pci_types)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 0b6cbae..1951ae4 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -170,7 +170,7 @@ static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v,
* properties need to be initialized manually by
* q35_host_initfn() after the object_initialize() call.
*/
-static Property q35_host_props[] = {
+static const Property q35_host_props[] = {
DEFINE_PROP_UINT64(PCIE_HOST_MCFG_BASE, Q35PCIHost, parent_obj.base_addr,
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost,
@@ -182,10 +182,9 @@ static Property q35_host_props[] = {
DEFINE_PROP_BOOL(PCI_HOST_PROP_SMM_RANGES, Q35PCIHost,
mch.has_smm_ranges, true),
DEFINE_PROP_BOOL("x-pci-hole64-fix", Q35PCIHost, pci_hole64_fix, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void q35_host_class_init(ObjectClass *klass, void *data)
+static void q35_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
@@ -662,31 +661,20 @@ static void mch_realize(PCIDevice *d, Error **errp)
OBJECT(&mch->smram));
}
-uint64_t mch_mcfg_base(void)
-{
- bool ambiguous;
- Object *o = object_resolve_path_type("", TYPE_MCH_PCI_DEVICE, &ambiguous);
- if (!o) {
- return 0;
- }
- return MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
-}
-
-static Property mch_props[] = {
+static const Property mch_props[] = {
DEFINE_PROP_UINT16("extended-tseg-mbytes", MCHPCIState, ext_tseg_mbytes,
16),
DEFINE_PROP_BOOL("smbase-smram", MCHPCIState, has_smram_at_smbase, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mch_class_init(ObjectClass *klass, void *data)
+static void mch_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
k->realize = mch_realize;
k->config_write = mch_write_config;
- dc->reset = mch_reset;
+ device_class_set_legacy_reset(dc, mch_reset);
device_class_set_props(dc, mch_props);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "Host bridge";
@@ -715,7 +703,7 @@ static const TypeInfo mch_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MCHPCIState),
.class_init = mch_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c
index a7dfddd..f8c0be5 100644
--- a/hw/pci-host/raven.c
+++ b/hw/pci-host/raven.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu/datadir.h"
#include "qemu/units.h"
#include "qemu/log.h"
#include "qapi/error.h"
@@ -35,9 +34,7 @@
#include "migration/vmstate.h"
#include "hw/intc/i8259.h"
#include "hw/irq.h"
-#include "hw/loader.h"
#include "hw/or-irq.h"
-#include "elf.h"
#include "qom/object.h"
#define TYPE_RAVEN_PCI_DEVICE "raven"
@@ -47,10 +44,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(RavenPCIState, RAVEN_PCI_DEVICE)
struct RavenPCIState {
PCIDevice dev;
-
- uint32_t elf_machine;
- char *bios_name;
- MemoryRegion bios;
};
typedef struct PRePPCIState PREPPCIState;
@@ -75,11 +68,8 @@ struct PRePPCIState {
RavenPCIState pci_dev;
int contiguous_map;
- bool is_legacy_prep;
};
-#define BIOS_SIZE (1 * MiB)
-
#define PCI_IO_BASE_ADDR 0x80000000 /* Physical address on main bus */
static inline uint32_t raven_pci_io_config(hwaddr addr)
@@ -243,22 +233,18 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
MemoryRegion *address_space_mem = get_system_memory();
int i;
- if (s->is_legacy_prep) {
- for (i = 0; i < PCI_NUM_PINS; i++) {
- sysbus_init_irq(dev, &s->pci_irqs[i]);
- }
- } else {
- /* According to PReP specification section 6.1.6 "System Interrupt
- * Assignments", all PCI interrupts are routed via IRQ 15 */
- s->or_irq = OR_IRQ(object_new(TYPE_OR_IRQ));
- object_property_set_int(OBJECT(s->or_irq), "num-lines", PCI_NUM_PINS,
- &error_fatal);
- qdev_realize(DEVICE(s->or_irq), NULL, &error_fatal);
- sysbus_init_irq(dev, &s->or_irq->out_irq);
-
- for (i = 0; i < PCI_NUM_PINS; i++) {
- s->pci_irqs[i] = qdev_get_gpio_in(DEVICE(s->or_irq), i);
- }
+ /*
+ * According to PReP specification section 6.1.6 "System Interrupt
+ * Assignments", all PCI interrupts are routed via IRQ 15
+ */
+ s->or_irq = OR_IRQ(object_new(TYPE_OR_IRQ));
+ object_property_set_int(OBJECT(s->or_irq), "num-lines", PCI_NUM_PINS,
+ &error_fatal);
+ qdev_realize(DEVICE(s->or_irq), NULL, &error_fatal);
+ sysbus_init_irq(dev, &s->or_irq->out_irq);
+
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ s->pci_irqs[i] = qdev_get_gpio_in(DEVICE(s->or_irq), i);
}
qdev_init_gpio_in(d, raven_change_gpio, 1);
@@ -338,48 +324,9 @@ static void raven_pcihost_initfn(Object *obj)
static void raven_realize(PCIDevice *d, Error **errp)
{
- RavenPCIState *s = RAVEN_PCI_DEVICE(d);
- char *filename;
- int bios_size = -1;
-
d->config[PCI_CACHE_LINE_SIZE] = 0x08;
d->config[PCI_LATENCY_TIMER] = 0x10;
d->config[PCI_CAPABILITY_LIST] = 0x00;
-
- if (!memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios",
- BIOS_SIZE, errp)) {
- return;
- }
- memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
- &s->bios);
- if (s->bios_name) {
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
- if (filename) {
- if (s->elf_machine != EM_NONE) {
- bios_size = load_elf(filename, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, 1, s->elf_machine,
- 0, 0);
- }
- if (bios_size < 0) {
- bios_size = get_image_size(filename);
- if (bios_size > 0 && bios_size <= BIOS_SIZE) {
- hwaddr bios_addr;
- bios_size = (bios_size + 0xfff) & ~0xfff;
- bios_addr = (uint32_t)(-BIOS_SIZE);
- bios_size = load_image_targphys(filename, bios_addr,
- bios_size);
- }
- }
- }
- g_free(filename);
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- memory_region_del_subregion(get_system_memory(), &s->bios);
- error_setg(errp, "Could not load bios image '%s'", s->bios_name);
- return;
- }
- }
-
- vmstate_register_ram_global(&s->bios);
}
static const VMStateDescription vmstate_raven = {
@@ -392,7 +339,7 @@ static const VMStateDescription vmstate_raven = {
},
};
-static void raven_class_init(ObjectClass *klass, void *data)
+static void raven_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -416,29 +363,18 @@ static const TypeInfo raven_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(RavenPCIState),
.class_init = raven_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static Property raven_pcihost_properties[] = {
- DEFINE_PROP_UINT32("elf-machine", PREPPCIState, pci_dev.elf_machine,
- EM_NONE),
- DEFINE_PROP_STRING("bios-name", PREPPCIState, pci_dev.bios_name),
- /* Temporary workaround until legacy prep machine is removed */
- DEFINE_PROP_BOOL("is-legacy-prep", PREPPCIState, is_legacy_prep,
- false),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void raven_pcihost_class_init(ObjectClass *klass, void *data)
+static void raven_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->realize = raven_pcihost_realizefn;
- device_class_set_props(dc, raven_pcihost_properties);
dc->fw_name = "pci";
}
diff --git a/hw/pci-host/remote.c b/hw/pci-host/remote.c
index bfb25ef..e6d2af4 100644
--- a/hw/pci-host/remote.c
+++ b/hw/pci-host/remote.c
@@ -28,7 +28,7 @@
#include "hw/pci/pcie_host.h"
#include "hw/qdev-properties.h"
#include "hw/pci-host/remote.h"
-#include "exec/memory.h"
+#include "system/memory.h"
static const char *remote_pcihost_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
@@ -46,7 +46,7 @@ static void remote_pcihost_realize(DeviceState *dev, Error **errp)
0, TYPE_PCIE_BUS);
}
-static void remote_pcihost_class_init(ObjectClass *klass, void *data)
+static void remote_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c
index d0851b4..538624c 100644
--- a/hw/pci-host/sabre.c
+++ b/hw/pci-host/sabre.c
@@ -37,7 +37,7 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "trace.h"
/*
@@ -456,7 +456,7 @@ static void sabre_pci_realize(PCIDevice *d, Error **errp)
PCI_STATUS_DEVSEL_MEDIUM);
}
-static void sabre_pci_class_init(ObjectClass *klass, void *data)
+static void sabre_pci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -477,7 +477,7 @@ static const TypeInfo sabre_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(SabrePCIState),
.class_init = sabre_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -492,19 +492,18 @@ static char *sabre_ofw_unit_address(const SysBusDevice *dev)
(uint32_t)(s->special_base & 0xffffffff));
}
-static Property sabre_properties[] = {
+static const Property sabre_properties[] = {
DEFINE_PROP_UINT64("special-base", SabreState, special_base, 0),
DEFINE_PROP_UINT64("mem-base", SabreState, mem_base, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sabre_class_init(ObjectClass *klass, void *data)
+static void sabre_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
dc->realize = sabre_realize;
- dc->reset = sabre_reset;
+ device_class_set_legacy_reset(dc, sabre_reset);
device_class_set_props(dc, sabre_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "pci";
diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c
index 4edebce..de8f6a8 100644
--- a/hw/pci-host/sh_pci.c
+++ b/hw/pci-host/sh_pci.c
@@ -153,7 +153,7 @@ static void sh_pcic_pci_realize(PCIDevice *d, Error **errp)
PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
}
-static void sh_pcic_pci_class_init(ObjectClass *klass, void *data)
+static void sh_pcic_pci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -168,7 +168,7 @@ static void sh_pcic_pci_class_init(ObjectClass *klass, void *data)
dc->user_creatable = false;
}
-static void sh_pcic_host_class_init(ObjectClass *klass, void *data)
+static void sh_pcic_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -186,7 +186,7 @@ static const TypeInfo sh_pcic_types[] = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = sh_pcic_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c
index e4c1abd..194037d 100644
--- a/hw/pci-host/uninorth.c
+++ b/hw/pci-host/uninorth.c
@@ -311,7 +311,7 @@ static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp)
d->config[PCI_CAPABILITY_LIST] = 0x00;
}
-static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
+static void unin_main_pci_host_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -333,13 +333,13 @@ static const TypeInfo unin_main_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = unin_main_pci_host_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
+static void u3_agp_pci_host_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -361,13 +361,13 @@ static const TypeInfo u3_agp_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = u3_agp_pci_host_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
+static void unin_agp_pci_host_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -389,13 +389,14 @@ static const TypeInfo unin_agp_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = unin_agp_pci_host_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
+static void unin_internal_pci_host_class_init(ObjectClass *klass,
+ const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -417,18 +418,17 @@ static const TypeInfo unin_internal_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = unin_internal_pci_host_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static Property pci_unin_main_pci_host_props[] = {
+static const Property pci_unin_main_pci_host_props[] = {
DEFINE_PROP_UINT32("ofw-addr", UNINHostState, ofw_addr, -1),
- DEFINE_PROP_END_OF_LIST()
};
-static void pci_unin_main_class_init(ObjectClass *klass, void *data)
+static void pci_unin_main_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
@@ -448,7 +448,7 @@ static const TypeInfo pci_unin_main_info = {
.class_init = pci_unin_main_class_init,
};
-static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
+static void pci_u3_agp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -464,7 +464,7 @@ static const TypeInfo pci_u3_agp_info = {
.class_init = pci_u3_agp_class_init,
};
-static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
+static void pci_unin_agp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -480,7 +480,7 @@ static const TypeInfo pci_unin_agp_info = {
.class_init = pci_unin_agp_class_init,
};
-static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
+static void pci_unin_internal_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -536,7 +536,7 @@ static void unin_init(Object *obj)
sysbus_init_mmio(sbd, &s->mem);
}
-static void unin_class_init(ObjectClass *klass, void *data)
+static void unin_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c
index 0e65deb..8ea26e3 100644
--- a/hw/pci-host/versatile.c
+++ b/hw/pci-host/versatile.c
@@ -246,7 +246,7 @@ static uint64_t pci_vpb_reg_read(void *opaque, hwaddr addr,
static const MemoryRegionOps pci_vpb_reg_ops = {
.read = pci_vpb_reg_read,
.write = pci_vpb_reg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -312,7 +312,7 @@ static uint64_t pci_vpb_config_read(void *opaque, hwaddr addr,
static const MemoryRegionOps pci_vpb_config_ops = {
.read = pci_vpb_config_read,
.write = pci_vpb_config_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
@@ -471,7 +471,7 @@ static void versatile_pci_host_realize(PCIDevice *d, Error **errp)
pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
}
-static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
+static void versatile_pci_host_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -492,24 +492,23 @@ static const TypeInfo versatile_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = versatile_pci_host_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static Property pci_vpb_properties[] = {
+static const Property pci_vpb_properties[] = {
DEFINE_PROP_UINT8("broken-irq-mapping", PCIVPBState, irq_mapping_prop,
PCI_VPB_IRQMAP_ASSUME_OK),
- DEFINE_PROP_END_OF_LIST()
};
-static void pci_vpb_class_init(ObjectClass *klass, void *data)
+static void pci_vpb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pci_vpb_realize;
- dc->reset = pci_vpb_reset;
+ device_class_set_legacy_reset(dc, pci_vpb_reset);
dc->vmsd = &pci_vpb_vmstate;
device_class_set_props(dc, pci_vpb_properties);
}
diff --git a/hw/pci-host/xen_igd_pt.c b/hw/pci-host/xen_igd_pt.c
index d094b67..5dd17ef 100644
--- a/hw/pci-host/xen_igd_pt.c
+++ b/hw/pci-host/xen_igd_pt.c
@@ -95,7 +95,8 @@ static void igd_pt_i440fx_realize(PCIDevice *pci_dev, Error **errp)
}
}
-static void igd_passthrough_i440fx_class_init(ObjectClass *klass, void *data)
+static void igd_passthrough_i440fx_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c
index c9ab705..c71492d 100644
--- a/hw/pci-host/xilinx-pcie.c
+++ b/hw/pci-host/xilinx-pcie.c
@@ -156,17 +156,16 @@ static void xilinx_pcie_host_init(Object *obj)
qdev_prop_set_bit(DEVICE(root), "multifunction", false);
}
-static Property xilinx_pcie_host_props[] = {
+static const Property xilinx_pcie_host_props[] = {
DEFINE_PROP_UINT32("bus_nr", XilinxPCIEHost, bus_nr, 0),
DEFINE_PROP_SIZE("cfg_base", XilinxPCIEHost, cfg_base, 0),
DEFINE_PROP_SIZE("cfg_size", XilinxPCIEHost, cfg_size, 32 * MiB),
DEFINE_PROP_SIZE("mmio_base", XilinxPCIEHost, mmio_base, 0),
DEFINE_PROP_SIZE("mmio_size", XilinxPCIEHost, mmio_size, 1 * MiB),
DEFINE_PROP_BOOL("link_up", XilinxPCIEHost, link_up, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xilinx_pcie_host_class_init(ObjectClass *klass, void *data)
+static void xilinx_pcie_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
@@ -287,7 +286,7 @@ static void xilinx_pcie_root_realize(PCIDevice *pci_dev, Error **errp)
}
}
-static void xilinx_pcie_root_class_init(ObjectClass *klass, void *data)
+static void xilinx_pcie_root_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -300,7 +299,7 @@ static void xilinx_pcie_root_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
k->realize = xilinx_pcie_root_realize;
k->exit = pci_bridge_exitfn;
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
k->config_read = xilinx_pcie_root_config_read;
k->config_write = xilinx_pcie_root_config_write;
/*
@@ -315,7 +314,7 @@ static const TypeInfo xilinx_pcie_root_info = {
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(XilinxPCIERoot),
.class_init = xilinx_pcie_root_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index 8104ac1..b9f5b45 100644
--- a/hw/pci/msi.c
+++ b/hw/pci/msi.c
@@ -23,7 +23,7 @@
#include "hw/xen/xen.h"
#include "qemu/range.h"
#include "qapi/error.h"
-#include "sysemu/xen.h"
+#include "system/xen.h"
#include "hw/i386/kvm/xen_evtchn.h"
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 487e498..8c7f670 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -15,11 +15,12 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci.h"
#include "hw/xen/xen.h"
-#include "sysemu/xen.h"
+#include "system/xen.h"
#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "qemu/range.h"
@@ -71,7 +72,7 @@ static uint8_t *msix_pending_byte(PCIDevice *dev, int vector)
return dev->msix_pba + vector / 8;
}
-static int msix_is_pending(PCIDevice *dev, int vector)
+int msix_is_pending(PCIDevice *dev, unsigned int vector)
{
return *msix_pending_byte(dev, vector) & msix_pending_mask(vector);
}
@@ -250,7 +251,7 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
PCIDevice *dev = opaque;
if (dev->msix_vector_poll_notifier) {
unsigned vector_start = addr * 8;
- unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr);
+ unsigned vector_end = MIN((addr + size) * 8, dev->msix_entries_nr);
dev->msix_vector_poll_notifier(dev, vector_start, vector_end);
}
@@ -260,6 +261,14 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
static void msix_pba_mmio_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
+ PCIDevice *dev = opaque;
+
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "PCI [%s:%02x:%02x.%x] attempt to write to MSI-X "
+ "PBA at 0x%" FMT_PCIBUS ", ignoring.\n",
+ pci_root_bus_path(dev), pci_dev_bus_num(dev),
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ addr);
}
static const MemoryRegionOps msix_pba_mmio_ops = {
diff --git a/hw/pci/pci-hmp-cmds.c b/hw/pci/pci-hmp-cmds.c
index b09fce9..a5f6483 100644
--- a/hw/pci/pci-hmp-cmds.c
+++ b/hw/pci/pci-hmp-cmds.c
@@ -20,7 +20,7 @@
#include "monitor/monitor.h"
#include "pci-internal.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/qapi-commands-pci.h"
#include "qemu/cutils.h"
@@ -83,15 +83,25 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar);
if (!strcmp(region->value->type, "io")) {
- monitor_printf(mon, "I/O at 0x%04" PRIx64
- " [0x%04" PRIx64 "].\n",
- addr, addr + size - 1);
+ if (addr != PCI_BAR_UNMAPPED) {
+ monitor_printf(mon, "I/O at 0x%04" PRIx64
+ " [0x%04" PRIx64 "]\n",
+ addr, addr + size - 1);
+ } else {
+ monitor_printf(mon, "I/O (not mapped)\n");
+ }
} else {
- monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
- " [0x%08" PRIx64 "].\n",
- region->value->mem_type_64 ? 64 : 32,
- region->value->prefetch ? " prefetchable" : "",
- addr, addr + size - 1);
+ if (addr != PCI_BAR_UNMAPPED) {
+ monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
+ " [0x%08" PRIx64 "]\n",
+ region->value->mem_type_64 ? 64 : 32,
+ region->value->prefetch ? " prefetchable" : "",
+ addr, addr + size - 1);
+ } else {
+ monitor_printf(mon, "%d bit%s memory (not mapped)\n",
+ region->value->mem_type_64 ? 64 : 32,
+ region->value->prefetch ? " prefetchable" : "");
+ }
}
}
diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c
index f050868..3397d0c 100644
--- a/hw/pci/pci-stub.c
+++ b/hw/pci/pci-stub.c
@@ -46,14 +46,12 @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
/* kvm-all wants this */
MSIMessage pci_get_msi_message(PCIDevice *dev, int vector)
{
- g_assert(false);
- return (MSIMessage){};
+ g_assert_not_reached();
}
uint16_t pci_requester_id(PCIDevice *dev)
{
- g_assert(false);
- return 0;
+ g_assert_not_reached();
}
/* Required by ahci.c */
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index fab86d0..c70b5ce 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -32,12 +32,13 @@
#include "hw/pci/pci_host.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
+#include "migration/cpr.h"
#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "net/net.h"
-#include "sysemu/numa.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/numa.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
@@ -46,6 +47,7 @@
#include "hw/pci/msix.h"
#include "hw/hotplug.h"
#include "hw/boards.h"
+#include "hw/nvram/fw_cfg.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "pci-internal.h"
@@ -53,13 +55,6 @@
#include "hw/xen/xen.h"
#include "hw/i386/kvm/xen_evtchn.h"
-//#define DEBUG_PCI
-#ifdef DEBUG_PCI
-# define PCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
-#else
-# define PCI_DPRINTF(format, ...) do { } while (0)
-#endif
-
bool pci_available = true;
static char *pcibus_get_dev_path(DeviceState *dev);
@@ -67,11 +62,24 @@ static char *pcibus_get_fw_dev_path(DeviceState *dev);
static void pcibus_reset_hold(Object *obj, ResetType type);
static bool pcie_has_upstream_port(PCIDevice *dev);
-static Property pci_props[] = {
+static void prop_pci_busnr_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t busnr = pci_dev_bus_num(PCI_DEVICE(obj));
+
+ visit_type_uint8(v, name, &busnr, errp);
+}
+
+static const PropertyInfo prop_pci_busnr = {
+ .type = "busnr",
+ .get = prop_pci_busnr_get,
+};
+
+static const Property pci_props[] = {
DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
DEFINE_PROP_UINT32("romsize", PCIDevice, romsize, UINT32_MAX),
- DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1),
+ DEFINE_PROP_INT32("rombar", PCIDevice, rom_bar, -1),
DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
DEFINE_PROP_BIT("x-pcie-lnksta-dllla", PCIDevice, cap_present,
@@ -85,7 +93,12 @@ static Property pci_props[] = {
QEMU_PCIE_ERR_UNC_MASK_BITNR, true),
DEFINE_PROP_BIT("x-pcie-ari-nextfn-1", PCIDevice, cap_present,
QEMU_PCIE_ARI_NEXTFN_1_BITNR, false),
- DEFINE_PROP_END_OF_LIST()
+ DEFINE_PROP_SIZE32("x-max-bounce-buffer-size", PCIDevice,
+ max_bounce_buffer_size, DEFAULT_MAX_BOUNCE_BUFFER_SIZE),
+ DEFINE_PROP_STRING("sriov-pf", PCIDevice, sriov_pf),
+ DEFINE_PROP_BIT("x-pcie-ext-tag", PCIDevice, cap_present,
+ QEMU_PCIE_EXT_TAG_BITNR, true),
+ { .name = "busnr", .info = &prop_pci_busnr },
};
static const VMStateDescription vmstate_pcibus = {
@@ -116,6 +129,12 @@ static GSequence *pci_acpi_index_list(void)
return used_acpi_index_list;
}
+static void pci_set_master(PCIDevice *d, bool enable)
+{
+ memory_region_set_enabled(&d->bus_master_enable_region, enable);
+ d->is_master = enable; /* cache the status */
+}
+
static void pci_init_bus_master(PCIDevice *pci_dev)
{
AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev);
@@ -123,7 +142,7 @@ static void pci_init_bus_master(PCIDevice *pci_dev)
memory_region_init_alias(&pci_dev->bus_master_enable_region,
OBJECT(pci_dev), "bus master",
dma_as->root, 0, memory_region_size(dma_as->root));
- memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
+ pci_set_master(pci_dev, false);
memory_region_add_subregion(&pci_dev->bus_master_container_region, 0,
&pci_dev->bus_master_enable_region);
}
@@ -198,11 +217,57 @@ static uint16_t pcibus_numa_node(PCIBus *bus)
return NUMA_NODE_UNASSIGNED;
}
-static void pci_bus_class_init(ObjectClass *klass, void *data)
+bool pci_bus_add_fw_cfg_extra_pci_roots(FWCfgState *fw_cfg,
+ PCIBus *bus,
+ Error **errp)
+{
+ Object *obj;
+
+ if (!bus) {
+ return true;
+ }
+ obj = OBJECT(bus);
+
+ return fw_cfg_add_file_from_generator(fw_cfg, obj->parent,
+ object_get_canonical_path_component(obj),
+ "etc/extra-pci-roots", errp);
+}
+
+static GByteArray *pci_bus_fw_cfg_gen_data(Object *obj, Error **errp)
+{
+ PCIBus *bus = PCI_BUS(obj);
+ GByteArray *byte_array;
+ uint64_t extra_hosts = 0;
+
+ if (!bus) {
+ return NULL;
+ }
+
+ QLIST_FOREACH(bus, &bus->child, sibling) {
+ /* look for expander root buses */
+ if (pci_bus_is_root(bus)) {
+ extra_hosts++;
+ }
+ }
+
+ if (!extra_hosts) {
+ return NULL;
+ }
+ extra_hosts = cpu_to_le64(extra_hosts);
+
+ byte_array = g_byte_array_new();
+ g_byte_array_append(byte_array,
+ (const void *)&extra_hosts, sizeof(extra_hosts));
+
+ return byte_array;
+}
+
+static void pci_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
PCIBusClass *pbc = PCI_BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
+ FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(klass);
k->print_dev = pcibus_dev_print;
k->get_dev_path = pcibus_get_dev_path;
@@ -214,6 +279,8 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
pbc->bus_num = pcibus_num;
pbc->numa_node = pcibus_numa_node;
+
+ fwgc->get_data = pci_bus_fw_cfg_gen_data;
}
static const TypeInfo pci_bus_info = {
@@ -222,6 +289,10 @@ static const TypeInfo pci_bus_info = {
.instance_size = sizeof(PCIBus),
.class_size = sizeof(PCIBusClass),
.class_init = pci_bus_class_init,
+ .interfaces = (const InterfaceInfo[]) {
+ { TYPE_FW_CFG_DATA_GENERATOR_INTERFACE },
+ { }
+ }
};
static const TypeInfo cxl_interface_info = {
@@ -239,7 +310,7 @@ static const TypeInfo conventional_pci_interface_info = {
.parent = TYPE_INTERFACE,
};
-static void pcie_bus_class_init(ObjectClass *klass, void *data)
+static void pcie_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
@@ -365,6 +436,84 @@ static void pci_msi_trigger(PCIDevice *dev, MSIMessage msg)
attrs, NULL);
}
+/*
+ * Register and track a PM capability. If wmask is also enabled for the power
+ * state field of the pmcsr register, guest writes may change the device PM
+ * state. BAR access is only enabled while the device is in the D0 state.
+ * Return the capability offset or negative error code.
+ */
+int pci_pm_init(PCIDevice *d, uint8_t offset, Error **errp)
+{
+ int cap = pci_add_capability(d, PCI_CAP_ID_PM, offset, PCI_PM_SIZEOF, errp);
+
+ if (cap < 0) {
+ return cap;
+ }
+
+ d->pm_cap = cap;
+ d->cap_present |= QEMU_PCI_CAP_PM;
+
+ return cap;
+}
+
+static uint8_t pci_pm_state(PCIDevice *d)
+{
+ uint16_t pmcsr;
+
+ if (!(d->cap_present & QEMU_PCI_CAP_PM)) {
+ return 0;
+ }
+
+ pmcsr = pci_get_word(d->config + d->pm_cap + PCI_PM_CTRL);
+
+ return pmcsr & PCI_PM_CTRL_STATE_MASK;
+}
+
+/*
+ * Update the PM capability state based on the new value stored in config
+ * space respective to the old, pre-write state provided. If the new value
+ * is rejected (unsupported or invalid transition) restore the old value.
+ * Return the resulting PM state.
+ */
+static uint8_t pci_pm_update(PCIDevice *d, uint32_t addr, int l, uint8_t old)
+{
+ uint16_t pmc;
+ uint8_t new;
+
+ if (!(d->cap_present & QEMU_PCI_CAP_PM) ||
+ !range_covers_byte(addr, l, d->pm_cap + PCI_PM_CTRL)) {
+ return old;
+ }
+
+ new = pci_pm_state(d);
+ if (new == old) {
+ return old;
+ }
+
+ pmc = pci_get_word(d->config + d->pm_cap + PCI_PM_PMC);
+
+ /*
+ * Transitions to D1 & D2 are only allowed if supported. Devices may
+ * only transition to higher D-states or to D0.
+ */
+ if ((!(pmc & PCI_PM_CAP_D1) && new == 1) ||
+ (!(pmc & PCI_PM_CAP_D2) && new == 2) ||
+ (old && new && new < old)) {
+ pci_word_test_and_clear_mask(d->config + d->pm_cap + PCI_PM_CTRL,
+ PCI_PM_CTRL_STATE_MASK);
+ pci_word_test_and_set_mask(d->config + d->pm_cap + PCI_PM_CTRL,
+ old);
+ trace_pci_pm_bad_transition(d->name, pci_dev_bus_num(d),
+ PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
+ old, new);
+ return old;
+ }
+
+ trace_pci_pm_transition(d->name, pci_dev_bus_num(d), PCI_SLOT(d->devfn),
+ PCI_FUNC(d->devfn), old, new);
+ return new;
+}
+
static void pci_reset_regions(PCIDevice *dev)
{
int r;
@@ -389,6 +538,10 @@ static void pci_reset_regions(PCIDevice *dev)
static void pci_do_device_reset(PCIDevice *dev)
{
+ if ((dev->cap_present & QEMU_PCI_SKIP_RESET_ON_CPR) && cpr_is_incoming()) {
+ return;
+ }
+
pci_device_deassert_intx(dev);
assert(dev->irq_state == 0);
@@ -404,6 +557,11 @@ static void pci_do_device_reset(PCIDevice *dev)
pci_get_word(dev->wmask + PCI_INTERRUPT_LINE) |
pci_get_word(dev->w1cmask + PCI_INTERRUPT_LINE));
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
+ /* Default PM state is D0 */
+ if (dev->cap_present & QEMU_PCI_CAP_PM) {
+ pci_word_test_and_clear_mask(dev->config + dev->pm_cap + PCI_PM_CTRL,
+ PCI_PM_CTRL_STATE_MASK);
+ }
pci_reset_regions(dev);
pci_update_mappings(dev);
@@ -657,9 +815,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size,
pci_bridge_update_mappings(PCI_BRIDGE(s));
}
- memory_region_set_enabled(&s->bus_master_enable_region,
- pci_get_word(s->config + PCI_COMMAND)
- & PCI_COMMAND_MASTER);
+ pci_set_master(s, pci_get_word(s->config + PCI_COMMAND)
+ & PCI_COMMAND_MASTER);
g_free(config);
return 0;
@@ -733,10 +890,17 @@ static bool migrate_is_not_pcie(void *opaque, int version_id)
return !pci_is_express((PCIDevice *)opaque);
}
+static int pci_post_load(void *opaque, int version_id)
+{
+ pcie_sriov_pf_post_load(opaque);
+ return 0;
+}
+
const VMStateDescription vmstate_pci_device = {
.name = "PCIDevice",
.version_id = 2,
.minimum_version_id = 1,
+ .post_load = pci_post_load,
.fields = (const VMStateField[]) {
VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice),
VMSTATE_BUFFER_UNSAFE_INFO_TEST(config, PCIDevice,
@@ -952,13 +1116,8 @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp)
dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
}
- /*
- * With SR/IOV and ARI, a device at function 0 need not be a multifunction
- * device, as it may just be a VF that ended up with function 0 in
- * the legacy PCI interpretation. Avoid failing in such cases:
- */
- if (pci_is_vf(dev) &&
- dev->exp.sriov_vf.pf->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+ /* SR/IOV is not handled here. */
+ if (pci_is_vf(dev)) {
return;
}
@@ -991,7 +1150,8 @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp)
}
/* function 0 indicates single function, so function > 0 must be NULL */
for (func = 1; func < PCI_FUNC_MAX; ++func) {
- if (bus->devices[PCI_DEVFN(slot, func)]) {
+ PCIDevice *device = bus->devices[PCI_DEVFN(slot, func)];
+ if (device && !pci_is_vf(device)) {
error_setg(errp, "PCI: %x.0 indicates single function, "
"but %x.%x is already populated.",
slot, slot, func);
@@ -1179,14 +1339,15 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev,
PCI_SLOT(devfn), PCI_FUNC(devfn), name,
bus->devices[devfn]->name, bus->devices[devfn]->qdev.id);
return NULL;
- } /*
- * Populating function 0 triggers a scan from the guest that
- * exposes other non-zero functions. Hence we need to ensure that
- * function 0 wasn't added yet.
- */
- else if (dev->hotplugged &&
- !pci_is_vf(pci_dev) &&
- pci_get_function_0(pci_dev)) {
+ }
+
+ /*
+ * Populating function 0 triggers a scan from the guest that
+ * exposes other non-zero functions. Hence we need to ensure that
+ * function 0 wasn't added yet.
+ */
+ if (dev->hotplugged && !pci_is_vf(pci_dev) &&
+ pci_get_function_0(pci_dev)) {
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" new func %s cannot be exposed to guest.",
PCI_SLOT(pci_get_function_0(pci_dev)->devfn),
@@ -1204,6 +1365,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev,
"bus master container", UINT64_MAX);
address_space_init(&pci_dev->bus_master_as,
&pci_dev->bus_master_container_region, pci_dev->name);
+ pci_dev->bus_master_as.max_bounce_buffer_size =
+ pci_dev->max_bounce_buffer_size;
if (phase_check(PHASE_MACHINE_READY)) {
pci_init_bus_master(pci_dev);
@@ -1276,6 +1439,7 @@ static void pci_qdev_unrealize(DeviceState *dev)
pci_unregister_io_regions(pci_dev);
pci_del_option_rom(pci_dev);
+ pcie_sriov_unregister_device(pci_dev);
if (pc->exit) {
pc->exit(pci_dev);
@@ -1307,7 +1471,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
pcibus_t size = memory_region_size(memory);
uint8_t hdr_type;
- assert(!pci_is_vf(pci_dev)); /* VFs must use pcie_sriov_vf_register_bar */
assert(region_num >= 0);
assert(region_num < PCI_NUM_REGIONS);
assert(is_power_of_2(size));
@@ -1318,7 +1481,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
assert(hdr_type != PCI_HEADER_TYPE_BRIDGE || region_num < 2);
r = &pci_dev->io_regions[region_num];
- r->addr = PCI_BAR_UNMAPPED;
+ assert(!r->size);
r->size = size;
r->type = type;
r->memory = memory;
@@ -1326,22 +1489,35 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
? pci_get_bus(pci_dev)->address_space_io
: pci_get_bus(pci_dev)->address_space_mem;
- wmask = ~(size - 1);
- if (region_num == PCI_ROM_SLOT) {
- /* ROM enable bit is writable */
- wmask |= PCI_ROM_ADDRESS_ENABLE;
- }
+ if (pci_is_vf(pci_dev)) {
+ PCIDevice *pf = pci_dev->exp.sriov_vf.pf;
+ assert(!pf || type == pf->exp.sriov_pf.vf_bar_type[region_num]);
- addr = pci_bar(pci_dev, region_num);
- pci_set_long(pci_dev->config + addr, type);
-
- if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
- r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- pci_set_quad(pci_dev->wmask + addr, wmask);
- pci_set_quad(pci_dev->cmask + addr, ~0ULL);
+ r->addr = pci_bar_address(pci_dev, region_num, r->type, r->size);
+ if (r->addr != PCI_BAR_UNMAPPED) {
+ memory_region_add_subregion_overlap(r->address_space,
+ r->addr, r->memory, 1);
+ }
} else {
- pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
- pci_set_long(pci_dev->cmask + addr, 0xffffffff);
+ r->addr = PCI_BAR_UNMAPPED;
+
+ wmask = ~(size - 1);
+ if (region_num == PCI_ROM_SLOT) {
+ /* ROM enable bit is writable */
+ wmask |= PCI_ROM_ADDRESS_ENABLE;
+ }
+
+ addr = pci_bar(pci_dev, region_num);
+ pci_set_long(pci_dev->config + addr, type);
+
+ if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
+ r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ pci_set_quad(pci_dev->wmask + addr, wmask);
+ pci_set_quad(pci_dev->cmask + addr, ~0ULL);
+ } else {
+ pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
+ pci_set_long(pci_dev->cmask + addr, 0xffffffff);
+ }
}
}
@@ -1430,7 +1606,11 @@ static pcibus_t pci_config_get_bar_addr(PCIDevice *d, int reg,
pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_OFFSET);
uint16_t vf_stride =
pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_STRIDE);
- uint32_t vf_num = (d->devfn - (pf->devfn + vf_offset)) / vf_stride;
+ uint32_t vf_num = d->devfn - (pf->devfn + vf_offset);
+
+ if (vf_num) {
+ vf_num /= vf_stride;
+ }
if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
new_addr = pci_get_quad(pf->config + bar);
@@ -1525,7 +1705,7 @@ static void pci_update_mappings(PCIDevice *d)
continue;
new_addr = pci_bar_address(d, i, r->type, r->size);
- if (!d->has_power) {
+ if (!d->enabled || pci_pm_state(d)) {
new_addr = PCI_BAR_UNMAPPED;
}
@@ -1555,7 +1735,7 @@ static void pci_update_mappings(PCIDevice *d)
pci_update_vga(d);
}
-static inline int pci_irq_disabled(PCIDevice *d)
+int pci_irq_disabled(PCIDevice *d)
{
return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
}
@@ -1591,6 +1771,7 @@ uint32_t pci_default_read_config(PCIDevice *d,
void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int l)
{
+ uint8_t new_pm_state, old_pm_state = pci_pm_state(d);
int i, was_irq_disabled = pci_irq_disabled(d);
uint32_t val = val_in;
@@ -1603,17 +1784,21 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int
d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
}
+
+ new_pm_state = pci_pm_update(d, addr, l, old_pm_state);
+
if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
- range_covers_byte(addr, l, PCI_COMMAND))
+ range_covers_byte(addr, l, PCI_COMMAND) ||
+ !!new_pm_state != !!old_pm_state) {
pci_update_mappings(d);
+ }
if (ranges_overlap(addr, l, PCI_COMMAND, 2)) {
pci_update_irq_disabled(d, was_irq_disabled);
- memory_region_set_enabled(&d->bus_master_enable_region,
- (pci_get_word(d->config + PCI_COMMAND)
- & PCI_COMMAND_MASTER) && d->has_power);
+ pci_set_master(d, (pci_get_word(d->config + PCI_COMMAND) &
+ PCI_COMMAND_MASTER) && d->enabled);
}
msi_write_config(d, addr, val_in, l);
@@ -2098,6 +2283,11 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
}
}
+ if (!pcie_sriov_register_device(pci_dev, errp)) {
+ pci_qdev_unrealize(DEVICE(pci_dev));
+ return;
+ }
+
/*
* A PCIe Downstream Port that do not have ARI Forwarding enabled must
* associate only Device 0 with the device attached to the bus
@@ -2269,12 +2459,12 @@ static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, uint32_t size)
/* Only a valid rom will be patched. */
rom_magic = pci_get_word(ptr);
if (rom_magic != 0xaa55) {
- PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic);
+ trace_pci_bad_rom_magic(rom_magic, 0xaa55);
return;
}
pcir_offset = pci_get_word(ptr + 0x18);
if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) {
- PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset);
+ trace_pci_bad_pcir_offset(pcir_offset);
return;
}
@@ -2283,8 +2473,8 @@ static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, uint32_t size)
rom_vendor_id = pci_get_word(ptr + pcir_offset + 4);
rom_device_id = pci_get_word(ptr + pcir_offset + 6);
- PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile,
- vendor_id, device_id, rom_vendor_id, rom_device_id);
+ trace_pci_rom_and_pci_ids(pdev->romfile, vendor_id, device_id,
+ rom_vendor_id, rom_device_id);
checksum = ptr[6];
@@ -2292,7 +2482,7 @@ static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, uint32_t size)
/* Patch vendor id and checksum (at offset 6 for etherboot roms). */
checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8);
checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8);
- PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
+ trace_pci_rom_checksum_change(ptr[6], checksum);
ptr[6] = checksum;
pci_set_word(ptr + pcir_offset + 4, vendor_id);
}
@@ -2301,7 +2491,7 @@ static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, uint32_t size)
/* Patch device id and checksum (at offset 6 for etherboot roms). */
checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8);
checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8);
- PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
+ trace_pci_rom_checksum_change(ptr[6], checksum);
ptr[6] = checksum;
pci_set_word(ptr + pcir_offset + 6, device_id);
}
@@ -2352,6 +2542,14 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
return;
}
+ if (pci_is_vf(pdev)) {
+ if (pdev->rom_bar > 0) {
+ error_setg(errp, "ROM BAR cannot be enabled for SR-IOV VF");
+ }
+
+ return;
+ }
+
if (load_file || pdev->romsize == UINT32_MAX) {
path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
if (path == NULL) {
@@ -2625,7 +2823,7 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev)
return pci_get_bus(dev)->address_space_io;
}
-static void pci_device_class_init(ObjectClass *klass, void *data)
+static void pci_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
@@ -2633,9 +2831,13 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
k->unrealize = pci_qdev_unrealize;
k->bus_type = TYPE_PCI_BUS;
device_class_set_props(k, pci_props);
+ object_class_property_set_description(
+ klass, "x-max-bounce-buffer-size",
+ "Maximum buffer size allocated for bounce buffers used for mapped "
+ "access to indirect DMA memory");
}
-static void pci_device_class_base_init(ObjectClass *klass, void *data)
+static void pci_device_class_base_init(ObjectClass *klass, const void *data)
{
if (!object_class_is_abstract(klass)) {
ObjectClass *conventional =
@@ -2742,6 +2944,23 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
return &address_space_memory;
}
+int pci_iommu_init_iotlb_notifier(PCIDevice *dev, IOMMUNotifier *n,
+ IOMMUNotify fn, void *opaque)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->init_iotlb_notifier) {
+ iommu_bus->iommu_ops->init_iotlb_notifier(bus, iommu_bus->iommu_opaque,
+ devfn, n, fn, opaque);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
bool pci_device_set_iommu_device(PCIDevice *dev, HostIOMMUDevice *hiod,
Error **errp)
{
@@ -2773,6 +2992,170 @@ void pci_device_unset_iommu_device(PCIDevice *dev)
}
}
+int pci_pri_request_page(PCIDevice *dev, uint32_t pasid, bool priv_req,
+ bool exec_req, hwaddr addr, bool lpig,
+ uint16_t prgi, bool is_read, bool is_write)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ if (!dev->is_master ||
+ ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) {
+ return -EPERM;
+ }
+
+ if (!pcie_pri_enabled(dev)) {
+ return -EPERM;
+ }
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->pri_request_page) {
+ return iommu_bus->iommu_ops->pri_request_page(bus,
+ iommu_bus->iommu_opaque,
+ devfn, pasid, priv_req,
+ exec_req, addr, lpig, prgi,
+ is_read, is_write);
+ }
+
+ return -ENODEV;
+}
+
+int pci_pri_register_notifier(PCIDevice *dev, uint32_t pasid,
+ IOMMUPRINotifier *notifier)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ if (!dev->is_master ||
+ ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) {
+ return -EPERM;
+ }
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->pri_register_notifier) {
+ iommu_bus->iommu_ops->pri_register_notifier(bus,
+ iommu_bus->iommu_opaque,
+ devfn, pasid, notifier);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+void pci_pri_unregister_notifier(PCIDevice *dev, uint32_t pasid)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->pri_unregister_notifier) {
+ iommu_bus->iommu_ops->pri_unregister_notifier(bus,
+ iommu_bus->iommu_opaque,
+ devfn, pasid);
+ }
+}
+
+ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid,
+ bool priv_req, bool exec_req,
+ hwaddr addr, size_t length,
+ bool no_write, IOMMUTLBEntry *result,
+ size_t result_length,
+ uint32_t *err_count)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ if (!dev->is_master ||
+ ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) {
+ return -EPERM;
+ }
+
+ if (result_length == 0) {
+ return -ENOSPC;
+ }
+
+ if (!pcie_ats_enabled(dev)) {
+ return -EPERM;
+ }
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->ats_request_translation) {
+ return iommu_bus->iommu_ops->ats_request_translation(bus,
+ iommu_bus->iommu_opaque,
+ devfn, pasid, priv_req,
+ exec_req, addr, length,
+ no_write, result,
+ result_length, err_count);
+ }
+
+ return -ENODEV;
+}
+
+int pci_iommu_register_iotlb_notifier(PCIDevice *dev, uint32_t pasid,
+ IOMMUNotifier *n)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ if ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev)) {
+ return -EPERM;
+ }
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->register_iotlb_notifier) {
+ iommu_bus->iommu_ops->register_iotlb_notifier(bus,
+ iommu_bus->iommu_opaque, devfn,
+ pasid, n);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid,
+ IOMMUNotifier *n)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ if ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev)) {
+ return -EPERM;
+ }
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->unregister_iotlb_notifier) {
+ iommu_bus->iommu_ops->unregister_iotlb_notifier(bus,
+ iommu_bus->iommu_opaque,
+ devfn, pasid, n);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width,
+ uint32_t *min_page_size)
+{
+ PCIBus *bus;
+ PCIBus *iommu_bus;
+ int devfn;
+
+ pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
+ if (iommu_bus && iommu_bus->iommu_ops->get_iotlb_info) {
+ iommu_bus->iommu_ops->get_iotlb_info(iommu_bus->iommu_opaque,
+ addr_width, min_page_size);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque)
{
/*
@@ -2886,16 +3269,30 @@ MSIMessage pci_get_msi_message(PCIDevice *dev, int vector)
void pci_set_power(PCIDevice *d, bool state)
{
- if (d->has_power == state) {
+ /*
+ * Don't change the enabled state of VFs when powering on/off the device.
+ *
+ * When powering on, VFs must not be enabled immediately but they must
+ * wait until the guest configures SR-IOV.
+ * When powering off, their corresponding PFs will be reset and disable
+ * VFs.
+ */
+ if (!pci_is_vf(d)) {
+ pci_set_enabled(d, state);
+ }
+}
+
+void pci_set_enabled(PCIDevice *d, bool state)
+{
+ if (d->enabled == state) {
return;
}
- d->has_power = state;
+ d->enabled = state;
pci_update_mappings(d);
- memory_region_set_enabled(&d->bus_master_enable_region,
- (pci_get_word(d->config + PCI_COMMAND)
- & PCI_COMMAND_MASTER) && d->has_power);
- if (!d->has_power) {
+ pci_set_master(d, (pci_get_word(d->config + PCI_COMMAND)
+ & PCI_COMMAND_MASTER) && d->enabled);
+ if (qdev_is_realized(&d->qdev)) {
pci_device_reset(d);
}
}
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index 6a4e388..76255c4 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -380,9 +380,12 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename)
sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
sec_bus->address_space_mem = &br->address_space_mem;
memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX);
+ address_space_init(&br->as_mem, &br->address_space_mem,
+ "pci_bridge_pci_mem");
sec_bus->address_space_io = &br->address_space_io;
memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io",
4 * GiB);
+ address_space_init(&br->as_io, &br->address_space_io, "pci_bridge_pci_io");
pci_bridge_region_init(br);
QLIST_INIT(&sec_bus->child);
QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
@@ -399,6 +402,8 @@ void pci_bridge_exitfn(PCIDevice *pci_dev)
PCIBridge *s = PCI_BRIDGE(pci_dev);
assert(QLIST_EMPTY(&s->sec_bus.child));
QLIST_REMOVE(&s->sec_bus, sibling);
+ address_space_destroy(&s->as_mem);
+ address_space_destroy(&s->as_io);
pci_bridge_region_del(s, &s->windows);
pci_bridge_region_cleanup(s, &s->windows);
/* object_unparent() is called automatically during device deletion */
@@ -472,13 +477,12 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
return 0;
}
-static Property pci_bridge_properties[] = {
+static const Property pci_bridge_properties[] = {
DEFINE_PROP_BOOL("x-pci-express-writeable-slt-bug", PCIBridge,
pcie_writeable_slt_bug, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pci_bridge_class_init(ObjectClass *klass, void *data)
+static void pci_bridge_class_init(ObjectClass *klass, const void *data)
{
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
DeviceClass *k = DEVICE_CLASS(klass);
@@ -493,7 +497,7 @@ static const TypeInfo pci_bridge_type_info = {
.instance_size = sizeof(PCIBridge),
.class_init = pci_bridge_class_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c
index dfe6fe6..7179d99 100644
--- a/hw/pci/pci_host.c
+++ b/hw/pci/pci_host.c
@@ -86,7 +86,7 @@ void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
* allowing direct removal of unexposed functions.
*/
if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
- !pci_dev->has_power || is_pci_dev_ejected(pci_dev)) {
+ !pci_dev->enabled || is_pci_dev_ejected(pci_dev)) {
return;
}
@@ -111,7 +111,7 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
* allowing direct removal of unexposed functions.
*/
if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
- !pci_dev->has_power || is_pci_dev_ejected(pci_dev)) {
+ !pci_dev->enabled || is_pci_dev_ejected(pci_dev)) {
return ~0x0;
}
@@ -217,12 +217,6 @@ const MemoryRegionOps pci_host_data_le_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-const MemoryRegionOps pci_host_data_be_ops = {
- .read = pci_host_data_read,
- .write = pci_host_data_write,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
static bool pci_host_needed(void *opaque)
{
PCIHostState *s = opaque;
@@ -240,14 +234,13 @@ const VMStateDescription vmstate_pcihost = {
}
};
-static Property pci_host_properties_common[] = {
+static const Property pci_host_properties_common[] = {
DEFINE_PROP_BOOL("x-config-reg-migration-enabled", PCIHostState,
mig_enabled, true),
DEFINE_PROP_BOOL(PCI_HOST_BYPASS_IOMMU, PCIHostState, bypass_iommu, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pci_host_class_init(ObjectClass *klass, void *data)
+static void pci_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, pci_host_properties_common);
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 4b2f080..eaeb688 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -86,7 +86,13 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
* Specification, Revision 1.1., or subsequent PCI Express Base
* Specification revisions.
*/
- pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
+ uint32_t devcap = PCI_EXP_DEVCAP_RBER;
+
+ if (dev->cap_present & QEMU_PCIE_EXT_TAG) {
+ devcap = PCI_EXP_DEVCAP_RBER | PCI_EXP_DEVCAP_EXT_TAG;
+ }
+
+ pci_set_long(exp_cap + PCI_EXP_DEVCAP, devcap);
pci_set_long(exp_cap + PCI_EXP_LNKCAP,
(port << PCI_EXP_LNKCAP_PN_SHIFT) |
@@ -105,46 +111,18 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
}
-static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
+/* Includes setting the target speed default */
+static void pcie_cap_fill_lnk(uint8_t *exp_cap, PCIExpLinkWidth width,
+ PCIExpLinkSpeed speed)
{
- PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
- uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
-
- /* Skip anything that isn't a PCIESlot */
- if (!s) {
- return;
- }
-
/* Clear and fill LNKCAP from what was configured above */
pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- QEMU_PCI_EXP_LNKCAP_MLW(s->width) |
- QEMU_PCI_EXP_LNKCAP_MLS(s->speed));
-
- /*
- * Link bandwidth notification is required for all root ports and
- * downstream ports supporting links wider than x1 or multiple link
- * speeds.
- */
- if (s->width > QEMU_PCI_EXP_LNK_X1 ||
- s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
- pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- PCI_EXP_LNKCAP_LBNC);
- }
-
- if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
- /*
- * Hot-plug capable downstream ports and downstream ports supporting
- * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
- * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
- * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
- * technically implement this, but it's not done here for compatibility.
- */
- pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- PCI_EXP_LNKCAP_DLLLARC);
- /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */
+ QEMU_PCI_EXP_LNKCAP_MLW(width) |
+ QEMU_PCI_EXP_LNKCAP_MLS(speed));
+ if (speed > QEMU_PCI_EXP_LNK_2_5GT) {
/*
* Target Link Speed defaults to the highest link speed supported by
* the component. 2.5GT/s devices are permitted to hardwire to zero.
@@ -152,7 +130,7 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
PCI_EXP_LNKCTL2_TLS);
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
- QEMU_PCI_EXP_LNKCAP_MLS(s->speed) &
+ QEMU_PCI_EXP_LNKCAP_MLS(speed) &
PCI_EXP_LNKCTL2_TLS);
}
@@ -161,27 +139,82 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
* actually a reference to the highest bit supported in this register.
* We assume the device supports all link speeds.
*/
- if (s->speed > QEMU_PCI_EXP_LNK_5GT) {
+ if (speed > QEMU_PCI_EXP_LNK_5GT) {
pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_2_5GB |
PCI_EXP_LNKCAP2_SLS_5_0GB |
PCI_EXP_LNKCAP2_SLS_8_0GB);
- if (s->speed > QEMU_PCI_EXP_LNK_8GT) {
+ if (speed > QEMU_PCI_EXP_LNK_8GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_16_0GB);
}
- if (s->speed > QEMU_PCI_EXP_LNK_16GT) {
+ if (speed > QEMU_PCI_EXP_LNK_16GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_32_0GB);
}
- if (s->speed > QEMU_PCI_EXP_LNK_32GT) {
+ if (speed > QEMU_PCI_EXP_LNK_32GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_64_0GB);
}
}
}
+void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
+ PCIExpLinkSpeed speed)
+{
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+ /*
+ * For an end point or USP need to set the current status as well
+ * as the capabilities.
+ */
+ pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
+ QEMU_PCI_EXP_LNKSTA_NLW(width) |
+ QEMU_PCI_EXP_LNKSTA_CLS(speed));
+
+ pcie_cap_fill_lnk(exp_cap, width, speed);
+}
+
+static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
+{
+ PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+ /* Skip anything that isn't a PCIESlot */
+ if (!s) {
+ return;
+ }
+
+ /*
+ * Link bandwidth notification is required for all root ports and
+ * downstream ports supporting links wider than x1 or multiple link
+ * speeds.
+ */
+ if (s->width > QEMU_PCI_EXP_LNK_X1 ||
+ s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
+ PCI_EXP_LNKCAP_LBNC);
+ }
+
+ if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
+ /*
+ * Hot-plug capable downstream ports and downstream ports supporting
+ * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
+ * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
+ * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
+ * technically implement this, but it's not done here for compatibility.
+ */
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
+ PCI_EXP_LNKCAP_DLLLARC);
+ /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */
+ }
+
+ pcie_cap_fill_lnk(exp_cap, s->width, s->speed);
+}
+
int pcie_cap_init(PCIDevice *dev, uint8_t offset,
uint8_t type, uint8_t port,
Error **errp)
@@ -1080,18 +1113,22 @@ void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
lnksta &= ~PCI_EXP_LNKSTA_NLW;
lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
- } else if (!(lnksta & PCI_EXP_LNKSTA_NLW)) {
- lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1);
}
if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
lnksta &= ~PCI_EXP_LNKSTA_CLS;
lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
- } else if (!(lnksta & PCI_EXP_LNKSTA_CLS)) {
- lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT);
}
}
+ if (!(lnksta & PCI_EXP_LNKSTA_NLW)) {
+ lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1);
+ }
+
+ if (!(lnksta & PCI_EXP_LNKSTA_CLS)) {
+ lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT);
+ }
+
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
@@ -1177,3 +1214,81 @@ void pcie_acs_reset(PCIDevice *dev)
pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, 0);
}
}
+
+/* PASID */
+void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width,
+ bool exec_perm, bool priv_mod)
+{
+ static const uint16_t control_reg_rw_mask = 0x07;
+ uint16_t capability_reg;
+
+ assert(pasid_width <= PCI_EXT_CAP_PASID_MAX_WIDTH);
+
+ pcie_add_capability(dev, PCI_EXT_CAP_ID_PASID, PCI_PASID_VER, offset,
+ PCI_EXT_CAP_PASID_SIZEOF);
+
+ capability_reg = ((uint16_t)pasid_width) << PCI_PASID_CAP_WIDTH_SHIFT;
+ capability_reg |= exec_perm ? PCI_PASID_CAP_EXEC : 0;
+ capability_reg |= priv_mod ? PCI_PASID_CAP_PRIV : 0;
+ pci_set_word(dev->config + offset + PCI_PASID_CAP, capability_reg);
+
+ /* Everything is disabled by default */
+ pci_set_word(dev->config + offset + PCI_PASID_CTRL, 0);
+
+ pci_set_word(dev->wmask + offset + PCI_PASID_CTRL, control_reg_rw_mask);
+
+ dev->exp.pasid_cap = offset;
+}
+
+/* PRI */
+void pcie_pri_init(PCIDevice *dev, uint16_t offset, uint32_t outstanding_pr_cap,
+ bool prg_response_pasid_req)
+{
+ static const uint16_t control_reg_rw_mask = 0x3;
+ static const uint16_t status_reg_rw1_mask = 0x3;
+ static const uint32_t pr_alloc_reg_rw_mask = 0xffffffff;
+ uint16_t status_reg;
+
+ status_reg = prg_response_pasid_req ? PCI_PRI_STATUS_PASID : 0;
+ status_reg |= PCI_PRI_STATUS_STOPPED; /* Stopped by default */
+
+ pcie_add_capability(dev, PCI_EXT_CAP_ID_PRI, PCI_PRI_VER, offset,
+ PCI_EXT_CAP_PRI_SIZEOF);
+ /* Disabled by default */
+
+ pci_set_word(dev->config + offset + PCI_PRI_STATUS, status_reg);
+ pci_set_long(dev->config + offset + PCI_PRI_MAX_REQ, outstanding_pr_cap);
+
+ pci_set_word(dev->wmask + offset + PCI_PRI_CTRL, control_reg_rw_mask);
+ pci_set_word(dev->w1cmask + offset + PCI_PRI_STATUS, status_reg_rw1_mask);
+ pci_set_long(dev->wmask + offset + PCI_PRI_ALLOC_REQ, pr_alloc_reg_rw_mask);
+
+ dev->exp.pri_cap = offset;
+}
+
+bool pcie_pri_enabled(const PCIDevice *dev)
+{
+ if (!pci_is_express(dev) || !dev->exp.pri_cap) {
+ return false;
+ }
+ return (pci_get_word(dev->config + dev->exp.pri_cap + PCI_PRI_CTRL) &
+ PCI_PRI_CTRL_ENABLE) != 0;
+}
+
+bool pcie_pasid_enabled(const PCIDevice *dev)
+{
+ if (!pci_is_express(dev) || !dev->exp.pasid_cap) {
+ return false;
+ }
+ return (pci_get_word(dev->config + dev->exp.pasid_cap + PCI_PASID_CTRL) &
+ PCI_PASID_CTRL_ENABLE) != 0;
+}
+
+bool pcie_ats_enabled(const PCIDevice *dev)
+{
+ if (!pci_is_express(dev) || !dev->exp.ats_cap) {
+ return false;
+ }
+ return (pci_get_word(dev->config + dev->exp.ats_cap + PCI_ATS_CTRL) &
+ PCI_ATS_CTRL_ENABLE) != 0;
+}
diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
index 20ff2b3..f3841a2 100644
--- a/hw/pci/pcie_port.c
+++ b/hw/pci/pcie_port.c
@@ -92,16 +92,6 @@ static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
return s;
}
-PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
-{
- struct PCIEChassis *c;
- c = pcie_chassis_find(chassis_number);
- if (!c) {
- return NULL;
- }
- return pcie_chassis_find_slot_with_chassis(c, slot);
-}
-
int pcie_chassis_add_slot(struct PCIESlot *slot)
{
struct PCIEChassis *c;
@@ -121,15 +111,14 @@ void pcie_chassis_del_slot(PCIESlot *s)
QLIST_REMOVE(s, next);
}
-static Property pcie_port_props[] = {
+static const Property pcie_port_props[] = {
DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
DEFINE_PROP_UINT16("aer_log_max", PCIEPort,
parent_obj.parent_obj.exp.aer_log.log_max,
PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST()
};
-static void pcie_port_class_init(ObjectClass *oc, void *data)
+static void pcie_port_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -199,7 +188,7 @@ int pcie_count_ds_ports(PCIBus *bus)
return dsp_count;
}
-static bool pcie_slot_is_hotpluggbale_bus(HotplugHandler *plug_handler,
+static bool pcie_slot_is_hotpluggable_bus(HotplugHandler *plug_handler,
BusState *bus)
{
PCIESlot *s = PCIE_SLOT(bus->parent);
@@ -214,16 +203,15 @@ static const TypeInfo pcie_port_type_info = {
.class_init = pcie_port_class_init,
};
-static Property pcie_slot_props[] = {
+static const Property pcie_slot_props[] = {
DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true),
DEFINE_PROP_BOOL("x-do-not-expose-native-hotplug-cap", PCIESlot,
hide_native_hotplug_cap, false),
- DEFINE_PROP_END_OF_LIST()
};
-static void pcie_slot_class_init(ObjectClass *oc, void *data)
+static void pcie_slot_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -233,7 +221,7 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
hc->plug = pcie_cap_slot_plug_cb;
hc->unplug = pcie_cap_slot_unplug_cb;
hc->unplug_request = pcie_cap_slot_unplug_request_cb;
- hc->is_hotpluggable_bus = pcie_slot_is_hotpluggbale_bus;
+ hc->is_hotpluggable_bus = pcie_slot_is_hotpluggable_bus;
}
static const TypeInfo pcie_slot_type_info = {
@@ -242,7 +230,7 @@ static const TypeInfo pcie_slot_type_info = {
.instance_size = sizeof(PCIESlot),
.abstract = true,
.class_init = pcie_slot_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index e9b2322..3ad1874 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -15,28 +15,83 @@
#include "hw/pci/pcie.h"
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
-#include "qemu/error-report.h"
#include "qemu/range.h"
#include "qapi/error.h"
#include "trace.h"
-static PCIDevice *register_vf(PCIDevice *pf, int devfn,
- const char *name, uint16_t vf_num);
-static void unregister_vfs(PCIDevice *dev);
+static GHashTable *pfs;
-void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
- const char *vfname, uint16_t vf_dev_id,
- uint16_t init_vfs, uint16_t total_vfs,
- uint16_t vf_offset, uint16_t vf_stride)
+static void unparent_vfs(PCIDevice *dev, uint16_t total_vfs)
+{
+ for (uint16_t i = 0; i < total_vfs; i++) {
+ PCIDevice *vf = dev->exp.sriov_pf.vf[i];
+ object_unparent(OBJECT(vf));
+ object_unref(OBJECT(vf));
+ }
+ g_free(dev->exp.sriov_pf.vf);
+ dev->exp.sriov_pf.vf = NULL;
+}
+
+static void register_vfs(PCIDevice *dev)
+{
+ uint16_t num_vfs;
+ uint16_t i;
+ uint16_t sriov_cap = dev->exp.sriov_cap;
+
+ assert(sriov_cap > 0);
+ num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
+
+ trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn), num_vfs);
+ for (i = 0; i < num_vfs; i++) {
+ pci_set_enabled(dev->exp.sriov_pf.vf[i], true);
+ }
+
+ pci_set_word(dev->wmask + sriov_cap + PCI_SRIOV_NUM_VF, 0);
+}
+
+static void unregister_vfs(PCIDevice *dev)
+{
+ uint8_t *cfg = dev->config + dev->exp.sriov_cap;
+ uint16_t i;
+
+ trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+ for (i = 0; i < pci_get_word(cfg + PCI_SRIOV_TOTAL_VF); i++) {
+ pci_set_enabled(dev->exp.sriov_pf.vf[i], false);
+ }
+
+ pci_set_word(dev->wmask + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0xffff);
+}
+
+static bool pcie_sriov_pf_init_common(PCIDevice *dev, uint16_t offset,
+ uint16_t vf_dev_id, uint16_t init_vfs,
+ uint16_t total_vfs, uint16_t vf_offset,
+ uint16_t vf_stride, Error **errp)
{
+ int32_t devfn = dev->devfn + vf_offset;
uint8_t *cfg = dev->config + offset;
uint8_t *wmask;
+ if (!pci_is_express(dev)) {
+ error_setg(errp, "PCI Express is required for SR-IOV PF");
+ return false;
+ }
+
+ if (pci_is_vf(dev)) {
+ error_setg(errp, "a device cannot be a SR-IOV PF and a VF at the same time");
+ return false;
+ }
+
+ if (total_vfs &&
+ (uint32_t)devfn + (uint32_t)(total_vfs - 1) * vf_stride >= PCI_DEVFN_MAX) {
+ error_setg(errp, "VF addr overflows");
+ return false;
+ }
+
pcie_add_capability(dev, PCI_EXT_CAP_ID_SRIOV, 1,
offset, PCI_EXT_CAP_SRIOV_SIZEOF);
dev->exp.sriov_cap = offset;
- dev->exp.sriov_pf.num_vfs = 0;
- dev->exp.sriov_pf.vfname = g_strdup(vfname);
dev->exp.sriov_pf.vf = NULL;
pci_set_word(cfg + PCI_SRIOV_VF_OFFSET, vf_offset);
@@ -69,13 +124,74 @@ void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, 0x553);
qdev_prop_set_bit(&dev->qdev, "multifunction", true);
+
+ return true;
+}
+
+bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
+ const char *vfname, uint16_t vf_dev_id,
+ uint16_t init_vfs, uint16_t total_vfs,
+ uint16_t vf_offset, uint16_t vf_stride,
+ Error **errp)
+{
+ BusState *bus = qdev_get_parent_bus(&dev->qdev);
+ int32_t devfn = dev->devfn + vf_offset;
+
+ if (pfs && g_hash_table_contains(pfs, dev->qdev.id)) {
+ error_setg(errp, "attaching user-created SR-IOV VF unsupported");
+ return false;
+ }
+
+ if (!pcie_sriov_pf_init_common(dev, offset, vf_dev_id, init_vfs,
+ total_vfs, vf_offset, vf_stride, errp)) {
+ return false;
+ }
+
+ dev->exp.sriov_pf.vf = g_new(PCIDevice *, total_vfs);
+
+ for (uint16_t i = 0; i < total_vfs; i++) {
+ PCIDevice *vf = pci_new(devfn, vfname);
+ vf->exp.sriov_vf.pf = dev;
+ vf->exp.sriov_vf.vf_number = i;
+
+ if (!qdev_realize(&vf->qdev, bus, errp)) {
+ object_unparent(OBJECT(vf));
+ object_unref(vf);
+ unparent_vfs(dev, i);
+ return false;
+ }
+
+ /* set vid/did according to sr/iov spec - they are not used */
+ pci_config_set_vendor_id(vf->config, 0xffff);
+ pci_config_set_device_id(vf->config, 0xffff);
+
+ dev->exp.sriov_pf.vf[i] = vf;
+ devfn += vf_stride;
+ }
+
+ return true;
}
void pcie_sriov_pf_exit(PCIDevice *dev)
{
- unregister_vfs(dev);
- g_free((char *)dev->exp.sriov_pf.vfname);
- dev->exp.sriov_pf.vfname = NULL;
+ uint8_t *cfg = dev->config + dev->exp.sriov_cap;
+
+ if (dev->exp.sriov_pf.vf_user_created) {
+ uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID);
+ uint16_t total_vfs = pci_get_word(dev->config + PCI_SRIOV_TOTAL_VF);
+ uint16_t vf_dev_id = pci_get_word(dev->config + PCI_SRIOV_VF_DID);
+
+ unregister_vfs(dev);
+
+ for (uint16_t i = 0; i < total_vfs; i++) {
+ dev->exp.sriov_pf.vf[i]->exp.sriov_vf.pf = NULL;
+
+ pci_config_set_vendor_id(dev->exp.sriov_pf.vf[i]->config, ven_id);
+ pci_config_set_device_id(dev->exp.sriov_pf.vf[i]->config, vf_dev_id);
+ }
+ } else {
+ unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF));
+ }
}
void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
@@ -108,113 +224,179 @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
MemoryRegion *memory)
{
- PCIIORegion *r;
- PCIBus *bus = pci_get_bus(dev);
uint8_t type;
- pcibus_t size = memory_region_size(memory);
- assert(pci_is_vf(dev)); /* PFs must use pci_register_bar */
- assert(region_num >= 0);
- assert(region_num < PCI_NUM_REGIONS);
+ assert(dev->exp.sriov_vf.pf);
type = dev->exp.sriov_vf.pf->exp.sriov_pf.vf_bar_type[region_num];
- if (!is_power_of_2(size)) {
- error_report("%s: PCI region size must be a power"
- " of two - type=0x%x, size=0x%"FMT_PCIBUS,
- __func__, type, size);
- exit(1);
- }
+ return pci_register_bar(dev, region_num, type, memory);
+}
- r = &dev->io_regions[region_num];
- r->memory = memory;
- r->address_space =
- type & PCI_BASE_ADDRESS_SPACE_IO
- ? bus->address_space_io
- : bus->address_space_mem;
- r->size = size;
- r->type = type;
-
- r->addr = pci_bar_address(dev, region_num, r->type, r->size);
- if (r->addr != PCI_BAR_UNMAPPED) {
- memory_region_add_subregion_overlap(r->address_space,
- r->addr, r->memory, 1);
- }
+static gint compare_vf_devfns(gconstpointer a, gconstpointer b)
+{
+ return (*(PCIDevice **)a)->devfn - (*(PCIDevice **)b)->devfn;
}
-static PCIDevice *register_vf(PCIDevice *pf, int devfn, const char *name,
- uint16_t vf_num)
+int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev,
+ uint16_t offset,
+ Error **errp)
{
- PCIDevice *dev = pci_new(devfn, name);
- dev->exp.sriov_vf.pf = pf;
- dev->exp.sriov_vf.vf_number = vf_num;
- PCIBus *bus = pci_get_bus(pf);
- Error *local_err = NULL;
-
- qdev_realize(&dev->qdev, &bus->qbus, &local_err);
- if (local_err) {
- error_report_err(local_err);
- return NULL;
+ GPtrArray *pf;
+ PCIDevice **vfs;
+ BusState *bus = qdev_get_parent_bus(DEVICE(dev));
+ uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID);
+ uint16_t size = PCI_EXT_CAP_SRIOV_SIZEOF;
+ uint16_t vf_dev_id;
+ uint16_t vf_offset;
+ uint16_t vf_stride;
+ uint16_t i;
+
+ if (!pfs || !dev->qdev.id) {
+ return 0;
+ }
+
+ pf = g_hash_table_lookup(pfs, dev->qdev.id);
+ if (!pf) {
+ return 0;
+ }
+
+ if (pf->len > UINT16_MAX) {
+ error_setg(errp, "too many VFs");
+ return -1;
}
- /* set vid/did according to sr/iov spec - they are not used */
- pci_config_set_vendor_id(dev->config, 0xffff);
- pci_config_set_device_id(dev->config, 0xffff);
+ g_ptr_array_sort(pf, compare_vf_devfns);
+ vfs = (void *)pf->pdata;
+
+ if (vfs[0]->devfn <= dev->devfn) {
+ error_setg(errp, "a VF function number is less than the PF function number");
+ return -1;
+ }
+
+ vf_dev_id = pci_get_word(vfs[0]->config + PCI_DEVICE_ID);
+ vf_offset = vfs[0]->devfn - dev->devfn;
+ vf_stride = pf->len < 2 ? 0 : vfs[1]->devfn - vfs[0]->devfn;
+
+ for (i = 0; i < pf->len; i++) {
+ if (bus != qdev_get_parent_bus(&vfs[i]->qdev)) {
+ error_setg(errp, "SR-IOV VF parent bus mismatches with PF");
+ return -1;
+ }
+
+ if (ven_id != pci_get_word(vfs[i]->config + PCI_VENDOR_ID)) {
+ error_setg(errp, "SR-IOV VF vendor ID mismatches with PF");
+ return -1;
+ }
+
+ if (vf_dev_id != pci_get_word(vfs[i]->config + PCI_DEVICE_ID)) {
+ error_setg(errp, "inconsistent SR-IOV VF device IDs");
+ return -1;
+ }
- return dev;
+ for (size_t j = 0; j < PCI_NUM_REGIONS; j++) {
+ if (vfs[i]->io_regions[j].size != vfs[0]->io_regions[j].size ||
+ vfs[i]->io_regions[j].type != vfs[0]->io_regions[j].type) {
+ error_setg(errp, "inconsistent SR-IOV BARs");
+ return -1;
+ }
+ }
+
+ if (vfs[i]->devfn - vfs[0]->devfn != vf_stride * i) {
+ error_setg(errp, "inconsistent SR-IOV stride");
+ return -1;
+ }
+ }
+
+ if (!pcie_sriov_pf_init_common(dev, offset, vf_dev_id, pf->len,
+ pf->len, vf_offset, vf_stride, errp)) {
+ return -1;
+ }
+
+ if (!pcie_find_capability(dev, PCI_EXT_CAP_ID_ARI)) {
+ pcie_ari_init(dev, offset + size);
+ size += PCI_ARI_SIZEOF;
+ }
+
+ for (i = 0; i < pf->len; i++) {
+ vfs[i]->exp.sriov_vf.pf = dev;
+ vfs[i]->exp.sriov_vf.vf_number = i;
+
+ /* set vid/did according to sr/iov spec - they are not used */
+ pci_config_set_vendor_id(vfs[i]->config, 0xffff);
+ pci_config_set_device_id(vfs[i]->config, 0xffff);
+ }
+
+ dev->exp.sriov_pf.vf = vfs;
+ dev->exp.sriov_pf.vf_user_created = true;
+
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ PCIIORegion *region = &vfs[0]->io_regions[i];
+
+ if (region->size) {
+ pcie_sriov_pf_init_vf_bar(dev, i, region->type, region->size);
+ }
+ }
+
+ return size;
}
-static void register_vfs(PCIDevice *dev)
+bool pcie_sriov_register_device(PCIDevice *dev, Error **errp)
{
- uint16_t num_vfs;
- uint16_t i;
- uint16_t sriov_cap = dev->exp.sriov_cap;
- uint16_t vf_offset =
- pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_OFFSET);
- uint16_t vf_stride =
- pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_STRIDE);
- int32_t devfn = dev->devfn + vf_offset;
-
- assert(sriov_cap > 0);
- num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
- if (num_vfs > pci_get_word(dev->config + sriov_cap + PCI_SRIOV_TOTAL_VF)) {
- return;
+ if (!dev->exp.sriov_pf.vf && dev->qdev.id &&
+ pfs && g_hash_table_contains(pfs, dev->qdev.id)) {
+ error_setg(errp, "attaching user-created SR-IOV VF unsupported");
+ return false;
}
- dev->exp.sriov_pf.vf = g_new(PCIDevice *, num_vfs);
+ if (dev->sriov_pf) {
+ PCIDevice *pci_pf;
+ GPtrArray *pf;
- trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn), num_vfs);
- for (i = 0; i < num_vfs; i++) {
- dev->exp.sriov_pf.vf[i] = register_vf(dev, devfn,
- dev->exp.sriov_pf.vfname, i);
- if (!dev->exp.sriov_pf.vf[i]) {
- num_vfs = i;
- break;
+ if (!PCI_DEVICE_GET_CLASS(dev)->sriov_vf_user_creatable) {
+ error_setg(errp, "user cannot create SR-IOV VF with this device type");
+ return false;
}
- devfn += vf_stride;
+
+ if (!pci_is_express(dev)) {
+ error_setg(errp, "PCI Express is required for SR-IOV VF");
+ return false;
+ }
+
+ if (!pci_qdev_find_device(dev->sriov_pf, &pci_pf)) {
+ error_setg(errp, "PCI device specified as SR-IOV PF already exists");
+ return false;
+ }
+
+ if (!pfs) {
+ pfs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ }
+
+ pf = g_hash_table_lookup(pfs, dev->sriov_pf);
+ if (!pf) {
+ pf = g_ptr_array_new();
+ g_hash_table_insert(pfs, g_strdup(dev->sriov_pf), pf);
+ }
+
+ g_ptr_array_add(pf, dev);
}
- dev->exp.sriov_pf.num_vfs = num_vfs;
+
+ return true;
}
-static void unregister_vfs(PCIDevice *dev)
+void pcie_sriov_unregister_device(PCIDevice *dev)
{
- uint16_t num_vfs = dev->exp.sriov_pf.num_vfs;
- uint16_t i;
+ if (dev->sriov_pf && pfs) {
+ GPtrArray *pf = g_hash_table_lookup(pfs, dev->sriov_pf);
- trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn), num_vfs);
- for (i = 0; i < num_vfs; i++) {
- Error *err = NULL;
- PCIDevice *vf = dev->exp.sriov_pf.vf[i];
- if (!object_property_set_bool(OBJECT(vf), "realized", false, &err)) {
- error_reportf_err(err, "Failed to unplug: ");
+ if (pf) {
+ g_ptr_array_remove_fast(pf, dev);
+
+ if (!pf->len) {
+ g_hash_table_remove(pfs, dev->sriov_pf);
+ g_ptr_array_free(pf, FALSE);
+ }
}
- object_unparent(OBJECT(vf));
- object_unref(OBJECT(vf));
}
- g_free(dev->exp.sriov_pf.vf);
- dev->exp.sriov_pf.vf = NULL;
- dev->exp.sriov_pf.num_vfs = 0;
}
void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
@@ -235,15 +417,29 @@ void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
PCI_FUNC(dev->devfn), off, val, len);
if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) {
- if (dev->exp.sriov_pf.num_vfs) {
- if (!(val & PCI_SRIOV_CTRL_VFE)) {
- unregister_vfs(dev);
- }
+ if (val & PCI_SRIOV_CTRL_VFE) {
+ register_vfs(dev);
} else {
- if (val & PCI_SRIOV_CTRL_VFE) {
- register_vfs(dev);
- }
+ unregister_vfs(dev);
}
+ } else if (range_covers_byte(off, len, PCI_SRIOV_NUM_VF)) {
+ uint8_t *cfg = dev->config + sriov_cap;
+ uint8_t *wmask = dev->wmask + sriov_cap;
+ uint16_t num_vfs = pci_get_word(cfg + PCI_SRIOV_NUM_VF);
+ uint16_t wmask_val = PCI_SRIOV_CTRL_MSE | PCI_SRIOV_CTRL_ARI;
+
+ if (num_vfs <= pci_get_word(cfg + PCI_SRIOV_TOTAL_VF)) {
+ wmask_val |= PCI_SRIOV_CTRL_VFE;
+ }
+
+ pci_set_word(wmask + PCI_SRIOV_CTRL, wmask_val);
+ }
+}
+
+void pcie_sriov_pf_post_load(PCIDevice *dev)
+{
+ if (dev->exp.sriov_cap) {
+ register_vfs(dev);
}
}
@@ -260,6 +456,8 @@ void pcie_sriov_pf_reset(PCIDevice *dev)
unregister_vfs(dev);
pci_set_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF, 0);
+ pci_set_word(dev->wmask + sriov_cap + PCI_SRIOV_CTRL,
+ PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE | PCI_SRIOV_CTRL_ARI);
/*
* Default is to use 4K pages, software can modify it
@@ -294,7 +492,7 @@ void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize)
uint16_t pcie_sriov_vf_number(PCIDevice *dev)
{
- assert(pci_is_vf(dev));
+ assert(dev->exp.sriov_vf.pf);
return dev->exp.sriov_vf.vf_number;
}
@@ -306,7 +504,7 @@ PCIDevice *pcie_sriov_get_pf(PCIDevice *dev)
PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
{
assert(!pci_is_vf(dev));
- if (n < dev->exp.sriov_pf.num_vfs) {
+ if (n < pcie_sriov_num_vfs(dev)) {
return dev->exp.sriov_pf.vf[n];
}
return NULL;
@@ -314,5 +512,10 @@ PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
uint16_t pcie_sriov_num_vfs(PCIDevice *dev)
{
- return dev->exp.sriov_pf.num_vfs;
+ uint16_t sriov_cap = dev->exp.sriov_cap;
+ uint8_t *cfg = dev->config + sriov_cap;
+
+ return sriov_cap &&
+ (pci_get_word(cfg + PCI_SRIOV_CTRL) & PCI_SRIOV_CTRL_VFE) ?
+ pci_get_word(cfg + PCI_SRIOV_NUM_VF) : 0;
}
diff --git a/hw/pci/trace-events b/hw/pci/trace-events
index 19643aa..02c80d3 100644
--- a/hw/pci/trace-events
+++ b/hw/pci/trace-events
@@ -1,9 +1,15 @@
# See docs/devel/tracing.rst for syntax documentation.
# pci.c
+pci_pm_bad_transition(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, uint8_t old, uint8_t new) "%s %02x:%02x.%x REJECTED PM transition D%d->D%d"
+pci_pm_transition(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, uint8_t old, uint8_t new) "%s %02x:%02x.%x PM transition D%d->D%d"
pci_update_mappings_del(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "%s %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64
pci_update_mappings_add(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "%s %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64
pci_route_irq(int dev_irq, const char *dev_path, int parent_irq, const char *parent_path) "IRQ %d @%s -> IRQ %d @%s"
+pci_bad_rom_magic(uint16_t bad_rom_magic, uint16_t good_rom_magic) "Bad ROM magic number: %04"PRIX16". Should be: %04"PRIX16
+pci_bad_pcir_offset(uint16_t pcir_offset) "Bad PCIR offset 0x%"PRIx16" or signature"
+pci_rom_and_pci_ids(char *romfile, uint16_t vendor_id, uint16_t device_id, uint16_t rom_vendor_id, uint16_t rom_device_id) "%s: ROM ID %04"PRIx16":%04"PRIx16" | PCI ID %04"PRIx16":%04"PRIx16
+pci_rom_checksum_change(uint8_t old_checksum, uint8_t new_checksum) "ROM checksum changed from %02"PRIx8" to %02"PRIx8
# pci_host.c
pci_cfg_read(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, unsigned offs, unsigned val) "%s %02x:%02x.%x @0x%x -> 0x%x"
@@ -14,7 +20,7 @@ msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d mask
# hw/pci/pcie_sriov.c
sriov_register_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: creating %d vf devs"
-sriov_unregister_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: Unregistering %d vf devs"
+sriov_unregister_vfs(const char *name, int slot, int function) "%s %02x:%x: Unregistering vf devs"
sriov_config_write(const char *name, int slot, int fun, uint32_t offset, uint32_t val, uint32_t len) "%s %02x:%x: sriov offset 0x%x val 0x%x len %d"
# pcie.c
diff --git a/hw/pcmcia/Kconfig b/hw/pcmcia/Kconfig
deleted file mode 100644
index 41f2df9..0000000
--- a/hw/pcmcia/Kconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-config PCMCIA
- bool
diff --git a/hw/pcmcia/meson.build b/hw/pcmcia/meson.build
deleted file mode 100644
index 04e29c1..0000000
--- a/hw/pcmcia/meson.build
+++ /dev/null
@@ -1,2 +0,0 @@
-system_ss.add(when: 'CONFIG_PCMCIA', if_true: files('pcmcia.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c'))
diff --git a/hw/pcmcia/pcmcia.c b/hw/pcmcia/pcmcia.c
deleted file mode 100644
index 03d13e7..0000000
--- a/hw/pcmcia/pcmcia.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * PCMCIA emulation
- *
- * Copyright 2013 SUSE LINUX Products GmbH
- */
-
-#include "qemu/osdep.h"
-#include "qemu/module.h"
-#include "hw/pcmcia.h"
-
-static const TypeInfo pcmcia_card_type_info = {
- .name = TYPE_PCMCIA_CARD,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(PCMCIACardState),
- .abstract = true,
- .class_size = sizeof(PCMCIACardClass),
-};
-
-static void pcmcia_register_types(void)
-{
- type_register_static(&pcmcia_card_type_info);
-}
-
-type_init(pcmcia_register_types)
diff --git a/hw/pcmcia/pxa2xx.c b/hw/pcmcia/pxa2xx.c
deleted file mode 100644
index e3111fd..0000000
--- a/hw/pcmcia/pxa2xx.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "hw/pcmcia.h"
-#include "hw/arm/pxa.h"
-
-struct PXA2xxPCMCIAState {
- SysBusDevice parent_obj;
-
- PCMCIASocket slot;
- MemoryRegion container_mem;
- MemoryRegion common_iomem;
- MemoryRegion attr_iomem;
- MemoryRegion iomem;
-
- qemu_irq irq;
- qemu_irq cd_irq;
-
- PCMCIACardState *card;
-};
-
-static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->common_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->common_write(s->card, offset, value);
- }
-}
-
-static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->attr_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->attr_write(s->card, offset, value);
- }
-}
-
-static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->io_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->io_write(s->card, offset, value);
- }
-}
-
-static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
- .read = pxa2xx_pcmcia_common_read,
- .write = pxa2xx_pcmcia_common_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
- .read = pxa2xx_pcmcia_attr_read,
- .write = pxa2xx_pcmcia_attr_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
- .read = pxa2xx_pcmcia_io_read,
- .write = pxa2xx_pcmcia_io_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- if (!s->irq)
- return;
-
- qemu_set_irq(s->irq, level);
-}
-
-static void pxa2xx_pcmcia_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(obj);
-
- memory_region_init(&s->container_mem, obj, "container", 0x10000000);
- sysbus_init_mmio(sbd, &s->container_mem);
-
- /* Socket I/O Memory Space */
- memory_region_init_io(&s->iomem, obj, &pxa2xx_pcmcia_io_ops, s,
- "pxa2xx-pcmcia-io", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x00000000,
- &s->iomem);
-
- /* Then next 64 MB is reserved */
-
- /* Socket Attribute Memory Space */
- memory_region_init_io(&s->attr_iomem, obj, &pxa2xx_pcmcia_attr_ops, s,
- "pxa2xx-pcmcia-attribute", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x08000000,
- &s->attr_iomem);
-
- /* Socket Common Memory Space */
- memory_region_init_io(&s->common_iomem, obj, &pxa2xx_pcmcia_common_ops, s,
- "pxa2xx-pcmcia-common", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x0c000000,
- &s->common_iomem);
-
- s->slot.irq = qemu_allocate_irq(pxa2xx_pcmcia_set_irq, s, 0);
-
- object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
- (Object **)&s->card,
- NULL, /* read-only property */
- 0);
-}
-
-/* Insert a new card into a slot */
-int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- return -EEXIST;
- }
-
- if (s->cd_irq) {
- qemu_irq_raise(s->cd_irq);
- }
-
- s->card = card;
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
-
- s->slot.attached = true;
- s->card->slot = &s->slot;
- pcc->attach(s->card);
-
- return 0;
-}
-
-/* Eject card from the slot */
-int pxa2xx_pcmcia_detach(void *opaque)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (!s->slot.attached) {
- return -ENOENT;
- }
-
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->detach(s->card);
- s->card->slot = NULL;
- s->card = NULL;
-
- s->slot.attached = false;
-
- if (s->irq) {
- qemu_irq_lower(s->irq);
- }
- if (s->cd_irq) {
- qemu_irq_lower(s->cd_irq);
- }
-
- return 0;
-}
-
-/* Who to notify on card events */
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- s->irq = irq;
- s->cd_irq = cd_irq;
-}
-
-static const TypeInfo pxa2xx_pcmcia_type_info = {
- .name = TYPE_PXA2XX_PCMCIA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxPCMCIAState),
- .instance_init = pxa2xx_pcmcia_initfn,
-};
-
-static void pxa2xx_pcmcia_register_types(void)
-{
- type_register_static(&pxa2xx_pcmcia_type_info);
-}
-
-type_init(pxa2xx_pcmcia_register_types)
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 5addad1..ced6bbc 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -44,15 +44,6 @@ config POWERNV
select SSI_M25P80
select PNV_SPI
-config PPC405
- bool
- default y
- depends on PPC
- select M48T59
- select PFLASH_CFI02
- select PPC4XX
- select SERIAL
-
config PPC440
bool
default y
@@ -63,7 +54,7 @@ config PPC440
select PCI_EXPRESS
select PPC440_PCIX
select PPC4XX
- select SERIAL
+ select SERIAL_MM
select FDT_PPC
config PPC4XX
@@ -80,7 +71,7 @@ config SAM460EX
select IDE_SII3112
select M41T80
select PPC440
- select SERIAL
+ select SERIAL_MM
select SM501
select SMBUS_EEPROM
select USB_EHCI_SYSBUS
@@ -163,7 +154,7 @@ config E500
select PLATFORM_BUS
select PPCE500_PCI
select SDHCI
- select SERIAL
+ select SERIAL_MM
select MPC_I2C
select FDT_PPC
select DS1338
@@ -187,7 +178,7 @@ config VIRTEX
depends on PPC && FDT
select PPC4XX
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select XILINX
select XILINX_ETHLITE
select FDT_PPC
diff --git a/hw/ppc/amigaone.c b/hw/ppc/amigaone.c
index 900f93c..12279f4 100644
--- a/hw/ppc/amigaone.c
+++ b/hw/ppc/amigaone.c
@@ -21,12 +21,26 @@
#include "hw/ide/pci.h"
#include "hw/i2c/smbus_eeprom.h"
#include "hw/ppc/ppc.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
+#include "system/block-backend.h"
+#include "system/qtest.h"
+#include "system/reset.h"
#include "kvm_ppc.h"
+#include "elf.h"
+
+#include <zlib.h> /* for crc32 */
#define BUS_FREQ_HZ 100000000
+#define INITRD_MIN_ADDR 0x600000
+#define INIT_RAM_ADDR 0x40000000
+
+#define PCI_HIGH_ADDR 0x80000000
+#define PCI_HIGH_SIZE 0x7d000000
+#define PCI_LOW_ADDR 0xfd000000
+#define PCI_LOW_SIZE 0xe0000
+
+#define ARTICIA_ADDR 0xfe000000
+
/*
* Firmware binary available at
* https://www.hyperion-entertainment.com/index.php/downloads?view=files&parent=28
@@ -41,20 +55,204 @@
/* AmigaOS calls this routine from ROM, use this if no firmware loaded */
static const char dummy_fw[] = {
- 0x38, 0x00, 0x00, 0x08, /* li r0,8 */
- 0x7c, 0x09, 0x03, 0xa6, /* mtctr r0 */
- 0x54, 0x63, 0xf8, 0x7e, /* srwi r3,r3,1 */
- 0x42, 0x00, 0xff, 0xfc, /* bdnz 0x8 */
+ 0x54, 0x63, 0xc2, 0x3e, /* srwi r3,r3,8 */
0x7c, 0x63, 0x18, 0xf8, /* not r3,r3 */
0x4e, 0x80, 0x00, 0x20, /* blr */
};
+#define NVRAM_ADDR 0xfd0e0000
+#define NVRAM_SIZE (4 * KiB)
+
+static const char default_env[] =
+ "baudrate=115200\0"
+ "stdout=vga\0"
+ "stdin=ps2kbd\0"
+ "bootcmd=boota; menu; run menuboot_cmd\0"
+ "boot1=ide\0"
+ "boot2=cdrom\0"
+ "boota_timeout=3\0"
+ "ide_doreset=on\0"
+ "pci_irqa=9\0"
+ "pci_irqa_select=level\0"
+ "pci_irqb=10\0"
+ "pci_irqb_select=level\0"
+ "pci_irqc=11\0"
+ "pci_irqc_select=level\0"
+ "pci_irqd=7\0"
+ "pci_irqd_select=level\0"
+ "a1ide_irq=1111\0"
+ "a1ide_xfer=FFFF\0";
+#define CRC32_DEFAULT_ENV 0xb5548481
+#define CRC32_ALL_ZEROS 0x603b0489
+
+#define TYPE_A1_NVRAM "a1-nvram"
+OBJECT_DECLARE_SIMPLE_TYPE(A1NVRAMState, A1_NVRAM)
+
+struct A1NVRAMState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mr;
+ BlockBackend *blk;
+};
+
+static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ /* read callback not used because of romd mode */
+ g_assert_not_reached();
+}
+
+static void nvram_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int size)
+{
+ A1NVRAMState *s = opaque;
+ uint8_t *p = memory_region_get_ram_ptr(&s->mr);
+
+ p[addr] = val;
+ if (s->blk && blk_pwrite(s->blk, addr, 1, &val, 0) < 0) {
+ error_report("%s: could not write %s", __func__, blk_name(s->blk));
+ }
+}
+
+static const MemoryRegionOps nvram_ops = {
+ .read = nvram_read,
+ .write = nvram_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
+
+static void nvram_realize(DeviceState *dev, Error **errp)
+{
+ A1NVRAMState *s = A1_NVRAM(dev);
+ void *p;
+ uint32_t crc, *c;
+
+ memory_region_init_rom_device(&s->mr, NULL, &nvram_ops, s, "nvram",
+ NVRAM_SIZE, &error_fatal);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
+ c = p = memory_region_get_ram_ptr(&s->mr);
+ if (s->blk) {
+ if (blk_getlength(s->blk) != NVRAM_SIZE) {
+ error_setg(errp, "NVRAM backing file size must be %" PRId64 "bytes",
+ NVRAM_SIZE);
+ return;
+ }
+ blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, &error_fatal);
+ if (blk_pread(s->blk, 0, NVRAM_SIZE, p, 0) < 0) {
+ error_setg(errp, "Cannot read NVRAM contents from backing file");
+ return;
+ }
+ }
+ crc = crc32(0, p + 4, NVRAM_SIZE - 4);
+ if (crc == CRC32_ALL_ZEROS) { /* If env is uninitialized set default */
+ *c = cpu_to_be32(CRC32_DEFAULT_ENV);
+ /* Also copies terminating \0 as env is terminated by \0\0 */
+ memcpy(p + 4, default_env, sizeof(default_env));
+ if (s->blk &&
+ blk_pwrite(s->blk, 0, sizeof(crc) + sizeof(default_env), p, 0) < 0
+ ) {
+ error_report("%s: could not write %s", __func__, blk_name(s->blk));
+ }
+ return;
+ }
+ if (*c == 0) {
+ *c = cpu_to_be32(crc32(0, p + 4, NVRAM_SIZE - 4));
+ if (s->blk && blk_pwrite(s->blk, 0, 4, p, 0) < 0) {
+ error_report("%s: could not write %s", __func__, blk_name(s->blk));
+ }
+ }
+ if (be32_to_cpu(*c) != crc) {
+ warn_report("NVRAM checksum mismatch");
+ }
+}
+
+static const Property nvram_properties[] = {
+ DEFINE_PROP_DRIVE("drive", A1NVRAMState, blk),
+};
+
+static void nvram_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = nvram_realize;
+ device_class_set_props(dc, nvram_properties);
+}
+
+static const TypeInfo nvram_types[] = {
+ {
+ .name = TYPE_A1_NVRAM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(A1NVRAMState),
+ .class_init = nvram_class_init,
+ },
+};
+DEFINE_TYPES(nvram_types)
+
+struct boot_info {
+ hwaddr entry;
+ hwaddr stack;
+ hwaddr bd_info;
+ hwaddr initrd_start;
+ hwaddr initrd_end;
+ hwaddr cmdline_start;
+ hwaddr cmdline_end;
+};
+
+/* Board info struct from U-Boot */
+struct bd_info {
+ uint32_t bi_memstart;
+ uint32_t bi_memsize;
+ uint32_t bi_flashstart;
+ uint32_t bi_flashsize;
+ uint32_t bi_flashoffset;
+ uint32_t bi_sramstart;
+ uint32_t bi_sramsize;
+ uint32_t bi_bootflags;
+ uint32_t bi_ip_addr;
+ uint8_t bi_enetaddr[6];
+ uint16_t bi_ethspeed;
+ uint32_t bi_intfreq;
+ uint32_t bi_busfreq;
+ uint32_t bi_baudrate;
+} QEMU_PACKED;
+
+static void create_bd_info(hwaddr addr, ram_addr_t ram_size)
+{
+ struct bd_info *bd = g_new0(struct bd_info, 1);
+
+ bd->bi_memsize = cpu_to_be32(ram_size);
+ bd->bi_flashstart = cpu_to_be32(PROM_ADDR);
+ bd->bi_flashsize = cpu_to_be32(1); /* match what U-Boot detects */
+ bd->bi_bootflags = cpu_to_be32(1);
+ bd->bi_intfreq = cpu_to_be32(11.5 * BUS_FREQ_HZ);
+ bd->bi_busfreq = cpu_to_be32(BUS_FREQ_HZ);
+ bd->bi_baudrate = cpu_to_be32(115200);
+
+ cpu_physical_memory_write(addr, bd, sizeof(*bd));
+}
+
static void amigaone_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
+ CPUPPCState *env = &cpu->env;
cpu_reset(CPU(cpu));
- cpu_ppc_tb_reset(&cpu->env);
+ if (env->load_info) {
+ struct boot_info *bi = env->load_info;
+
+ env->gpr[1] = bi->stack;
+ env->gpr[2] = 1024;
+ env->gpr[3] = bi->bd_info;
+ env->gpr[4] = bi->initrd_start;
+ env->gpr[5] = bi->initrd_end;
+ env->gpr[6] = bi->cmdline_start;
+ env->gpr[7] = bi->cmdline_end;
+ env->nip = bi->entry;
+ }
+ cpu_ppc_tb_reset(env);
}
static void fix_spd_data(uint8_t *spd)
@@ -75,7 +273,9 @@ static void amigaone_init(MachineState *machine)
DeviceState *dev;
I2CBus *i2c_bus;
uint8_t *spd_data;
- int i;
+ DriveInfo *di;
+ hwaddr loadaddr;
+ struct boot_info *bi = NULL;
/* init CPU */
cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
@@ -97,9 +297,19 @@ static void amigaone_init(MachineState *machine)
/* Firmware uses this area for startup */
mr = g_new(MemoryRegion, 1);
memory_region_init_ram(mr, NULL, "init-cache", 32 * KiB, &error_fatal);
- memory_region_add_subregion(get_system_memory(), 0x40000000, mr);
+ memory_region_add_subregion(get_system_memory(), INIT_RAM_ADDR, mr);
}
+ /* nvram */
+ dev = qdev_new(TYPE_A1_NVRAM);
+ di = drive_get(IF_MTD, 0, 0);
+ if (di) {
+ qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di));
+ }
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ memory_region_add_subregion(get_system_memory(), NVRAM_ADDR,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
+
/* allocate and load firmware */
rom = g_new(MemoryRegion, 1);
memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal);
@@ -122,7 +332,7 @@ static void amigaone_init(MachineState *machine)
}
/* Articia S */
- dev = sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL);
+ dev = sysbus_create_simple(TYPE_ARTICIA, ARTICIA_ADDR, NULL);
i2c_bus = I2C_BUS(qdev_get_child_bus(dev, "smbus"));
if (machine->ram_size > 512 * MiB) {
@@ -139,12 +349,12 @@ static void amigaone_init(MachineState *machine)
pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
mr = g_new(MemoryRegion, 1);
memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem,
- 0, 0x1000000);
- memory_region_add_subregion(get_system_memory(), 0xfd000000, mr);
+ 0, PCI_LOW_SIZE);
+ memory_region_add_subregion(get_system_memory(), PCI_LOW_ADDR, mr);
mr = g_new(MemoryRegion, 1);
memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem,
- 0x80000000, 0x7d000000);
- memory_region_add_subregion(get_system_memory(), 0x80000000, mr);
+ PCI_HIGH_ADDR, PCI_HIGH_SIZE);
+ memory_region_add_subregion(get_system_memory(), PCI_HIGH_ADDR, mr);
pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
/* VIA VT82c686B South Bridge (multifunction PCI device) */
@@ -156,12 +366,62 @@ static void amigaone_init(MachineState *machine)
qdev_connect_gpio_out_named(DEVICE(via), "intr", 0,
qdev_get_gpio_in(DEVICE(cpu),
PPC6xx_INPUT_INT));
- for (i = 0; i < PCI_NUM_PINS; i++) {
+ for (int i = 0; i < PCI_NUM_PINS; i++) {
qdev_connect_gpio_out(dev, i, qdev_get_gpio_in_named(DEVICE(via),
"pirq", i));
}
pci_ide_create_devs(PCI_DEVICE(object_resolve_path_component(via, "ide")));
pci_vga_init(pci_bus);
+
+ if (!machine->kernel_filename) {
+ return;
+ }
+
+ /* handle -kernel, -initrd, -append options and emulate U-Boot */
+ bi = g_new0(struct boot_info, 1);
+ cpu->env.load_info = bi;
+
+ loadaddr = MIN(machine->ram_size, 256 * MiB);
+ bi->bd_info = loadaddr - 8 * MiB;
+ create_bd_info(bi->bd_info, machine->ram_size);
+ bi->stack = bi->bd_info - 64 * KiB - 8;
+
+ if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
+ size_t len = strlen(machine->kernel_cmdline);
+
+ loadaddr = bi->bd_info + 1 * MiB;
+ cpu_physical_memory_write(loadaddr, machine->kernel_cmdline, len + 1);
+ bi->cmdline_start = loadaddr;
+ bi->cmdline_end = loadaddr + len + 1; /* including terminating '\0' */
+ }
+
+ sz = load_elf(machine->kernel_filename, NULL, NULL, NULL,
+ &bi->entry, &loadaddr, NULL, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
+ if (sz <= 0) {
+ sz = load_uimage(machine->kernel_filename, &bi->entry, &loadaddr,
+ NULL, NULL, NULL);
+ }
+ if (sz <= 0) {
+ error_report("Could not load kernel '%s'",
+ machine->kernel_filename);
+ exit(1);
+ }
+ loadaddr += sz;
+
+ if (machine->initrd_filename) {
+ loadaddr = ROUND_UP(loadaddr + 4 * MiB, 4 * KiB);
+ loadaddr = MAX(loadaddr, INITRD_MIN_ADDR);
+ sz = load_image_targphys(machine->initrd_filename, loadaddr,
+ bi->bd_info - loadaddr);
+ if (sz <= 0) {
+ error_report("Could not load initrd '%s'",
+ machine->initrd_filename);
+ exit(1);
+ }
+ bi->initrd_start = loadaddr;
+ bi->initrd_end = loadaddr + sz;
+ }
}
static void amigaone_machine_init(MachineClass *mc)
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 3bd12b5..723c97f 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -18,21 +18,22 @@
#include "qemu/datadir.h"
#include "qemu/units.h"
#include "qemu/guest-random.h"
+#include "exec/target_page.h"
#include "qapi/error.h"
#include "e500.h"
#include "e500-ccsr.h"
#include "net/net.h"
#include "qemu/config-file.h"
#include "hw/block/flash.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/pci/pci.h"
-#include "sysemu/block-backend-io.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/block-backend-io.h"
+#include "system/system.h"
+#include "system/kvm.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "kvm_ppc.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/ppc/openpic.h"
#include "hw/ppc/openpic_kvm.h"
#include "hw/ppc/ppc.h"
@@ -78,8 +79,6 @@
#define MPC85XX_ESDHC_IRQ 72
#define RTC_REGS_OFFSET 0x68
-#define PLATFORM_CLK_FREQ_HZ (400 * 1000 * 1000)
-
struct boot_info
{
uint32_t dt_base;
@@ -119,7 +118,7 @@ static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
}
static void dt_serial_create(void *fdt, unsigned long long offset,
- const char *soc, const char *mpic,
+ const char *soc, uint32_t freq, const char *mpic,
const char *alias, int idx, bool defcon)
{
char *ser;
@@ -130,7 +129,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
- qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", PLATFORM_CLK_FREQ_HZ);
+ qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", freq);
qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
@@ -203,6 +202,8 @@ static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
+ qemu_fdt_setprop_cell(fdt, i2c, "#size-cells", 0);
+ qemu_fdt_setprop_cell(fdt, i2c, "#address-cells", 1);
qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
g_free(i2c);
@@ -379,8 +380,7 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
int fdt_size;
void *fdt;
uint8_t hypercall[16];
- uint32_t clock_freq = PLATFORM_CLK_FREQ_HZ;
- uint32_t tb_freq = PLATFORM_CLK_FREQ_HZ;
+ uint32_t clock_freq, tb_freq;
int i;
char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
char *soc;
@@ -408,7 +408,7 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
if (dtb_file) {
char *filename;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
+ filename = qemu_find_file(QEMU_FILE_TYPE_DTB, dtb_file);
if (!filename) {
goto out;
}
@@ -481,6 +481,9 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
if (kvmppc_get_hasidle(env)) {
qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
}
+ } else {
+ clock_freq = pmc->clock_freq;
+ tb_freq = pmc->tb_freq;
}
/* Create CPU nodes */
@@ -561,12 +564,12 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
*/
if (serial_hd(1)) {
dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
- soc, mpic, "serial1", 1, false);
+ soc, pmc->clock_freq, mpic, "serial1", 1, false);
}
if (serial_hd(0)) {
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
- soc, mpic, "serial0", 0, true);
+ soc, pmc->clock_freq, mpic, "serial0", 0, true);
}
/* i2c */
@@ -656,7 +659,6 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
done:
if (!dry_run) {
- qemu_fdt_dumpdtb(fdt, fdt_size);
cpu_physical_memory_write(addr, fdt, fdt_size);
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
@@ -721,11 +723,21 @@ static int ppce500_prep_device_tree(PPCE500MachineState *machine,
kernel_base, kernel_size, true);
}
-hwaddr booke206_page_size_to_tlb(uint64_t size)
+static hwaddr booke206_page_size_to_tlb(uint64_t size)
{
return 63 - clz64(size / KiB);
}
+void booke206_set_tlb(ppcmas_tlb_t *tlb, target_ulong va, hwaddr pa,
+ hwaddr len)
+{
+ tlb->mas1 = booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT;
+ tlb->mas1 |= MAS1_VALID;
+ tlb->mas2 = va & TARGET_PAGE_MASK;
+ tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+ tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+}
+
static int booke206_initial_map_tsize(CPUPPCState *env)
{
struct boot_info *bi = env->load_info;
@@ -751,25 +763,6 @@ static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
return (1ULL << 10 << tsize);
}
-/* Create -kernel TLB entries for BookE. */
-static void mmubooke_create_initial_mapping(CPUPPCState *env)
-{
- ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
- hwaddr size;
- int ps;
-
- ps = booke206_initial_map_tsize(env);
- size = (ps << MAS1_TSIZE_SHIFT);
- tlb->mas1 = MAS1_VALID | size;
- tlb->mas2 = 0;
- tlb->mas7_3 = 0;
- tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
-
-#ifdef CONFIG_KVM
- env->tlb_dirty = true;
-#endif
-}
-
static void ppce500_cpu_reset_sec(void *opaque)
{
PowerPCCPU *cpu = opaque;
@@ -786,6 +779,8 @@ static void ppce500_cpu_reset(void *opaque)
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
struct boot_info *bi = env->load_info;
+ uint64_t map_size = mmubooke_initial_mapsize(env);
+ ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
cpu_reset(cs);
@@ -796,11 +791,15 @@ static void ppce500_cpu_reset(void *opaque)
env->gpr[4] = 0;
env->gpr[5] = 0;
env->gpr[6] = EPAPR_MAGIC;
- env->gpr[7] = mmubooke_initial_mapsize(env);
+ env->gpr[7] = map_size;
env->gpr[8] = 0;
env->gpr[9] = 0;
env->nip = bi->entry;
- mmubooke_create_initial_mapping(env);
+ /* create initial mapping */
+ booke206_set_tlb(tlb, 0, 0, map_size);
+#ifdef CONFIG_KVM
+ env->tlb_dirty = true;
+#endif
}
static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
@@ -832,7 +831,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
}
static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
- IrqLines *irqs, Error **errp)
+ Error **errp)
{
#ifdef CONFIG_KVM
DeviceState *dev;
@@ -872,7 +871,7 @@ static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
Error *err = NULL;
if (kvm_kernel_irqchip_allowed()) {
- dev = ppce500_init_mpic_kvm(pmc, irqs, &err);
+ dev = ppce500_init_mpic_kvm(pmc, &err);
}
if (kvm_kernel_irqchip_required() && !dev) {
error_reportf_err(err,
@@ -932,7 +931,6 @@ void ppce500_init(MachineState *machine)
CPUPPCState *firstenv = NULL;
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
- PPCE500CCSRState *ccsr;
I2CBus *i2c;
irqs = g_new0(IrqLines, smp_cpus);
@@ -969,7 +967,7 @@ void ppce500_init(MachineState *machine)
env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
- ppc_booke_timers_init(cpu, PLATFORM_CLK_FREQ_HZ, PPC_TIMER_E500);
+ ppc_booke_timers_init(cpu, pmc->tb_freq, PPC_TIMER_E500);
/* Register reset handler */
if (!i) {
@@ -994,10 +992,10 @@ void ppce500_init(MachineState *machine)
memory_region_add_subregion(address_space_mem, 0, machine->ram);
dev = qdev_new("e500-ccsr");
+ s = SYS_BUS_DEVICE(dev);
object_property_add_child(OBJECT(machine), "e500-ccsr", OBJECT(dev));
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- ccsr = CCSR(dev);
- ccsr_addr_space = &ccsr->ccsr_space;
+ sysbus_realize_and_unref(s, &error_fatal);
+ ccsr_addr_space = sysbus_mmio_get_region(s, 0);
memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base,
ccsr_addr_space);
@@ -1024,7 +1022,7 @@ void ppce500_init(MachineState *machine)
sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
sysbus_mmio_get_region(s, 0));
- i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
+ i2c = I2C_BUS(qdev_get_child_bus(dev, "i2c"));
i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET);
/* eSDHC */
@@ -1045,6 +1043,7 @@ void ppce500_init(MachineState *machine)
dev = qdev_new(TYPE_SYSBUS_SDHCI);
qdev_prop_set_uint8(dev, "sd-spec-version", 2);
qdev_prop_set_uint8(dev, "endianness", DEVICE_BIG_ENDIAN);
+ qdev_prop_set_uint8(dev, "vendor", SDHCI_VENDOR_FSL);
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC85XX_ESDHC_IRQ));
@@ -1073,7 +1072,7 @@ void ppce500_init(MachineState *machine)
memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
sysbus_mmio_get_region(s, 0));
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+ pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
if (!pci_bus)
printf("couldn't create PCI controller!\n");
@@ -1195,7 +1194,7 @@ void ppce500_init(MachineState *machine)
payload_size = load_elf(filename, NULL, NULL, NULL,
&bios_entry, &loadaddr, NULL, NULL,
- 1, PPC_ELF_MACHINE, 0, 0);
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (payload_size < 0) {
/*
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
@@ -1284,6 +1283,7 @@ static void e500_ccsr_initfn(Object *obj)
PPCE500CCSRState *ccsr = CCSR(obj);
memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
MPC8544_CCSRBAR_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(ccsr), &ccsr->ccsr_space);
}
static const TypeInfo e500_ccsr_info = {
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 8c09ef9..00f4905 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -5,6 +5,8 @@
#include "hw/platform-bus.h"
#include "qom/object.h"
+#define PLATFORM_CLK_FREQ_HZ (400 * 1000 * 1000)
+
struct PPCE500MachineState {
/*< private >*/
MachineState parent_obj;
@@ -37,12 +39,12 @@ struct PPCE500MachineClass {
hwaddr pci_mmio_base;
hwaddr pci_mmio_bus_base;
hwaddr spin_base;
+ uint32_t clock_freq;
+ uint32_t tb_freq;
};
void ppce500_init(MachineState *machine);
-hwaddr booke206_page_size_to_tlb(uint64_t size);
-
#define TYPE_PPCE500_MACHINE "ppce500-base-machine"
OBJECT_DECLARE_TYPE(PPCE500MachineState, PPCE500MachineClass, PPCE500_MACHINE)
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index 7aa2f21..4f1d659 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -13,8 +13,8 @@
#include "qemu/units.h"
#include "e500.h"
#include "hw/net/fsl_etsec/etsec.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/kvm.h"
+#include "system/device_tree.h"
+#include "system/kvm.h"
#include "hw/sysbus.h"
#include "hw/pci/pci.h"
#include "hw/ppc/openpic.h"
@@ -68,7 +68,7 @@ HotplugHandler *e500plat_machine_get_hotpug_handler(MachineState *machine,
#define TYPE_E500PLAT_MACHINE MACHINE_TYPE_NAME("ppce500")
-static void e500plat_machine_class_init(ObjectClass *oc, void *data)
+static void e500plat_machine_class_init(ObjectClass *oc, const void *data)
{
PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -93,6 +93,8 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data)
pmc->pci_mmio_base = 0xC00000000ULL;
pmc->pci_mmio_bus_base = 0xE0000000ULL;
pmc->spin_base = 0xFEF000000ULL;
+ pmc->clock_freq = PLATFORM_CLK_FREQ_HZ;
+ pmc->tb_freq = PLATFORM_CLK_FREQ_HZ;
mc->desc = "generic paravirt e500 platform";
mc->init = e500plat_init;
@@ -107,7 +109,7 @@ static const TypeInfo e500plat_info = {
.name = TYPE_E500PLAT_MACHINE,
.parent = TYPE_PPCE500_MACHINE,
.class_init = e500plat_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index ff9e490..0b6e096 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -50,6 +50,7 @@
#include "qemu/datadir.h"
#include "qemu/units.h"
#include "qapi/error.h"
+#include "exec/target_page.h"
#include "hw/ppc/ppc.h"
#include "hw/qdev-properties.h"
#include "hw/nvram/mac_nvram.h"
@@ -59,7 +60,7 @@
#include "hw/ppc/mac_dbdma.h"
#include "hw/pci/pci.h"
#include "net/net.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
@@ -68,8 +69,8 @@
#include "hw/fw-path-provider.h"
#include "elf.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
+#include "system/kvm.h"
+#include "system/reset.h"
#include "kvm_ppc.h"
#include "hw/usb.h"
#include "hw/sysbus.h"
@@ -182,7 +183,8 @@ static void ppc_core99_init(MachineState *machine)
if (filename) {
/* Load OpenBIOS (ELF) */
bios_size = load_elf(filename, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+ NULL, NULL, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (bios_size <= 0) {
/* or load binary ROM image */
@@ -196,19 +198,14 @@ static void ppc_core99_init(MachineState *machine)
}
if (machine->kernel_filename) {
- int bswap_needed = 0;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#endif
kernel_base = KERNEL_LOAD_ADDR;
kernel_size = load_elf(machine->kernel_filename, NULL,
translate_kernel_address, NULL, NULL, NULL,
- NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+ NULL, NULL, ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (kernel_size < 0) {
kernel_size = load_aout(machine->kernel_filename, kernel_base,
machine->ram_size - kernel_base,
- bswap_needed, TARGET_PAGE_SIZE);
+ true, TARGET_PAGE_SIZE);
}
if (kernel_size < 0) {
kernel_size = load_image_targphys(machine->kernel_filename,
@@ -566,12 +563,12 @@ static int core99_kvm_type(MachineState *machine, const char *arg)
return 2;
}
-static void core99_machine_class_init(ObjectClass *oc, void *data)
+static void core99_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
- mc->desc = "Mac99 based PowerMAC";
+ mc->desc = "Mac99 based PowerMac";
mc->init = ppc_core99_init;
mc->block_default_type = IF_IDE;
/* SMP is not supported currently */
@@ -634,8 +631,6 @@ static void core99_instance_init(Object *obj)
object_property_set_description(obj, "via",
"Set VIA configuration. "
"Valid values are cuda, pmu and pmu-adb");
-
- return;
}
static const TypeInfo core99_machine_info = {
@@ -644,7 +639,7 @@ static const TypeInfo core99_machine_info = {
.class_init = core99_machine_class_init,
.instance_init = core99_instance_init,
.instance_size = sizeof(Core99MachineState),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
{ }
},
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 1981d3d..40ae936 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -28,11 +28,12 @@
#include "qemu/datadir.h"
#include "qemu/units.h"
#include "qapi/error.h"
+#include "exec/target_page.h"
#include "hw/ppc/ppc.h"
#include "hw/qdev-properties.h"
#include "hw/boards.h"
#include "hw/input/adb.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "net/net.h"
#include "hw/isa/isa.h"
#include "hw/pci/pci.h"
@@ -45,8 +46,8 @@
#include "hw/fw-path-provider.h"
#include "elf.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
+#include "system/kvm.h"
+#include "system/reset.h"
#include "kvm_ppc.h"
#define MAX_IDE_BUS 2
@@ -136,7 +137,7 @@ static void ppc_heathrow_init(MachineState *machine)
if (filename) {
/* Load OpenBIOS (ELF) */
bios_size = load_elf(filename, NULL, NULL, NULL, NULL, &bios_addr,
- NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+ NULL, NULL, ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
/* Unfortunately, load_elf sign-extends reading elf32 */
bios_addr = (uint32_t)bios_addr;
@@ -153,19 +154,14 @@ static void ppc_heathrow_init(MachineState *machine)
}
if (machine->kernel_filename) {
- int bswap_needed = 0;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#endif
kernel_base = KERNEL_LOAD_ADDR;
kernel_size = load_elf(machine->kernel_filename, NULL,
translate_kernel_address, NULL, NULL, NULL,
- NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+ NULL, NULL, ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (kernel_size < 0) {
kernel_size = load_aout(machine->kernel_filename, kernel_base,
machine->ram_size - kernel_base,
- bswap_needed, TARGET_PAGE_SIZE);
+ true, TARGET_PAGE_SIZE);
}
if (kernel_size < 0) {
kernel_size = load_image_targphys(machine->kernel_filename,
@@ -406,12 +402,12 @@ static int heathrow_kvm_type(MachineState *machine, const char *arg)
return 2;
}
-static void heathrow_class_init(ObjectClass *oc, void *data)
+static void heathrow_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
- mc->desc = "Heathrow based PowerMAC";
+ mc->desc = "Heathrow based PowerMac";
mc->init = ppc_heathrow_init;
mc->block_default_type = IF_IDE;
/* SMP is not supported currently */
@@ -434,7 +430,7 @@ static const TypeInfo ppc_heathrow_machine_info = {
.name = MACHINE_TYPE_NAME("g3beige"),
.parent = TYPE_MACHINE,
.class_init = heathrow_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
{ }
},
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 7cd9189..9893f8a 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -57,9 +57,6 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
'pnv_n1_chiplet.c',
))
# PowerPC 4xx boards
-ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
- 'ppc405_boards.c',
- 'ppc405_uc.c'))
ppc_ss.add(when: 'CONFIG_PPC440', if_true: files(
'ppc440_bamboo.c',
'ppc440_uc.c'))
diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c
index e3540b0..a25041e 100644
--- a/hw/ppc/mpc8544_guts.c
+++ b/hw/ppc/mpc8544_guts.c
@@ -18,9 +18,8 @@
*/
#include "qemu/osdep.h"
-#include "qemu/module.h"
#include "qemu/log.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "cpu.h"
#include "hw/sysbus.h"
#include "qom/object.h"
@@ -29,6 +28,12 @@
#define MPC8544_GUTS_RSTCR_RESET 0x02
#define MPC8544_GUTS_ADDR_PORPLLSR 0x00
+REG32(GUTS_PORPLLSR, 0x00)
+ FIELD(GUTS_PORPLLSR, E500_1_RATIO, 24, 6)
+ FIELD(GUTS_PORPLLSR, E500_0_RATIO, 16, 6)
+ FIELD(GUTS_PORPLLSR, DDR_RATIO, 9, 5)
+ FIELD(GUTS_PORPLLSR, PLAT_RATIO, 1, 5)
+
#define MPC8544_GUTS_ADDR_PORBMSR 0x04
#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08
#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C
@@ -75,6 +80,12 @@ static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr,
addr &= MPC8544_GUTS_MMIO_SIZE - 1;
switch (addr) {
+ case MPC8544_GUTS_ADDR_PORPLLSR:
+ value = FIELD_DP32(value, GUTS_PORPLLSR, E500_1_RATIO, 6); /* 3:1 */
+ value = FIELD_DP32(value, GUTS_PORPLLSR, E500_0_RATIO, 6); /* 3:1 */
+ value = FIELD_DP32(value, GUTS_PORPLLSR, DDR_RATIO, 12); /* 12:1 */
+ value = FIELD_DP32(value, GUTS_PORPLLSR, PLAT_RATIO, 6); /* 6:1 */
+ break;
case MPC8544_GUTS_ADDR_PVR:
value = env->spr[SPR_PVR];
break;
@@ -129,16 +140,13 @@ static void mpc8544_guts_initfn(Object *obj)
sysbus_init_mmio(d, &s->iomem);
}
-static const TypeInfo mpc8544_guts_info = {
- .name = TYPE_MPC8544_GUTS,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(GutsState),
- .instance_init = mpc8544_guts_initfn,
+static const TypeInfo mpc8544_guts_types[] = {
+ {
+ .name = TYPE_MPC8544_GUTS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GutsState),
+ .instance_init = mpc8544_guts_initfn,
+ },
};
-static void mpc8544_guts_register_types(void)
-{
- type_register_static(&mpc8544_guts_info);
-}
-
-type_init(mpc8544_guts_register_types)
+DEFINE_TYPES(mpc8544_guts_types)
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index b713090..5826985 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "e500.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/ppc/openpic.h"
#include "qemu/error-report.h"
#include "qemu/units.h"
@@ -37,7 +37,7 @@ static void mpc8544ds_init(MachineState *machine)
ppce500_init(machine);
}
-static void mpc8544ds_machine_class_init(ObjectClass *oc, void *data)
+static void mpc8544ds_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc);
@@ -55,6 +55,8 @@ static void mpc8544ds_machine_class_init(ObjectClass *oc, void *data)
pmc->pci_mmio_bus_base = 0xC0000000ULL;
pmc->pci_pio_base = 0xE1000000ULL;
pmc->spin_base = 0xEF000000ULL;
+ pmc->clock_freq = PLATFORM_CLK_FREQ_HZ;
+ pmc->tb_freq = PLATFORM_CLK_FREQ_HZ;
mc->desc = "mpc8544ds";
mc->init = mpc8544ds_init;
diff --git a/hw/ppc/pef.c b/hw/ppc/pef.c
index 4755334..254f570 100644
--- a/hw/ppc/pef.c
+++ b/hw/ppc/pef.c
@@ -12,9 +12,9 @@
#include "qapi/error.h"
#include "qom/object_interfaces.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "migration/blocker.h"
-#include "exec/confidential-guest-support.h"
+#include "system/confidential-guest-support.h"
#define TYPE_PEF_GUEST "pef-guest"
OBJECT_DECLARE_SIMPLE_TYPE(PefGuest, PEF_GUEST)
@@ -128,7 +128,7 @@ OBJECT_DEFINE_TYPE_WITH_INTERFACES(PefGuest,
{ TYPE_USER_CREATABLE },
{ NULL })
-static void pef_guest_class_init(ObjectClass *oc, void *data)
+static void pef_guest_class_init(ObjectClass *oc, const void *data)
{
ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 9b0a6b7..e15cf96 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -14,28 +14,29 @@
#include "hw/sysbus.h"
#include "hw/pci/pci_host.h"
#include "hw/irq.h"
+#include "hw/or-irq.h"
#include "hw/pci-host/mv64361.h"
#include "hw/isa/vt82c686.h"
#include "hw/ide/pci.h"
#include "hw/i2c/smbus_eeprom.h"
#include "hw/qdev-properties.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/qtest.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/qtest.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
#include "elf.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_ppc.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qom/qom-qobject.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "trace.h"
#include "qemu/datadir.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/ppc/vof.h"
#include <libfdt.h>
@@ -73,8 +74,11 @@ OBJECT_DECLARE_TYPE(Pegasos2MachineState, MachineClass, PEGASOS2_MACHINE)
struct Pegasos2MachineState {
MachineState parent_obj;
+
PowerPCCPU *cpu;
DeviceState *mv;
+ IRQState pci_irqs[PCI_NUM_PINS];
+ OrIRQState orirq[PCI_NUM_PINS];
qemu_irq mv_pirq[PCI_NUM_PINS];
qemu_irq via_pirq[PCI_NUM_PINS];
Vof *vof;
@@ -156,8 +160,8 @@ static void pegasos2_init(MachineState *machine)
}
memory_region_init_rom(rom, NULL, "pegasos2.rom", PROM_SIZE, &error_fatal);
memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom);
- sz = load_elf(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1,
- PPC_ELF_MACHINE, 0, 0);
+ sz = load_elf(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (sz <= 0) {
sz = load_image_targphys(filename, pm->vof ? 0 : PROM_ADDR, PROM_SIZE);
}
@@ -177,7 +181,6 @@ static void pegasos2_init(MachineState *machine)
pm->mv_pirq[i] = qdev_get_gpio_in_named(pm->mv, "gpp", 12 + i);
}
pci_bus = mv64361_get_pci_bus(pm->mv, 1);
- pci_bus_irqs(pci_bus, pegasos2_pci_irq, pm, PCI_NUM_PINS);
/* VIA VT8231 South Bridge (multifunction PCI device) */
via = OBJECT(pci_new_multifunction(PCI_DEVFN(12, 0), TYPE_VT8231_ISA));
@@ -209,10 +212,35 @@ static void pegasos2_init(MachineState *machine)
/* other PC hardware */
pci_vga_init(pci_bus);
+ /* PCI interrupt routing: lines from pci.0 and pci.1 are ORed */
+ for (int h = 0; h < 2; h++) {
+ DeviceState *pd;
+ g_autofree const char *pn = g_strdup_printf("pcihost%d", h);
+
+ pd = DEVICE(object_resolve_path_component(OBJECT(pm->mv), pn));
+ assert(pd);
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ OrIRQState *ori = &pm->orirq[i];
+
+ if (h == 0) {
+ g_autofree const char *n = g_strdup_printf("pci-orirq[%d]", i);
+
+ object_initialize_child_with_props(OBJECT(pm), n,
+ ori, sizeof(*ori),
+ TYPE_OR_IRQ, &error_fatal,
+ "num-lines", "2", NULL);
+ qdev_realize(DEVICE(ori), NULL, &error_fatal);
+ qemu_init_irq(&pm->pci_irqs[i], pegasos2_pci_irq, pm, i);
+ qdev_connect_gpio_out(DEVICE(ori), 0, &pm->pci_irqs[i]);
+ }
+ qdev_connect_gpio_out(pd, i, qdev_get_gpio_in(DEVICE(ori), h));
+ }
+ }
+
if (machine->kernel_filename) {
sz = load_elf(machine->kernel_filename, NULL, NULL, NULL,
- &pm->kernel_entry, &pm->kernel_addr, NULL, NULL, 1,
- PPC_ELF_MACHINE, 0, 0);
+ &pm->kernel_entry, &pm->kernel_addr, NULL, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (sz <= 0) {
error_report("Could not load kernel '%s'",
machine->kernel_filename);
@@ -291,14 +319,14 @@ static void pegasos2_superio_write(uint8_t addr, uint8_t val)
cpu_physical_memory_write(PCI1_IO_BASE + 0x3f1, &val, 1);
}
-static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason)
+static void pegasos2_machine_reset(MachineState *machine, ResetType type)
{
Pegasos2MachineState *pm = PEGASOS2_MACHINE(machine);
void *fdt;
uint64_t d[2];
int sz;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
if (!pm->vof) {
return; /* Firmware should set up machine so nothing to do */
}
@@ -389,7 +417,6 @@ static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason)
d[1] = cpu_to_be64(pm->kernel_size - (pm->kernel_entry - pm->kernel_addr));
qemu_fdt_setprop(fdt, "/chosen", "qemu,boot-kernel", d, sizeof(d));
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
g_free(pm->fdt_blob);
pm->fdt_blob = fdt;
@@ -561,7 +588,7 @@ static bool pegasos2_setprop(MachineState *ms, const char *path,
return true;
}
-static void pegasos2_machine_class_init(ObjectClass *oc, void *data)
+static void pegasos2_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
@@ -592,7 +619,7 @@ static const TypeInfo pegasos2_machine_info = {
.parent = TYPE_MACHINE,
.class_init = pegasos2_machine_class_init,
.instance_size = sizeof(Pegasos2MachineState),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PPC_VIRTUAL_HYPERVISOR },
{ TYPE_VOF_MACHINE_IF },
{ }
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 3526852..4a49e9d 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1,7 +1,9 @@
/*
* QEMU PowerPC PowerNV machine model
*
- * Copyright (c) 2016, IBM Corporation.
+ * Copyright (c) 2016-2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,14 +24,14 @@
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "sysemu/qtest.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/numa.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/cpus.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/hw_accel.h"
+#include "system/qtest.h"
+#include "system/system.h"
+#include "system/numa.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/cpus.h"
+#include "system/device_tree.h"
+#include "system/hw_accel.h"
#include "target/ppc/cpu.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/ppc.h"
@@ -53,7 +55,7 @@
#include "hw/ppc/pnv_pnor.h"
#include "hw/isa/isa.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/rtc/mc146818rtc.h"
#include <libfdt.h>
@@ -64,6 +66,8 @@
#define FW_LOAD_ADDR 0x0
#define FW_MAX_SIZE (16 * MiB)
+#define PNOR_FILE_NAME "pnv-pnor.bin"
+
#define KERNEL_LOAD_ADDR 0x20000000
#define KERNEL_MAX_SIZE (128 * MiB)
#define INITRD_LOAD_ADDR 0x28000000
@@ -709,13 +713,13 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque)
}
}
-static void pnv_reset(MachineState *machine, ShutdownCause reason)
+static void pnv_reset(MachineState *machine, ResetType type)
{
PnvMachineState *pnv = PNV_MACHINE(machine);
IPMIBmc *bmc;
void *fdt;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/*
* The machine should provide by default an internal BMC simulator.
@@ -736,21 +740,26 @@ static void pnv_reset(MachineState *machine, ShutdownCause reason)
}
}
- fdt = pnv_dt_create(machine);
-
- /* Pack resulting tree */
- _FDT((fdt_pack(fdt)));
+ if (machine->fdt) {
+ fdt = machine->fdt;
+ } else {
+ fdt = pnv_dt_create(machine);
+ /* Pack resulting tree */
+ _FDT((fdt_pack(fdt)));
+ }
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
- /*
- * Set machine->fdt for 'dumpdtb' QMP/HMP command. Free
- * the existing machine->fdt to avoid leaking it during
- * a reset.
- */
- g_free(machine->fdt);
- machine->fdt = fdt;
+ /* Update machine->fdt with latest fdt */
+ if (machine->fdt != fdt) {
+ /*
+ * Set machine->fdt for 'dumpdtb' QMP/HMP command. Free
+ * the existing machine->fdt to avoid leaking it during
+ * a reset.
+ */
+ g_free(machine->fdt);
+ machine->fdt = fdt;
+ }
}
static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
@@ -936,7 +945,7 @@ static void pnv_init(MachineState *machine)
uint64_t chip_ram_start = 0;
int i;
char *chip_typename;
- DriveInfo *pnor = drive_get(IF_MTD, 0, 0);
+ DriveInfo *pnor;
DeviceState *dev;
if (kvm_enabled()) {
@@ -952,12 +961,32 @@ static void pnv_init(MachineState *machine)
g_free(sz);
exit(EXIT_FAILURE);
}
+
+ /* checks for invalid option combinations */
+ if (machine->dtb && (strlen(machine->kernel_cmdline) != 0)) {
+ error_report("-append and -dtb cannot be used together, as passed"
+ " command line is ignored in case of custom dtb");
+ exit(EXIT_FAILURE);
+ }
+
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
/*
* Create our simple PNOR device
*/
dev = qdev_new(TYPE_PNV_PNOR);
+ pnor = drive_get(IF_MTD, 0, 0);
+ if (!pnor && defaults_enabled()) {
+ fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, PNOR_FILE_NAME);
+ if (!fw_filename) {
+ warn_report("Could not find PNOR '%s'", PNOR_FILE_NAME);
+ } else {
+ QemuOpts *opts;
+ opts = drive_add(IF_MTD, -1, fw_filename, "format=raw,readonly=on");
+ pnor = drive_new(opts, IF_MTD, &error_fatal);
+ g_free(fw_filename);
+ }
+ }
if (pnor) {
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(pnor));
}
@@ -1003,6 +1032,21 @@ static void pnv_init(MachineState *machine)
}
}
+ /* load dtb if passed */
+ if (machine->dtb) {
+ int fdt_size;
+
+ warn_report("with manually passed dtb, some options like '-append'"
+ " will get ignored and the dtb passed will be used as-is");
+
+ /* read the file 'machine->dtb', and load it into 'fdt' buffer */
+ machine->fdt = load_device_tree(machine->dtb, &fdt_size);
+ if (!machine->fdt) {
+ error_report("Could not load dtb '%s'", machine->dtb);
+ exit(1);
+ }
+ }
+
/* MSIs are supported on this platform */
msi_nonbroken = true;
@@ -1147,7 +1191,7 @@ static void pnv_init(MachineState *machine)
* Since we can not reach the remote BMC machine with LPC memops,
* map it always for now.
*/
- memory_region_add_subregion(pnv->chips[0]->fw_mr, PNOR_SPI_OFFSET,
+ memory_region_add_subregion(pnv->chips[0]->fw_mr, pnv->pnor->lpc_address,
&pnv->pnor->mmio);
/*
@@ -1527,7 +1571,21 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
return;
}
+ /* HOMER (must be created before OCC) */
+ object_property_set_link(OBJECT(&chip8->homer), "chip", OBJECT(chip),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip8->homer), NULL, errp)) {
+ return;
+ }
+ /* Homer Xscom region */
+ pnv_xscom_add_subregion(chip, PNV_XSCOM_PBA_BASE, &chip8->homer.pba_regs);
+ /* Homer RAM region */
+ memory_region_add_subregion(get_system_memory(), chip8->homer.base,
+ &chip8->homer.mem);
+
/* Create the simplified OCC model */
+ object_property_set_link(OBJECT(&chip8->occ), "homer",
+ OBJECT(&chip8->homer), &error_abort);
if (!qdev_realize(DEVICE(&chip8->occ), NULL, errp)) {
return;
}
@@ -1539,19 +1597,6 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(), PNV_OCC_SENSOR_BASE(chip),
&chip8->occ.sram_regs);
- /* HOMER */
- object_property_set_link(OBJECT(&chip8->homer), "chip", OBJECT(chip),
- &error_abort);
- if (!qdev_realize(DEVICE(&chip8->homer), NULL, errp)) {
- return;
- }
- /* Homer Xscom region */
- pnv_xscom_add_subregion(chip, PNV_XSCOM_PBA_BASE, &chip8->homer.pba_regs);
-
- /* Homer mmio region */
- memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip),
- &chip8->homer.regs);
-
/* PHB controllers */
for (i = 0; i < chip8->num_phbs; i++) {
PnvPHB *phb = chip8->phbs[i];
@@ -1573,7 +1618,7 @@ static uint32_t pnv_chip_power8_xscom_pcba(PnvChip *chip, uint64_t addr)
return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);
}
-static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power8e_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1597,7 +1642,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
&k->parent_realize);
}
-static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power8_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1621,7 +1666,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
&k->parent_realize);
}
-static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power8nvl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1725,6 +1770,7 @@ static void pnv_chip_power9_pec_realize(PnvChip *chip, Error **errp)
for (i = 0; i < chip->num_pecs; i++) {
PnvPhb4PecState *pec = &chip9->pecs[i];
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
+ uint32_t pec_cplt_base;
uint32_t pec_nest_base;
uint32_t pec_pci_base;
@@ -1737,9 +1783,12 @@ static void pnv_chip_power9_pec_realize(PnvChip *chip, Error **errp)
return;
}
+ pec_cplt_base = pecc->xscom_cplt_base(pec);
pec_nest_base = pecc->xscom_nest_base(pec);
pec_pci_base = pecc->xscom_pci_base(pec);
+ pnv_xscom_add_subregion(chip, pec_cplt_base,
+ &pec->nest_pervasive.xscom_ctrl_regs_mr);
pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr);
pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr);
}
@@ -1831,18 +1880,6 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
pnv_xscom_add_subregion(chip, PNV9_XSCOM_CHIPTOD_BASE,
&chip9->chiptod.xscom_regs);
- /* Create the simplified OCC model */
- if (!qdev_realize(DEVICE(&chip9->occ), NULL, errp)) {
- return;
- }
- pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
- qdev_connect_gpio_out(DEVICE(&chip9->occ), 0, qdev_get_gpio_in(
- DEVICE(psi9), PSIHB9_IRQ_OCC));
-
- /* OCC SRAM model */
- memory_region_add_subregion(get_system_memory(), PNV9_OCC_SENSOR_BASE(chip),
- &chip9->occ.sram_regs);
-
/* SBE */
if (!qdev_realize(DEVICE(&chip9->sbe), NULL, errp)) {
return;
@@ -1854,7 +1891,7 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
qdev_connect_gpio_out(DEVICE(&chip9->sbe), 0, qdev_get_gpio_in(
DEVICE(psi9), PSIHB9_IRQ_PSU));
- /* HOMER */
+ /* HOMER (must be created before OCC) */
object_property_set_link(OBJECT(&chip9->homer), "chip", OBJECT(chip),
&error_abort);
if (!qdev_realize(DEVICE(&chip9->homer), NULL, errp)) {
@@ -1862,10 +1899,23 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
}
/* Homer Xscom region */
pnv_xscom_add_subregion(chip, PNV9_XSCOM_PBA_BASE, &chip9->homer.pba_regs);
+ /* Homer RAM region */
+ memory_region_add_subregion(get_system_memory(), chip9->homer.base,
+ &chip9->homer.mem);
+
+ /* Create the simplified OCC model */
+ object_property_set_link(OBJECT(&chip9->occ), "homer",
+ OBJECT(&chip9->homer), &error_abort);
+ if (!qdev_realize(DEVICE(&chip9->occ), NULL, errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
+ qdev_connect_gpio_out(DEVICE(&chip9->occ), 0, qdev_get_gpio_in(
+ DEVICE(psi9), PSIHB9_IRQ_OCC));
- /* Homer mmio region */
- memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip),
- &chip9->homer.regs);
+ /* OCC SRAM model */
+ memory_region_add_subregion(get_system_memory(), PNV9_OCC_SENSOR_BASE(chip),
+ &chip9->occ.sram_regs);
/* PEC PHBs */
pnv_chip_power9_pec_realize(chip, &local_err);
@@ -1904,7 +1954,7 @@ static uint32_t pnv_chip_power9_xscom_pcba(PnvChip *chip, uint64_t addr)
return addr >> 3;
}
-static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power9_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -1999,6 +2049,7 @@ static void pnv_chip_power10_phb_realize(PnvChip *chip, Error **errp)
for (i = 0; i < chip->num_pecs; i++) {
PnvPhb4PecState *pec = &chip10->pecs[i];
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
+ uint32_t pec_cplt_base;
uint32_t pec_nest_base;
uint32_t pec_pci_base;
@@ -2011,9 +2062,12 @@ static void pnv_chip_power10_phb_realize(PnvChip *chip, Error **errp)
return;
}
+ pec_cplt_base = pecc->xscom_cplt_base(pec);
pec_nest_base = pecc->xscom_nest_base(pec);
pec_pci_base = pecc->xscom_pci_base(pec);
+ pnv_xscom_add_subregion(chip, pec_cplt_base,
+ &pec->nest_pervasive.xscom_ctrl_regs_mr);
pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr);
pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr);
}
@@ -2108,7 +2162,22 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
pnv_xscom_add_subregion(chip, PNV10_XSCOM_CHIPTOD_BASE,
&chip10->chiptod.xscom_regs);
+ /* HOMER (must be created before OCC) */
+ object_property_set_link(OBJECT(&chip10->homer), "chip", OBJECT(chip),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip10->homer), NULL, errp)) {
+ return;
+ }
+ /* Homer Xscom region */
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_PBA_BASE,
+ &chip10->homer.pba_regs);
+ /* Homer RAM region */
+ memory_region_add_subregion(get_system_memory(), chip10->homer.base,
+ &chip10->homer.mem);
+
/* Create the simplified OCC model */
+ object_property_set_link(OBJECT(&chip10->occ), "homer",
+ OBJECT(&chip10->homer), &error_abort);
if (!qdev_realize(DEVICE(&chip10->occ), NULL, errp)) {
return;
}
@@ -2133,20 +2202,6 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
qdev_connect_gpio_out(DEVICE(&chip10->sbe), 0, qdev_get_gpio_in(
DEVICE(&chip10->psi), PSIHB9_IRQ_PSU));
- /* HOMER */
- object_property_set_link(OBJECT(&chip10->homer), "chip", OBJECT(chip),
- &error_abort);
- if (!qdev_realize(DEVICE(&chip10->homer), NULL, errp)) {
- return;
- }
- /* Homer Xscom region */
- pnv_xscom_add_subregion(chip, PNV10_XSCOM_PBA_BASE,
- &chip10->homer.pba_regs);
-
- /* Homer mmio region */
- memory_region_add_subregion(get_system_memory(), PNV10_HOMER_BASE(chip),
- &chip10->homer.regs);
-
/* N1 chiplet */
if (!qdev_realize(DEVICE(&chip10->n1_chiplet), NULL, errp)) {
return;
@@ -2197,6 +2252,8 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
/* pib_spic[2] connected to 25csm04 which implements 1 byte transfer */
object_property_set_int(OBJECT(&chip10->pib_spic[i]), "transfer_len",
(i == 2) ? 1 : 4, &error_fatal);
+ object_property_set_int(OBJECT(&chip10->pib_spic[i]), "chip-id",
+ chip->chip_id, &error_fatal);
if (!sysbus_realize(SYS_BUS_DEVICE(OBJECT
(&chip10->pib_spic[i])), errp)) {
return;
@@ -2245,7 +2302,7 @@ static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
return addr >> 3;
}
-static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_power10_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvChipClass *k = PNV_CHIP_CLASS(klass);
@@ -2393,7 +2450,7 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
}
}
-static Property pnv_chip_properties[] = {
+static const Property pnv_chip_properties[] = {
DEFINE_PROP_UINT32("chip-id", PnvChip, chip_id, 0),
DEFINE_PROP_UINT64("ram-start", PnvChip, ram_start, 0),
DEFINE_PROP_UINT64("ram-size", PnvChip, ram_size, 0),
@@ -2402,10 +2459,9 @@ static Property pnv_chip_properties[] = {
DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
DEFINE_PROP_BOOL("big-core", PnvChip, big_core, false),
DEFINE_PROP_BOOL("lpar-per-core", PnvChip, lpar_per_core, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_chip_class_init(ObjectClass *klass, void *data)
+static void pnv_chip_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2554,7 +2610,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, GString *buf)
static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv,
XiveTCTXMatch *match)
{
@@ -2568,8 +2624,8 @@ static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
- priority, logic_serv, match);
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
+ cam_ignore, priority, logic_serv, match);
if (count < 0) {
return count;
@@ -2583,7 +2639,7 @@ static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv,
XiveTCTXMatch *match)
{
@@ -2597,8 +2653,8 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
- priority, logic_serv, match);
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
+ cam_ignore, priority, logic_serv, match);
if (count < 0) {
return count;
@@ -2610,6 +2666,24 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
return total_count;
}
+static int pnv10_xive_broadcast(XiveFabric *xfb,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool crowd, bool cam_ignore,
+ uint8_t priority)
+{
+ PnvMachineState *pnv = PNV_MACHINE(xfb);
+ int i;
+
+ for (i = 0; i < pnv->num_chips; i++) {
+ Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
+ XivePresenter *xptr = XIVE_PRESENTER(&chip10->xive);
+ XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
+
+ xpc->broadcast(xptr, nvt_blk, nvt_idx, crowd, cam_ignore, priority);
+ }
+ return 0;
+}
+
static bool pnv_machine_get_big_core(Object *obj, Error **errp)
{
PnvMachineState *pnv = PNV_MACHINE(obj);
@@ -2650,7 +2724,7 @@ static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
}
}
-static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_power8_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
@@ -2679,7 +2753,7 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
-static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_power9_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc);
@@ -2718,7 +2792,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
"Use 1 LPAR per core mode");
}
-static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_p10_common_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
@@ -2743,11 +2817,12 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
pmc->dt_power_mgt = pnv_dt_power_mgt;
xfc->match_nvt = pnv10_xive_match_nvt;
+ xfc->broadcast = pnv10_xive_broadcast;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
-static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_power10_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -2772,7 +2847,8 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
"Use 1 LPAR per core mode");
}
-static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_p10_rainier_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc);
@@ -2837,7 +2913,7 @@ static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
}
}
-static void pnv_machine_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
@@ -2897,7 +2973,7 @@ static const TypeInfo types[] = {
.name = MACHINE_TYPE_NAME("powernv10"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power10_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_FABRIC },
{ },
},
@@ -2906,7 +2982,7 @@ static const TypeInfo types[] = {
.name = MACHINE_TYPE_NAME("powernv9"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power9_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_FABRIC },
{ },
},
@@ -2915,7 +2991,7 @@ static const TypeInfo types[] = {
.name = MACHINE_TYPE_NAME("powernv8"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power8_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
{ },
},
@@ -2927,7 +3003,7 @@ static const TypeInfo types[] = {
.instance_size = sizeof(PnvMachineState),
.class_init = pnv_machine_class_init,
.class_size = sizeof(PnvMachineClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ TYPE_NMI },
{ },
diff --git a/hw/ppc/pnv_adu.c b/hw/ppc/pnv_adu.c
index 81b7d6e..005fbda 100644
--- a/hw/ppc/pnv_adu.c
+++ b/hw/ppc/pnv_adu.c
@@ -116,6 +116,12 @@ static void pnv_adu_xscom_write(void *opaque, hwaddr addr, uint64_t val,
uint32_t lpc_size = lpc_cmd_size(adu);
uint64_t data = 0;
+ if (!is_power_of_2(lpc_size) || lpc_size > sizeof(data)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "ADU: Unsupported LPC access "
+ "size:%" PRId32 "\n", lpc_size);
+ break;
+ }
+
pnv_lpc_opb_read(adu->lpc, lpc_addr, (void *)&data, lpc_size);
/*
@@ -135,6 +141,12 @@ static void pnv_adu_xscom_write(void *opaque, hwaddr addr, uint64_t val,
uint32_t lpc_size = lpc_cmd_size(adu);
uint64_t data;
+ if (!is_power_of_2(lpc_size) || lpc_size > sizeof(data)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "ADU: Unsupported LPC access "
+ "size:%" PRId32 "\n", lpc_size);
+ break;
+ }
+
data = cpu_to_be64(val) >> ((lpc_addr & 7) * 8); /* See above */
pnv_lpc_opb_write(adu->lpc, lpc_addr, (void *)&data, lpc_size);
}
@@ -173,12 +185,11 @@ static void pnv_adu_realize(DeviceState *dev, Error **errp)
PNV9_XSCOM_ADU_SIZE);
}
-static Property pnv_adu_properties[] = {
+static const Property pnv_adu_properties[] = {
DEFINE_PROP_LINK("lpc", PnvADU, lpc, TYPE_PNV_LPC, PnvLpcController *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_adu_class_init(ObjectClass *klass, void *data)
+static void pnv_adu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -193,7 +204,7 @@ static const TypeInfo pnv_adu_type_info = {
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvADU),
.class_init = pnv_adu_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ } },
};
diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
index 0c1274d..fb70a8c 100644
--- a/hw/ppc/pnv_bmc.c
+++ b/hw/ppc/pnv_bmc.c
@@ -174,8 +174,8 @@ static void hiomap_cmd(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len,
{
PnvPnor *pnor = PNV_PNOR(object_property_get_link(OBJECT(ibs), "pnor",
&error_abort));
+ uint32_t pnor_addr = pnor->lpc_address;
uint32_t pnor_size = pnor->size;
- uint32_t pnor_addr = PNOR_SPI_OFFSET;
bool readonly = false;
rsp_buffer_push(rsp, cmd[2]);
@@ -251,10 +251,38 @@ static const IPMINetfn hiomap_netfn = {
void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor)
{
+ uint32_t pnor_addr = pnor->lpc_address;
+ uint32_t pnor_size = pnor->size;
+
if (!pnv_bmc_is_simulator(bmc)) {
return;
}
+ /*
+ * The HIOMAP protocol uses block units and 16-bit addressing.
+ * Prevent overflow or misalign.
+ */
+ if (pnor_addr >= 1U << (BLOCK_SHIFT + 16)) {
+ warn_report("PNOR address is larger than 2^%d, disabling PNOR",
+ BLOCK_SHIFT + 16);
+ return;
+ }
+ if (pnor_addr & ((1U << BLOCK_SHIFT) - 1)) {
+ warn_report("PNOR address is not aligned to 2^%d, disabling PNOR",
+ BLOCK_SHIFT);
+ return;
+ }
+ if (pnor_size > 1U << (BLOCK_SHIFT + 16)) {
+ warn_report("PNOR size is larger than 2^%d, disabling PNOR",
+ BLOCK_SHIFT + 16);
+ return;
+ }
+ if (pnor_size & ((1U << BLOCK_SHIFT) - 1)) {
+ warn_report("PNOR size is not aligned to 2^%d, disabling PNOR",
+ BLOCK_SHIFT);
+ return;
+ }
+
object_ref(OBJECT(pnor));
object_property_add_const_link(OBJECT(bmc), "pnor", OBJECT(pnor));
diff --git a/hw/ppc/pnv_chiptod.c b/hw/ppc/pnv_chiptod.c
index 1e41fe5..b9e9c7b 100644
--- a/hw/ppc/pnv_chiptod.c
+++ b/hw/ppc/pnv_chiptod.c
@@ -23,7 +23,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "target/ppc/cpu.h"
#include "qapi/error.h"
#include "qemu/log.h"
@@ -450,14 +450,13 @@ static int pnv_chiptod_power9_dt_xscom(PnvXScomInterface *dev, void *fdt,
return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat));
}
-static Property pnv_chiptod_properties[] = {
+static const Property pnv_chiptod_properties[] = {
DEFINE_PROP_BOOL("primary", PnvChipTOD, primary, false),
DEFINE_PROP_BOOL("secondary", PnvChipTOD, secondary, false),
DEFINE_PROP_LINK("chip", PnvChipTOD , chip, TYPE_PNV_CHIP, PnvChip *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_chiptod_power9_class_init(ObjectClass *klass, void *data)
+static void pnv_chiptod_power9_class_init(ObjectClass *klass, const void *data)
{
PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -479,7 +478,7 @@ static const TypeInfo pnv_chiptod_power9_type_info = {
.parent = TYPE_PNV_CHIPTOD,
.instance_size = sizeof(PnvChipTOD),
.class_init = pnv_chiptod_power9_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
@@ -493,7 +492,7 @@ static int pnv_chiptod_power10_dt_xscom(PnvXScomInterface *dev, void *fdt,
return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat));
}
-static void pnv_chiptod_power10_class_init(ObjectClass *klass, void *data)
+static void pnv_chiptod_power10_class_init(ObjectClass *klass, const void *data)
{
PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -515,7 +514,7 @@ static const TypeInfo pnv_chiptod_power10_type_info = {
.parent = TYPE_PNV_CHIPTOD,
.instance_size = sizeof(PnvChipTOD),
.class_init = pnv_chiptod_power10_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
@@ -556,7 +555,7 @@ static void pnv_chiptod_unrealize(DeviceState *dev)
qemu_unregister_reset(pnv_chiptod_reset, chiptod);
}
-static void pnv_chiptod_class_init(ObjectClass *klass, void *data)
+static void pnv_chiptod_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index a306939..08c2022 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -18,7 +18,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -217,8 +217,8 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
case PNV10_XSCOM_EC_CORE_RAS_STATUS:
for (i = 0; i < nr_threads; i++) {
PowerPCCPU *cpu = pc->threads[i];
- CPUState *cs = CPU(cpu);
- if (cs->stopped) {
+ CPUPPCState *env = &cpu->env;
+ if (env->quiesced) {
val |= PPC_BIT(0 + 8 * i) | PPC_BIT(1 + 8 * i);
}
}
@@ -244,20 +244,29 @@ static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
for (i = 0; i < nr_threads; i++) {
PowerPCCPU *cpu = pc->threads[i];
CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
if (val & PPC_BIT(7 + 8 * i)) { /* stop */
val &= ~PPC_BIT(7 + 8 * i);
+ env->quiesced = true;
+ ppc_maybe_interrupt(env);
cpu_pause(cs);
}
if (val & PPC_BIT(6 + 8 * i)) { /* start */
val &= ~PPC_BIT(6 + 8 * i);
+ env->quiesced = false;
+ ppc_maybe_interrupt(env);
cpu_resume(cs);
}
if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
val &= ~PPC_BIT(4 + 8 * i);
+ env->quiesced = false;
+ ppc_maybe_interrupt(env);
pnv_cpu_do_nmi_resume(cs);
}
if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
+ env->quiesced = false;
+ ppc_maybe_interrupt(env);
/*
* Hardware has very particular cases for where clear maint
* must be used and where start must be used to resume a
@@ -317,6 +326,8 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
pir_spr->default_value = pir;
tir_spr->default_value = tir;
+ env->chip_index = pc->chip->chip_id;
+
if (pc->big_core) {
/* 2 "small cores" get the same core index for SMT operations */
env->core_index = core_hwid >> 1;
@@ -428,7 +439,7 @@ static void pnv_core_unrealize(DeviceState *dev)
g_free(pc->threads);
}
-static Property pnv_core_properties[] = {
+static const Property pnv_core_properties[] = {
DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
@@ -436,10 +447,9 @@ static Property pnv_core_properties[] = {
false),
DEFINE_PROP_BOOL("lpar-per-core", PnvCore, lpar_per_core, false),
DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
+static void pnv_core_power8_class_init(ObjectClass *oc, const void *data)
{
PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
@@ -447,7 +457,7 @@ static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
pcc->xscom_size = PNV_XSCOM_EX_SIZE;
}
-static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
+static void pnv_core_power9_class_init(ObjectClass *oc, const void *data)
{
PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
@@ -455,7 +465,7 @@ static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
pcc->xscom_size = PNV_XSCOM_EX_SIZE;
}
-static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
+static void pnv_core_power10_class_init(ObjectClass *oc, const void *data)
{
PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
@@ -463,7 +473,7 @@ static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
}
-static void pnv_core_class_init(ObjectClass *oc, void *data)
+static void pnv_core_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -686,12 +696,11 @@ static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
pqc->xscom_qme_size);
}
-static Property pnv_quad_properties[] = {
+static const Property pnv_quad_properties[] = {
DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
+static void pnv_quad_power9_class_init(ObjectClass *oc, const void *data)
{
PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -702,7 +711,7 @@ static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
}
-static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
+static void pnv_quad_power10_class_init(ObjectClass *oc, const void *data)
{
PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -716,7 +725,7 @@ static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
}
-static void pnv_quad_class_init(ObjectClass *oc, void *data)
+static void pnv_quad_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/ppc/pnv_homer.c b/hw/ppc/pnv_homer.c
index f9a203d..2208ffe 100644
--- a/hw/ppc/pnv_homer.c
+++ b/hw/ppc/pnv_homer.c
@@ -20,8 +20,8 @@
#include "qemu/log.h"
#include "qapi/error.h"
#include "exec/hwaddr.h"
-#include "exec/memory.h"
-#include "sysemu/cpus.h"
+#include "system/memory.h"
+#include "system/cpus.h"
#include "hw/qdev-core.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/pnv.h"
@@ -29,94 +29,6 @@
#include "hw/ppc/pnv_homer.h"
#include "hw/ppc/pnv_xscom.h"
-
-static bool core_max_array(PnvHomer *homer, hwaddr addr)
-{
- int i;
- PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
-
- for (i = 0; i <= homer->chip->nr_cores; i++) {
- if (addr == (hmrc->core_max_base + i)) {
- return true;
- }
- }
- return false;
-}
-
-/* P8 Pstate table */
-
-#define PNV8_OCC_PSTATE_VERSION 0x1f8001
-#define PNV8_OCC_PSTATE_MIN 0x1f8003
-#define PNV8_OCC_PSTATE_VALID 0x1f8000
-#define PNV8_OCC_PSTATE_THROTTLE 0x1f8002
-#define PNV8_OCC_PSTATE_NOM 0x1f8004
-#define PNV8_OCC_PSTATE_TURBO 0x1f8005
-#define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006
-#define PNV8_OCC_PSTATE_DATA 0x1f8008
-#define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010
-#define PNV8_OCC_PSTATE_ID_ONE 0x1f8018
-#define PNV8_OCC_PSTATE_ID_TWO 0x1f8020
-#define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012
-#define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013
-#define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014
-#define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c
-#define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024
-#define PNV8_CORE_MAX_BASE 0x1f8810
-
-
-static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PnvHomer *homer = PNV_HOMER(opaque);
-
- switch (addr) {
- case PNV8_OCC_PSTATE_VERSION:
- case PNV8_OCC_PSTATE_MIN:
- case PNV8_OCC_PSTATE_ID_ZERO:
- return 0;
- case PNV8_OCC_PSTATE_VALID:
- case PNV8_OCC_PSTATE_THROTTLE:
- case PNV8_OCC_PSTATE_NOM:
- case PNV8_OCC_PSTATE_TURBO:
- case PNV8_OCC_PSTATE_ID_ONE:
- case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER:
- case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER:
- return 1;
- case PNV8_OCC_PSTATE_ULTRA_TURBO:
- case PNV8_OCC_PSTATE_ID_TWO:
- return 2;
- case PNV8_OCC_PSTATE_DATA:
- return 0x1000000000000000;
- /* P8 frequency for 0, 1, and 2 pstates */
- case PNV8_OCC_PSTATE_ZERO_FREQUENCY:
- case PNV8_OCC_PSTATE_ONE_FREQUENCY:
- case PNV8_OCC_PSTATE_TWO_FREQUENCY:
- return 3000;
- }
- /* pstate table core max array */
- if (core_max_array(homer, addr)) {
- return 1;
- }
- return 0;
-}
-
-static void pnv_power8_homer_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- /* callback function defined to homer write */
- return;
-}
-
-static const MemoryRegionOps pnv_power8_homer_ops = {
- .read = pnv_power8_homer_read,
- .write = pnv_power8_homer_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 8,
- .impl.min_access_size = 1,
- .impl.max_access_size = 8,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
/* P8 PBA BARs */
#define PBA_BAR0 0x00
#define PBA_BAR1 0x01
@@ -131,16 +43,16 @@ static uint64_t pnv_homer_power8_pba_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvHomer *homer = PNV_HOMER(opaque);
- PnvChip *chip = homer->chip;
+ PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
uint32_t reg = addr >> 3;
uint64_t val = 0;
switch (reg) {
case PBA_BAR0:
- val = PNV_HOMER_BASE(chip);
+ val = homer->base;
break;
case PBA_BARMASK0: /* P8 homer region mask */
- val = (PNV_HOMER_SIZE - 1) & 0x300000;
+ val = (hmrc->size - 1) & 0x300000;
break;
case PBA_BAR3: /* P8 occ common area */
val = PNV_OCC_COMMON_AREA_BASE;
@@ -172,15 +84,19 @@ static const MemoryRegionOps pnv_homer_power8_pba_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_homer_power8_class_init(ObjectClass *klass, void *data)
+static hwaddr pnv_homer_power8_get_base(PnvChip *chip)
+{
+ return PNV_HOMER_BASE(chip);
+}
+
+static void pnv_homer_power8_class_init(ObjectClass *klass, const void *data)
{
PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
+ homer->get_base = pnv_homer_power8_get_base;
+ homer->size = PNV_HOMER_SIZE;
homer->pba_size = PNV_XSCOM_PBA_SIZE;
homer->pba_ops = &pnv_homer_power8_pba_ops;
- homer->homer_size = PNV_HOMER_SIZE;
- homer->homer_ops = &pnv_power8_homer_ops;
- homer->core_max_base = PNV8_CORE_MAX_BASE;
}
static const TypeInfo pnv_homer_power8_type_info = {
@@ -190,100 +106,20 @@ static const TypeInfo pnv_homer_power8_type_info = {
.class_init = pnv_homer_power8_class_init,
};
-/* P9 Pstate table */
-
-#define PNV9_OCC_PSTATE_ID_ZERO 0xe2018
-#define PNV9_OCC_PSTATE_ID_ONE 0xe2020
-#define PNV9_OCC_PSTATE_ID_TWO 0xe2028
-#define PNV9_OCC_PSTATE_DATA 0xe2000
-#define PNV9_OCC_PSTATE_DATA_AREA 0xe2008
-#define PNV9_OCC_PSTATE_MIN 0xe2003
-#define PNV9_OCC_PSTATE_NOM 0xe2004
-#define PNV9_OCC_PSTATE_TURBO 0xe2005
-#define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818
-#define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006
-#define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001
-#define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85
-#define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008
-#define PNV9_CHIP_HOMER_BASE 0x0
-#define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c
-#define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024
-#define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c
-#define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002
-#define PNV9_CORE_MAX_BASE 0xe2819
-
-
-static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PnvHomer *homer = PNV_HOMER(opaque);
-
- switch (addr) {
- case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO:
- case PNV9_OCC_PSTATE_ID_ZERO:
- return 0;
- case PNV9_OCC_PSTATE_DATA:
- case PNV9_OCC_ROLE_MASTER_OR_SLAVE:
- case PNV9_OCC_PSTATE_NOM:
- case PNV9_OCC_PSTATE_TURBO:
- case PNV9_OCC_PSTATE_ID_ONE:
- case PNV9_OCC_PSTATE_ULTRA_TURBO:
- case PNV9_OCC_OPAL_RUNTIME_DATA:
- return 1;
- case PNV9_OCC_PSTATE_MIN:
- case PNV9_OCC_PSTATE_ID_TWO:
- return 2;
-
- /* 3000 khz frequency for 0, 1, and 2 pstates */
- case PNV9_OCC_PSTATE_ZERO_FREQUENCY:
- case PNV9_OCC_PSTATE_ONE_FREQUENCY:
- case PNV9_OCC_PSTATE_TWO_FREQUENCY:
- return 3000;
- case PNV9_OCC_PSTATE_MAJOR_VERSION:
- return 0x90;
- case PNV9_CHIP_HOMER_BASE:
- case PNV9_OCC_PSTATE_DATA_AREA:
- case PNV9_CHIP_HOMER_IMAGE_POINTER:
- return 0x1000000000000000;
- }
- /* pstate table core max array */
- if (core_max_array(homer, addr)) {
- return 1;
- }
- return 0;
-}
-
-static void pnv_power9_homer_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- /* callback function defined to homer write */
- return;
-}
-
-static const MemoryRegionOps pnv_power9_homer_ops = {
- .read = pnv_power9_homer_read,
- .write = pnv_power9_homer_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 8,
- .impl.min_access_size = 1,
- .impl.max_access_size = 8,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
static uint64_t pnv_homer_power9_pba_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvHomer *homer = PNV_HOMER(opaque);
- PnvChip *chip = homer->chip;
+ PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
uint32_t reg = addr >> 3;
uint64_t val = 0;
switch (reg) {
case PBA_BAR0:
- val = PNV9_HOMER_BASE(chip);
+ val = homer->base;
break;
case PBA_BARMASK0: /* P9 homer region mask */
- val = (PNV9_HOMER_SIZE - 1) & 0x300000;
+ val = (hmrc->size - 1) & 0x300000;
break;
case PBA_BAR2: /* P9 occ common area */
val = PNV9_OCC_COMMON_AREA_BASE;
@@ -315,15 +151,19 @@ static const MemoryRegionOps pnv_homer_power9_pba_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_homer_power9_class_init(ObjectClass *klass, void *data)
+static hwaddr pnv_homer_power9_get_base(PnvChip *chip)
+{
+ return PNV9_HOMER_BASE(chip);
+}
+
+static void pnv_homer_power9_class_init(ObjectClass *klass, const void *data)
{
PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
+ homer->get_base = pnv_homer_power9_get_base;
+ homer->size = PNV_HOMER_SIZE;
homer->pba_size = PNV9_XSCOM_PBA_SIZE;
homer->pba_ops = &pnv_homer_power9_pba_ops;
- homer->homer_size = PNV9_HOMER_SIZE;
- homer->homer_ops = &pnv_power9_homer_ops;
- homer->core_max_base = PNV9_CORE_MAX_BASE;
}
static const TypeInfo pnv_homer_power9_type_info = {
@@ -337,16 +177,16 @@ static uint64_t pnv_homer_power10_pba_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvHomer *homer = PNV_HOMER(opaque);
- PnvChip *chip = homer->chip;
+ PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
uint32_t reg = addr >> 3;
uint64_t val = 0;
switch (reg) {
case PBA_BAR0:
- val = PNV10_HOMER_BASE(chip);
+ val = homer->base;
break;
case PBA_BARMASK0: /* P10 homer region mask */
- val = (PNV10_HOMER_SIZE - 1) & 0x300000;
+ val = (hmrc->size - 1) & 0x300000;
break;
case PBA_BAR2: /* P10 occ common area */
val = PNV10_OCC_COMMON_AREA_BASE;
@@ -378,15 +218,19 @@ static const MemoryRegionOps pnv_homer_power10_pba_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_homer_power10_class_init(ObjectClass *klass, void *data)
+static hwaddr pnv_homer_power10_get_base(PnvChip *chip)
+{
+ return PNV10_HOMER_BASE(chip);
+}
+
+static void pnv_homer_power10_class_init(ObjectClass *klass, const void *data)
{
PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
+ homer->get_base = pnv_homer_power10_get_base;
+ homer->size = PNV_HOMER_SIZE;
homer->pba_size = PNV10_XSCOM_PBA_SIZE;
homer->pba_ops = &pnv_homer_power10_pba_ops;
- homer->homer_size = PNV10_HOMER_SIZE;
- homer->homer_ops = &pnv_power9_homer_ops; /* TODO */
- homer->core_max_base = PNV9_CORE_MAX_BASE;
}
static const TypeInfo pnv_homer_power10_type_info = {
@@ -400,24 +244,29 @@ static void pnv_homer_realize(DeviceState *dev, Error **errp)
{
PnvHomer *homer = PNV_HOMER(dev);
PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
+ char homer_str[32];
assert(homer->chip);
pnv_xscom_region_init(&homer->pba_regs, OBJECT(dev), hmrc->pba_ops,
homer, "xscom-pba", hmrc->pba_size);
- /* homer region */
- memory_region_init_io(&homer->regs, OBJECT(dev),
- hmrc->homer_ops, homer, "homer-main-memory",
- hmrc->homer_size);
+ /* Homer RAM region */
+ homer->base = hmrc->get_base(homer->chip);
+
+ snprintf(homer_str, sizeof(homer_str), "homer-chip%d-memory",
+ homer->chip->chip_id);
+ if (!memory_region_init_ram(&homer->mem, OBJECT(homer),
+ homer_str, hmrc->size, errp)) {
+ return;
+ }
}
-static Property pnv_homer_properties[] = {
+static const Property pnv_homer_properties[] = {
DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_homer_class_init(ObjectClass *klass, void *data)
+static void pnv_homer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
index eec5047..60de479 100644
--- a/hw/ppc/pnv_i2c.c
+++ b/hw/ppc/pnv_i2c.c
@@ -9,7 +9,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/log.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
@@ -543,14 +543,13 @@ static void pnv_i2c_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out(DEVICE(dev), &i2c->psi_irq, 1);
}
-static Property pnv_i2c_properties[] = {
+static const Property pnv_i2c_properties[] = {
DEFINE_PROP_LINK("chip", PnvI2C, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_UINT32("engine", PnvI2C, engine, 1),
DEFINE_PROP_UINT32("num-busses", PnvI2C, num_busses, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_i2c_class_init(ObjectClass *klass, void *data)
+static void pnv_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -570,7 +569,7 @@ static const TypeInfo pnv_i2c_info = {
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvI2C),
.class_init = pnv_i2c_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index f8aad95..f6beba0 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -85,7 +85,7 @@ enum {
#define ISA_IO_SIZE 0x00010000
#define ISA_MEM_SIZE 0x10000000
-#define ISA_FW_SIZE 0x10000000
+#define ISA_FW_SIZE 0x100000000
#define LPC_IO_OPB_ADDR 0xd0010000
#define LPC_IO_OPB_SIZE 0x00010000
#define LPC_MEM_OPB_ADDR 0xe0000000
@@ -353,6 +353,8 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
+static void pnv_lpc_opb_noresponse(PnvLpcController *lpc);
+
static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
{
PnvLpcController *lpc = PNV_LPC(opaque);
@@ -376,6 +378,7 @@ static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
}
if (result != MEMTX_OK) {
+ pnv_lpc_opb_noresponse(lpc);
qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
HWADDR_PRIx "\n", addr);
}
@@ -406,6 +409,7 @@ static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
}
if (result != MEMTX_OK) {
+ pnv_lpc_opb_noresponse(lpc);
qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
HWADDR_PRIx "\n", addr);
}
@@ -427,21 +431,27 @@ static void pnv_lpc_eval_serirq_routes(PnvLpcController *lpc)
int irq;
if (!lpc->psi_has_serirq) {
- if ((lpc->opb_irq_route0 & PPC_BITMASK(8, 13)) ||
- (lpc->opb_irq_route1 & PPC_BITMASK(4, 31))) {
+ if ((lpc->opb_irq_route0 & PPC_BITMASK32(8, 13)) ||
+ (lpc->opb_irq_route1 & PPC_BITMASK32(4, 31))) {
qemu_log_mask(LOG_GUEST_ERROR,
"OPB: setting serirq routing on POWER8 system, ignoring.\n");
}
return;
}
+ /*
+ * Each of the ISA irqs is routed to one of the 4 SERIRQ irqs with 2
+ * bits, split across 2 OPB registers.
+ */
for (irq = 0; irq <= 13; irq++) {
- int serirq = (lpc->opb_irq_route1 >> (31 - 5 - (irq * 2))) & 0x3;
+ int serirq = extract32(lpc->opb_irq_route1,
+ PPC_BIT32_NR(5 + irq * 2), 2);
lpc->irq_to_serirq_route[irq] = serirq;
}
for (irq = 14; irq < ISA_NUM_IRQS; irq++) {
- int serirq = (lpc->opb_irq_route0 >> (31 - 9 - (irq * 2))) & 0x3;
+ int serirq = extract32(lpc->opb_irq_route0,
+ PPC_BIT32_NR(9 + (irq - 14) * 2), 2);
lpc->irq_to_serirq_route[irq] = serirq;
}
}
@@ -450,46 +460,18 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
{
uint32_t active_irqs = 0;
- if (lpc->lpc_hc_irqstat & PPC_BITMASK32(16, 31)) {
- qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented irqs in IRQSTAT: "
- "0x%08"PRIx32"\n", lpc->lpc_hc_irqstat);
- }
-
- if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
- active_irqs = lpc->lpc_hc_irqstat & lpc->lpc_hc_irqmask;
+ active_irqs = lpc->lpc_hc_irqstat & lpc->lpc_hc_irqmask;
+ if (!(lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN)) {
+ active_irqs &= ~LPC_HC_IRQ_SERIRQ_ALL;
}
/* Reflect the interrupt */
- if (!lpc->psi_has_serirq) {
- /*
- * POWER8 ORs all irqs together (also with LPCHC internal interrupt
- * sources) and outputs a single line that raises the PSI LPCHC irq
- * which then latches an OPB IRQ status register that sends the irq
- * to PSI.
- *
- * We don't honor the polarity register, it's pointless and unused
- * anyway
- */
- if (active_irqs) {
- lpc->opb_irq_input |= OPB_MASTER_IRQ_LPC;
- } else {
- lpc->opb_irq_input &= ~OPB_MASTER_IRQ_LPC;
- }
-
- /* Update OPB internal latch */
- lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
-
- qemu_set_irq(lpc->psi_irq_lpchc, lpc->opb_irq_stat != 0);
- } else {
+ if (lpc->psi_has_serirq) {
/*
- * POWER9 and POWER10 have routing fields in OPB master registers that
+ * POWER9 and later have routing fields in OPB master registers that
* send LPC irqs to 4 output lines that raise the PSI SERIRQ irqs.
* These don't appear to get latched into an OPB register like the
* LPCHC irqs.
- *
- * POWER9 LPC controller internal irqs still go via the OPB
- * and LPCHC PSI irqs like P8, but we have no such internal sources
- * modelled yet.
*/
bool serirq_out[4] = { false, false, false, false };
int irq;
@@ -504,7 +486,39 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
qemu_set_irq(lpc->psi_irq_serirq[1], serirq_out[1]);
qemu_set_irq(lpc->psi_irq_serirq[2], serirq_out[2]);
qemu_set_irq(lpc->psi_irq_serirq[3], serirq_out[3]);
+
+ /*
+ * POWER9 and later LPC controller internal irqs still go via the OPB
+ * and LPCHC PSI irqs like P8, so take the SERIRQs out and continue.
+ */
+ active_irqs &= ~LPC_HC_IRQ_SERIRQ_ALL;
+ }
+
+ /*
+ * POWER8 ORs all irqs together (also with LPCHC internal interrupt
+ * sources) and outputs a single line that raises the PSI LPCHC irq
+ * which then latches an OPB IRQ status register that sends the irq
+ * to PSI.
+ *
+ * We don't honor the polarity register, it's pointless and unused
+ * anyway
+ */
+ if (active_irqs) {
+ lpc->opb_irq_input |= OPB_MASTER_IRQ_LPC;
+ } else {
+ lpc->opb_irq_input &= ~OPB_MASTER_IRQ_LPC;
}
+
+ /* Update OPB internal latch */
+ lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
+
+ qemu_set_irq(lpc->psi_irq_lpchc, lpc->opb_irq_stat != 0);
+}
+
+static void pnv_lpc_opb_noresponse(PnvLpcController *lpc)
+{
+ lpc->lpc_hc_irqstat |= LPC_HC_IRQ_SYNC_NORESP_ERR;
+ pnv_lpc_eval_irqs(lpc);
}
static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
@@ -547,10 +561,13 @@ static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val,
switch (addr) {
case LPC_HC_FW_SEG_IDSEL:
- /* XXX Actually figure out how that works as this impact
- * memory regions/aliases
+ /*
+ * ISA FW "devices" are modeled as 16x256MB windows into a
+ * 4GB LPC FW address space.
*/
+ val &= 0xf; /* Selects device 0-15 */
lpc->lpc_hc_fw_seg_idsel = val;
+ memory_region_set_alias_offset(&lpc->opb_isa_fw, val * LPC_FW_OPB_SIZE);
break;
case LPC_HC_FW_RD_ACC_SIZE:
lpc->lpc_hc_fw_rd_acc_size = val;
@@ -697,7 +714,7 @@ static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp)
PNV_XSCOM_LPC_SIZE);
}
-static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data)
+static void pnv_lpc_power8_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -715,7 +732,7 @@ static const TypeInfo pnv_lpc_power8_info = {
.name = TYPE_PNV8_LPC,
.parent = TYPE_PNV_LPC,
.class_init = pnv_lpc_power8_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
@@ -743,7 +760,7 @@ static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out_named(dev, lpc->psi_irq_serirq, "SERIRQ", 4);
}
-static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
+static void pnv_lpc_power9_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvLpcClass *plc = PNV_LPC_CLASS(klass);
@@ -760,7 +777,7 @@ static const TypeInfo pnv_lpc_power9_info = {
.class_init = pnv_lpc_power9_class_init,
};
-static void pnv_lpc_power10_class_init(ObjectClass *klass, void *data)
+static void pnv_lpc_power10_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -784,9 +801,9 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
memory_region_init(&lpc->opb_mr, OBJECT(dev), "lpc-opb", 0x100000000ull);
address_space_init(&lpc->opb_as, &lpc->opb_mr, "lpc-opb");
- /* Create ISA IO and Mem space regions which are the root of
- * the ISA bus (ie, ISA address spaces). We don't create a
- * separate one for FW which we alias to memory.
+ /*
+ * Create ISA IO, Mem, and FW space regions which are the root of
+ * the ISA bus (ie, ISA address spaces).
*/
memory_region_init(&lpc->isa_io, OBJECT(dev), "isa-io", ISA_IO_SIZE);
memory_region_init(&lpc->isa_mem, OBJECT(dev), "isa-mem", ISA_MEM_SIZE);
@@ -822,12 +839,11 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out_named(dev, &lpc->psi_irq_lpchc, "LPCHC", 1);
}
-static Property pnv_lpc_properties[] = {
+static const Property pnv_lpc_properties[] = {
DEFINE_PROP_BOOL("psi-serirq", PnvLpcController, psi_has_serirq, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_lpc_class_init(ObjectClass *klass, void *data)
+static void pnv_lpc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/pnv_n1_chiplet.c b/hw/ppc/pnv_n1_chiplet.c
index 03ff9fb..053f647 100644
--- a/hw/ppc/pnv_n1_chiplet.c
+++ b/hw/ppc/pnv_n1_chiplet.c
@@ -136,7 +136,7 @@ static void pnv_n1_chiplet_realize(DeviceState *dev, Error **errp)
PNV10_XSCOM_N1_PB_SCOM_ES_SIZE);
}
-static void pnv_n1_chiplet_class_init(ObjectClass *klass, void *data)
+static void pnv_n1_chiplet_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -159,7 +159,7 @@ static const TypeInfo pnv_n1_chiplet_info = {
.instance_init = pnv_n1_chiplet_instance_init,
.instance_size = sizeof(PnvN1Chiplet),
.class_init = pnv_n1_chiplet_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/ppc/pnv_nest_pervasive.c b/hw/ppc/pnv_nest_pervasive.c
index 7747675..1b1b14f 100644
--- a/hw/ppc/pnv_nest_pervasive.c
+++ b/hw/ppc/pnv_nest_pervasive.c
@@ -177,11 +177,11 @@ static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp)
pnv_xscom_region_init(&nest_pervasive->xscom_ctrl_regs_mr,
OBJECT(nest_pervasive),
&pnv_nest_pervasive_control_xscom_ops,
- nest_pervasive, "pervasive-control",
+ nest_pervasive, "xscom-pervasive-control",
PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE);
}
-static void pnv_nest_pervasive_class_init(ObjectClass *klass, void *data)
+static void pnv_nest_pervasive_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -194,7 +194,7 @@ static const TypeInfo pnv_nest_pervasive_info = {
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvNestChipletPervasive),
.class_init = pnv_nest_pervasive_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
index 48123ce..24b789c 100644
--- a/hw/ppc/pnv_occ.c
+++ b/hw/ppc/pnv_occ.c
@@ -24,40 +24,53 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_chip.h"
#include "hw/ppc/pnv_xscom.h"
#include "hw/ppc/pnv_occ.h"
+#define P8_HOMER_OPAL_DATA_OFFSET 0x1F8000
+#define P9_HOMER_OPAL_DATA_OFFSET 0x0E2000
+
#define OCB_OCI_OCCMISC 0x4020
#define OCB_OCI_OCCMISC_AND 0x4021
#define OCB_OCI_OCCMISC_OR 0x4022
+#define OCCMISC_PSI_IRQ PPC_BIT(0)
+#define OCCMISC_IRQ_SHMEM PPC_BIT(3)
/* OCC sensors */
-#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000
-#define OCC_SENSOR_DATA_VALID 0x580001
-#define OCC_SENSOR_DATA_VERSION 0x580002
-#define OCC_SENSOR_DATA_READING_VERSION 0x580004
-#define OCC_SENSOR_DATA_NR_SENSORS 0x580008
-#define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010
-#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014
-#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c
-#define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d
-#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023
-#define OCC_SENSOR_LOC_CORE 0x580022
-#define OCC_SENSOR_LOC_GPU 0x580020
-#define OCC_SENSOR_TYPE_POWER 0x580003
-#define OCC_SENSOR_NAME 0x580005
-#define HWMON_SENSORS_MASK 0x58001e
-#define SLW_IMAGE_BASE 0x0
+#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x0000
+#define OCC_SENSOR_DATA_VALID 0x0001
+#define OCC_SENSOR_DATA_VERSION 0x0002
+#define OCC_SENSOR_DATA_READING_VERSION 0x0004
+#define OCC_SENSOR_DATA_NR_SENSORS 0x0008
+#define OCC_SENSOR_DATA_NAMES_OFFSET 0x0010
+#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x0014
+#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x000c
+#define OCC_SENSOR_DATA_NAME_LENGTH 0x000d
+#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x0023
+#define OCC_SENSOR_LOC_CORE 0x0022
+#define OCC_SENSOR_LOC_GPU 0x0020
+#define OCC_SENSOR_TYPE_POWER 0x0003
+#define OCC_SENSOR_NAME 0x0005
+#define HWMON_SENSORS_MASK 0x001e
static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
{
- bool irq_state;
-
- val &= 0xffff000000000000ull;
+ val &= PPC_BITMASK(0, 18); /* Mask out unimplemented bits */
occ->occmisc = val;
- irq_state = !!(val >> 63);
- qemu_set_irq(occ->psi_irq, irq_state);
+
+ /*
+ * OCCMISC IRQ bit triggers the interrupt on a 0->1 edge, but not clear
+ * how that is handled in PSI so it is level-triggered here, which is not
+ * really correct (but skiboot is okay with it).
+ */
+ qemu_set_irq(occ->psi_irq, !!(val & OCCMISC_PSI_IRQ));
+}
+
+static void pnv_occ_raise_msg_irq(PnvOCC *occ)
+{
+ pnv_occ_set_misc(occ, occ->occmisc | OCCMISC_PSI_IRQ | OCCMISC_IRQ_SHMEM);
}
static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr,
@@ -129,8 +142,6 @@ static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
case HWMON_SENSORS_MASK:
case OCC_SENSOR_LOC_GPU:
return 0x8e00;
- case SLW_IMAGE_BASE:
- return 0x1000000000000000;
}
return 0;
}
@@ -139,7 +150,6 @@ static void pnv_occ_common_area_write(void *opaque, hwaddr addr,
uint64_t val, unsigned width)
{
/* callback function defined to occ common area write */
- return;
}
static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
@@ -162,10 +172,14 @@ const MemoryRegionOps pnv_occ_sram_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
+static void pnv_occ_power8_class_init(ObjectClass *klass, const void *data)
{
PnvOCCClass *poc = PNV_OCC_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->desc = "PowerNV OCC Controller (POWER8)";
+ poc->opal_shared_memory_offset = P8_HOMER_OPAL_DATA_OFFSET;
+ poc->opal_shared_memory_version = 0x02;
poc->xscom_size = PNV_XSCOM_OCC_SIZE;
poc->xscom_ops = &pnv_occ_power8_xscom_ops;
}
@@ -232,14 +246,17 @@ static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
+static void pnv_occ_power9_class_init(ObjectClass *klass, const void *data)
{
PnvOCCClass *poc = PNV_OCC_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "PowerNV OCC Controller (POWER9)";
+ poc->opal_shared_memory_offset = P9_HOMER_OPAL_DATA_OFFSET;
+ poc->opal_shared_memory_version = 0x90;
poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
poc->xscom_ops = &pnv_occ_power9_xscom_ops;
+ assert(!dc->user_creatable);
}
static const TypeInfo pnv_occ_power9_type_info = {
@@ -249,23 +266,52 @@ static const TypeInfo pnv_occ_power9_type_info = {
.class_init = pnv_occ_power9_class_init,
};
-static void pnv_occ_power10_class_init(ObjectClass *klass, void *data)
+static void pnv_occ_power10_class_init(ObjectClass *klass, const void *data)
{
+ PnvOCCClass *poc = PNV_OCC_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "PowerNV OCC Controller (POWER10)";
+ poc->opal_shared_memory_offset = P9_HOMER_OPAL_DATA_OFFSET;
+ poc->opal_shared_memory_version = 0xA0;
+ poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
+ poc->xscom_ops = &pnv_occ_power9_xscom_ops;
+ assert(!dc->user_creatable);
}
static const TypeInfo pnv_occ_power10_type_info = {
.name = TYPE_PNV10_OCC,
- .parent = TYPE_PNV9_OCC,
+ .parent = TYPE_PNV_OCC,
.class_init = pnv_occ_power10_class_init,
};
+static bool occ_init_homer_memory(PnvOCC *occ, Error **errp);
+static bool occ_model_tick(PnvOCC *occ);
+
+/* Relatively arbitrary */
+#define OCC_POLL_MS 100
+
+static void occ_state_machine_timer(void *opaque)
+{
+ PnvOCC *occ = opaque;
+ uint64_t next = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + OCC_POLL_MS;
+
+ if (occ_model_tick(occ)) {
+ timer_mod(&occ->state_machine_timer, next);
+ }
+}
+
static void pnv_occ_realize(DeviceState *dev, Error **errp)
{
PnvOCC *occ = PNV_OCC(dev);
PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
+ PnvHomer *homer = occ->homer;
+
+ assert(homer);
+
+ if (!occ_init_homer_memory(occ, errp)) {
+ return;
+ }
occ->occmisc = 0;
@@ -279,14 +325,22 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
PNV_OCC_SENSOR_DATA_BLOCK_SIZE);
qdev_init_gpio_out(dev, &occ->psi_irq, 1);
+
+ timer_init_ms(&occ->state_machine_timer, QEMU_CLOCK_VIRTUAL,
+ occ_state_machine_timer, occ);
+ timer_mod(&occ->state_machine_timer, OCC_POLL_MS);
}
-static void pnv_occ_class_init(ObjectClass *klass, void *data)
+static const Property pnv_occ_properties[] = {
+ DEFINE_PROP_LINK("homer", PnvOCC, homer, TYPE_PNV_HOMER, PnvHomer *),
+};
+
+static void pnv_occ_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pnv_occ_realize;
- dc->desc = "PowerNV OCC Controller";
+ device_class_set_props(dc, pnv_occ_properties);
dc->user_creatable = false;
}
@@ -308,3 +362,561 @@ static void pnv_occ_register_types(void)
}
type_init(pnv_occ_register_types);
+
+/*
+ * From skiboot/hw/occ.c with following changes:
+ * - tab to space conversion
+ * - Type conversions u8->uint8_t s8->int8_t __be16->uint16_t etc
+ * - __packed -> QEMU_PACKED
+ */
+/* OCC Communication Area for PStates */
+
+#define OPAL_DYNAMIC_DATA_OFFSET 0x0B80
+/* relative to HOMER_OPAL_DATA_OFFSET */
+
+#define MAX_PSTATES 256
+#define MAX_P8_CORES 12
+#define MAX_P9_CORES 24
+#define MAX_P10_CORES 32
+
+#define MAX_OPAL_CMD_DATA_LENGTH 4090
+#define MAX_OCC_RSP_DATA_LENGTH 8698
+
+#define P8_PIR_CORE_MASK 0xFFF8
+#define P9_PIR_QUAD_MASK 0xFFF0
+#define P10_PIR_CHIP_MASK 0x0000
+#define FREQ_MAX_IN_DOMAIN 0
+#define FREQ_MOST_RECENTLY_SET 1
+
+/**
+ * OCC-OPAL Shared Memory Region
+ *
+ * Reference document :
+ * https://github.com/open-power/docs/blob/master/occ/OCC_OpenPwr_FW_Interfaces.pdf
+ *
+ * Supported layout versions:
+ * - 0x01, 0x02 : P8
+ * https://github.com/open-power/occ/blob/master_p8/src/occ/proc/proc_pstate.h
+ *
+ * - 0x90 : P9
+ * https://github.com/open-power/occ/blob/master/src/occ_405/proc/proc_pstate.h
+ * In 0x90 the data is separated into :-
+ * -- Static Data (struct occ_pstate_table): Data is written once by OCC
+ * -- Dynamic Data (struct occ_dynamic_data): Data is updated at runtime
+ *
+ * struct occ_pstate_table - Pstate table layout
+ * @valid: Indicates if data is valid
+ * @version: Layout version [Major/Minor]
+ * @v2.throttle: Reason for limiting the max pstate
+ * @v9.occ_role: OCC role (Master/Slave)
+ * @v#.pstate_min: Minimum pstate ever allowed
+ * @v#.pstate_nom: Nominal pstate
+ * @v#.pstate_turbo: Maximum turbo pstate
+ * @v#.pstate_ultra_turbo: Maximum ultra turbo pstate and the maximum
+ * pstate ever allowed
+ * @v#.pstates: Pstate-id and frequency list from Pmax to Pmin
+ * @v#.pstates.id: Pstate-id
+ * @v#.pstates.flags: Pstate-flag(reserved)
+ * @v2.pstates.vdd: Voltage Identifier
+ * @v2.pstates.vcs: Voltage Identifier
+ * @v#.pstates.freq_khz: Frequency in KHz
+ * @v#.core_max[1..N]: Max pstate with N active cores
+ * @spare/reserved/pad: Unused data
+ */
+struct occ_pstate_table {
+ uint8_t valid;
+ uint8_t version;
+ union QEMU_PACKED {
+ struct QEMU_PACKED { /* Version 0x01 and 0x02 */
+ uint8_t throttle;
+ int8_t pstate_min;
+ int8_t pstate_nom;
+ int8_t pstate_turbo;
+ int8_t pstate_ultra_turbo;
+ uint8_t spare;
+ uint64_t reserved;
+ struct QEMU_PACKED {
+ int8_t id;
+ uint8_t flags;
+ uint8_t vdd;
+ uint8_t vcs;
+ uint32_t freq_khz;
+ } pstates[MAX_PSTATES];
+ int8_t core_max[MAX_P8_CORES];
+ uint8_t pad[100];
+ } v2;
+ struct QEMU_PACKED { /* Version 0x90 */
+ uint8_t occ_role;
+ uint8_t pstate_min;
+ uint8_t pstate_nom;
+ uint8_t pstate_turbo;
+ uint8_t pstate_ultra_turbo;
+ uint8_t spare;
+ uint64_t reserved1;
+ uint64_t reserved2;
+ struct QEMU_PACKED {
+ uint8_t id;
+ uint8_t flags;
+ uint16_t reserved;
+ uint32_t freq_khz;
+ } pstates[MAX_PSTATES];
+ uint8_t core_max[MAX_P9_CORES];
+ uint8_t pad[56];
+ } v9;
+ struct QEMU_PACKED { /* Version 0xA0 */
+ uint8_t occ_role;
+ uint8_t pstate_min;
+ uint8_t pstate_fixed_freq;
+ uint8_t pstate_base;
+ uint8_t pstate_ultra_turbo;
+ uint8_t pstate_fmax;
+ uint8_t minor;
+ uint8_t pstate_bottom_throttle;
+ uint8_t spare;
+ uint8_t spare1;
+ uint32_t reserved_32;
+ uint64_t reserved_64;
+ struct QEMU_PACKED {
+ uint8_t id;
+ uint8_t valid;
+ uint16_t reserved;
+ uint32_t freq_khz;
+ } pstates[MAX_PSTATES];
+ uint8_t core_max[MAX_P10_CORES];
+ uint8_t pad[48];
+ } v10;
+ };
+} QEMU_PACKED;
+
+/**
+ * OPAL-OCC Command Response Interface
+ *
+ * OPAL-OCC Command Buffer
+ *
+ * ---------------------------------------------------------------------
+ * | OPAL | Cmd | OPAL | | Cmd Data | Cmd Data | OPAL |
+ * | Cmd | Request | OCC | Reserved | Length | Length | Cmd |
+ * | Flags | ID | Cmd | | (MSB) | (LSB) | Data... |
+ * ---------------------------------------------------------------------
+ * | ….OPAL Command Data up to max of Cmd Data Length 4090 bytes |
+ * | |
+ * ---------------------------------------------------------------------
+ *
+ * OPAL Command Flag
+ *
+ * -----------------------------------------------------------------
+ * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
+ * | (msb) | | | | | | | (lsb) |
+ * -----------------------------------------------------------------
+ * |Cmd | | | | | | | |
+ * |Ready | | | | | | | |
+ * -----------------------------------------------------------------
+ *
+ * struct opal_command_buffer - Defines the layout of OPAL command buffer
+ * @flag: Provides general status of the command
+ * @request_id: Token to identify request
+ * @cmd: Command sent
+ * @data_size: Command data length
+ * @data: Command specific data
+ * @spare: Unused byte
+ */
+struct opal_command_buffer {
+ uint8_t flag;
+ uint8_t request_id;
+ uint8_t cmd;
+ uint8_t spare;
+ uint16_t data_size;
+ uint8_t data[MAX_OPAL_CMD_DATA_LENGTH];
+} QEMU_PACKED;
+
+/**
+ * OPAL-OCC Response Buffer
+ *
+ * ---------------------------------------------------------------------
+ * | OCC | Cmd | OPAL | Response | Rsp Data | Rsp Data | OPAL |
+ * | Rsp | Request | OCC | Status | Length | Length | Rsp |
+ * | Flags | ID | Cmd | | (MSB) | (LSB) | Data... |
+ * ---------------------------------------------------------------------
+ * | ….OPAL Response Data up to max of Rsp Data Length 8698 bytes |
+ * | |
+ * ---------------------------------------------------------------------
+ *
+ * OCC Response Flag
+ *
+ * -----------------------------------------------------------------
+ * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
+ * | (msb) | | | | | | | (lsb) |
+ * -----------------------------------------------------------------
+ * | | | | | | |OCC in | Rsp |
+ * | | | | | | |progress|Ready |
+ * -----------------------------------------------------------------
+ *
+ * struct occ_response_buffer - Defines the layout of OCC response buffer
+ * @flag: Provides general status of the response
+ * @request_id: Token to identify request
+ * @cmd: Command requested
+ * @status: Indicates success/failure status of
+ * the command
+ * @data_size: Response data length
+ * @data: Response specific data
+ */
+struct occ_response_buffer {
+ uint8_t flag;
+ uint8_t request_id;
+ uint8_t cmd;
+ uint8_t status;
+ uint16_t data_size;
+ uint8_t data[MAX_OCC_RSP_DATA_LENGTH];
+} QEMU_PACKED;
+
+/**
+ * OCC-OPAL Shared Memory Interface Dynamic Data Vx90
+ *
+ * struct occ_dynamic_data - Contains runtime attributes
+ * @occ_state: Current state of OCC
+ * @major_version: Major version number
+ * @minor_version: Minor version number (backwards compatible)
+ * Version 1 indicates GPU presence populated
+ * @gpus_present: Bitmask of GPUs present (on systems where GPU
+ * presence is detected through APSS)
+ * @cpu_throttle: Reason for limiting the max pstate
+ * @mem_throttle: Reason for throttling memory
+ * @quick_pwr_drop: Indicates if QPD is asserted
+ * @pwr_shifting_ratio: Indicates the current percentage of power to
+ * take away from the CPU vs GPU when shifting
+ * power to maintain a power cap. Value of 100
+ * means take all power from CPU.
+ * @pwr_cap_type: Indicates type of power cap in effect
+ * @hard_min_pwr_cap: Hard minimum system power cap in Watts.
+ * Guaranteed unless hardware failure
+ * @max_pwr_cap: Maximum allowed system power cap in Watts
+ * @cur_pwr_cap: Current system power cap
+ * @soft_min_pwr_cap: Soft powercap minimum. OCC may or may not be
+ * able to maintain this
+ * @spare/reserved: Unused data
+ * @cmd: Opal Command Buffer
+ * @rsp: OCC Response Buffer
+ */
+struct occ_dynamic_data {
+ uint8_t occ_state;
+ uint8_t major_version;
+ uint8_t minor_version;
+ uint8_t gpus_present;
+ union QEMU_PACKED {
+ struct QEMU_PACKED { /* Version 0x90 */
+ uint8_t spare1;
+ } v9;
+ struct QEMU_PACKED { /* Version 0xA0 */
+ uint8_t wof_enabled;
+ } v10;
+ };
+ uint8_t cpu_throttle;
+ uint8_t mem_throttle;
+ uint8_t quick_pwr_drop;
+ uint8_t pwr_shifting_ratio;
+ uint8_t pwr_cap_type;
+ uint16_t hard_min_pwr_cap;
+ uint16_t max_pwr_cap;
+ uint16_t cur_pwr_cap;
+ uint16_t soft_min_pwr_cap;
+ uint8_t pad[110];
+ struct opal_command_buffer cmd;
+ struct occ_response_buffer rsp;
+} QEMU_PACKED;
+
+enum occ_response_status {
+ OCC_RSP_SUCCESS = 0x00,
+ OCC_RSP_INVALID_COMMAND = 0x11,
+ OCC_RSP_INVALID_CMD_DATA_LENGTH = 0x12,
+ OCC_RSP_INVALID_DATA = 0x13,
+ OCC_RSP_INTERNAL_ERROR = 0x15,
+};
+
+#define OCC_ROLE_SLAVE 0x00
+#define OCC_ROLE_MASTER 0x01
+
+#define OCC_FLAG_RSP_READY 0x01
+#define OCC_FLAG_CMD_IN_PROGRESS 0x02
+#define OPAL_FLAG_CMD_READY 0x80
+
+#define PCAP_MAX_POWER_W 100
+#define PCAP_SOFT_MIN_POWER_W 20
+#define PCAP_HARD_MIN_POWER_W 10
+
+static bool occ_write_static_data(PnvOCC *occ,
+ struct occ_pstate_table *static_data,
+ Error **errp)
+{
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
+ PnvHomer *homer = occ->homer;
+ hwaddr static_addr = homer->base + poc->opal_shared_memory_offset;
+ MemTxResult ret;
+
+ ret = address_space_write(&address_space_memory, static_addr,
+ MEMTXATTRS_UNSPECIFIED, static_data,
+ sizeof(*static_data));
+ if (ret != MEMTX_OK) {
+ error_setg(errp, "OCC: cannot write OCC-OPAL static data");
+ return false;
+ }
+
+ return true;
+}
+
+static bool occ_read_dynamic_data(PnvOCC *occ,
+ struct occ_dynamic_data *dynamic_data,
+ Error **errp)
+{
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
+ PnvHomer *homer = occ->homer;
+ hwaddr static_addr = homer->base + poc->opal_shared_memory_offset;
+ hwaddr dynamic_addr = static_addr + OPAL_DYNAMIC_DATA_OFFSET;
+ MemTxResult ret;
+
+ ret = address_space_read(&address_space_memory, dynamic_addr,
+ MEMTXATTRS_UNSPECIFIED, dynamic_data,
+ sizeof(*dynamic_data));
+ if (ret != MEMTX_OK) {
+ error_setg(errp, "OCC: cannot read OCC-OPAL dynamic data");
+ return false;
+ }
+
+ return true;
+}
+
+static bool occ_write_dynamic_data(PnvOCC *occ,
+ struct occ_dynamic_data *dynamic_data,
+ Error **errp)
+{
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
+ PnvHomer *homer = occ->homer;
+ hwaddr static_addr = homer->base + poc->opal_shared_memory_offset;
+ hwaddr dynamic_addr = static_addr + OPAL_DYNAMIC_DATA_OFFSET;
+ MemTxResult ret;
+
+ ret = address_space_write(&address_space_memory, dynamic_addr,
+ MEMTXATTRS_UNSPECIFIED, dynamic_data,
+ sizeof(*dynamic_data));
+ if (ret != MEMTX_OK) {
+ error_setg(errp, "OCC: cannot write OCC-OPAL dynamic data");
+ return false;
+ }
+
+ return true;
+}
+
+static bool occ_opal_send_response(PnvOCC *occ,
+ struct occ_dynamic_data *dynamic_data,
+ enum occ_response_status status,
+ uint8_t *data, uint16_t datalen)
+{
+ struct opal_command_buffer *cmd = &dynamic_data->cmd;
+ struct occ_response_buffer *rsp = &dynamic_data->rsp;
+
+ rsp->request_id = cmd->request_id;
+ rsp->cmd = cmd->cmd;
+ rsp->status = status;
+ rsp->data_size = cpu_to_be16(datalen);
+ if (datalen) {
+ memcpy(rsp->data, data, datalen);
+ }
+ if (!occ_write_dynamic_data(occ, dynamic_data, NULL)) {
+ return false;
+ }
+ /* Would be a memory barrier here */
+ rsp->flag = OCC_FLAG_RSP_READY;
+ cmd->flag = 0;
+ if (!occ_write_dynamic_data(occ, dynamic_data, NULL)) {
+ return false;
+ }
+
+ pnv_occ_raise_msg_irq(occ);
+
+ return true;
+}
+
+/* Returns error status */
+static bool occ_opal_process_command(PnvOCC *occ,
+ struct occ_dynamic_data *dynamic_data)
+{
+ struct opal_command_buffer *cmd = &dynamic_data->cmd;
+ struct occ_response_buffer *rsp = &dynamic_data->rsp;
+
+ if (rsp->flag == 0) {
+ /* Spend one "tick" in the in-progress state */
+ rsp->flag = OCC_FLAG_CMD_IN_PROGRESS;
+ return occ_write_dynamic_data(occ, dynamic_data, NULL);
+ } else if (rsp->flag != OCC_FLAG_CMD_IN_PROGRESS) {
+ return occ_opal_send_response(occ, dynamic_data,
+ OCC_RSP_INTERNAL_ERROR,
+ NULL, 0);
+ }
+
+ switch (cmd->cmd) {
+ case 0xD1: { /* SET_POWER_CAP */
+ uint16_t data;
+ if (be16_to_cpu(cmd->data_size) != 2) {
+ return occ_opal_send_response(occ, dynamic_data,
+ OCC_RSP_INVALID_CMD_DATA_LENGTH,
+ (uint8_t *)&dynamic_data->cur_pwr_cap,
+ 2);
+ }
+ data = be16_to_cpu(*(uint16_t *)cmd->data);
+ if (data == 0) { /* clear power cap */
+ dynamic_data->pwr_cap_type = 0x00; /* none */
+ data = PCAP_MAX_POWER_W;
+ } else {
+ dynamic_data->pwr_cap_type = 0x02; /* user set in-band */
+ if (data < PCAP_HARD_MIN_POWER_W) {
+ data = PCAP_HARD_MIN_POWER_W;
+ } else if (data > PCAP_MAX_POWER_W) {
+ data = PCAP_MAX_POWER_W;
+ }
+ }
+ dynamic_data->cur_pwr_cap = cpu_to_be16(data);
+ return occ_opal_send_response(occ, dynamic_data,
+ OCC_RSP_SUCCESS,
+ (uint8_t *)&dynamic_data->cur_pwr_cap, 2);
+ }
+
+ default:
+ return occ_opal_send_response(occ, dynamic_data,
+ OCC_RSP_INVALID_COMMAND,
+ NULL, 0);
+ }
+ g_assert_not_reached();
+}
+
+static bool occ_model_tick(PnvOCC *occ)
+{
+ QEMU_UNINITIALIZED struct occ_dynamic_data dynamic_data;
+
+ if (!occ_read_dynamic_data(occ, &dynamic_data, NULL)) {
+ /* Can't move OCC state field to safe because we can't map it! */
+ qemu_log("OCC: failed to read HOMER data, shutting down OCC\n");
+ return false;
+ }
+ if (dynamic_data.cmd.flag == OPAL_FLAG_CMD_READY) {
+ if (!occ_opal_process_command(occ, &dynamic_data)) {
+ qemu_log("OCC: failed to write HOMER data, shutting down OCC\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool occ_init_homer_memory(PnvOCC *occ, Error **errp)
+{
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
+ PnvHomer *homer = occ->homer;
+ PnvChip *chip = homer->chip;
+ struct occ_pstate_table static_data;
+ struct occ_dynamic_data dynamic_data;
+ int i;
+
+ memset(&static_data, 0, sizeof(static_data));
+ static_data.valid = 1;
+ static_data.version = poc->opal_shared_memory_version;
+ switch (poc->opal_shared_memory_version) {
+ case 0x02:
+ static_data.v2.throttle = 0;
+ static_data.v2.pstate_min = -2;
+ static_data.v2.pstate_nom = -1;
+ static_data.v2.pstate_turbo = -1;
+ static_data.v2.pstate_ultra_turbo = 0;
+ static_data.v2.pstates[0].id = 0;
+ static_data.v2.pstates[1].freq_khz = cpu_to_be32(4000000);
+ static_data.v2.pstates[1].id = -1;
+ static_data.v2.pstates[1].freq_khz = cpu_to_be32(3000000);
+ static_data.v2.pstates[2].id = -2;
+ static_data.v2.pstates[2].freq_khz = cpu_to_be32(2000000);
+ for (i = 0; i < chip->nr_cores; i++) {
+ static_data.v2.core_max[i] = 1;
+ }
+ break;
+ case 0x90:
+ if (chip->chip_id == 0) {
+ static_data.v9.occ_role = OCC_ROLE_MASTER;
+ } else {
+ static_data.v9.occ_role = OCC_ROLE_SLAVE;
+ }
+ static_data.v9.pstate_min = 2;
+ static_data.v9.pstate_nom = 1;
+ static_data.v9.pstate_turbo = 1;
+ static_data.v9.pstate_ultra_turbo = 0;
+ static_data.v9.pstates[0].id = 0;
+ static_data.v9.pstates[0].freq_khz = cpu_to_be32(4000000);
+ static_data.v9.pstates[1].id = 1;
+ static_data.v9.pstates[1].freq_khz = cpu_to_be32(3000000);
+ static_data.v9.pstates[2].id = 2;
+ static_data.v9.pstates[2].freq_khz = cpu_to_be32(2000000);
+ for (i = 0; i < chip->nr_cores; i++) {
+ static_data.v9.core_max[i] = 1;
+ }
+ break;
+ case 0xA0:
+ if (chip->chip_id == 0) {
+ static_data.v10.occ_role = OCC_ROLE_MASTER;
+ } else {
+ static_data.v10.occ_role = OCC_ROLE_SLAVE;
+ }
+ static_data.v10.pstate_min = 4;
+ static_data.v10.pstate_fixed_freq = 3;
+ static_data.v10.pstate_base = 2;
+ static_data.v10.pstate_ultra_turbo = 0;
+ static_data.v10.pstate_fmax = 1;
+ static_data.v10.minor = 0x01;
+ static_data.v10.pstates[0].valid = 1;
+ static_data.v10.pstates[0].id = 0;
+ static_data.v10.pstates[0].freq_khz = cpu_to_be32(4200000);
+ static_data.v10.pstates[1].valid = 1;
+ static_data.v10.pstates[1].id = 1;
+ static_data.v10.pstates[1].freq_khz = cpu_to_be32(4000000);
+ static_data.v10.pstates[2].valid = 1;
+ static_data.v10.pstates[2].id = 2;
+ static_data.v10.pstates[2].freq_khz = cpu_to_be32(3800000);
+ static_data.v10.pstates[3].valid = 1;
+ static_data.v10.pstates[3].id = 3;
+ static_data.v10.pstates[3].freq_khz = cpu_to_be32(3000000);
+ static_data.v10.pstates[4].valid = 1;
+ static_data.v10.pstates[4].id = 4;
+ static_data.v10.pstates[4].freq_khz = cpu_to_be32(2000000);
+ for (i = 0; i < chip->nr_cores; i++) {
+ static_data.v10.core_max[i] = 1;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ if (!occ_write_static_data(occ, &static_data, errp)) {
+ return false;
+ }
+
+ memset(&dynamic_data, 0, sizeof(dynamic_data));
+ dynamic_data.occ_state = 0x3; /* active */
+ dynamic_data.major_version = 0x0;
+ dynamic_data.hard_min_pwr_cap = cpu_to_be16(PCAP_HARD_MIN_POWER_W);
+ dynamic_data.max_pwr_cap = cpu_to_be16(PCAP_MAX_POWER_W);
+ dynamic_data.cur_pwr_cap = cpu_to_be16(PCAP_MAX_POWER_W);
+ dynamic_data.soft_min_pwr_cap = cpu_to_be16(PCAP_SOFT_MIN_POWER_W);
+ switch (poc->opal_shared_memory_version) {
+ case 0xA0:
+ dynamic_data.minor_version = 0x1;
+ dynamic_data.v10.wof_enabled = 0x1;
+ break;
+ case 0x90:
+ dynamic_data.minor_version = 0x1;
+ break;
+ case 0x02:
+ dynamic_data.minor_version = 0x0;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ if (!occ_write_dynamic_data(occ, &dynamic_data, errp)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c
index 6280408..af7cfd0 100644
--- a/hw/ppc/pnv_pnor.c
+++ b/hw/ppc/pnv_pnor.c
@@ -11,8 +11,8 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/units.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
#include "hw/loader.h"
#include "hw/ppc/pnv_pnor.h"
#include "hw/qdev-properties.h"
@@ -108,17 +108,18 @@ static void pnv_pnor_realize(DeviceState *dev, Error **errp)
memset(s->storage, 0xFF, s->size);
}
+ s->lpc_address = PNOR_SPI_OFFSET;
+
memory_region_init_io(&s->mmio, OBJECT(s), &pnv_pnor_ops, s,
TYPE_PNV_PNOR, s->size);
}
-static Property pnv_pnor_properties[] = {
+static const Property pnv_pnor_properties[] = {
DEFINE_PROP_INT64("size", PnvPnor, size, 128 * MiB),
DEFINE_PROP_DRIVE("drive", PnvPnor, blk),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_pnor_class_init(ObjectClass *klass, void *data)
+static void pnv_pnor_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 18cc76a..5d947d8 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -18,12 +18,12 @@
*/
#include "qemu/osdep.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/irq.h"
#include "target/ppc/cpu.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "qapi/error.h"
@@ -552,13 +552,12 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
return 0;
}
-static Property pnv_psi_properties[] = {
+static const Property pnv_psi_properties[] = {
DEFINE_PROP_UINT64("bar", PnvPsi, bar, 0),
DEFINE_PROP_UINT64("fsp-bar", PnvPsi, fsp_bar, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pnv_psi_power8_class_init(ObjectClass *klass, void *data)
+static void pnv_psi_power8_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
@@ -888,7 +887,7 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
pnv_psi_realize(dev, errp);
}
-static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
+static void pnv_psi_power9_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
@@ -897,7 +896,7 @@ static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV PSI Controller POWER9";
dc->realize = pnv_psi_power9_realize;
- dc->reset = pnv_psi_power9_reset;
+ device_class_set_legacy_reset(dc, pnv_psi_power9_reset);
ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
@@ -914,13 +913,13 @@ static const TypeInfo pnv_psi_power9_info = {
.instance_size = sizeof(Pnv9Psi),
.instance_init = pnv_psi_power9_instance_init,
.class_init = pnv_psi_power9_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_XIVE_NOTIFIER },
{ },
},
};
-static void pnv_psi_power10_class_init(ObjectClass *klass, void *data)
+static void pnv_psi_power10_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
@@ -940,7 +939,7 @@ static const TypeInfo pnv_psi_power10_info = {
.class_init = pnv_psi_power10_class_init,
};
-static void pnv_psi_class_init(ObjectClass *klass, void *data)
+static void pnv_psi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -949,7 +948,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV PSI Controller";
device_class_set_props(dc, pnv_psi_properties);
- dc->reset = pnv_psi_reset;
+ device_class_set_legacy_reset(dc, pnv_psi_reset);
dc->user_creatable = false;
}
@@ -960,7 +959,7 @@ static const TypeInfo pnv_psi_info = {
.class_init = pnv_psi_class_init,
.class_size = sizeof(PnvPsiClass),
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/ppc/pnv_sbe.c b/hw/ppc/pnv_sbe.c
index 74cee4e..34dc013 100644
--- a/hw/ppc/pnv_sbe.c
+++ b/hw/ppc/pnv_sbe.c
@@ -331,7 +331,7 @@ static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_sbe_power9_class_init(ObjectClass *klass, void *data)
+static void pnv_sbe_power9_class_init(ObjectClass *klass, const void *data)
{
PnvSBEClass *psc = PNV_SBE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -350,7 +350,7 @@ static const TypeInfo pnv_sbe_power9_type_info = {
.class_init = pnv_sbe_power9_class_init,
};
-static void pnv_sbe_power10_class_init(ObjectClass *klass, void *data)
+static void pnv_sbe_power10_class_init(ObjectClass *klass, const void *data)
{
PnvSBEClass *psc = PNV_SBE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -386,7 +386,7 @@ static void pnv_sbe_realize(DeviceState *dev, Error **errp)
sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe);
}
-static void pnv_sbe_class_init(ObjectClass *klass, void *data)
+static void pnv_sbe_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index d192bbe..fbfec82 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/hw_accel.h"
+#include "system/hw_accel.h"
#include "target/ppc/cpu.h"
#include "hw/sysbus.h"
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index e6fa558..43d0d0e 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -27,13 +27,14 @@
#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc_e500.h"
#include "qemu/timer.h"
-#include "sysemu/cpus.h"
+#include "exec/cpu-interrupt.h"
+#include "system/cpus.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "sysemu/replay.h"
-#include "sysemu/runstate.h"
+#include "system/kvm.h"
+#include "system/replay.h"
+#include "system/runstate.h"
#include "kvm_ppc.h"
#include "migration/vmstate.h"
#include "trace.h"
@@ -267,7 +268,6 @@ static void power9_set_irq(void *opaque, int pin, int level)
break;
default:
g_assert_not_reached();
- return;
}
}
@@ -729,7 +729,9 @@ static inline int64_t __cpu_ppc_load_decr(CPUPPCState *env, int64_t now,
int64_t decr;
n = ns_to_tb(tb_env->decr_freq, now);
- if (next > n && tb_env->flags & PPC_TIMER_BOOKE) {
+
+ /* BookE timers stop when reaching 0. */
+ if (next < n && tb_env->flags & PPC_TIMER_BOOKE) {
decr = 0;
} else {
decr = next - n;
@@ -1122,16 +1124,21 @@ void cpu_ppc_tb_reset(CPUPPCState *env)
timer_del(tb_env->hdecr_timer);
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
tb_env->hdecr_next = 0;
+ _cpu_ppc_store_hdecr(cpu, 0, 0, 0, 64);
}
/*
* There is a bug in Linux 2.4 kernels:
* if a decrementer exception is pending when it enables msr_ee at startup,
* it's not ready to handle it...
+ *
+ * On machine reset, this is called before icount is reset, so for
+ * icount-mode, setting TB registers using now == qemu_clock_get_ns()
+ * results in them being garbage after icount is reset. Use an
+ * explicit now == 0 to get a consistent reset state.
*/
- cpu_ppc_store_decr(env, -1);
- cpu_ppc_store_hdecr(env, -1);
- cpu_ppc_store_purr(env, 0x0000000000000000ULL);
+ _cpu_ppc_store_decr(cpu, 0, 0, -1, 64);
+ _cpu_ppc_store_purr(env, 0, 0);
}
void cpu_ppc_tb_free(CPUPPCState *env)
diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h
deleted file mode 100644
index 9a43126..0000000
--- a/hw/ppc/ppc405.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * QEMU PowerPC 405 shared definitions
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef PPC405_H
-#define PPC405_H
-
-#include "qom/object.h"
-#include "hw/ppc/ppc4xx.h"
-#include "hw/intc/ppc-uic.h"
-#include "hw/i2c/ppc4xx_i2c.h"
-
-/* PLB to OPB bridge */
-#define TYPE_PPC405_POB "ppc405-pob"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405PobState, PPC405_POB);
-struct Ppc405PobState {
- Ppc4xxDcrDeviceState parent_obj;
-
- uint32_t bear;
- uint32_t besr0;
- uint32_t besr1;
-};
-
-/* OPB arbitrer */
-#define TYPE_PPC405_OPBA "ppc405-opba"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405OpbaState, PPC405_OPBA);
-struct Ppc405OpbaState {
- SysBusDevice parent_obj;
-
- MemoryRegion io;
- uint8_t cr;
- uint8_t pr;
-};
-
-/* DMA controller */
-#define TYPE_PPC405_DMA "ppc405-dma"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405DmaState, PPC405_DMA);
-struct Ppc405DmaState {
- Ppc4xxDcrDeviceState parent_obj;
-
- qemu_irq irqs[4];
- uint32_t cr[4];
- uint32_t ct[4];
- uint32_t da[4];
- uint32_t sa[4];
- uint32_t sg[4];
- uint32_t sr;
- uint32_t sgc;
- uint32_t slp;
- uint32_t pol;
-};
-
-/* GPIO */
-#define TYPE_PPC405_GPIO "ppc405-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405GpioState, PPC405_GPIO);
-struct Ppc405GpioState {
- SysBusDevice parent_obj;
-
- MemoryRegion io;
- uint32_t or;
- uint32_t tcr;
- uint32_t osrh;
- uint32_t osrl;
- uint32_t tsrh;
- uint32_t tsrl;
- uint32_t odr;
- uint32_t ir;
- uint32_t rr1;
- uint32_t isr1h;
- uint32_t isr1l;
-};
-
-/* On Chip Memory */
-#define TYPE_PPC405_OCM "ppc405-ocm"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405OcmState, PPC405_OCM);
-struct Ppc405OcmState {
- Ppc4xxDcrDeviceState parent_obj;
-
- MemoryRegion ram;
- MemoryRegion isarc_ram;
- MemoryRegion dsarc_ram;
- uint32_t isarc;
- uint32_t isacntl;
- uint32_t dsarc;
- uint32_t dsacntl;
-};
-
-/* General purpose timers */
-#define TYPE_PPC405_GPT "ppc405-gpt"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405GptState, PPC405_GPT);
-struct Ppc405GptState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- int64_t tb_offset;
- uint32_t tb_freq;
- QEMUTimer *timer;
- qemu_irq irqs[5];
- uint32_t oe;
- uint32_t ol;
- uint32_t im;
- uint32_t is;
- uint32_t ie;
- uint32_t comp[5];
- uint32_t mask[5];
-};
-
-#define TYPE_PPC405_CPC "ppc405-cpc"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405CpcState, PPC405_CPC);
-
-enum {
- PPC405EP_CPU_CLK = 0,
- PPC405EP_PLB_CLK = 1,
- PPC405EP_OPB_CLK = 2,
- PPC405EP_EBC_CLK = 3,
- PPC405EP_MAL_CLK = 4,
- PPC405EP_PCI_CLK = 5,
- PPC405EP_UART0_CLK = 6,
- PPC405EP_UART1_CLK = 7,
- PPC405EP_CLK_NB = 8,
-};
-
-struct Ppc405CpcState {
- Ppc4xxDcrDeviceState parent_obj;
-
- uint32_t sysclk;
- clk_setup_t clk_setup[PPC405EP_CLK_NB];
- uint32_t boot;
- uint32_t epctl;
- uint32_t pllmr[2];
- uint32_t ucr;
- uint32_t srr;
- uint32_t jtagid;
- uint32_t pci;
- /* Clock and power management */
- uint32_t er;
- uint32_t fr;
- uint32_t sr;
-};
-
-#define TYPE_PPC405_SOC "ppc405-soc"
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405SoCState, PPC405_SOC);
-
-struct Ppc405SoCState {
- /* Private */
- DeviceState parent_obj;
-
- /* Public */
- PowerPCCPU cpu;
- PPCUIC uic;
- Ppc405CpcState cpc;
- Ppc405GptState gpt;
- Ppc405OcmState ocm;
- Ppc405GpioState gpio;
- Ppc405DmaState dma;
- PPC4xxI2CState i2c;
- Ppc4xxEbcState ebc;
- Ppc405OpbaState opba;
- Ppc405PobState pob;
- Ppc4xxPlbState plb;
- Ppc4xxMalState mal;
- Ppc4xxSdramDdrState sdram;
-};
-
-#endif /* PPC405_H */
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
deleted file mode 100644
index c44e7ed..0000000
--- a/hw/ppc/ppc405_boards.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * QEMU PowerPC 405 evaluation boards emulation
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "qapi/error.h"
-#include "qemu/datadir.h"
-#include "cpu.h"
-#include "hw/ppc/ppc.h"
-#include "hw/qdev-properties.h"
-#include "hw/sysbus.h"
-#include "ppc405.h"
-#include "hw/rtc/m48t59.h"
-#include "hw/block/flash.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/block-backend.h"
-#include "hw/boards.h"
-#include "qemu/error-report.h"
-#include "hw/loader.h"
-#include "qemu/cutils.h"
-#include "elf.h"
-
-#define BIOS_FILENAME "ppc405_rom.bin"
-#define BIOS_SIZE (2 * MiB)
-
-#define KERNEL_LOAD_ADDR 0x01000000
-#define INITRD_LOAD_ADDR 0x01800000
-
-#define PPC405EP_SDRAM_BASE 0x00000000
-#define PPC405EP_SRAM_BASE 0xFFF00000
-#define PPC405EP_SRAM_SIZE (512 * KiB)
-
-#define USE_FLASH_BIOS
-
-#define TYPE_PPC405_MACHINE MACHINE_TYPE_NAME("ppc405")
-OBJECT_DECLARE_SIMPLE_TYPE(Ppc405MachineState, PPC405_MACHINE);
-
-struct Ppc405MachineState {
- /* Private */
- MachineState parent_obj;
- /* Public */
-
- Ppc405SoCState soc;
-};
-
-/* CPU reset handler when booting directly from a loaded kernel */
-static struct boot_info {
- uint32_t entry;
- uint32_t bdloc;
- uint32_t initrd_base;
- uint32_t initrd_size;
- uint32_t cmdline_base;
- uint32_t cmdline_size;
-} boot_info;
-
-static void main_cpu_reset(void *opaque)
-{
- PowerPCCPU *cpu = opaque;
- CPUPPCState *env = &cpu->env;
- struct boot_info *bi = env->load_info;
-
- cpu_reset(CPU(cpu));
-
- /* stack: top of sram */
- env->gpr[1] = PPC405EP_SRAM_BASE + PPC405EP_SRAM_SIZE - 8;
-
- /* Tune our boot state */
- env->gpr[3] = bi->bdloc;
- env->gpr[4] = bi->initrd_base;
- env->gpr[5] = bi->initrd_base + bi->initrd_size;
- env->gpr[6] = bi->cmdline_base;
- env->gpr[7] = bi->cmdline_size;
-
- env->nip = bi->entry;
-}
-
-/* Bootinfo as set-up by u-boot */
-typedef struct {
- uint32_t bi_memstart;
- uint32_t bi_memsize;
- uint32_t bi_flashstart;
- uint32_t bi_flashsize;
- uint32_t bi_flashoffset; /* 0x10 */
- uint32_t bi_sramstart;
- uint32_t bi_sramsize;
- uint32_t bi_bootflags;
- uint32_t bi_ipaddr; /* 0x20 */
- uint8_t bi_enetaddr[6];
- uint16_t bi_ethspeed;
- uint32_t bi_intfreq;
- uint32_t bi_busfreq; /* 0x30 */
- uint32_t bi_baudrate;
- uint8_t bi_s_version[4];
- uint8_t bi_r_version[32];
- uint32_t bi_procfreq;
- uint32_t bi_plb_busfreq;
- uint32_t bi_pci_busfreq;
- uint8_t bi_pci_enetaddr[6];
- uint8_t bi_pci_enetaddr2[6]; /* PPC405EP specific */
- uint32_t bi_opbfreq;
- uint32_t bi_iic_fast[2];
-} ppc4xx_bd_info_t;
-
-static void ppc405_set_default_bootinfo(ppc4xx_bd_info_t *bd,
- ram_addr_t ram_size)
-{
- memset(bd, 0, sizeof(*bd));
-
- bd->bi_memstart = PPC405EP_SDRAM_BASE;
- bd->bi_memsize = ram_size;
- bd->bi_sramstart = PPC405EP_SRAM_BASE;
- bd->bi_sramsize = PPC405EP_SRAM_SIZE;
- bd->bi_bootflags = 0;
- bd->bi_intfreq = 133333333;
- bd->bi_busfreq = 33333333;
- bd->bi_baudrate = 115200;
- bd->bi_s_version[0] = 'Q';
- bd->bi_s_version[1] = 'M';
- bd->bi_s_version[2] = 'U';
- bd->bi_s_version[3] = '\0';
- bd->bi_r_version[0] = 'Q';
- bd->bi_r_version[1] = 'E';
- bd->bi_r_version[2] = 'M';
- bd->bi_r_version[3] = 'U';
- bd->bi_r_version[4] = '\0';
- bd->bi_procfreq = 133333333;
- bd->bi_plb_busfreq = 33333333;
- bd->bi_pci_busfreq = 33333333;
- bd->bi_opbfreq = 33333333;
-}
-
-static ram_addr_t __ppc405_set_bootinfo(CPUPPCState *env, ppc4xx_bd_info_t *bd)
-{
- CPUState *cs = env_cpu(env);
- ram_addr_t bdloc;
- int i, n;
-
- /* We put the bd structure at the top of memory */
- if (bd->bi_memsize >= 0x01000000UL) {
- bdloc = 0x01000000UL - sizeof(ppc4xx_bd_info_t);
- } else {
- bdloc = bd->bi_memsize - sizeof(ppc4xx_bd_info_t);
- }
- stl_be_phys(cs->as, bdloc + 0x00, bd->bi_memstart);
- stl_be_phys(cs->as, bdloc + 0x04, bd->bi_memsize);
- stl_be_phys(cs->as, bdloc + 0x08, bd->bi_flashstart);
- stl_be_phys(cs->as, bdloc + 0x0C, bd->bi_flashsize);
- stl_be_phys(cs->as, bdloc + 0x10, bd->bi_flashoffset);
- stl_be_phys(cs->as, bdloc + 0x14, bd->bi_sramstart);
- stl_be_phys(cs->as, bdloc + 0x18, bd->bi_sramsize);
- stl_be_phys(cs->as, bdloc + 0x1C, bd->bi_bootflags);
- stl_be_phys(cs->as, bdloc + 0x20, bd->bi_ipaddr);
- for (i = 0; i < 6; i++) {
- stb_phys(cs->as, bdloc + 0x24 + i, bd->bi_enetaddr[i]);
- }
- stw_be_phys(cs->as, bdloc + 0x2A, bd->bi_ethspeed);
- stl_be_phys(cs->as, bdloc + 0x2C, bd->bi_intfreq);
- stl_be_phys(cs->as, bdloc + 0x30, bd->bi_busfreq);
- stl_be_phys(cs->as, bdloc + 0x34, bd->bi_baudrate);
- for (i = 0; i < 4; i++) {
- stb_phys(cs->as, bdloc + 0x38 + i, bd->bi_s_version[i]);
- }
- for (i = 0; i < 32; i++) {
- stb_phys(cs->as, bdloc + 0x3C + i, bd->bi_r_version[i]);
- }
- stl_be_phys(cs->as, bdloc + 0x5C, bd->bi_procfreq);
- stl_be_phys(cs->as, bdloc + 0x60, bd->bi_plb_busfreq);
- stl_be_phys(cs->as, bdloc + 0x64, bd->bi_pci_busfreq);
- for (i = 0; i < 6; i++) {
- stb_phys(cs->as, bdloc + 0x68 + i, bd->bi_pci_enetaddr[i]);
- }
- n = 0x70; /* includes 2 bytes hole */
- for (i = 0; i < 6; i++) {
- stb_phys(cs->as, bdloc + n++, bd->bi_pci_enetaddr2[i]);
- }
- stl_be_phys(cs->as, bdloc + n, bd->bi_opbfreq);
- n += 4;
- for (i = 0; i < 2; i++) {
- stl_be_phys(cs->as, bdloc + n, bd->bi_iic_fast[i]);
- n += 4;
- }
-
- return bdloc;
-}
-
-static ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size)
-{
- ppc4xx_bd_info_t bd;
-
- memset(&bd, 0, sizeof(bd));
-
- ppc405_set_default_bootinfo(&bd, ram_size);
-
- return __ppc405_set_bootinfo(env, &bd);
-}
-
-static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- hwaddr boot_entry;
- hwaddr kernel_base;
- int kernel_size;
- hwaddr initrd_base;
- int initrd_size;
- ram_addr_t bdloc;
- int len;
-
- bdloc = ppc405_set_bootinfo(env, machine->ram_size);
- boot_info.bdloc = bdloc;
-
- kernel_size = load_elf(machine->kernel_filename, NULL, NULL, NULL,
- &boot_entry, &kernel_base, NULL, NULL,
- 1, PPC_ELF_MACHINE, 0, 0);
- if (kernel_size < 0) {
- error_report("Could not load kernel '%s' : %s",
- machine->kernel_filename, load_elf_strerror(kernel_size));
- exit(1);
- }
- boot_info.entry = boot_entry;
-
- /* load initrd */
- if (machine->initrd_filename) {
- initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
- machine->ram_size - initrd_base);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- machine->initrd_filename);
- exit(1);
- }
-
- boot_info.initrd_base = initrd_base;
- boot_info.initrd_size = initrd_size;
- }
-
- if (machine->kernel_cmdline) {
- len = strlen(machine->kernel_cmdline);
- bdloc -= ((len + 255) & ~255);
- cpu_physical_memory_write(bdloc, machine->kernel_cmdline, len + 1);
- boot_info.cmdline_base = bdloc;
- boot_info.cmdline_size = bdloc + len;
- }
-
- /* Install our custom reset handler to start from Linux */
- qemu_register_reset(main_cpu_reset, cpu);
- env->load_info = &boot_info;
-}
-
-static void ppc405_init(MachineState *machine)
-{
- Ppc405MachineState *ppc405 = PPC405_MACHINE(machine);
- const char *kernel_filename = machine->kernel_filename;
- MemoryRegion *sysmem = get_system_memory();
-
- object_initialize_child(OBJECT(machine), "soc", &ppc405->soc,
- TYPE_PPC405_SOC);
- object_property_set_link(OBJECT(&ppc405->soc), "dram",
- OBJECT(machine->ram), &error_abort);
- object_property_set_uint(OBJECT(&ppc405->soc), "sys-clk", 33333333,
- &error_abort);
- qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal);
-
- /* allocate and load BIOS */
- if (machine->firmware) {
- MemoryRegion *bios = g_new(MemoryRegion, 1);
- g_autofree char *filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
- machine->firmware);
- long bios_size;
-
- memory_region_init_rom(bios, NULL, "ef405ep.bios", BIOS_SIZE,
- &error_fatal);
-
- if (!filename) {
- error_report("Could not find firmware '%s'", machine->firmware);
- exit(1);
- }
-
- bios_size = load_image_size(filename,
- memory_region_get_ram_ptr(bios),
- BIOS_SIZE);
- if (bios_size < 0) {
- error_report("Could not load PowerPC BIOS '%s'", machine->firmware);
- exit(1);
- }
-
- bios_size = (bios_size + 0xfff) & ~0xfff;
- memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
- }
-
- /* Load kernel and initrd using U-Boot images */
- if (kernel_filename && machine->firmware) {
- target_ulong kernel_base, initrd_base;
- long kernel_size, initrd_size;
-
- kernel_base = KERNEL_LOAD_ADDR;
- kernel_size = load_image_targphys(kernel_filename, kernel_base,
- machine->ram_size - kernel_base);
- if (kernel_size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- if (machine->initrd_filename) {
- initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image_targphys(machine->initrd_filename,
- initrd_base,
- machine->ram_size - initrd_base);
- if (initrd_size < 0) {
- error_report("could not load initial ram disk '%s'",
- machine->initrd_filename);
- exit(1);
- }
- }
-
- /* Load ELF kernel and rootfs.cpio */
- } else if (kernel_filename && !machine->firmware) {
- ppc4xx_sdram_ddr_enable(&ppc405->soc.sdram);
- boot_from_kernel(machine, &ppc405->soc.cpu);
- }
-}
-
-static void ppc405_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "PPC405 generic machine";
- mc->init = ppc405_init;
- mc->default_ram_size = 128 * MiB;
- mc->default_ram_id = "ppc405.ram";
- mc->deprecation_reason = "machine is old and unmaintained";
-}
-
-static const TypeInfo ppc405_machine_type = {
- .name = TYPE_PPC405_MACHINE,
- .parent = TYPE_MACHINE,
- .instance_size = sizeof(Ppc405MachineState),
- .class_init = ppc405_machine_class_init,
- .abstract = true,
-};
-
-/*****************************************************************************/
-/* PPC405EP reference board (IBM) */
-/*
- * Standalone board with:
- * - PowerPC 405EP CPU
- * - SDRAM (0x00000000)
- * - Flash (0xFFF80000)
- * - SRAM (0xFFF00000)
- * - NVRAM (0xF0000000)
- * - FPGA (0xF0300000)
- */
-
-#define PPC405EP_NVRAM_BASE 0xF0000000
-#define PPC405EP_FPGA_BASE 0xF0300000
-#define PPC405EP_FLASH_BASE 0xFFF80000
-
-#define TYPE_REF405EP_FPGA "ref405ep-fpga"
-OBJECT_DECLARE_SIMPLE_TYPE(Ref405epFpgaState, REF405EP_FPGA);
-struct Ref405epFpgaState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- uint8_t reg0;
- uint8_t reg1;
-};
-
-static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size)
-{
- Ref405epFpgaState *fpga = opaque;
- uint32_t ret;
-
- switch (addr) {
- case 0x0:
- ret = fpga->reg0;
- break;
- case 0x1:
- ret = fpga->reg1;
- break;
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- Ref405epFpgaState *fpga = opaque;
-
- switch (addr) {
- case 0x0:
- /* Read only */
- break;
- case 0x1:
- fpga->reg1 = value;
- break;
- default:
- break;
- }
-}
-
-static const MemoryRegionOps ref405ep_fpga_ops = {
- .read = ref405ep_fpga_readb,
- .write = ref405ep_fpga_writeb,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static void ref405ep_fpga_reset(DeviceState *dev)
-{
- Ref405epFpgaState *fpga = REF405EP_FPGA(dev);
-
- fpga->reg0 = 0x00;
- fpga->reg1 = 0x0F;
-}
-
-static void ref405ep_fpga_realize(DeviceState *dev, Error **errp)
-{
- Ref405epFpgaState *s = REF405EP_FPGA(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &ref405ep_fpga_ops, s,
- "fpga", 0x00000100);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
-}
-
-static void ref405ep_fpga_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ref405ep_fpga_realize;
- dc->reset = ref405ep_fpga_reset;
- /* Reason: only works as part of a ppc405 board */
- dc->user_creatable = false;
-}
-
-static const TypeInfo ref405ep_fpga_type = {
- .name = TYPE_REF405EP_FPGA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Ref405epFpgaState),
- .class_init = ref405ep_fpga_class_init,
-};
-
-static void ref405ep_init(MachineState *machine)
-{
- DeviceState *dev;
- SysBusDevice *s;
- MemoryRegion *sram = g_new(MemoryRegion, 1);
-
- ppc405_init(machine);
-
- /* allocate SRAM */
- memory_region_init_ram(sram, NULL, "ref405ep.sram", PPC405EP_SRAM_SIZE,
- &error_fatal);
- memory_region_add_subregion(get_system_memory(), PPC405EP_SRAM_BASE, sram);
-
- /* Register FPGA */
- dev = qdev_new(TYPE_REF405EP_FPGA);
- object_property_add_child(OBJECT(machine), "fpga", OBJECT(dev));
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, PPC405EP_FPGA_BASE);
-
- /* Register NVRAM */
- dev = qdev_new("sysbus-m48t08");
- qdev_prop_set_int32(dev, "base-year", 1968);
- s = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, PPC405EP_NVRAM_BASE);
-}
-
-static void ref405ep_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "ref405ep";
- mc->init = ref405ep_init;
-}
-
-static const TypeInfo ref405ep_type = {
- .name = MACHINE_TYPE_NAME("ref405ep"),
- .parent = TYPE_PPC405_MACHINE,
- .class_init = ref405ep_class_init,
-};
-
-static void ppc405_machine_init(void)
-{
- type_register_static(&ppc405_machine_type);
- type_register_static(&ref405ep_type);
- type_register_static(&ref405ep_fpga_type);
-}
-
-type_init(ppc405_machine_init)
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
deleted file mode 100644
index 0cc6817..0000000
--- a/hw/ppc/ppc405_uc.c
+++ /dev/null
@@ -1,1217 +0,0 @@
-/*
- * QEMU PowerPC 405 embedded processors emulation
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-#include "cpu.h"
-#include "hw/ppc/ppc.h"
-#include "hw/i2c/ppc4xx_i2c.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "ppc405.h"
-#include "hw/char/serial.h"
-#include "qemu/timer.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-#include "hw/intc/ppc-uic.h"
-#include "trace.h"
-
-/*****************************************************************************/
-/* Shared peripherals */
-
-/*****************************************************************************/
-/* PLB to OPB bridge */
-enum {
- POB0_BESR0 = 0x0A0,
- POB0_BESR1 = 0x0A2,
- POB0_BEAR = 0x0A4,
-};
-
-static uint32_t dcr_read_pob(void *opaque, int dcrn)
-{
- Ppc405PobState *pob = opaque;
- uint32_t ret;
-
- switch (dcrn) {
- case POB0_BEAR:
- ret = pob->bear;
- break;
- case POB0_BESR0:
- ret = pob->besr0;
- break;
- case POB0_BESR1:
- ret = pob->besr1;
- break;
- default:
- /* Avoid gcc warning */
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_pob(void *opaque, int dcrn, uint32_t val)
-{
- Ppc405PobState *pob = opaque;
-
- switch (dcrn) {
- case POB0_BEAR:
- /* Read only */
- break;
- case POB0_BESR0:
- /* Write-clear */
- pob->besr0 &= ~val;
- break;
- case POB0_BESR1:
- /* Write-clear */
- pob->besr1 &= ~val;
- break;
- }
-}
-
-static void ppc405_pob_reset(DeviceState *dev)
-{
- Ppc405PobState *pob = PPC405_POB(dev);
-
- /* No error */
- pob->bear = 0x00000000;
- pob->besr0 = 0x0000000;
- pob->besr1 = 0x0000000;
-}
-
-static void ppc405_pob_realize(DeviceState *dev, Error **errp)
-{
- Ppc405PobState *pob = PPC405_POB(dev);
- Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
-
- ppc4xx_dcr_register(dcr, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
- ppc4xx_dcr_register(dcr, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
- ppc4xx_dcr_register(dcr, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
-}
-
-static void ppc405_pob_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_pob_realize;
- dc->reset = ppc405_pob_reset;
- /* Reason: only works as function of a ppc4xx SoC */
- dc->user_creatable = false;
-}
-
-/*****************************************************************************/
-/* OPB arbitrer */
-static uint64_t opba_readb(void *opaque, hwaddr addr, unsigned size)
-{
- Ppc405OpbaState *opba = opaque;
- uint32_t ret;
-
- switch (addr) {
- case 0x00:
- ret = opba->cr;
- break;
- case 0x01:
- ret = opba->pr;
- break;
- default:
- ret = 0x00;
- break;
- }
-
- trace_opba_readb(addr, ret);
- return ret;
-}
-
-static void opba_writeb(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- Ppc405OpbaState *opba = opaque;
-
- trace_opba_writeb(addr, value);
-
- switch (addr) {
- case 0x00:
- opba->cr = value & 0xF8;
- break;
- case 0x01:
- opba->pr = value & 0xFF;
- break;
- default:
- break;
- }
-}
-static const MemoryRegionOps opba_ops = {
- .read = opba_readb,
- .write = opba_writeb,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static void ppc405_opba_reset(DeviceState *dev)
-{
- Ppc405OpbaState *opba = PPC405_OPBA(dev);
-
- opba->cr = 0x00; /* No dynamic priorities - park disabled */
- opba->pr = 0x11;
-}
-
-static void ppc405_opba_realize(DeviceState *dev, Error **errp)
-{
- Ppc405OpbaState *s = PPC405_OPBA(dev);
-
- memory_region_init_io(&s->io, OBJECT(s), &opba_ops, s, "opba", 2);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io);
-}
-
-static void ppc405_opba_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_opba_realize;
- dc->reset = ppc405_opba_reset;
- /* Reason: only works as function of a ppc4xx SoC */
- dc->user_creatable = false;
-}
-
-/*****************************************************************************/
-/* Code decompression controller */
-/* XXX: TODO */
-
-/*****************************************************************************/
-/* DMA controller */
-enum {
- DMA0_CR0 = 0x100,
- DMA0_CT0 = 0x101,
- DMA0_DA0 = 0x102,
- DMA0_SA0 = 0x103,
- DMA0_SG0 = 0x104,
- DMA0_CR1 = 0x108,
- DMA0_CT1 = 0x109,
- DMA0_DA1 = 0x10A,
- DMA0_SA1 = 0x10B,
- DMA0_SG1 = 0x10C,
- DMA0_CR2 = 0x110,
- DMA0_CT2 = 0x111,
- DMA0_DA2 = 0x112,
- DMA0_SA2 = 0x113,
- DMA0_SG2 = 0x114,
- DMA0_CR3 = 0x118,
- DMA0_CT3 = 0x119,
- DMA0_DA3 = 0x11A,
- DMA0_SA3 = 0x11B,
- DMA0_SG3 = 0x11C,
- DMA0_SR = 0x120,
- DMA0_SGC = 0x123,
- DMA0_SLP = 0x125,
- DMA0_POL = 0x126,
-};
-
-static uint32_t dcr_read_dma(void *opaque, int dcrn)
-{
- return 0;
-}
-
-static void dcr_write_dma(void *opaque, int dcrn, uint32_t val)
-{
-}
-
-static void ppc405_dma_reset(DeviceState *dev)
-{
- Ppc405DmaState *dma = PPC405_DMA(dev);
- int i;
-
- for (i = 0; i < 4; i++) {
- dma->cr[i] = 0x00000000;
- dma->ct[i] = 0x00000000;
- dma->da[i] = 0x00000000;
- dma->sa[i] = 0x00000000;
- dma->sg[i] = 0x00000000;
- }
- dma->sr = 0x00000000;
- dma->sgc = 0x00000000;
- dma->slp = 0x7C000000;
- dma->pol = 0x00000000;
-}
-
-static void ppc405_dma_realize(DeviceState *dev, Error **errp)
-{
- Ppc405DmaState *dma = PPC405_DMA(dev);
- Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dma->irqs); i++) {
- sysbus_init_irq(SYS_BUS_DEVICE(dma), &dma->irqs[i]);
- }
-
- ppc4xx_dcr_register(dcr, DMA0_CR0, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_CT0, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_DA0, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SA0, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SG0, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_CR1, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_CT1, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_DA1, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SA1, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SG1, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_CR2, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_CT2, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_DA2, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SA2, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SG2, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_CR3, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_CT3, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_DA3, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SA3, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SG3, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SR, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SGC, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_SLP, dma, &dcr_read_dma, &dcr_write_dma);
- ppc4xx_dcr_register(dcr, DMA0_POL, dma, &dcr_read_dma, &dcr_write_dma);
-}
-
-static void ppc405_dma_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_dma_realize;
- dc->reset = ppc405_dma_reset;
- /* Reason: only works as function of a ppc4xx SoC */
- dc->user_creatable = false;
-}
-
-/*****************************************************************************/
-/* GPIO */
-static uint64_t ppc405_gpio_read(void *opaque, hwaddr addr, unsigned size)
-{
- trace_ppc405_gpio_read(addr, size);
- return 0;
-}
-
-static void ppc405_gpio_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- trace_ppc405_gpio_write(addr, size, value);
-}
-
-static const MemoryRegionOps ppc405_gpio_ops = {
- .read = ppc405_gpio_read,
- .write = ppc405_gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc405_gpio_realize(DeviceState *dev, Error **errp)
-{
- Ppc405GpioState *s = PPC405_GPIO(dev);
-
- memory_region_init_io(&s->io, OBJECT(s), &ppc405_gpio_ops, s, "gpio",
- 0x38);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io);
-}
-
-static void ppc405_gpio_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_gpio_realize;
- /* Reason: only works as function of a ppc4xx SoC */
- dc->user_creatable = false;
-}
-
-/*****************************************************************************/
-/* On Chip Memory */
-enum {
- OCM0_ISARC = 0x018,
- OCM0_ISACNTL = 0x019,
- OCM0_DSARC = 0x01A,
- OCM0_DSACNTL = 0x01B,
-};
-
-static void ocm_update_mappings(Ppc405OcmState *ocm,
- uint32_t isarc, uint32_t isacntl,
- uint32_t dsarc, uint32_t dsacntl)
-{
- trace_ocm_update_mappings(isarc, isacntl, dsarc, dsacntl, ocm->isarc,
- ocm->isacntl, ocm->dsarc, ocm->dsacntl);
-
- if (ocm->isarc != isarc ||
- (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
- if (ocm->isacntl & 0x80000000) {
- /* Unmap previously assigned memory region */
- trace_ocm_unmap("ISA", ocm->isarc);
- memory_region_del_subregion(get_system_memory(), &ocm->isarc_ram);
- }
- if (isacntl & 0x80000000) {
- /* Map new instruction memory region */
- trace_ocm_map("ISA", isarc);
- memory_region_add_subregion(get_system_memory(), isarc,
- &ocm->isarc_ram);
- }
- }
- if (ocm->dsarc != dsarc ||
- (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
- if (ocm->dsacntl & 0x80000000) {
- /* Beware not to unmap the region we just mapped */
- if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) {
- /* Unmap previously assigned memory region */
- trace_ocm_unmap("DSA", ocm->dsarc);
- memory_region_del_subregion(get_system_memory(),
- &ocm->dsarc_ram);
- }
- }
- if (dsacntl & 0x80000000) {
- /* Beware not to remap the region we just mapped */
- if (!(isacntl & 0x80000000) || dsarc != isarc) {
- /* Map new data memory region */
- trace_ocm_map("DSA", dsarc);
- memory_region_add_subregion(get_system_memory(), dsarc,
- &ocm->dsarc_ram);
- }
- }
- }
-}
-
-static uint32_t dcr_read_ocm(void *opaque, int dcrn)
-{
- Ppc405OcmState *ocm = opaque;
- uint32_t ret;
-
- switch (dcrn) {
- case OCM0_ISARC:
- ret = ocm->isarc;
- break;
- case OCM0_ISACNTL:
- ret = ocm->isacntl;
- break;
- case OCM0_DSARC:
- ret = ocm->dsarc;
- break;
- case OCM0_DSACNTL:
- ret = ocm->dsacntl;
- break;
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_ocm(void *opaque, int dcrn, uint32_t val)
-{
- Ppc405OcmState *ocm = opaque;
- uint32_t isarc, dsarc, isacntl, dsacntl;
-
- isarc = ocm->isarc;
- dsarc = ocm->dsarc;
- isacntl = ocm->isacntl;
- dsacntl = ocm->dsacntl;
- switch (dcrn) {
- case OCM0_ISARC:
- isarc = val & 0xFC000000;
- break;
- case OCM0_ISACNTL:
- isacntl = val & 0xC0000000;
- break;
- case OCM0_DSARC:
- isarc = val & 0xFC000000;
- break;
- case OCM0_DSACNTL:
- isacntl = val & 0xC0000000;
- break;
- }
- ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
- ocm->isarc = isarc;
- ocm->dsarc = dsarc;
- ocm->isacntl = isacntl;
- ocm->dsacntl = dsacntl;
-}
-
-static void ppc405_ocm_reset(DeviceState *dev)
-{
- Ppc405OcmState *ocm = PPC405_OCM(dev);
- uint32_t isarc, dsarc, isacntl, dsacntl;
-
- isarc = 0x00000000;
- isacntl = 0x00000000;
- dsarc = 0x00000000;
- dsacntl = 0x00000000;
- ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
- ocm->isarc = isarc;
- ocm->dsarc = dsarc;
- ocm->isacntl = isacntl;
- ocm->dsacntl = dsacntl;
-}
-
-static void ppc405_ocm_realize(DeviceState *dev, Error **errp)
-{
- Ppc405OcmState *ocm = PPC405_OCM(dev);
- Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
-
- /* XXX: Size is 4096 or 0x04000000 */
- memory_region_init_ram(&ocm->isarc_ram, OBJECT(ocm), "ppc405.ocm", 4 * KiB,
- &error_fatal);
- memory_region_init_alias(&ocm->dsarc_ram, OBJECT(ocm), "ppc405.dsarc",
- &ocm->isarc_ram, 0, 4 * KiB);
-
- ppc4xx_dcr_register(dcr, OCM0_ISARC, ocm, &dcr_read_ocm, &dcr_write_ocm);
- ppc4xx_dcr_register(dcr, OCM0_ISACNTL, ocm, &dcr_read_ocm, &dcr_write_ocm);
- ppc4xx_dcr_register(dcr, OCM0_DSARC, ocm, &dcr_read_ocm, &dcr_write_ocm);
- ppc4xx_dcr_register(dcr, OCM0_DSACNTL, ocm, &dcr_read_ocm, &dcr_write_ocm);
-}
-
-static void ppc405_ocm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_ocm_realize;
- dc->reset = ppc405_ocm_reset;
- /* Reason: only works as function of a ppc4xx SoC */
- dc->user_creatable = false;
-}
-
-/*****************************************************************************/
-/* General purpose timers */
-static int ppc4xx_gpt_compare(Ppc405GptState *gpt, int n)
-{
- /* XXX: TODO */
- return 0;
-}
-
-static void ppc4xx_gpt_set_output(Ppc405GptState *gpt, int n, int level)
-{
- /* XXX: TODO */
-}
-
-static void ppc4xx_gpt_set_outputs(Ppc405GptState *gpt)
-{
- uint32_t mask;
- int i;
-
- mask = 0x80000000;
- for (i = 0; i < 5; i++) {
- if (gpt->oe & mask) {
- /* Output is enabled */
- if (ppc4xx_gpt_compare(gpt, i)) {
- /* Comparison is OK */
- ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask);
- } else {
- /* Comparison is KO */
- ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1);
- }
- }
- mask = mask >> 1;
- }
-}
-
-static void ppc4xx_gpt_set_irqs(Ppc405GptState *gpt)
-{
- uint32_t mask;
- int i;
-
- mask = 0x00008000;
- for (i = 0; i < 5; i++) {
- if (gpt->is & gpt->im & mask) {
- qemu_irq_raise(gpt->irqs[i]);
- } else {
- qemu_irq_lower(gpt->irqs[i]);
- }
- mask = mask >> 1;
- }
-}
-
-static void ppc4xx_gpt_compute_timer(Ppc405GptState *gpt)
-{
- /* XXX: TODO */
-}
-
-static uint64_t ppc4xx_gpt_read(void *opaque, hwaddr addr, unsigned size)
-{
- Ppc405GptState *gpt = opaque;
- uint32_t ret;
- int idx;
-
- trace_ppc4xx_gpt_read(addr, size);
-
- switch (addr) {
- case 0x00:
- /* Time base counter */
- ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + gpt->tb_offset,
- gpt->tb_freq, NANOSECONDS_PER_SECOND);
- break;
- case 0x10:
- /* Output enable */
- ret = gpt->oe;
- break;
- case 0x14:
- /* Output level */
- ret = gpt->ol;
- break;
- case 0x18:
- /* Interrupt mask */
- ret = gpt->im;
- break;
- case 0x1C:
- case 0x20:
- /* Interrupt status */
- ret = gpt->is;
- break;
- case 0x24:
- /* Interrupt enable */
- ret = gpt->ie;
- break;
- case 0x80 ... 0x90:
- /* Compare timer */
- idx = (addr - 0x80) >> 2;
- ret = gpt->comp[idx];
- break;
- case 0xC0 ... 0xD0:
- /* Compare mask */
- idx = (addr - 0xC0) >> 2;
- ret = gpt->mask[idx];
- break;
- default:
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-static void ppc4xx_gpt_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- Ppc405GptState *gpt = opaque;
- int idx;
-
- trace_ppc4xx_gpt_write(addr, size, value);
-
- switch (addr) {
- case 0x00:
- /* Time base counter */
- gpt->tb_offset = muldiv64(value, NANOSECONDS_PER_SECOND, gpt->tb_freq)
- - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ppc4xx_gpt_compute_timer(gpt);
- break;
- case 0x10:
- /* Output enable */
- gpt->oe = value & 0xF8000000;
- ppc4xx_gpt_set_outputs(gpt);
- break;
- case 0x14:
- /* Output level */
- gpt->ol = value & 0xF8000000;
- ppc4xx_gpt_set_outputs(gpt);
- break;
- case 0x18:
- /* Interrupt mask */
- gpt->im = value & 0x0000F800;
- break;
- case 0x1C:
- /* Interrupt status set */
- gpt->is |= value & 0x0000F800;
- ppc4xx_gpt_set_irqs(gpt);
- break;
- case 0x20:
- /* Interrupt status clear */
- gpt->is &= ~(value & 0x0000F800);
- ppc4xx_gpt_set_irqs(gpt);
- break;
- case 0x24:
- /* Interrupt enable */
- gpt->ie = value & 0x0000F800;
- ppc4xx_gpt_set_irqs(gpt);
- break;
- case 0x80 ... 0x90:
- /* Compare timer */
- idx = (addr - 0x80) >> 2;
- gpt->comp[idx] = value & 0xF8000000;
- ppc4xx_gpt_compute_timer(gpt);
- break;
- case 0xC0 ... 0xD0:
- /* Compare mask */
- idx = (addr - 0xC0) >> 2;
- gpt->mask[idx] = value & 0xF8000000;
- ppc4xx_gpt_compute_timer(gpt);
- break;
- }
-}
-
-static const MemoryRegionOps gpt_ops = {
- .read = ppc4xx_gpt_read,
- .write = ppc4xx_gpt_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ppc4xx_gpt_cb(void *opaque)
-{
- Ppc405GptState *gpt = opaque;
-
- ppc4xx_gpt_set_irqs(gpt);
- ppc4xx_gpt_set_outputs(gpt);
- ppc4xx_gpt_compute_timer(gpt);
-}
-
-static void ppc405_gpt_reset(DeviceState *dev)
-{
- Ppc405GptState *gpt = PPC405_GPT(dev);
- int i;
-
- timer_del(gpt->timer);
- gpt->oe = 0x00000000;
- gpt->ol = 0x00000000;
- gpt->im = 0x00000000;
- gpt->is = 0x00000000;
- gpt->ie = 0x00000000;
- for (i = 0; i < 5; i++) {
- gpt->comp[i] = 0x00000000;
- gpt->mask[i] = 0x00000000;
- }
-}
-
-static void ppc405_gpt_realize(DeviceState *dev, Error **errp)
-{
- Ppc405GptState *s = PPC405_GPT(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i;
-
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ppc4xx_gpt_cb, s);
- memory_region_init_io(&s->iomem, OBJECT(s), &gpt_ops, s, "gpt", 0xd4);
- sysbus_init_mmio(sbd, &s->iomem);
-
- for (i = 0; i < ARRAY_SIZE(s->irqs); i++) {
- sysbus_init_irq(sbd, &s->irqs[i]);
- }
-}
-
-static void ppc405_gpt_finalize(Object *obj)
-{
- /* timer will be NULL if the GPT wasn't realized */
- if (PPC405_GPT(obj)->timer) {
- timer_del(PPC405_GPT(obj)->timer);
- }
-}
-
-static void ppc405_gpt_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_gpt_realize;
- dc->reset = ppc405_gpt_reset;
- /* Reason: only works as function of a ppc4xx SoC */
- dc->user_creatable = false;
-}
-
-/*****************************************************************************/
-/* PowerPC 405EP */
-/* CPU control */
-enum {
- PPC405EP_CPC0_PLLMR0 = 0x0F0,
- PPC405EP_CPC0_BOOT = 0x0F1,
- PPC405EP_CPC0_EPCTL = 0x0F3,
- PPC405EP_CPC0_PLLMR1 = 0x0F4,
- PPC405EP_CPC0_UCR = 0x0F5,
- PPC405EP_CPC0_SRR = 0x0F6,
- PPC405EP_CPC0_JTAGID = 0x0F7,
- PPC405EP_CPC0_PCI = 0x0F9,
-#if 0
- PPC405EP_CPC0_ER = xxx,
- PPC405EP_CPC0_FR = xxx,
- PPC405EP_CPC0_SR = xxx,
-#endif
-};
-
-static void ppc405ep_compute_clocks(Ppc405CpcState *cpc)
-{
- uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk;
- uint32_t UART0_clk, UART1_clk;
- uint64_t VCO_out, PLL_out;
- int M, D;
-
- VCO_out = 0;
- if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) {
- M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */
- trace_ppc405ep_clocks_compute("FBMUL", (cpc->pllmr[1] >> 20) & 0xF, M);
- D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */
- trace_ppc405ep_clocks_compute("FWDA", (cpc->pllmr[1] >> 16) & 0x7, D);
- VCO_out = (uint64_t)cpc->sysclk * M * D;
- if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
- /* Error - unlock the PLL */
- qemu_log_mask(LOG_GUEST_ERROR, "VCO out of range %" PRIu64 "\n",
- VCO_out);
-#if 0
- cpc->pllmr[1] &= ~0x80000000;
- goto pll_bypass;
-#endif
- }
- PLL_out = VCO_out / D;
- /* Pretend the PLL is locked */
- cpc->boot |= 0x00000001;
- } else {
-#if 0
- pll_bypass:
-#endif
- PLL_out = cpc->sysclk;
- if (cpc->pllmr[1] & 0x40000000) {
- /* Pretend the PLL is not locked */
- cpc->boot &= ~0x00000001;
- }
- }
- /* Now, compute all other clocks */
- D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */
- trace_ppc405ep_clocks_compute("CCDV", (cpc->pllmr[0] >> 20) & 0x3, D);
- CPU_clk = PLL_out / D;
- D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */
- trace_ppc405ep_clocks_compute("CBDV", (cpc->pllmr[0] >> 16) & 0x3, D);
- PLB_clk = CPU_clk / D;
- D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */
- trace_ppc405ep_clocks_compute("OPDV", (cpc->pllmr[0] >> 12) & 0x3, D);
- OPB_clk = PLB_clk / D;
- D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */
- trace_ppc405ep_clocks_compute("EPDV", (cpc->pllmr[0] >> 8) & 0x3, D);
- EBC_clk = PLB_clk / D;
- D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */
- trace_ppc405ep_clocks_compute("MPDV", (cpc->pllmr[0] >> 4) & 0x3, D);
- MAL_clk = PLB_clk / D;
- D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */
- trace_ppc405ep_clocks_compute("PPDV", cpc->pllmr[0] & 0x3, D);
- PCI_clk = PLB_clk / D;
- D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */
- trace_ppc405ep_clocks_compute("U0DIV", cpc->ucr & 0x7F, D);
- UART0_clk = PLL_out / D;
- D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */
- trace_ppc405ep_clocks_compute("U1DIV", (cpc->ucr >> 8) & 0x7F, D);
- UART1_clk = PLL_out / D;
-
- if (trace_event_get_state_backends(TRACE_PPC405EP_CLOCKS_SETUP)) {
- g_autofree char *trace = g_strdup_printf(
- "Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64
- " PLL out %" PRIu64 " Hz\n"
- "CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32
- " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32
- " UART1 %" PRIu32 "\n",
- cpc->sysclk, VCO_out, PLL_out,
- CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk,
- UART0_clk, UART1_clk);
- trace_ppc405ep_clocks_setup(trace);
- }
-
- /* Setup CPU clocks */
- clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk);
- /* Setup PLB clock */
- clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk);
- /* Setup OPB clock */
- clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk);
- /* Setup external clock */
- clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk);
- /* Setup MAL clock */
- clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk);
- /* Setup PCI clock */
- clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk);
- /* Setup UART0 clock */
- clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk);
- /* Setup UART1 clock */
- clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk);
-}
-
-static uint32_t dcr_read_epcpc(void *opaque, int dcrn)
-{
- Ppc405CpcState *cpc = opaque;
- uint32_t ret;
-
- switch (dcrn) {
- case PPC405EP_CPC0_BOOT:
- ret = cpc->boot;
- break;
- case PPC405EP_CPC0_EPCTL:
- ret = cpc->epctl;
- break;
- case PPC405EP_CPC0_PLLMR0:
- ret = cpc->pllmr[0];
- break;
- case PPC405EP_CPC0_PLLMR1:
- ret = cpc->pllmr[1];
- break;
- case PPC405EP_CPC0_UCR:
- ret = cpc->ucr;
- break;
- case PPC405EP_CPC0_SRR:
- ret = cpc->srr;
- break;
- case PPC405EP_CPC0_JTAGID:
- ret = cpc->jtagid;
- break;
- case PPC405EP_CPC0_PCI:
- ret = cpc->pci;
- break;
- default:
- /* Avoid gcc warning */
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_epcpc(void *opaque, int dcrn, uint32_t val)
-{
- Ppc405CpcState *cpc = opaque;
-
- switch (dcrn) {
- case PPC405EP_CPC0_BOOT:
- /* Read-only register */
- break;
- case PPC405EP_CPC0_EPCTL:
- /* Don't care for now */
- cpc->epctl = val & 0xC00000F3;
- break;
- case PPC405EP_CPC0_PLLMR0:
- cpc->pllmr[0] = val & 0x00633333;
- ppc405ep_compute_clocks(cpc);
- break;
- case PPC405EP_CPC0_PLLMR1:
- cpc->pllmr[1] = val & 0xC0F73FFF;
- ppc405ep_compute_clocks(cpc);
- break;
- case PPC405EP_CPC0_UCR:
- /* UART control - don't care for now */
- cpc->ucr = val & 0x003F7F7F;
- break;
- case PPC405EP_CPC0_SRR:
- cpc->srr = val;
- break;
- case PPC405EP_CPC0_JTAGID:
- /* Read-only */
- break;
- case PPC405EP_CPC0_PCI:
- cpc->pci = val;
- break;
- }
-}
-
-static void ppc405_cpc_reset(DeviceState *dev)
-{
- Ppc405CpcState *cpc = PPC405_CPC(dev);
-
- cpc->boot = 0x00000010; /* Boot from PCI - IIC EEPROM disabled */
- cpc->epctl = 0x00000000;
- cpc->pllmr[0] = 0x00021002;
- cpc->pllmr[1] = 0x80a552be;
- cpc->ucr = 0x00004646;
- cpc->srr = 0x00040000;
- cpc->pci = 0x00000000;
- cpc->er = 0x00000000;
- cpc->fr = 0x00000000;
- cpc->sr = 0x00000000;
- cpc->jtagid = 0x20267049;
- ppc405ep_compute_clocks(cpc);
-}
-
-/* XXX: sysclk should be between 25 and 100 MHz */
-static void ppc405_cpc_realize(DeviceState *dev, Error **errp)
-{
- Ppc405CpcState *cpc = PPC405_CPC(dev);
- Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
-
- assert(dcr->cpu);
- cpc->clk_setup[PPC405EP_CPU_CLK].cb =
- ppc_40x_timers_init(&dcr->cpu->env, cpc->sysclk, PPC_INTERRUPT_PIT);
- cpc->clk_setup[PPC405EP_CPU_CLK].opaque = &dcr->cpu->env;
-
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_BOOT, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_EPCTL, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_PLLMR0, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_PLLMR1, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_UCR, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_SRR, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_JTAGID, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
- ppc4xx_dcr_register(dcr, PPC405EP_CPC0_PCI, cpc,
- &dcr_read_epcpc, &dcr_write_epcpc);
-}
-
-static Property ppc405_cpc_properties[] = {
- DEFINE_PROP_UINT32("sys-clk", Ppc405CpcState, sysclk, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ppc405_cpc_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_cpc_realize;
- dc->reset = ppc405_cpc_reset;
- /* Reason: only works as function of a ppc4xx SoC */
- dc->user_creatable = false;
- device_class_set_props(dc, ppc405_cpc_properties);
-}
-
-/* PPC405_SOC */
-
-static void ppc405_soc_instance_init(Object *obj)
-{
- Ppc405SoCState *s = PPC405_SOC(obj);
-
- object_initialize_child(obj, "cpu", &s->cpu,
- POWERPC_CPU_TYPE_NAME("405ep"));
-
- object_initialize_child(obj, "uic", &s->uic, TYPE_PPC_UIC);
-
- object_initialize_child(obj, "cpc", &s->cpc, TYPE_PPC405_CPC);
- object_property_add_alias(obj, "sys-clk", OBJECT(&s->cpc), "sys-clk");
-
- object_initialize_child(obj, "gpt", &s->gpt, TYPE_PPC405_GPT);
-
- object_initialize_child(obj, "ocm", &s->ocm, TYPE_PPC405_OCM);
-
- object_initialize_child(obj, "gpio", &s->gpio, TYPE_PPC405_GPIO);
-
- object_initialize_child(obj, "dma", &s->dma, TYPE_PPC405_DMA);
-
- object_initialize_child(obj, "i2c", &s->i2c, TYPE_PPC4xx_I2C);
-
- object_initialize_child(obj, "ebc", &s->ebc, TYPE_PPC4xx_EBC);
-
- object_initialize_child(obj, "opba", &s->opba, TYPE_PPC405_OPBA);
-
- object_initialize_child(obj, "pob", &s->pob, TYPE_PPC405_POB);
-
- object_initialize_child(obj, "plb", &s->plb, TYPE_PPC4xx_PLB);
-
- object_initialize_child(obj, "mal", &s->mal, TYPE_PPC4xx_MAL);
-
- object_initialize_child(obj, "sdram", &s->sdram, TYPE_PPC4xx_SDRAM_DDR);
- object_property_add_alias(obj, "dram", OBJECT(&s->sdram), "dram");
-}
-
-static void ppc405_reset(void *opaque)
-{
- cpu_reset(CPU(opaque));
-}
-
-static void ppc405_soc_realize(DeviceState *dev, Error **errp)
-{
- Ppc405SoCState *s = PPC405_SOC(dev);
- CPUPPCState *env;
- SysBusDevice *sbd;
- int i;
-
- /* init CPUs */
- if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) {
- return;
- }
- qemu_register_reset(ppc405_reset, &s->cpu);
-
- env = &s->cpu.env;
-
- ppc_dcr_init(env, NULL, NULL);
-
- /* CPU control */
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->cpc), &s->cpu, errp)) {
- return;
- }
-
- /* PLB arbitrer */
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->plb), &s->cpu, errp)) {
- return;
- }
-
- /* PLB to OPB bridge */
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->pob), &s->cpu, errp)) {
- return;
- }
-
- /* OBP arbitrer */
- sbd = SYS_BUS_DEVICE(&s->opba);
- if (!sysbus_realize(sbd, errp)) {
- return;
- }
- sysbus_mmio_map(sbd, 0, 0xef600600);
-
- /* Universal interrupt controller */
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->uic), &s->cpu, errp)) {
- return;
- }
- sbd = SYS_BUS_DEVICE(&s->uic);
- sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
- qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_INT));
- sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
- qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_CINT));
-
- /* SDRAM controller */
- /*
- * We use the 440 DDR SDRAM controller which has more regs and features
- * but it's compatible enough for now
- */
- object_property_set_int(OBJECT(&s->sdram), "nbanks", 2, &error_abort);
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->sdram), &s->cpu, errp)) {
- return;
- }
- /* XXX 405EP has no ECC interrupt */
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdram), 0,
- qdev_get_gpio_in(DEVICE(&s->uic), 17));
-
- /* External bus controller */
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ebc), &s->cpu, errp)) {
- return;
- }
-
- /* DMA controller */
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->dma), &s->cpu, errp)) {
- return;
- }
- sbd = SYS_BUS_DEVICE(&s->dma);
- for (i = 0; i < ARRAY_SIZE(s->dma.irqs); i++) {
- sysbus_connect_irq(sbd, i, qdev_get_gpio_in(DEVICE(&s->uic), 5 + i));
- }
-
- /* I2C controller */
- sbd = SYS_BUS_DEVICE(&s->i2c);
- if (!sysbus_realize(sbd, errp)) {
- return;
- }
- sysbus_mmio_map(sbd, 0, 0xef600500);
- sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(DEVICE(&s->uic), 2));
-
- /* GPIO */
- sbd = SYS_BUS_DEVICE(&s->gpio);
- if (!sysbus_realize(sbd, errp)) {
- return;
- }
- sysbus_mmio_map(sbd, 0, 0xef600700);
-
- /* Serial ports */
- if (serial_hd(0) != NULL) {
- serial_mm_init(get_system_memory(), 0xef600300, 0,
- qdev_get_gpio_in(DEVICE(&s->uic), 0),
- PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
- DEVICE_BIG_ENDIAN);
- }
- if (serial_hd(1) != NULL) {
- serial_mm_init(get_system_memory(), 0xef600400, 0,
- qdev_get_gpio_in(DEVICE(&s->uic), 1),
- PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
- DEVICE_BIG_ENDIAN);
- }
-
- /* OCM */
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ocm), &s->cpu, errp)) {
- return;
- }
-
- /* GPT */
- sbd = SYS_BUS_DEVICE(&s->gpt);
- if (!sysbus_realize(sbd, errp)) {
- return;
- }
- sysbus_mmio_map(sbd, 0, 0xef600000);
- for (i = 0; i < ARRAY_SIZE(s->gpt.irqs); i++) {
- sysbus_connect_irq(sbd, i, qdev_get_gpio_in(DEVICE(&s->uic), 19 + i));
- }
-
- /* MAL */
- object_property_set_int(OBJECT(&s->mal), "txc-num", 4, &error_abort);
- object_property_set_int(OBJECT(&s->mal), "rxc-num", 2, &error_abort);
- if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->mal), &s->cpu, errp)) {
- return;
- }
- sbd = SYS_BUS_DEVICE(&s->mal);
- for (i = 0; i < ARRAY_SIZE(s->mal.irqs); i++) {
- sysbus_connect_irq(sbd, i, qdev_get_gpio_in(DEVICE(&s->uic), 11 + i));
- }
-
- /* Ethernet */
- /* Uses UIC IRQs 9, 15, 17 */
-}
-
-static void ppc405_soc_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = ppc405_soc_realize;
- /* Reason: only works as part of a ppc405 board/machine */
- dc->user_creatable = false;
-}
-
-static const TypeInfo ppc405_types[] = {
- {
- .name = TYPE_PPC405_POB,
- .parent = TYPE_PPC4xx_DCR_DEVICE,
- .instance_size = sizeof(Ppc405PobState),
- .class_init = ppc405_pob_class_init,
- }, {
- .name = TYPE_PPC405_OPBA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Ppc405OpbaState),
- .class_init = ppc405_opba_class_init,
- }, {
- .name = TYPE_PPC405_DMA,
- .parent = TYPE_PPC4xx_DCR_DEVICE,
- .instance_size = sizeof(Ppc405DmaState),
- .class_init = ppc405_dma_class_init,
- }, {
- .name = TYPE_PPC405_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Ppc405GpioState),
- .class_init = ppc405_gpio_class_init,
- }, {
- .name = TYPE_PPC405_OCM,
- .parent = TYPE_PPC4xx_DCR_DEVICE,
- .instance_size = sizeof(Ppc405OcmState),
- .class_init = ppc405_ocm_class_init,
- }, {
- .name = TYPE_PPC405_GPT,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Ppc405GptState),
- .instance_finalize = ppc405_gpt_finalize,
- .class_init = ppc405_gpt_class_init,
- }, {
- .name = TYPE_PPC405_CPC,
- .parent = TYPE_PPC4xx_DCR_DEVICE,
- .instance_size = sizeof(Ppc405CpcState),
- .class_init = ppc405_cpc_class_init,
- }, {
- .name = TYPE_PPC405_SOC,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(Ppc405SoCState),
- .instance_init = ppc405_soc_instance_init,
- .class_init = ppc405_soc_class_init,
- }
-};
-
-DEFINE_TYPES(ppc405_types)
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 73f80cf..6fff0d8 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -19,15 +19,15 @@
#include "net/net.h"
#include "hw/pci/pci.h"
#include "hw/boards.h"
-#include "sysemu/kvm.h"
-#include "sysemu/device_tree.h"
+#include "system/kvm.h"
+#include "system/device_tree.h"
#include "hw/loader.h"
#include "elf.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/ppc/ppc.h"
#include "hw/pci-host/ppc4xx.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/reset.h"
+#include "system/system.h"
+#include "system/reset.h"
#include "hw/sysbus.h"
#include "hw/intc/ppc-uic.h"
#include "hw/qdev-properties.h"
@@ -64,7 +64,7 @@ static int bamboo_load_device_tree(MachineState *machine,
uint32_t tb_freq = 400000000;
uint32_t clock_freq = 400000000;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ filename = qemu_find_file(QEMU_FILE_TYPE_DTB, BINARY_DEVICE_TREE_FILE);
if (!filename) {
return -1;
}
@@ -110,29 +110,6 @@ static int bamboo_load_device_tree(MachineState *machine,
return 0;
}
-/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- hwaddr pa)
-{
- ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0x80000000 */
- tlb->EPN = va & TARGET_PAGE_MASK;
- tlb->RPN = pa & TARGET_PAGE_MASK;
- tlb->PID = 0;
-
- tlb = &env->tlb.tlbe[1];
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0xffffffff */
- tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->PID = 0;
-}
-
static void main_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
@@ -143,8 +120,9 @@ static void main_cpu_reset(void *opaque)
env->gpr[3] = FDT_ADDR;
env->nip = entry;
- /* Create a mapping for the kernel. */
- mmubooke_create_initial_mapping(env, 0, 0);
+ /* Create a mapping spanning the 32bit addr space. */
+ booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1U << 31);
+ booke_set_tlb(&env->tlb.tlbe[1], 0x80000000, 0x80000000, 1U << 31);
}
static void bamboo_init(MachineState *machine)
@@ -250,7 +228,8 @@ static void bamboo_init(MachineState *machine)
if (success < 0) {
uint64_t elf_entry;
success = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
- NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+ NULL, NULL, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
entry = elf_entry;
}
/* XXX try again as binary */
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 1312aa2..89e3fae 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -17,7 +17,7 @@
#include "hw/pci-host/ppc4xx.h"
#include "hw/qdev-properties.h"
#include "hw/pci/pci.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "cpu.h"
#include "ppc440.h"
@@ -1020,15 +1020,14 @@ static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
ppc460ex_pcie_register_dcrs(s);
}
-static Property ppc460ex_pcie_props[] = {
+static const Property ppc460ex_pcie_props[] = {
DEFINE_PROP_INT32("busnum", PPC460EXPCIEState, num, -1),
DEFINE_PROP_INT32("dcrn-base", PPC460EXPCIEState, dcrn_base, -1),
DEFINE_PROP_LINK("cpu", PPC460EXPCIEState, cpu, TYPE_POWERPC_CPU,
PowerPCCPU *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ppc460ex_pcie_class_init(ObjectClass *klass, void *data)
+static void ppc460ex_pcie_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index c1d1114..f36c519 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -231,18 +231,17 @@ static void ppc4xx_mal_finalize(Object *obj)
g_free(mal->txctpr);
}
-static Property ppc4xx_mal_properties[] = {
+static const Property ppc4xx_mal_properties[] = {
DEFINE_PROP_UINT8("txc-num", Ppc4xxMalState, txcnum, 0),
DEFINE_PROP_UINT8("rxc-num", Ppc4xxMalState, rxcnum, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ppc4xx_mal_class_init(ObjectClass *oc, void *data)
+static void ppc4xx_mal_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_mal_realize;
- dc->reset = ppc4xx_mal_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_mal_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_mal_properties);
@@ -327,12 +326,12 @@ static void ppc405_plb_realize(DeviceState *dev, Error **errp)
ppc4xx_dcr_register(dcr, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb);
}
-static void ppc405_plb_class_init(ObjectClass *oc, void *data)
+static void ppc405_plb_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_plb_realize;
- dc->reset = ppc405_plb_reset;
+ device_class_set_legacy_reset(dc, ppc405_plb_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -513,12 +512,12 @@ static void ppc405_ebc_realize(DeviceState *dev, Error **errp)
ppc4xx_dcr_register(dcr, EBC0_CFGDATA, ebc, &dcr_read_ebc, &dcr_write_ebc);
}
-static void ppc405_ebc_class_init(ObjectClass *oc, void *data)
+static void ppc405_ebc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_ebc_realize;
- dc->reset = ppc405_ebc_reset;
+ device_class_set_legacy_reset(dc, ppc405_ebc_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -539,13 +538,12 @@ bool ppc4xx_dcr_realize(Ppc4xxDcrDeviceState *dev, PowerPCCPU *cpu,
return sysbus_realize(SYS_BUS_DEVICE(dev), errp);
}
-static Property ppc4xx_dcr_properties[] = {
+static const Property ppc4xx_dcr_properties[] = {
DEFINE_PROP_LINK("cpu", Ppc4xxDcrDeviceState, cpu, TYPE_POWERPC_CPU,
PowerPCCPU *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data)
+static void ppc4xx_dcr_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/ppc/ppc4xx_sdram.c b/hw/ppc/ppc4xx_sdram.c
index c0c87ff..5927698 100644
--- a/hw/ppc/ppc4xx_sdram.c
+++ b/hw/ppc/ppc4xx_sdram.c
@@ -34,7 +34,7 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
-#include "exec/address-spaces.h" /* get_system_memory() */
+#include "system/address-spaces.h" /* get_system_memory() */
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/ppc/ppc4xx.h"
@@ -425,19 +425,18 @@ static void ppc4xx_sdram_ddr_realize(DeviceState *dev, Error **errp)
s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write);
}
-static Property ppc4xx_sdram_ddr_props[] = {
+static const Property ppc4xx_sdram_ddr_props[] = {
DEFINE_PROP_LINK("dram", Ppc4xxSdramDdrState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdrState, nbanks, 4),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, void *data)
+static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_sdram_ddr_realize;
- dc->reset = ppc4xx_sdram_ddr_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_sdram_ddr_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_sdram_ddr_props);
@@ -710,19 +709,18 @@ static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp)
s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
}
-static Property ppc4xx_sdram_ddr2_props[] = {
+static const Property ppc4xx_sdram_ddr2_props[] = {
DEFINE_PROP_LINK("dram", Ppc4xxSdramDdr2State, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data)
+static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_sdram_ddr2_realize;
- dc->reset = ppc4xx_sdram_ddr2_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_sdram_ddr2_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_sdram_ddr2_props);
diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
index ca22da1..3872ae2 100644
--- a/hw/ppc/ppc_booke.c
+++ b/hw/ppc/ppc_booke.c
@@ -24,13 +24,24 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "exec/target_page.h"
#include "hw/ppc/ppc.h"
#include "qemu/timer.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "hw/loader.h"
#include "kvm_ppc.h"
+void booke_set_tlb(ppcemb_tlb_t *tlb, target_ulong va, hwaddr pa,
+ target_ulong size)
+{
+ tlb->attr = 0;
+ tlb->prot = PAGE_RWX << 4 | PAGE_VALID;
+ tlb->size = size;
+ tlb->EPN = va & TARGET_PAGE_MASK;
+ tlb->RPN = pa & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+}
/* Timer Control Register */
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index dfbe759..2310f62 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -32,7 +32,8 @@
#include "qemu/units.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
-#include "sysemu/hw_accel.h"
+#include "system/hw_accel.h"
+#include "hw/ppc/ppc.h"
#include "e500.h"
#include "qom/object.h"
@@ -70,30 +71,12 @@ static void spin_reset(DeviceState *dev)
}
}
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- hwaddr pa,
- hwaddr len)
-{
- ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
- hwaddr size;
-
- size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
- tlb->mas1 = MAS1_VALID | size;
- tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
- tlb->mas7_3 = pa & TARGET_PAGE_MASK;
- tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
-#ifdef CONFIG_KVM
- env->tlb_dirty = true;
-#endif
-}
-
static void spin_kick(CPUState *cs, run_on_cpu_data data)
{
CPUPPCState *env = cpu_env(cs);
SpinInfo *curspin = data.host_ptr;
- hwaddr map_size = 64 * MiB;
- hwaddr map_start;
+ hwaddr map_start, map_size = 64 * MiB;
+ ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
cpu_synchronize_state(cs);
stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]);
@@ -107,7 +90,12 @@ static void spin_kick(CPUState *cs, run_on_cpu_data data)
env->gpr[9] = 0;
map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
- mmubooke_create_initial_mapping(env, 0, map_start, map_size);
+ /* create initial mapping */
+ booke206_set_tlb(tlb, 0, map_start, map_size);
+ tlb->mas2 |= MAS2_M;
+#ifdef CONFIG_KVM
+ env->tlb_dirty = true;
+#endif
cs->halted = 0;
cs->exception_index = -1;
@@ -187,11 +175,11 @@ static void ppce500_spin_initfn(Object *obj)
sysbus_init_mmio(dev, &s->iomem);
}
-static void ppce500_spin_class_init(ObjectClass *klass, void *data)
+static void ppce500_spin_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = spin_reset;
+ device_class_set_legacy_reset(dc, spin_reset);
}
static const TypeInfo ppce500_spin_info = {
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 4eb5477..982e40e 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -25,7 +25,6 @@
#include "qemu/osdep.h"
#include "hw/rtc/m48t59.h"
-#include "hw/char/serial.h"
#include "hw/block/fdc.h"
#include "net/net.h"
#include "hw/isa/isa.h"
@@ -36,12 +35,14 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
+#include "qemu/datadir.h"
#include "hw/loader.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/isa/pc87312.h"
#include "hw/qdev-properties.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
+#include "exec/target_page.h"
+#include "system/kvm.h"
+#include "system/reset.h"
#include "trace.h"
#include "elf.h"
#include "qemu/units.h"
@@ -55,6 +56,8 @@
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
+#define BIOS_ADDR 0xfff00000
+#define BIOS_SIZE (1 * MiB)
#define NVRAM_SIZE 0x2000
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
@@ -241,6 +244,9 @@ static void ibm_40p_init(MachineState *machine)
ISADevice *isa_dev;
ISABus *isa_bus;
void *fw_cfg;
+ MemoryRegion *bios = g_new(MemoryRegion, 1);
+ char *filename;
+ ssize_t bios_size = -1;
uint32_t kernel_base = 0, initrd_base = 0;
long kernel_size = 0, initrd_size = 0;
char boot_device;
@@ -263,10 +269,27 @@ static void ibm_40p_init(MachineState *machine)
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
qemu_register_reset(ppc_prep_reset, cpu);
+ /* allocate and load firmware */
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (!filename) {
+ error_report("Could not find bios image '%s'", bios_name);
+ exit(1);
+ }
+ memory_region_init_rom(bios, NULL, "bios", BIOS_SIZE, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), BIOS_ADDR, bios);
+ bios_size = load_elf(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
+ if (bios_size < 0) {
+ bios_size = load_image_targphys(filename, BIOS_ADDR, BIOS_SIZE);
+ }
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ error_report("Could not load bios image '%s'", filename);
+ return;
+ }
+ g_free(filename);
+
/* PCI host */
dev = qdev_new("raven-pcihost");
- qdev_prop_set_string(dev, "bios-name", bios_name);
- qdev_prop_set_uint32(dev, "elf-machine", PPC_ELF_MACHINE);
pcihost = SYS_BUS_DEVICE(dev);
object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev));
sysbus_realize_and_unref(pcihost, &error_fatal);
diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c
index 4d3a251..41cd923 100644
--- a/hw/ppc/prep_systemio.c
+++ b/hw/ppc/prep_systemio.c
@@ -28,11 +28,11 @@
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qom/object.h"
#include "qemu/error-report.h" /* for error_report() */
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "cpu.h"
#include "trace.h"
@@ -285,13 +285,12 @@ static const VMStateDescription vmstate_prep_systemio = {
},
};
-static Property prep_systemio_properties[] = {
+static const Property prep_systemio_properties[] = {
DEFINE_PROP_UINT8("ibm-planar-id", PrepSystemIoState, ibm_planar_id, 0),
DEFINE_PROP_UINT8("equipment", PrepSystemIoState, equipment, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void prep_systemio_class_initfn(ObjectClass *klass, void *data)
+static void prep_systemio_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c
index e6ec4b4..a096405 100644
--- a/hw/ppc/rs6000_mc.c
+++ b/hw/ppc/rs6000_mc.c
@@ -3,10 +3,12 @@
*
* Copyright (c) 2017 Hervé Poussineau
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
- * (at your option) version 3 or any later version.
+ * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,7 +24,7 @@
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qapi/error.h"
#include "trace.h"
#include "qom/object.h"
@@ -205,13 +207,12 @@ static const VMStateDescription vmstate_rs6000mc = {
},
};
-static Property rs6000mc_properties[] = {
+static const Property rs6000mc_properties[] = {
DEFINE_PROP_UINT32("ram-size", RS6000MCState, ram_size, 0),
DEFINE_PROP_BOOL("auto-configure", RS6000MCState, autoconfigure, true),
- DEFINE_PROP_END_OF_LIST()
};
-static void rs6000mc_class_initfn(ObjectClass *klass, void *data)
+static void rs6000mc_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index 8dc75fb..ee31bd8 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -17,21 +17,21 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/boards.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_ppc.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/block-backend.h"
+#include "system/device_tree.h"
+#include "system/block-backend.h"
#include "exec/page-protection.h"
#include "hw/loader.h"
#include "elf.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "ppc440.h"
#include "hw/pci-host/ppc4xx.h"
#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/reset.h"
+#include "system/system.h"
+#include "system/reset.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/i2c/ppc4xx_i2c.h"
#include "hw/i2c/smbus_eeprom.h"
#include "hw/ide/pci.h"
@@ -142,7 +142,7 @@ static int sam460ex_load_device_tree(MachineState *machine,
uint32_t clock_freq = CPU_FREQ;
int offset;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ filename = qemu_find_file(QEMU_FILE_TYPE_DTB, BINARY_DEVICE_TREE_FILE);
if (!filename) {
error_report("Couldn't find dtb file `%s'", BINARY_DEVICE_TREE_FILE);
exit(1);
@@ -213,38 +213,6 @@ static int sam460ex_load_device_tree(MachineState *machine,
return fdt_size;
}
-/* Create reset TLB entries for BookE, mapping only the flash memory. */
-static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
-{
- ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
- /* on reset the flash is mapped by a shadow TLB,
- * but since we don't implement them we need to use
- * the same values U-Boot will use to avoid a fault.
- */
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 0x10000000; /* up to 0xffffffff */
- tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
- tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
- tlb->PID = 0;
-}
-
-/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- hwaddr pa)
-{
- ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1 << 31; /* up to 0x80000000 */
- tlb->EPN = va & TARGET_PAGE_MASK;
- tlb->RPN = pa & TARGET_PAGE_MASK;
- tlb->PID = 0;
-}
-
static void main_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
@@ -253,20 +221,27 @@ static void main_cpu_reset(void *opaque)
cpu_reset(CPU(cpu));
- /* either we have a kernel to boot or we jump to U-Boot */
+ /*
+ * On reset the flash is mapped by a shadow TLB, but since we
+ * don't implement them we need to use the same values U-Boot
+ * will use to avoid a fault.
+ * either we have a kernel to boot or we jump to U-Boot
+ */
if (bi->entry != UBOOT_ENTRY) {
env->gpr[1] = (16 * MiB) - 8;
env->gpr[3] = FDT_ADDR;
env->nip = bi->entry;
/* Create a mapping for the kernel. */
- mmubooke_create_initial_mapping(env, 0, 0);
- env->gpr[6] = tswap32(EPAPR_MAGIC);
+ booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1 << 31);
+ env->gpr[6] = EPAPR_MAGIC;
env->gpr[7] = (16 * MiB) - 8; /* bi->ima_size; */
} else {
env->nip = UBOOT_ENTRY;
- mmubooke_create_initial_mapping_uboot(env);
+ /* Create a mapping for U-Boot. */
+ booke_set_tlb(&env->tlb.tlbe[0], 0xf0000000, 0xf0000000, 0x10000000);
+ env->tlb.tlbe[0].RPN |= 4;
}
}
@@ -504,7 +479,7 @@ static void sam460ex_init(MachineState *machine)
success = load_elf(machine->kernel_filename, NULL, NULL, NULL,
&elf_entry, NULL, NULL, NULL,
- 1, PPC_ELF_MACHINE, 0, 0);
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
entry = elf_entry;
}
/* XXX try again as binary */
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 370d7c3..702f774 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -4,6 +4,9 @@
* Copyright (c) 2004-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
* Copyright (c) 2010 David Gibson, IBM Corporation.
+ * Copyright (c) 2010-2024, IBM Corporation..
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -32,20 +35,20 @@
#include "qapi/qapi-events-machine.h"
#include "qapi/qapi-events-qdev.h"
#include "qapi/visitor.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/numa.h"
-#include "sysemu/tcg.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/hostmem.h"
+#include "system/numa.h"
+#include "system/tcg.h"
+#include "system/qtest.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "qemu/log.h"
#include "hw/fw-path-provider.h"
#include "elf.h"
#include "net/net.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/cpus.h"
-#include "sysemu/hw_accel.h"
+#include "system/device_tree.h"
+#include "system/cpus.h"
+#include "system/hw_accel.h"
#include "kvm_ppc.h"
#include "migration/misc.h"
#include "migration/qemu-file-types.h"
@@ -74,8 +77,8 @@
#include "hw/virtio/virtio-scsi.h"
#include "hw/virtio/vhost-scsi-common.h"
-#include "exec/ram_addr.h"
-#include "exec/confidential-guest-support.h"
+#include "system/ram_addr.h"
+#include "system/confidential-guest-support.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
@@ -132,61 +135,6 @@ static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
}
-static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
-{
- /* Dummy entries correspond to unused ICPState objects in older QEMUs,
- * and newer QEMUs don't even have them. In both cases, we don't want
- * to send anything on the wire.
- */
- return false;
-}
-
-static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
- /*
- * Hack ahead. We can't have two devices with the same name and
- * instance id. So I rename this to pass make check.
- * Real help from people who knows the hardware is needed.
- */
- .name = "icp/server",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = pre_2_10_vmstate_dummy_icp_needed,
- .fields = (const VMStateField[]) {
- VMSTATE_UNUSED(4), /* uint32_t xirr */
- VMSTATE_UNUSED(1), /* uint8_t pending_priority */
- VMSTATE_UNUSED(1), /* uint8_t mfrr */
- VMSTATE_END_OF_LIST()
- },
-};
-
-/*
- * See comment in hw/intc/xics.c:icp_realize()
- *
- * You have to remove vmstate_replace_hack_for_ppc() when you remove
- * the machine types that need the following function.
- */
-static void pre_2_10_vmstate_register_dummy_icp(int i)
-{
- vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
- (void *)(uintptr_t) i);
-}
-
-/*
- * See comment in hw/intc/xics.c:icp_realize()
- *
- * You have to remove vmstate_replace_hack_for_ppc() when you remove
- * the machine types that need the following function.
- */
-static void pre_2_10_vmstate_unregister_dummy_icp(int i)
-{
- /*
- * This used to be:
- *
- * vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
- * (void *)(uintptr_t) i);
- */
-}
-
int spapr_max_server_number(SpaprMachineState *spapr)
{
MachineState *ms = MACHINE(spapr);
@@ -298,7 +246,7 @@ static void spapr_dt_pa_features(SpaprMachineState *spapr,
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 48 - 53 */
/* 54: DecFP, 56: DecI, 58: SHA */
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 54 - 59 */
- /* 60: NM atomic, 62: RNG */
+ /* 60: NM atomic, 62: RNG, 64: DAWR1 (ISA 3.1) */
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */
/* 68: DEXCR[SBHE|IBRTPDUS|SRAPD|NPHIE|PHIE] */
0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 66 - 71 */
@@ -347,6 +295,10 @@ static void spapr_dt_pa_features(SpaprMachineState *spapr,
* in pa-features. So hide it from them. */
pa_features[40 + 2] &= ~0x80; /* Radix MMU */
}
+ if (spapr_get_cap(spapr, SPAPR_CAP_DAWR1)) {
+ g_assert(pa_size > 66);
+ pa_features[66] |= 0x80;
+ }
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
}
@@ -682,7 +634,6 @@ static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
{
MachineState *machine = MACHINE(spapr);
- SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
hwaddr mem_start, node_size;
int i, nb_nodes = machine->numa_state->num_nodes;
NodeInfo *nodes = machine->numa_state->nodes;
@@ -724,7 +675,6 @@ static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
int ret;
- g_assert(smc->dr_lmb_enabled);
ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
if (ret) {
return ret;
@@ -758,7 +708,7 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
int i;
- drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
+ drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, env->core_index);
if (drc) {
drc_index = spapr_drc_index(drc);
_FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
@@ -1307,9 +1257,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
spapr_dt_cpus(fdt, spapr);
/* ibm,drc-indexes and friends */
- if (smc->dr_lmb_enabled) {
- root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_LMB;
- }
+ root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_LMB;
if (smc->dr_phb_enabled) {
root_drc_type_mask |= SPAPR_DR_CONNECTOR_TYPE_PHB;
}
@@ -1458,11 +1406,34 @@ static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
}
}
-#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2))
-#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
-#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
-#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
-#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
+static uint64_t *hpte_get_ptr(SpaprMachineState *s, unsigned index)
+{
+ uint64_t *table = s->htab;
+
+ return &table[2 * index];
+}
+
+static bool hpte_is_valid(SpaprMachineState *s, unsigned index)
+{
+ return ldq_be_p(hpte_get_ptr(s, index)) & HPTE64_V_VALID;
+}
+
+static bool hpte_is_dirty(SpaprMachineState *s, unsigned index)
+{
+ return ldq_be_p(hpte_get_ptr(s, index)) & HPTE64_V_HPTE_DIRTY;
+}
+
+static void hpte_set_clean(SpaprMachineState *s, unsigned index)
+{
+ stq_be_p(hpte_get_ptr(s, index),
+ ldq_be_p(hpte_get_ptr(s, index)) & ~HPTE64_V_HPTE_DIRTY);
+}
+
+static void hpte_set_dirty(SpaprMachineState *s, unsigned index)
+{
+ stq_be_p(hpte_get_ptr(s, index),
+ ldq_be_p(hpte_get_ptr(s, index)) | HPTE64_V_HPTE_DIRTY);
+}
/*
* Get the fd to access the kernel htab, re-opening it if necessary
@@ -1673,7 +1644,7 @@ int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp)
spapr->htab_shift = shift;
for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
- DIRTY_HPTE(HPTE(spapr->htab, i));
+ hpte_set_dirty(spapr, i);
}
}
/* We're setting up a hash table, so that means we're not radix */
@@ -1725,7 +1696,7 @@ void spapr_check_mmu_mode(bool guest_radix)
}
}
-static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
+static void spapr_machine_reset(MachineState *machine, ResetType type)
{
SpaprMachineState *spapr = SPAPR_MACHINE(machine);
PowerPCCPU *first_ppc_cpu;
@@ -1733,7 +1704,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
void *fdt;
int rc;
- if (reason != SHUTDOWN_CAUSE_SNAPSHOT_LOAD) {
+ if (type != RESET_TYPE_SNAPSHOT_LOAD) {
/*
* Record-replay snapshot load must not consume random, this was
* already replayed from initial machine reset.
@@ -1762,7 +1733,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
spapr_setup_hpt(spapr);
}
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
spapr_ovec_cleanup(spapr->ov5_cas);
spapr->ov5_cas = spapr_ovec_new();
@@ -1819,7 +1790,6 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
0, fdt_addr, 0);
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
}
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
g_free(spapr->fdt_blob);
spapr->fdt_size = fdt_totalsize(fdt);
@@ -2197,6 +2167,7 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_cap_rpt_invalidate,
&vmstate_spapr_cap_ail_mode_3,
&vmstate_spapr_cap_nested_papr,
+ &vmstate_spapr_cap_dawr1,
NULL
}
};
@@ -2231,7 +2202,7 @@ static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
qemu_put_be32(f, chunkstart);
qemu_put_be16(f, n_valid);
qemu_put_be16(f, n_invalid);
- qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
+ qemu_put_buffer(f, (void *)hpte_get_ptr(spapr, chunkstart),
HASH_PTE_SIZE_64 * n_valid);
}
@@ -2257,16 +2228,16 @@ static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
/* Consume invalid HPTEs */
while ((index < htabslots)
- && !HPTE_VALID(HPTE(spapr->htab, index))) {
- CLEAN_HPTE(HPTE(spapr->htab, index));
+ && !hpte_is_valid(spapr, index)) {
+ hpte_set_clean(spapr, index);
index++;
}
/* Consume valid HPTEs */
chunkstart = index;
while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
- && HPTE_VALID(HPTE(spapr->htab, index))) {
- CLEAN_HPTE(HPTE(spapr->htab, index));
+ && hpte_is_valid(spapr, index)) {
+ hpte_set_clean(spapr, index);
index++;
}
@@ -2306,7 +2277,7 @@ static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
/* Consume non-dirty HPTEs */
while ((index < htabslots)
- && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
+ && !hpte_is_dirty(spapr, index)) {
index++;
examined++;
}
@@ -2314,9 +2285,9 @@ static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
chunkstart = index;
/* Consume valid dirty HPTEs */
while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
- && HPTE_DIRTY(HPTE(spapr->htab, index))
- && HPTE_VALID(HPTE(spapr->htab, index))) {
- CLEAN_HPTE(HPTE(spapr->htab, index));
+ && hpte_is_dirty(spapr, index)
+ && hpte_is_valid(spapr, index)) {
+ hpte_set_clean(spapr, index);
index++;
examined++;
}
@@ -2324,9 +2295,9 @@ static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
invalidstart = index;
/* Consume invalid dirty HPTEs */
while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
- && HPTE_DIRTY(HPTE(spapr->htab, index))
- && !HPTE_VALID(HPTE(spapr->htab, index))) {
- CLEAN_HPTE(HPTE(spapr->htab, index));
+ && hpte_is_dirty(spapr, index)
+ && !hpte_is_valid(spapr, index)) {
+ hpte_set_clean(spapr, index);
index++;
examined++;
}
@@ -2508,11 +2479,11 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
if (spapr->htab) {
if (n_valid) {
- qemu_get_buffer(f, HPTE(spapr->htab, index),
+ qemu_get_buffer(f, (void *)hpte_get_ptr(spapr, index),
HASH_PTE_SIZE_64 * n_valid);
}
if (n_invalid) {
- memset(HPTE(spapr->htab, index + n_valid), 0,
+ memset(hpte_get_ptr(spapr, index + n_valid), 0,
HASH_PTE_SIZE_64 * n_invalid);
}
} else {
@@ -2715,7 +2686,6 @@ static void spapr_init_cpus(SpaprMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
- SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
const char *type = spapr_get_cpu_core_type(machine->cpu_type);
const CPUArchIdList *possible_cpus;
unsigned int smp_cpus = machine->smp.cpus;
@@ -2744,15 +2714,6 @@ static void spapr_init_cpus(SpaprMachineState *spapr)
boot_cores_nr = possible_cpus->len;
}
- if (smc->pre_2_10_has_unused_icps) {
- for (i = 0; i < spapr_max_server_number(spapr); i++) {
- /* Dummy entries get deregistered when real ICPState objects
- * are registered during CPU core hotplug.
- */
- pre_2_10_vmstate_register_dummy_icp(i);
- }
- }
-
for (i = 0; i < possible_cpus->len; i++) {
int core_id = i * smp_threads;
@@ -2929,10 +2890,8 @@ static void spapr_machine_init(MachineState *machine)
spapr->ov5 = spapr_ovec_new();
spapr->ov5_cas = spapr_ovec_new();
- if (smc->dr_lmb_enabled) {
- spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
- spapr_validate_node_memory(machine, &error_fatal);
- }
+ spapr_ovec_set(spapr->ov5, OV5_DRCONF_MEMORY);
+ spapr_validate_node_memory(machine, &error_fatal);
spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
@@ -2959,6 +2918,9 @@ static void spapr_machine_init(MachineState *machine)
spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
}
+ qemu_guest_getrandom_nofail(&spapr->hashpkey_val,
+ sizeof(spapr->hashpkey_val));
+
/* init CPUs */
spapr_init_cpus(spapr);
@@ -3016,9 +2978,7 @@ static void spapr_machine_init(MachineState *machine)
machine_memory_devices_init(machine, device_mem_base, device_mem_size);
}
- if (smc->dr_lmb_enabled) {
- spapr_create_lmb_dr_connectors(spapr);
- }
+ spapr_create_lmb_dr_connectors(spapr);
if (mc->nvdimm_supported) {
spapr_create_nvdimm_dr_connectors(spapr);
@@ -3078,11 +3038,7 @@ static void spapr_machine_init(MachineState *machine)
}
if (machine->usb) {
- if (smc->use_ohci_by_default) {
- pci_create_simple(phb->bus, -1, "pci-ohci");
- } else {
- pci_create_simple(phb->bus, -1, "nec-usb-xhci");
- }
+ pci_create_simple(phb->bus, -1, "nec-usb-xhci");
if (has_vga) {
USBBus *usb_bus;
@@ -3099,13 +3055,13 @@ static void spapr_machine_init(MachineState *machine)
spapr->kernel_size = load_elf(kernel_filename, NULL,
translate_kernel_address, spapr,
- NULL, &loaded_addr, NULL, NULL, 1,
- PPC_ELF_MACHINE, 0, 0);
+ NULL, &loaded_addr, NULL, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (spapr->kernel_size == ELF_LOAD_WRONG_ENDIAN) {
spapr->kernel_size = load_elf(kernel_filename, NULL,
translate_kernel_address, spapr,
- NULL, &loaded_addr, NULL, NULL, 0,
- PPC_ELF_MACHINE, 0, 0);
+ NULL, &loaded_addr, NULL, NULL,
+ ELFDATA2LSB, PPC_ELF_MACHINE, 0, 0);
spapr->kernel_le = spapr->kernel_size > 0;
}
if (spapr->kernel_size < 0) {
@@ -3662,7 +3618,6 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
- const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
PCDIMMDevice *dimm = PC_DIMM(dev);
@@ -3671,11 +3626,6 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Object *memdev;
hwaddr pagesize;
- if (!smc->dr_lmb_enabled) {
- error_setg(errp, "Memory hotplug not supported for this machine");
- return;
- }
-
size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -3932,21 +3882,9 @@ void spapr_core_release(DeviceState *dev)
static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
{
MachineState *ms = MACHINE(hotplug_dev);
- SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
CPUCore *cc = CPU_CORE(dev);
CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
- if (smc->pre_2_10_has_unused_icps) {
- SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
- int i;
-
- for (i = 0; i < cc->nr_threads; i++) {
- CPUState *cs = CPU(sc->threads[i]);
-
- pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
- }
- }
-
assert(core_slot);
core_slot->cpu = NULL;
qdev_unrealize(dev);
@@ -4027,7 +3965,6 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
{
SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
MachineClass *mc = MACHINE_GET_CLASS(spapr);
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
SpaprDrc *drc;
@@ -4077,12 +4014,6 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev)
}
}
- if (smc->pre_2_10_has_unused_icps) {
- for (i = 0; i < cc->nr_threads; i++) {
- CPUState *cs = CPU(core->threads[i]);
- pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
- }
- }
}
static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
@@ -4539,7 +4470,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, GString *buf)
*/
static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
- bool cam_ignore, uint8_t priority,
+ bool crowd, bool cam_ignore, uint8_t priority,
uint32_t logic_serv, XiveTCTXMatch *match)
{
SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
@@ -4547,7 +4478,7 @@ static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
int count;
- count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, cam_ignore,
+ count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd, cam_ignore,
priority, logic_serv, match);
if (count < 0) {
return count;
@@ -4664,7 +4595,7 @@ static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
}
}
-static void spapr_machine_class_init(ObjectClass *oc, void *data)
+static void spapr_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
@@ -4713,7 +4644,6 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
hc->unplug_request = spapr_machine_device_unplug_request;
hc->unplug = spapr_machine_device_unplug;
- smc->dr_lmb_enabled = true;
smc->update_dt_enabled = true;
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v2.0");
mc->has_hotpluggable_cpus = true;
@@ -4758,6 +4688,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
smc->default_caps.caps[SPAPR_CAP_RPT_INVALIDATE] = SPAPR_CAP_OFF;
+ smc->default_caps.caps[SPAPR_CAP_DAWR1] = SPAPR_CAP_ON;
/*
* This cap specifies whether the AIL 3 mode for
@@ -4786,7 +4717,7 @@ static const TypeInfo spapr_machine_info = {
.instance_finalize = spapr_machine_finalizefn,
.class_size = sizeof(SpaprMachineClass),
.class_init = spapr_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
{ TYPE_NMI },
{ TYPE_HOTPLUG_HANDLER },
@@ -4808,7 +4739,7 @@ static void spapr_machine_latest_class_options(MachineClass *mc)
#define DEFINE_SPAPR_MACHINE_IMPL(latest, ...) \
static void MACHINE_VER_SYM(class_init, spapr, __VA_ARGS__)( \
ObjectClass *oc, \
- void *data) \
+ const void *data) \
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
MACHINE_VER_SYM(class_options, spapr, __VA_ARGS__)(mc); \
@@ -4826,7 +4757,7 @@ static void spapr_machine_latest_class_options(MachineClass *mc)
static void MACHINE_VER_SYM(register, spapr, __VA_ARGS__)(void) \
{ \
MACHINE_VER_DELETION(__VA_ARGS__); \
- type_register(&MACHINE_VER_SYM(info, spapr, __VA_ARGS__)); \
+ type_register_static(&MACHINE_VER_SYM(info, spapr, __VA_ARGS__)); \
} \
type_init(MACHINE_VER_SYM(register, spapr, __VA_ARGS__))
@@ -4834,18 +4765,49 @@ static void spapr_machine_latest_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE_IMPL(true, major, minor)
#define DEFINE_SPAPR_MACHINE(major, minor) \
DEFINE_SPAPR_MACHINE_IMPL(false, major, minor)
-#define DEFINE_SPAPR_MACHINE_TAGGED(major, minor, tag) \
- DEFINE_SPAPR_MACHINE_IMPL(false, major, minor, _, tag)
+
+/*
+ * pseries-10.1
+ */
+static void spapr_machine_10_1_class_options(MachineClass *mc)
+{
+ /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE_AS_LATEST(10, 1);
+
+/*
+ * pseries-10.0
+ */
+static void spapr_machine_10_0_class_options(MachineClass *mc)
+{
+ spapr_machine_10_1_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len);
+}
+
+DEFINE_SPAPR_MACHINE(10, 0);
+
+/*
+ * pseries-9.2
+ */
+static void spapr_machine_9_2_class_options(MachineClass *mc)
+{
+ spapr_machine_10_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_2, hw_compat_9_2_len);
+}
+
+DEFINE_SPAPR_MACHINE(9, 2);
/*
* pseries-9.1
*/
static void spapr_machine_9_1_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ spapr_machine_9_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
}
-DEFINE_SPAPR_MACHINE_AS_LATEST(9, 1);
+DEFINE_SPAPR_MACHINE(9, 1);
/*
* pseries-9.0
@@ -4865,6 +4827,7 @@ static void spapr_machine_8_2_class_options(MachineClass *mc)
{
spapr_machine_9_0_class_options(mc);
compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.2");
}
DEFINE_SPAPR_MACHINE(8, 2);
@@ -5109,278 +5072,6 @@ static void spapr_machine_3_0_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE(3, 0);
-/*
- * pseries-2.12
- */
-static void spapr_machine_2_12_class_options(MachineClass *mc)
-{
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
- static GlobalProperty compat[] = {
- { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
- { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
- };
-
- spapr_machine_3_0_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-
- /* We depend on kvm_enabled() to choose a default value for the
- * hpt-max-page-size capability. Of course we can't do it here
- * because this is too early and the HW accelerator isn't initialized
- * yet. Postpone this to machine init (see default_caps_with_cpu()).
- */
- smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 0;
-}
-
-DEFINE_SPAPR_MACHINE(2, 12);
-
-static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
-{
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
-
- spapr_machine_2_12_class_options(mc);
- smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
- smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
- smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
-}
-
-DEFINE_SPAPR_MACHINE_TAGGED(2, 12, sxxm);
-
-/*
- * pseries-2.11
- */
-
-static void spapr_machine_2_11_class_options(MachineClass *mc)
-{
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
-
- spapr_machine_2_12_class_options(mc);
- smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
- compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
-}
-
-DEFINE_SPAPR_MACHINE(2, 11);
-
-/*
- * pseries-2.10
- */
-
-static void spapr_machine_2_10_class_options(MachineClass *mc)
-{
- spapr_machine_2_11_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
-}
-
-DEFINE_SPAPR_MACHINE(2, 10);
-
-/*
- * pseries-2.9
- */
-
-static void spapr_machine_2_9_class_options(MachineClass *mc)
-{
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
- static GlobalProperty compat[] = {
- { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
- };
-
- spapr_machine_2_10_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
- smc->pre_2_10_has_unused_icps = true;
- smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
-}
-
-DEFINE_SPAPR_MACHINE(2, 9);
-
-/*
- * pseries-2.8
- */
-
-static void spapr_machine_2_8_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
- };
-
- spapr_machine_2_9_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
- mc->numa_mem_align_shift = 23;
-}
-
-DEFINE_SPAPR_MACHINE(2, 8);
-
-/*
- * pseries-2.7
- */
-
-static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index,
- uint64_t *buid, hwaddr *pio,
- hwaddr *mmio32, hwaddr *mmio64,
- unsigned n_dma, uint32_t *liobns, Error **errp)
-{
- /* Legacy PHB placement for pseries-2.7 and earlier machine types */
- const uint64_t base_buid = 0x800000020000000ULL;
- const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */
- const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */
- const hwaddr pio_offset = 0x80000000; /* 2 GiB */
- const uint32_t max_index = 255;
- const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */
-
- uint64_t ram_top = MACHINE(spapr)->ram_size;
- hwaddr phb0_base, phb_base;
- int i;
-
- /* Do we have device memory? */
- if (MACHINE(spapr)->device_memory) {
- /* Can't just use maxram_size, because there may be an
- * alignment gap between normal and device memory regions
- */
- ram_top = MACHINE(spapr)->device_memory->base +
- memory_region_size(&MACHINE(spapr)->device_memory->mr);
- }
-
- phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment);
-
- if (index > max_index) {
- error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
- max_index);
- return false;
- }
-
- *buid = base_buid + index;
- for (i = 0; i < n_dma; ++i) {
- liobns[i] = SPAPR_PCI_LIOBN(index, i);
- }
-
- phb_base = phb0_base + index * phb_spacing;
- *pio = phb_base + pio_offset;
- *mmio32 = phb_base + mmio_offset;
- /*
- * We don't set the 64-bit MMIO window, relying on the PHB's
- * fallback behaviour of automatically splitting a large "32-bit"
- * window into contiguous 32-bit and 64-bit windows
- */
-
- return true;
-}
-
-static void spapr_machine_2_7_class_options(MachineClass *mc)
-{
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
- static GlobalProperty compat[] = {
- { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
- { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
- { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
- { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
- };
-
- spapr_machine_2_8_class_options(mc);
- mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
- mc->default_machine_opts = "modern-hotplug-events=off";
- compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
- smc->phb_placement = phb_placement_2_7;
-}
-
-DEFINE_SPAPR_MACHINE(2, 7);
-
-/*
- * pseries-2.6
- */
-
-static void spapr_machine_2_6_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
- };
-
- spapr_machine_2_7_class_options(mc);
- mc->has_hotpluggable_cpus = false;
- compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-}
-
-DEFINE_SPAPR_MACHINE(2, 6);
-
-/*
- * pseries-2.5
- */
-
-static void spapr_machine_2_5_class_options(MachineClass *mc)
-{
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
- static GlobalProperty compat[] = {
- { "spapr-vlan", "use-rx-buffer-pools", "off" },
- };
-
- spapr_machine_2_6_class_options(mc);
- smc->use_ohci_by_default = true;
- compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-}
-
-DEFINE_SPAPR_MACHINE(2, 5);
-
-/*
- * pseries-2.4
- */
-
-static void spapr_machine_2_4_class_options(MachineClass *mc)
-{
- SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
-
- spapr_machine_2_5_class_options(mc);
- smc->dr_lmb_enabled = false;
- compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
-}
-
-DEFINE_SPAPR_MACHINE(2, 4);
-
-/*
- * pseries-2.3
- */
-
-static void spapr_machine_2_3_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
- };
- spapr_machine_2_4_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-}
-DEFINE_SPAPR_MACHINE(2, 3);
-
-/*
- * pseries-2.2
- */
-
-static void spapr_machine_2_2_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
- };
-
- spapr_machine_2_3_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
- mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
-}
-DEFINE_SPAPR_MACHINE(2, 2);
-
-/*
- * pseries-2.1
- */
-
-static void spapr_machine_2_1_class_options(MachineClass *mc)
-{
- spapr_machine_2_2_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
-}
-DEFINE_SPAPR_MACHINE(2, 1);
-
static void spapr_machine_register_types(void)
{
type_register_static(&spapr_machine_info);
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 2f74923..f2f5722 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -26,14 +26,15 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#include "sysemu/hw_accel.h"
-#include "exec/ram_addr.h"
+#include "system/hw_accel.h"
+#include "system/ram_addr.h"
#include "target/ppc/cpu.h"
#include "target/ppc/mmu-hash64.h"
#include "cpu-models.h"
#include "kvm_ppc.h"
#include "migration/vmstate.h"
-#include "sysemu/tcg.h"
+#include "system/tcg.h"
+#include "system/hostmem.h"
#include "hw/ppc/spapr.h"
@@ -696,6 +697,34 @@ static void cap_ail_mode_3_apply(SpaprMachineState *spapr,
}
}
+static void cap_dawr1_apply(SpaprMachineState *spapr, uint8_t val,
+ Error **errp)
+{
+ ERRP_GUARD();
+
+ if (!val) {
+ return; /* Disable by default */
+ }
+
+ if (!ppc_type_check_compat(MACHINE(spapr)->cpu_type,
+ CPU_POWERPC_LOGICAL_3_10, 0,
+ spapr->max_compat_pvr)) {
+ error_setg(errp, "DAWR1 supported only on POWER10 and later CPUs");
+ error_append_hint(errp, "Try appending -machine cap-dawr1=off\n");
+ return;
+ }
+
+ if (kvm_enabled()) {
+ if (!kvmppc_has_cap_dawr1()) {
+ error_setg(errp, "DAWR1 not supported by KVM.");
+ error_append_hint(errp, "Try appending -machine cap-dawr1=off");
+ } else if (kvmppc_set_cap_dawr1(val) < 0) {
+ error_setg(errp, "Error enabling cap-dawr1 with KVM.");
+ error_append_hint(errp, "Try appending -machine cap-dawr1=off");
+ }
+ }
+}
+
SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
[SPAPR_CAP_HTM] = {
.name = "htm",
@@ -831,6 +860,15 @@ SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.type = "bool",
.apply = cap_ail_mode_3_apply,
},
+ [SPAPR_CAP_DAWR1] = {
+ .name = "dawr1",
+ .description = "Allow 2nd Data Address Watchpoint Register (DAWR1)",
+ .index = SPAPR_CAP_DAWR1,
+ .get = spapr_cap_get_bool,
+ .set = spapr_cap_set_bool,
+ .type = "bool",
+ .apply = cap_dawr1_apply,
+ },
};
static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
@@ -841,6 +879,11 @@ static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
caps = smc->default_caps;
+ if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_3_10,
+ 0, spapr->max_compat_pvr)) {
+ caps.caps[SPAPR_CAP_DAWR1] = SPAPR_CAP_OFF;
+ }
+
if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_3_00,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
@@ -975,6 +1018,7 @@ SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST);
SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI);
SPAPR_CAP_MIG_STATE(rpt_invalidate, SPAPR_CAP_RPT_INVALIDATE);
SPAPR_CAP_MIG_STATE(ail_mode_3, SPAPR_CAP_AIL_MODE_3);
+SPAPR_CAP_MIG_STATE(dawr1, SPAPR_CAP_DAWR1);
void spapr_caps_init(SpaprMachineState *spapr)
{
@@ -1034,7 +1078,7 @@ void spapr_caps_add_properties(SpaprMachineClass *smc)
for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
SpaprCapabilityInfo *cap = &capability_table[i];
g_autofree char *name = g_strdup_printf("cap-%s", cap->name);
- g_autofree char *desc = g_strdup_printf("%s", cap->description);
+ g_autofree char *desc = g_strdup(cap->description);
object_class_property_add(klass, name, cap->type,
cap->get, cap->set,
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 56090ab..4952f9b 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -15,15 +15,15 @@
#include "target/ppc/cpu.h"
#include "hw/ppc/spapr.h"
#include "qapi/error.h"
-#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
+#include "system/cpus.h"
+#include "system/kvm.h"
#include "target/ppc/kvm_ppc.h"
#include "hw/ppc/ppc.h"
#include "target/ppc/mmu-hash64.h"
#include "target/ppc/power8-pmu.h"
-#include "sysemu/numa.h"
-#include "sysemu/reset.h"
-#include "sysemu/hw_accel.h"
+#include "system/numa.h"
+#include "system/reset.h"
+#include "system/hw_accel.h"
#include "qemu/error-report.h"
static void spapr_reset_vcpu(PowerPCCPU *cpu)
@@ -37,6 +37,9 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
cpu_reset(cs);
+ env->quiesced = true; /* set "RTAS stopped" state. */
+ ppc_maybe_interrupt(env);
+
/*
* "PowerPC Processor binding to IEEE 1275" defines the initial MSR state
* as 32bit (MSR_SF=0) with MSR_ME=1 and MSR_FP=1 in "8.2.1. Initial
@@ -98,6 +101,9 @@ void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
CPU(cpu)->halted = 0;
/* Enable Power-saving mode Exit Cause exceptions */
ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm);
+
+ env->quiesced = false; /* clear "RTAS stopped" state. */
+ ppc_maybe_interrupt(env);
}
/*
@@ -197,9 +203,7 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc)
{
CPUPPCState *env = &cpu->env;
- if (!sc->pre_3_0_migration) {
- vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
- }
+ vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
spapr_irq_cpu_intc_destroy(SPAPR_MACHINE(qdev_get_machine()), cpu);
cpu_ppc_tb_free(env);
qdev_unrealize(DEVICE(cpu));
@@ -275,6 +279,8 @@ static bool spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr,
env->spr_cb[SPR_PIR].default_value = cs->cpu_index;
env->spr_cb[SPR_TIR].default_value = thread_index;
+ env->spr_cb[SPR_HASHPKEYR].default_value = spapr->hashpkey_val;
+
cpu_ppc_set_1lpar(cpu);
/* Set time-base frequency to 512 MHz. vhyp must be set first. */
@@ -285,10 +291,8 @@ static bool spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr,
return false;
}
- if (!sc->pre_3_0_migration) {
- vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
- cpu->machine_data);
- }
+ vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
+ cpu->machine_data);
return true;
}
@@ -317,6 +321,7 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
return NULL;
}
+ env->chip_index = sc->node_id;
env->core_index = cc->core_id;
cpu->node_id = sc->node_id;
@@ -364,21 +369,18 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
}
}
-static Property spapr_cpu_core_properties[] = {
+static const Property spapr_cpu_core_properties[] = {
DEFINE_PROP_INT32("node-id", SpaprCpuCore, node_id, CPU_UNSET_NUMA_NODE_ID),
- DEFINE_PROP_BOOL("pre-3.0-migration", SpaprCpuCore, pre_3_0_migration,
- false),
- DEFINE_PROP_END_OF_LIST()
};
-static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
+static void spapr_cpu_core_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
dc->realize = spapr_cpu_core_realize;
dc->unrealize = spapr_cpu_core_unrealize;
- dc->reset = spapr_cpu_core_reset;
+ device_class_set_legacy_reset(dc, spapr_cpu_core_reset);
device_class_set_props(dc, spapr_cpu_core_properties);
scc->cpu_type = data;
}
@@ -386,7 +388,7 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
#define DEFINE_SPAPR_CPU_CORE_TYPE(cpu_model) \
{ \
.parent = TYPE_SPAPR_CPU_CORE, \
- .class_data = (void *) POWERPC_CPU_TYPE_NAME(cpu_model), \
+ .class_data = POWERPC_CPU_TYPE_NAME(cpu_model), \
.class_init = spapr_cpu_core_class_init, \
.name = SPAPR_CPU_CORE_TYPE_NAME(cpu_model), \
}
@@ -411,6 +413,7 @@ static const TypeInfo spapr_cpu_core_type_infos[] = {
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.2"),
DEFINE_SPAPR_CPU_CORE_TYPE("power10_v2.0"),
+ DEFINE_SPAPR_CPU_CORE_TYPE("power11_v2.0"),
#ifdef CONFIG_KVM
DEFINE_SPAPR_CPU_CORE_TYPE("host"),
#endif
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 1484e32..d2044b4 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qnull.h"
+#include "qobject/qnull.h"
#include "qemu/cutils.h"
#include "hw/ppc/spapr_drc.h"
#include "qom/object.h"
@@ -23,11 +23,11 @@
#include "hw/ppc/spapr.h" /* for RTAS return codes */
#include "hw/pci-host/spapr.h" /* spapr_phb_remove_pci_device_cb callback */
#include "hw/ppc/spapr_nvdimm.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/reset.h"
+#include "system/device_tree.h"
+#include "system/reset.h"
#include "trace.h"
-#define DRC_CONTAINER_PATH "/dr-connector"
+#define DRC_CONTAINER_PATH "dr-connector"
#define DRC_INDEX_TYPE_SHIFT 28
#define DRC_INDEX_ID_MASK ((1ULL << DRC_INDEX_TYPE_SHIFT) - 1)
@@ -514,6 +514,16 @@ static const VMStateDescription vmstate_spapr_drc = {
}
};
+static void drc_container_create(void)
+{
+ object_property_add_new_container(object_get_root(), DRC_CONTAINER_PATH);
+}
+
+static Object *drc_container_get(void)
+{
+ return object_resolve_path_component(object_get_root(), DRC_CONTAINER_PATH);
+}
+
static void drc_realize(DeviceState *d, Error **errp)
{
SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
@@ -529,7 +539,7 @@ static void drc_realize(DeviceState *d, Error **errp)
* inaccessible by the guest, since lookups rely on this path
* existing in the composition tree
*/
- root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
+ root_container = drc_container_get();
child_name = object_get_canonical_path_component(OBJECT(drc));
trace_spapr_drc_realize_child(spapr_drc_index(drc), child_name);
object_property_add_alias(root_container, link_name,
@@ -543,12 +553,10 @@ static void drc_unrealize(DeviceState *d)
{
SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
g_autofree gchar *name = g_strdup_printf("%x", spapr_drc_index(drc));
- Object *root_container;
trace_spapr_drc_unrealize(spapr_drc_index(drc));
vmstate_unregister(VMSTATE_IF(drc), &vmstate_spapr_drc, drc);
- root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
- object_property_del(root_container, name);
+ object_property_del(drc_container_get(), name);
}
SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
@@ -581,10 +589,12 @@ static void spapr_dr_connector_instance_init(Object *obj)
drc->state = drck->empty_state;
}
-static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
+static void spapr_dr_connector_class_init(ObjectClass *k, const void *data)
{
DeviceClass *dk = DEVICE_CLASS(k);
+ drc_container_create();
+
dk->realize = drc_realize;
dk->unrealize = drc_unrealize;
/*
@@ -655,7 +665,7 @@ static void unrealize_physical(DeviceState *d)
qemu_unregister_reset(drc_physical_reset, drcp);
}
-static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
+static void spapr_drc_physical_class_init(ObjectClass *k, const void *data)
{
DeviceClass *dk = DEVICE_CLASS(k);
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
@@ -669,7 +679,7 @@ static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
drck->empty_state = SPAPR_DRC_STATE_PHYSICAL_POWERON;
}
-static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
+static void spapr_drc_logical_class_init(ObjectClass *k, const void *data)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
@@ -680,7 +690,7 @@ static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
drck->empty_state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE;
}
-static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
+static void spapr_drc_cpu_class_init(ObjectClass *k, const void *data)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
@@ -691,7 +701,7 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
drck->dt_populate = spapr_core_dt_populate;
}
-static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
+static void spapr_drc_pci_class_init(ObjectClass *k, const void *data)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
@@ -702,7 +712,7 @@ static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
drck->dt_populate = spapr_pci_dt_populate;
}
-static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
+static void spapr_drc_lmb_class_init(ObjectClass *k, const void *data)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
@@ -713,7 +723,7 @@ static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
drck->dt_populate = spapr_lmb_dt_populate;
}
-static void spapr_drc_phb_class_init(ObjectClass *k, void *data)
+static void spapr_drc_phb_class_init(ObjectClass *k, const void *data)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
@@ -724,7 +734,7 @@ static void spapr_drc_phb_class_init(ObjectClass *k, void *data)
drck->dt_populate = spapr_phb_dt_populate;
}
-static void spapr_drc_pmem_class_init(ObjectClass *k, void *data)
+static void spapr_drc_pmem_class_init(ObjectClass *k, const void *data)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
@@ -796,9 +806,8 @@ static const TypeInfo spapr_drc_pmem_info = {
SpaprDrc *spapr_drc_by_index(uint32_t index)
{
Object *obj;
- g_autofree gchar *name = g_strdup_printf("%s/%x", DRC_CONTAINER_PATH,
- index);
- obj = object_resolve_path(name, NULL);
+ g_autofree gchar *name = g_strdup_printf("%x", index);
+ obj = object_resolve_path_component(drc_container_get(), name);
return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
}
@@ -860,7 +869,7 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
/* aliases for all DRConnector objects will be rooted in QOM
* composition tree at DRC_CONTAINER_PATH
*/
- root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
+ root_container = drc_container_get();
object_property_iter_init(&iter, root_container);
while ((prop = object_property_iter_next(&iter))) {
@@ -953,7 +962,7 @@ void spapr_drc_reset_all(SpaprMachineState *spapr)
ObjectProperty *prop;
ObjectPropertyIterator iter;
- drc_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
+ drc_container = drc_container_get();
restart:
object_property_iter_init(&iter, drc_container);
while ((prop = object_property_iter_next(&iter))) {
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index cb0eeee..832b021 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -27,8 +27,8 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/runstate.h"
+#include "system/device_tree.h"
+#include "system/runstate.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/spapr.h"
@@ -645,8 +645,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
/* we shouldn't be signaling hotplug events for resources
* that don't support them
*/
- g_assert(false);
- return;
+ g_assert_not_reached();
}
if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT) {
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 5e1d020..1e936f3 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1,14 +1,15 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/runstate.h"
-#include "sysemu/tcg.h"
+#include "system/hw_accel.h"
+#include "system/runstate.h"
+#include "system/tcg.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "exec/tb-flush.h"
+#include "exec/target_page.h"
#include "helper_regs.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/spapr.h"
@@ -299,8 +300,10 @@ static target_ulong h_page_init(PowerPCCPU *cpu, SpaprMachineState *spapr,
if (flags & (H_ICACHE_SYNCHRONIZE | H_ICACHE_INVALIDATE)) {
if (kvm_enabled()) {
kvmppc_icbi_range(cpu, pdst, len);
- } else {
+ } else if (tcg_enabled()) {
tb_flush(CPU(cpu));
+ } else {
+ g_assert_not_reached();
}
}
@@ -578,6 +581,8 @@ static target_ulong h_confer(PowerPCCPU *cpu, SpaprMachineState *spapr,
CPUState *cs = CPU(cpu);
SpaprCpuState *spapr_cpu;
+ assert(tcg_enabled()); /* KVM will have handled this */
+
/*
* -1 means confer to all other CPUs without dispatch counter check,
* otherwise it's a targeted confer.
@@ -818,11 +823,12 @@ static target_ulong h_set_mode_resource_set_ciabr(PowerPCCPU *cpu,
return H_SUCCESS;
}
-static target_ulong h_set_mode_resource_set_dawr0(PowerPCCPU *cpu,
- SpaprMachineState *spapr,
- target_ulong mflags,
- target_ulong value1,
- target_ulong value2)
+static target_ulong h_set_mode_resource_set_dawr(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong mflags,
+ target_ulong resource,
+ target_ulong value1,
+ target_ulong value2)
{
CPUPPCState *env = &cpu->env;
@@ -835,8 +841,15 @@ static target_ulong h_set_mode_resource_set_dawr0(PowerPCCPU *cpu,
return H_P4;
}
- ppc_store_dawr0(env, value1);
- ppc_store_dawrx0(env, value2);
+ if (resource == H_SET_MODE_RESOURCE_SET_DAWR0) {
+ ppc_store_dawr0(env, value1);
+ ppc_store_dawrx0(env, value2);
+ } else if (resource == H_SET_MODE_RESOURCE_SET_DAWR1) {
+ ppc_store_dawr1(env, value1);
+ ppc_store_dawrx1(env, value2);
+ } else {
+ g_assert_not_reached();
+ }
return H_SUCCESS;
}
@@ -915,8 +928,9 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, SpaprMachineState *spapr,
args[3]);
break;
case H_SET_MODE_RESOURCE_SET_DAWR0:
- ret = h_set_mode_resource_set_dawr0(cpu, spapr, args[0], args[2],
- args[3]);
+ case H_SET_MODE_RESOURCE_SET_DAWR1:
+ ret = h_set_mode_resource_set_dawr(cpu, spapr, args[0], args[1],
+ args[2], args[3]);
break;
case H_SET_MODE_RESOURCE_LE:
ret = h_set_mode_resource_le(cpu, spapr, args[0], args[2], args[3]);
@@ -968,7 +982,6 @@ static void spapr_check_setup_free_hpt(SpaprMachineState *spapr,
/* RADIX->HASH || NOTHING->HASH : Allocate HPT */
spapr_setup_hpt(spapr);
}
- return;
}
#define FLAGS_MASK 0x01FULL
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index e3c01ef..c2432a0 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -21,10 +21,10 @@
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "kvm_ppc.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "trace.h"
#include "hw/ppc/spapr.h"
@@ -668,11 +668,11 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
tcet->liobn, 0, tcet->nb_table << tcet->page_shift);
}
-static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
+static void spapr_tce_table_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = spapr_tce_table_realize;
- dc->reset = spapr_tce_reset;
+ device_class_set_legacy_reset(dc, spapr_tce_reset);
dc->unrealize = spapr_tce_table_unrealize;
/* Reason: This is just an internal device for handling the hypercalls */
dc->user_creatable = false;
@@ -693,7 +693,8 @@ static const TypeInfo spapr_tce_table_info = {
.class_init = spapr_tce_table_class_init,
};
-static void spapr_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+static void spapr_iommu_memory_region_class_init(ObjectClass *klass,
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index aebd7ea..d6d368d 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -19,7 +19,7 @@
#include "hw/ppc/xics_spapr.h"
#include "hw/qdev-properties.h"
#include "cpu-models.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "trace.h"
diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c
index c027857..10cf634 100644
--- a/hw/ppc/spapr_nested.c
+++ b/hw/ppc/spapr_nested.c
@@ -1,6 +1,7 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
-#include "exec/exec-all.h"
+#include "exec/cputlb.h"
+#include "exec/target_long.h"
#include "helper_regs.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/spapr.h"
@@ -64,10 +65,9 @@ static
SpaprMachineStateNestedGuest *spapr_get_nested_guest(SpaprMachineState *spapr,
target_ulong guestid)
{
- SpaprMachineStateNestedGuest *guest;
-
- guest = g_hash_table_lookup(spapr->nested.guests, GINT_TO_POINTER(guestid));
- return guest;
+ return spapr->nested.guests ?
+ g_hash_table_lookup(spapr->nested.guests,
+ GINT_TO_POINTER(guestid)) : NULL;
}
bool spapr_get_pate_nested_papr(SpaprMachineState *spapr, PowerPCCPU *cpu,
@@ -593,26 +593,37 @@ static bool spapr_nested_vcpu_check(SpaprMachineStateNestedGuest *guest,
return false;
}
-static void *get_vcpu_state_ptr(SpaprMachineStateNestedGuest *guest,
- target_ulong vcpuid)
+static void *get_vcpu_state_ptr(SpaprMachineState *spapr,
+ SpaprMachineStateNestedGuest *guest,
+ target_ulong vcpuid)
{
assert(spapr_nested_vcpu_check(guest, vcpuid, false));
return &guest->vcpus[vcpuid].state;
}
-static void *get_vcpu_ptr(SpaprMachineStateNestedGuest *guest,
- target_ulong vcpuid)
+static void *get_vcpu_ptr(SpaprMachineState *spapr,
+ SpaprMachineStateNestedGuest *guest,
+ target_ulong vcpuid)
{
assert(spapr_nested_vcpu_check(guest, vcpuid, false));
return &guest->vcpus[vcpuid];
}
-static void *get_guest_ptr(SpaprMachineStateNestedGuest *guest,
+static void *get_guest_ptr(SpaprMachineState *spapr,
+ SpaprMachineStateNestedGuest *guest,
target_ulong vcpuid)
{
return guest; /* for GSBE_NESTED */
}
+static void *get_machine_ptr(SpaprMachineState *spapr,
+ SpaprMachineStateNestedGuest *guest,
+ target_ulong vcpuid)
+{
+ /* ignore guest and vcpuid for this */
+ return &spapr->nested;
+}
+
/*
* set=1 means the L1 is trying to set some state
* set=0 means the L1 is trying to get some state
@@ -771,6 +782,7 @@ static void copy_logical_pvr(void *a, void *b, bool set)
if (*pvr_logical_ptr) {
switch (*pvr_logical_ptr) {
+ case CPU_POWERPC_LOGICAL_3_10_P11:
case CPU_POWERPC_LOGICAL_3_10:
pcr = PCR_COMPAT_3_10 | PCR_COMPAT_3_00;
break;
@@ -982,6 +994,7 @@ struct guest_state_element_type guest_state_element_types[] = {
GUEST_STATE_ELEMENT_ENV_DW(GSB_VCPU_SPR_FSCR, fscr),
GUEST_STATE_ELEMENT_ENV_W(GSB_VCPU_SPR_PSPB, pspb),
GUEST_STATE_ELEMENT_ENV_DW(GSB_VCPU_SPR_CTRL, ctrl),
+ GUEST_STATE_ELEMENT_ENV_DW(GSB_VCPU_SPR_DPDES, dpdes),
GUEST_STATE_ELEMENT_ENV_W(GSB_VCPU_SPR_VRSAVE, vrsave),
GUEST_STATE_ELEMENT_ENV_DW(GSB_VCPU_SPR_DAR, dar),
GUEST_STATE_ELEMENT_ENV_W(GSB_VCPU_SPR_DSISR, dsisr),
@@ -1010,7 +1023,15 @@ struct guest_state_element_type guest_state_element_types[] = {
GSBE_NESTED_VCPU(GSB_VCPU_OUT_BUFFER, 0x10, runbufout, copy_state_runbuf),
GSBE_NESTED_VCPU(GSB_VCPU_OUT_BUF_MIN_SZ, 0x8, runbufout, out_buf_min_size),
GSBE_NESTED_VCPU(GSB_VCPU_HDEC_EXPIRY_TB, 0x8, hdecr_expiry_tb,
- copy_state_hdecr)
+ copy_state_hdecr),
+ GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_HEAP_INUSE, l0_guest_heap_inuse),
+ GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_HEAP_MAX, l0_guest_heap_max),
+ GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_PGTABLE_SIZE_INUSE,
+ l0_guest_pgtable_size_inuse),
+ GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_PGTABLE_SIZE_MAX,
+ l0_guest_pgtable_size_max),
+ GSBE_NESTED_MACHINE_DW(GSB_L0_GUEST_PGTABLE_RECLAIMED,
+ l0_guest_pgtable_reclaimed),
};
void spapr_nested_gsb_init(void)
@@ -1028,8 +1049,13 @@ void spapr_nested_gsb_init(void)
else if (type->id >= GSB_VCPU_IN_BUFFER)
/* 0x0c00 - 0xf000 Thread + RW */
type->flags = 0;
+ else if (type->id >= GSB_L0_GUEST_HEAP_INUSE)
+
+ /*0x0800 - 0x0804 Hostwide Counters + RO */
+ type->flags = GUEST_STATE_ELEMENT_TYPE_FLAG_HOST_WIDE |
+ GUEST_STATE_ELEMENT_TYPE_FLAG_READ_ONLY;
else if (type->id >= GSB_VCPU_LPVR)
- /* 0x0003 - 0x0bff Guest + RW */
+ /* 0x0003 - 0x07ff Guest + RW */
type->flags = GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE;
else if (type->id >= GSB_HV_VCPU_STATE_SIZE)
/* 0x0001 - 0x0002 Guest + RO */
@@ -1136,18 +1162,26 @@ static bool guest_state_request_check(struct guest_state_request *gsr)
return false;
}
- if (type->flags & GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE) {
+ if (type->flags & GUEST_STATE_ELEMENT_TYPE_FLAG_HOST_WIDE) {
+ /* Hostwide elements cant be clubbed with other types */
+ if (!(gsr->flags & GUEST_STATE_REQUEST_HOST_WIDE)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "trying to get/set a host wide "
+ "Element ID:%04x.\n", id);
+ return false;
+ }
+ } else if (type->flags & GUEST_STATE_ELEMENT_TYPE_FLAG_GUEST_WIDE) {
/* guest wide element type */
if (!(gsr->flags & GUEST_STATE_REQUEST_GUEST_WIDE)) {
- qemu_log_mask(LOG_GUEST_ERROR, "trying to set a guest wide "
+ qemu_log_mask(LOG_GUEST_ERROR, "trying to get/set a guest wide "
"Element ID:%04x.\n", id);
return false;
}
} else {
/* thread wide element type */
- if (gsr->flags & GUEST_STATE_REQUEST_GUEST_WIDE) {
- qemu_log_mask(LOG_GUEST_ERROR, "trying to set a thread wide "
- "Element ID:%04x.\n", id);
+ if (gsr->flags & (GUEST_STATE_REQUEST_GUEST_WIDE |
+ GUEST_STATE_REQUEST_HOST_WIDE)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "trying to get/set a thread wide"
+ " Element ID:%04x.\n", id);
return false;
}
}
@@ -1184,6 +1218,12 @@ static target_ulong h_guest_get_capabilities(PowerPCCPU *cpu,
return H_PARAMETER;
}
+ /* P11 capabilities */
+ if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10_P11, 0,
+ spapr->max_compat_pvr)) {
+ env->gpr[4] |= H_GUEST_CAPABILITIES_P11_MODE;
+ }
+
/* P10 capabilities */
if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0,
spapr->max_compat_pvr)) {
@@ -1226,7 +1266,10 @@ static target_ulong h_guest_set_capabilities(PowerPCCPU *cpu,
env->gpr[4] = 1;
/* set R5 to the first supported Power Processor Mode */
- if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0,
+ if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10_P11, 0,
+ spapr->max_compat_pvr)) {
+ env->gpr[5] = H_GUEST_CAP_P11_MODE_BMAP;
+ } else if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0,
spapr->max_compat_pvr)) {
env->gpr[5] = H_GUEST_CAP_P10_MODE_BMAP;
} else if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0,
@@ -1407,7 +1450,8 @@ static target_ulong h_guest_create_vcpu(PowerPCCPU *cpu,
return H_SUCCESS;
}
-static target_ulong getset_state(SpaprMachineStateNestedGuest *guest,
+static target_ulong getset_state(SpaprMachineState *spapr,
+ SpaprMachineStateNestedGuest *guest,
uint64_t vcpuid,
struct guest_state_request *gsr)
{
@@ -1440,7 +1484,7 @@ static target_ulong getset_state(SpaprMachineStateNestedGuest *guest,
/* Get pointer to guest data to get/set */
if (type->location && type->copy) {
- ptr = type->location(guest, vcpuid);
+ ptr = type->location(spapr, guest, vcpuid);
assert(ptr);
if (!~(type->mask) && is_gsr_invalid(gsr, element, type)) {
return H_INVALID_ELEMENT_VALUE;
@@ -1457,6 +1501,7 @@ next_element:
}
static target_ulong map_and_getset_state(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
SpaprMachineStateNestedGuest *guest,
uint64_t vcpuid,
struct guest_state_request *gsr)
@@ -1480,7 +1525,7 @@ static target_ulong map_and_getset_state(PowerPCCPU *cpu,
goto out1;
}
- rc = getset_state(guest, vcpuid, gsr);
+ rc = getset_state(spapr, guest, vcpuid, gsr);
out1:
address_space_unmap(CPU(cpu)->as, gsr->gsb, len, is_write, len);
@@ -1498,27 +1543,46 @@ static target_ulong h_guest_getset_state(PowerPCCPU *cpu,
target_ulong buf = args[3];
target_ulong buflen = args[4];
struct guest_state_request gsr;
- SpaprMachineStateNestedGuest *guest;
+ SpaprMachineStateNestedGuest *guest = NULL;
- guest = spapr_get_nested_guest(spapr, lpid);
- if (!guest) {
- return H_P2;
- }
gsr.buf = buf;
assert(buflen <= GSB_MAX_BUF_SIZE);
gsr.len = buflen;
gsr.flags = 0;
- if (flags & H_GUEST_GETSET_STATE_FLAG_GUEST_WIDE) {
+
+ /* Works for both get/set state */
+ if ((flags & H_GUEST_GET_STATE_FLAGS_GUEST_WIDE) ||
+ (flags & H_GUEST_SET_STATE_FLAGS_GUEST_WIDE)) {
gsr.flags |= GUEST_STATE_REQUEST_GUEST_WIDE;
}
- if (flags & ~H_GUEST_GETSET_STATE_FLAG_GUEST_WIDE) {
- return H_PARAMETER; /* flag not supported yet */
- }
if (set) {
+ if (flags & ~H_GUEST_SET_STATE_FLAGS_MASK) {
+ return H_PARAMETER;
+ }
gsr.flags |= GUEST_STATE_REQUEST_SET;
+ } else {
+ /*
+ * No reserved fields to be set in flags nor both
+ * GUEST/HOST wide bits
+ */
+ if ((flags & ~H_GUEST_GET_STATE_FLAGS_MASK) ||
+ (flags == H_GUEST_GET_STATE_FLAGS_MASK)) {
+ return H_PARAMETER;
+ }
+
+ if (flags & H_GUEST_GET_STATE_FLAGS_HOST_WIDE) {
+ gsr.flags |= GUEST_STATE_REQUEST_HOST_WIDE;
+ }
+ }
+
+ if (!(gsr.flags & GUEST_STATE_REQUEST_HOST_WIDE)) {
+ guest = spapr_get_nested_guest(spapr, lpid);
+ if (!guest) {
+ return H_P2;
+ }
}
- return map_and_getset_state(cpu, guest, vcpuid, &gsr);
+ return map_and_getset_state(cpu, spapr, guest, vcpuid, &gsr);
}
static target_ulong h_guest_set_state(PowerPCCPU *cpu,
@@ -1629,7 +1693,8 @@ static int get_exit_ids(uint64_t srr0, uint16_t ids[16])
return nr;
}
-static void exit_process_output_buffer(PowerPCCPU *cpu,
+static void exit_process_output_buffer(SpaprMachineState *spapr,
+ PowerPCCPU *cpu,
SpaprMachineStateNestedGuest *guest,
target_ulong vcpuid,
target_ulong *r3)
@@ -1667,10 +1732,9 @@ static void exit_process_output_buffer(PowerPCCPU *cpu,
gsr.gsb = gsb;
gsr.len = VCPU_OUT_BUF_MIN_SZ;
gsr.flags = 0; /* get + never guest wide */
- getset_state(guest, vcpuid, &gsr);
+ getset_state(spapr, guest, vcpuid, &gsr);
address_space_unmap(CPU(cpu)->as, gsb, len, true, len);
- return;
}
static
@@ -1693,7 +1757,7 @@ void spapr_exit_nested_papr(SpaprMachineState *spapr, PowerPCCPU *cpu, int excp)
exit_nested_store_l2(cpu, excp, vcpu);
/* do the output buffer for run_vcpu*/
- exit_process_output_buffer(cpu, guest, vcpuid, &r3_return);
+ exit_process_output_buffer(spapr, cpu, guest, vcpuid, &r3_return);
assert(env->spr[SPR_LPIDR] != 0);
nested_load_state(cpu, spapr_cpu->nested_host_state);
@@ -1808,7 +1872,7 @@ static target_ulong h_guest_run_vcpu(PowerPCCPU *cpu,
gsr.buf = vcpu->runbufin.addr;
gsr.len = vcpu->runbufin.size;
gsr.flags = GUEST_STATE_REQUEST_SET; /* Thread wide + writing */
- rc = map_and_getset_state(cpu, guest, vcpuid, &gsr);
+ rc = map_and_getset_state(cpu, spapr, guest, vcpuid, &gsr);
if (rc == H_SUCCESS) {
nested_papr_run_vcpu(cpu, lpid, vcpu);
} else {
diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c
index 7d2dfe5..72b4a63 100644
--- a/hw/ppc/spapr_nvdimm.c
+++ b/hw/ppc/spapr_nvdimm.c
@@ -235,8 +235,6 @@ void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt)
spapr_dt_nvdimm(spapr, fdt, offset, nvdimm);
}
g_slist_free(nvdimms);
-
- return;
}
static target_ulong h_scm_read_metadata(PowerPCCPU *cpu,
@@ -884,22 +882,22 @@ static void spapr_nvdimm_unrealize(NVDIMMDevice *dimm)
vmstate_unregister(NULL, &vmstate_spapr_nvdimm_states, dimm);
}
-static Property spapr_nvdimm_properties[] = {
#ifdef CONFIG_LIBPMEM
+static const Property spapr_nvdimm_properties[] = {
DEFINE_PROP_BOOL("pmem-override", SpaprNVDIMMDevice, pmem_override, false),
-#endif
- DEFINE_PROP_END_OF_LIST(),
};
+#endif
-static void spapr_nvdimm_class_init(ObjectClass *oc, void *data)
+static void spapr_nvdimm_class_init(ObjectClass *oc, const void *data)
{
- DeviceClass *dc = DEVICE_CLASS(oc);
NVDIMMClass *nvc = NVDIMM_CLASS(oc);
nvc->realize = spapr_nvdimm_realize;
nvc->unrealize = spapr_nvdimm_unrealize;
- device_class_set_props(dc, spapr_nvdimm_properties);
+#ifdef CONFIG_LIBPMEM
+ device_class_set_props(DEVICE_CLASS(oc), spapr_nvdimm_properties);
+#endif
}
static void spapr_nvdimm_init(Object *obj)
diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c
index 88e2953..75ab4fe 100644
--- a/hw/ppc/spapr_ovec.c
+++ b/hw/ppc/spapr_ovec.c
@@ -15,7 +15,8 @@
#include "hw/ppc/spapr_ovec.h"
#include "migration/vmstate.h"
#include "qemu/bitmap.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
+#include "system/memory.h"
#include "qemu/error-report.h"
#include "trace.h"
#include <libfdt.h>
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 7cf9904..1ac1185 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -34,7 +34,7 @@
#include "hw/pci/pci_host.h"
#include "hw/ppc/spapr.h"
#include "hw/pci-host/spapr.h"
-#include "exec/ram_addr.h"
+#include "system/ram_addr.h"
#include <libfdt.h>
#include "trace.h"
#include "qemu/error-report.h"
@@ -45,10 +45,10 @@
#include "hw/pci/pci_ids.h"
#include "hw/ppc/spapr_drc.h"
#include "hw/qdev-properties.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/kvm.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/numa.h"
+#include "system/device_tree.h"
+#include "system/kvm.h"
+#include "system/hostmem.h"
+#include "system/numa.h"
#include "hw/ppc/spapr_numa.h"
#include "qemu/log.h"
@@ -1237,10 +1237,6 @@ static void add_drcs(SpaprPhbState *phb, PCIBus *bus)
int i;
uint8_t chassis;
- if (!phb->dr_enabled) {
- return;
- }
-
chassis = chassis_from_bus(bus);
if (pci_bus_is_root(bus)) {
@@ -1260,10 +1256,6 @@ static void remove_drcs(SpaprPhbState *phb, PCIBus *bus)
int i;
uint8_t chassis;
- if (!phb->dr_enabled) {
- return;
- }
-
chassis = chassis_from_bus(bus);
for (i = PCI_SLOT_MAX * PCI_FUNC_MAX - 1; i >= 0; i--) {
@@ -1291,8 +1283,7 @@ static void spapr_dt_pci_device_cb(PCIBus *bus, PCIDevice *pdev,
PciWalkFdt *p = opaque;
int err;
- if (p->err) {
- /* Something's already broken, don't keep going */
+ if (p->err || !pdev->enabled) {
return;
}
@@ -1548,17 +1539,6 @@ static void spapr_pci_pre_plug(HotplugHandler *plug_handler,
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
- if (!phb->dr_enabled) {
- /* if this is a hotplug operation initiated by the user
- * we need to let them know it's not enabled
- */
- if (plugged_dev->hotplugged) {
- error_setg(errp, "Bus '%s' does not support hotplugging",
- phb->parent_obj.bus->qbus.name);
- return;
- }
- }
-
if (IS_PCI_BRIDGE(plugged_dev)) {
if (!bridge_has_valid_chassis_nr(OBJECT(plugged_dev), errp)) {
return;
@@ -1569,7 +1549,9 @@ static void spapr_pci_pre_plug(HotplugHandler *plug_handler,
* hotplug, we do not allow functions to be hotplugged to a
* slot that already has function 0 present
*/
- if (plugged_dev->hotplugged && bus->devices[PCI_DEVFN(slotnr, 0)] &&
+ if (plugged_dev->hotplugged &&
+ !pci_is_vf(pdev) &&
+ bus->devices[PCI_DEVFN(slotnr, 0)] &&
PCI_FUNC(pdev->devfn) != 0) {
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" additional functions can no longer be exposed to guest.",
@@ -1592,10 +1574,10 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
uint32_t slotnr = PCI_SLOT(pdev->devfn);
/*
- * If DR is disabled we don't need to do anything in the case of
- * hotplug or coldplug callbacks.
+ * If DR or the PCI device is disabled we don't need to do anything
+ * in the case of hotplug or coldplug callbacks.
*/
- if (!phb->dr_enabled) {
+ if (!pdev->enabled) {
return;
}
@@ -1673,13 +1655,12 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
SpaprDrc *drc = drc_from_dev(phb, pdev);
- if (!phb->dr_enabled) {
- error_setg(errp, "Bus '%s' does not support hotplugging",
- phb->parent_obj.bus->qbus.name);
+ g_assert(drc);
+
+ if (!drc->dev) {
return;
}
- g_assert(drc);
g_assert(drc->dev == plugged_dev);
if (!spapr_drc_unplug_requested(drc)) {
@@ -1847,30 +1828,15 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
assert(sphb->index != (uint32_t)-1); /* checked in spapr_phb_pre_plug() */
- if (sphb->mem64_win_size != 0) {
- if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) {
- error_setg(errp, "32-bit memory window of size 0x%"HWADDR_PRIx
- " (max 2 GiB)", sphb->mem_win_size);
- return;
- }
-
- /* 64-bit window defaults to identity mapping */
- sphb->mem64_win_pciaddr = sphb->mem64_win_addr;
- } else if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) {
- /*
- * For compatibility with old configuration, if no 64-bit MMIO
- * window is specified, but the ordinary (32-bit) memory
- * window is specified as > 2GiB, we treat it as a 2GiB 32-bit
- * window, with a 64-bit MMIO window following on immediately
- * afterwards
- */
- sphb->mem64_win_size = sphb->mem_win_size - SPAPR_PCI_MEM32_WIN_SIZE;
- sphb->mem64_win_addr = sphb->mem_win_addr + SPAPR_PCI_MEM32_WIN_SIZE;
- sphb->mem64_win_pciaddr =
- SPAPR_PCI_MEM_WIN_BUS_OFFSET + SPAPR_PCI_MEM32_WIN_SIZE;
- sphb->mem_win_size = SPAPR_PCI_MEM32_WIN_SIZE;
+ if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) {
+ error_setg(errp, "32-bit memory window of size 0x%"HWADDR_PRIx
+ " (max 2 GiB)", sphb->mem_win_size);
+ return;
}
+ /* 64-bit window defaults to identity mapping */
+ sphb->mem64_win_pciaddr = sphb->mem64_win_addr;
+
if (spapr_pci_find_phb(spapr, sphb->buid)) {
SpaprPhbState *s;
@@ -2081,7 +2047,7 @@ static void spapr_phb_reset(DeviceState *qdev)
g_hash_table_remove_all(sphb->msi);
}
-static Property spapr_phb_properties[] = {
+static const Property spapr_phb_properties[] = {
DEFINE_PROP_UINT32("index", SpaprPhbState, index, -1),
DEFINE_PROP_UINT64("mem_win_size", SpaprPhbState, mem_win_size,
SPAPR_PCI_MEM32_WIN_SIZE),
@@ -2089,8 +2055,6 @@ static Property spapr_phb_properties[] = {
SPAPR_PCI_MEM64_WIN_SIZE),
DEFINE_PROP_UINT64("io_win_size", SpaprPhbState, io_win_size,
SPAPR_PCI_IO_WIN_SIZE),
- DEFINE_PROP_BOOL("dynamic-reconfiguration", SpaprPhbState, dr_enabled,
- true),
/* Default DMA window is 0..1GB */
DEFINE_PROP_UINT64("dma_win_addr", SpaprPhbState, dma_win_addr, 0),
DEFINE_PROP_UINT64("dma_win_size", SpaprPhbState, dma_win_size, 0x40000000),
@@ -2101,13 +2065,10 @@ static Property spapr_phb_properties[] = {
(1ULL << 12) | (1ULL << 16)
| (1ULL << 21) | (1ULL << 24)),
DEFINE_PROP_UINT32("numa_node", SpaprPhbState, numa_node, -1),
- DEFINE_PROP_BOOL("pre-2.8-migration", SpaprPhbState,
- pre_2_8_migration, false),
DEFINE_PROP_BOOL("pcie-extended-configuration-space", SpaprPhbState,
pcie_ecs, true),
DEFINE_PROP_BOOL("pre-5.1-associativity", SpaprPhbState,
pre_5_1_assoc, false),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_spapr_pci_lsi = {
@@ -2140,20 +2101,6 @@ static int spapr_pci_pre_save(void *opaque)
gpointer key, value;
int i;
- if (sphb->pre_2_8_migration) {
- sphb->mig_liobn = sphb->dma_liobn[0];
- sphb->mig_mem_win_addr = sphb->mem_win_addr;
- sphb->mig_mem_win_size = sphb->mem_win_size;
- sphb->mig_io_win_addr = sphb->io_win_addr;
- sphb->mig_io_win_size = sphb->io_win_size;
-
- if ((sphb->mem64_win_size != 0)
- && (sphb->mem64_win_addr
- == (sphb->mem_win_addr + sphb->mem_win_size))) {
- sphb->mig_mem_win_size += sphb->mem64_win_size;
- }
- }
-
g_free(sphb->msi_devs);
sphb->msi_devs = NULL;
sphb->msi_devs_num = g_hash_table_size(sphb->msi);
@@ -2200,13 +2147,6 @@ static int spapr_pci_post_load(void *opaque, int version_id)
return 0;
}
-static bool pre_2_8_migration(void *opaque, int version_id)
-{
- SpaprPhbState *sphb = opaque;
-
- return sphb->pre_2_8_migration;
-}
-
static const VMStateDescription vmstate_spapr_pci = {
.name = "spapr_pci",
.version_id = 2,
@@ -2216,11 +2156,6 @@ static const VMStateDescription vmstate_spapr_pci = {
.post_load = spapr_pci_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT64_EQUAL(buid, SpaprPhbState, NULL),
- VMSTATE_UINT32_TEST(mig_liobn, SpaprPhbState, pre_2_8_migration),
- VMSTATE_UINT64_TEST(mig_mem_win_addr, SpaprPhbState, pre_2_8_migration),
- VMSTATE_UINT64_TEST(mig_mem_win_size, SpaprPhbState, pre_2_8_migration),
- VMSTATE_UINT64_TEST(mig_io_win_addr, SpaprPhbState, pre_2_8_migration),
- VMSTATE_UINT64_TEST(mig_io_win_size, SpaprPhbState, pre_2_8_migration),
VMSTATE_STRUCT_ARRAY(lsi_table, SpaprPhbState, PCI_NUM_PINS, 0,
vmstate_spapr_pci_lsi, SpaprPciLsi),
VMSTATE_INT32(msi_devs_num, SpaprPhbState),
@@ -2238,7 +2173,7 @@ static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge,
return sphb->dtbusname;
}
-static void spapr_phb_class_init(ObjectClass *klass, void *data)
+static void spapr_phb_class_init(ObjectClass *klass, const void *data)
{
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2248,7 +2183,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->realize = spapr_phb_realize;
dc->unrealize = spapr_phb_unrealize;
device_class_set_props(dc, spapr_phb_properties);
- dc->reset = spapr_phb_reset;
+ device_class_set_legacy_reset(dc, spapr_phb_reset);
dc->vmsd = &vmstate_spapr_pci;
/* Supported by TYPE_SPAPR_MACHINE */
dc->user_creatable = true;
@@ -2265,7 +2200,7 @@ static const TypeInfo spapr_phb_info = {
.instance_size = sizeof(SpaprPhbState),
.instance_finalize = spapr_phb_finalizefn,
.class_init = spapr_phb_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c
index 76b2a34..e318d0d 100644
--- a/hw/ppc/spapr_pci_vfio.c
+++ b/hw/ppc/spapr_pci_vfio.c
@@ -24,7 +24,7 @@
#include "hw/pci-host/spapr.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci_device.h"
-#include "hw/vfio/vfio-common.h"
+#include "hw/vfio/vfio-container.h"
#include "qemu/error-report.h"
#include CONFIG_DEVICES /* CONFIG_VFIO_PCI */
@@ -85,7 +85,7 @@ static int vfio_eeh_container_op(VFIOContainer *container, uint32_t op)
static VFIOContainer *vfio_eeh_as_container(AddressSpace *as)
{
- VFIOAddressSpace *space = vfio_get_address_space(as);
+ VFIOAddressSpace *space = vfio_address_space_get(as);
VFIOContainerBase *bcontainer = NULL;
if (QLIST_EMPTY(&space->containers)) {
@@ -105,7 +105,7 @@ static VFIOContainer *vfio_eeh_as_container(AddressSpace *as)
}
out:
- vfio_put_address_space(space);
+ vfio_address_space_put(space);
return container_of(bcontainer, VFIOContainer, bcontainer);
}
diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c
index c2fda7a..6fec607 100644
--- a/hw/ppc/spapr_rng.c
+++ b/hw/ppc/spapr_rng.c
@@ -22,8 +22,8 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/rng.h"
+#include "system/device_tree.h"
+#include "system/rng.h"
#include "hw/ppc/spapr.h"
#include "hw/qdev-properties.h"
#include "kvm_ppc.h"
@@ -130,14 +130,13 @@ static void spapr_rng_realize(DeviceState *dev, Error **errp)
}
}
-static Property spapr_rng_properties[] = {
+static const Property spapr_rng_properties[] = {
DEFINE_PROP_BOOL("use-kvm", SpaprRngState, use_kvm, false),
DEFINE_PROP_LINK("rng", SpaprRngState, backend, TYPE_RNG_BACKEND,
RngBackend *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void spapr_rng_class_init(ObjectClass *oc, void *data)
+static void spapr_rng_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index f329693..78309db 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -28,12 +28,12 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/cpus.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/runstate.h"
-#include "sysemu/qtest.h"
+#include "system/system.h"
+#include "system/device_tree.h"
+#include "system/cpus.h"
+#include "system/hw_accel.h"
+#include "system/runstate.h"
+#include "system/qtest.h"
#include "kvm_ppc.h"
#include "hw/ppc/spapr.h"
@@ -110,7 +110,8 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
id = rtas_ld(args, 0);
cpu = spapr_find_cpu(id);
if (cpu != NULL) {
- if (CPU(cpu)->halted) {
+ CPUPPCState *env = &cpu->env;
+ if (env->quiesced) {
rtas_st(rets, 1, 0);
} else {
rtas_st(rets, 1, 2);
@@ -215,6 +216,8 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
* For the same reason, set PSSCR_EC.
*/
env->spr[SPR_PSSCR] |= PSSCR_EC;
+ env->quiesced = true; /* set "RTAS stopped" state. */
+ ppc_maybe_interrupt(env);
cs->halted = 1;
ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
kvmppc_set_reg_ppc_online(cpu, 0);
@@ -565,7 +568,6 @@ static bool spapr_qtest_callback(CharBackend *chr, gchar **words)
g_assert(rc == 0);
res = qtest_rtas_call(words[1], nargs, args, nret, ret);
- qtest_send_prefix(chr);
qtest_sendf(chr, "OK %"PRIu64"\n", res);
return true;
diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c
index deb3ea4..1f7d2d8 100644
--- a/hw/ppc/spapr_rtc.c
+++ b/hw/ppc/spapr_rtc.c
@@ -27,8 +27,8 @@
#include "qemu/osdep.h"
#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
+#include "system/system.h"
+#include "system/rtc.h"
#include "hw/ppc/spapr.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
@@ -163,7 +163,7 @@ static const VMStateDescription vmstate_spapr_rtc = {
},
};
-static void spapr_rtc_class_init(ObjectClass *oc, void *data)
+static void spapr_rtc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c
index e10af35..1297b3a 100644
--- a/hw/ppc/spapr_tpm_proxy.c
+++ b/hw/ppc/spapr_tpm_proxy.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/ppc/spapr.h"
#include "hw/qdev-properties.h"
#include "trace.h"
@@ -41,8 +41,8 @@ static ssize_t tpm_execute(SpaprTpmProxy *tpm_proxy, target_ulong *args)
target_ulong data_in_size = args[2];
uint64_t data_out = ppc64_phys_to_real(args[3]);
target_ulong data_out_size = args[4];
- uint8_t buf_in[TPM_SPAPR_BUFSIZE];
- uint8_t buf_out[TPM_SPAPR_BUFSIZE];
+ QEMU_UNINITIALIZED uint8_t buf_in[TPM_SPAPR_BUFSIZE];
+ QEMU_UNINITIALIZED uint8_t buf_out[TPM_SPAPR_BUFSIZE];
ssize_t ret;
trace_spapr_tpm_execute(data_in, data_in_size, data_out, data_out_size);
@@ -145,12 +145,11 @@ static void spapr_tpm_proxy_unrealize(DeviceState *d)
qemu_unregister_reset(spapr_tpm_proxy_reset, tpm_proxy);
}
-static Property spapr_tpm_proxy_properties[] = {
+static const Property spapr_tpm_proxy_properties[] = {
DEFINE_PROP_STRING("host-path", SpaprTpmProxy, host_path),
- DEFINE_PROP_END_OF_LIST(),
};
-static void spapr_tpm_proxy_class_init(ObjectClass *k, void *data)
+static void spapr_tpm_proxy_class_init(ObjectClass *k, const void *data)
{
DeviceClass *dk = DEVICE_CLASS(k);
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 3221874..7759436 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -27,8 +27,8 @@
#include "hw/loader.h"
#include "elf.h"
#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "sysemu/device_tree.h"
+#include "system/kvm.h"
+#include "system/device_tree.h"
#include "kvm_ppc.h"
#include "migration/vmstate.h"
@@ -50,7 +50,7 @@ static char *spapr_vio_get_dev_name(DeviceState *qdev)
return g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
}
-static void spapr_vio_bus_class_init(ObjectClass *klass, void *data)
+static void spapr_vio_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
@@ -599,7 +599,7 @@ SpaprVioBus *spapr_vio_bus_init(void)
return bus;
}
-static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
+static void spapr_vio_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -631,11 +631,11 @@ const VMStateDescription vmstate_spapr_vio = {
},
};
-static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
+static void vio_spapr_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = spapr_vio_busdev_realize;
- k->reset = spapr_vio_busdev_reset;
+ device_class_set_legacy_reset(k, spapr_vio_busdev_reset);
k->bus_type = TYPE_SPAPR_VIO_BUS;
}
diff --git a/hw/ppc/spapr_vof.c b/hw/ppc/spapr_vof.c
index c02eaac..46d7875 100644
--- a/hw/ppc/spapr_vof.c
+++ b/hw/ppc/spapr_vof.c
@@ -10,7 +10,7 @@
#include "hw/ppc/spapr_cpu_core.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/vof.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qom/qom-qobject.h"
#include "trace.h"
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index c49da1f..c9969ae 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -28,12 +28,12 @@
#include "exec/page-protection.h"
#include "cpu.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/reset.h"
+#include "system/system.h"
+#include "system/reset.h"
#include "hw/boards.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/loader.h"
#include "elf.h"
#include "qapi/error.h"
@@ -67,29 +67,6 @@ static struct boot_info
void *vfdt;
} boot_info;
-/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- hwaddr pa)
-{
- ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
-
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0x80000000 */
- tlb->EPN = va & TARGET_PAGE_MASK;
- tlb->RPN = pa & TARGET_PAGE_MASK;
- tlb->PID = 0;
-
- tlb = &env->tlb.tlbe[1];
- tlb->attr = 0;
- tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1U << 31; /* up to 0xffffffff */
- tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
- tlb->PID = 0;
-}
-
static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
{
PowerPCCPU *cpu;
@@ -139,9 +116,10 @@ static void main_cpu_reset(void *opaque)
env->gpr[3] = bi->fdt;
env->nip = bi->bootstrap_pc;
- /* Create a mapping for the kernel. */
- mmubooke_create_initial_mapping(env, 0, 0);
- env->gpr[6] = tswap32(EPAPR_MAGIC);
+ /* Create a mapping spanning the 32bit addr space. */
+ booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1U << 31);
+ booke_set_tlb(&env->tlb.tlbe[1], 0x80000000, 0x80000000, 1U << 31);
+ env->gpr[6] = EPAPR_MAGIC;
env->gpr[7] = bi->ima_size;
}
@@ -168,7 +146,7 @@ static int xilinx_load_device_tree(MachineState *machine,
/* Try the local "ppc.dtb" override. */
fdt = load_device_tree("ppc.dtb", &fdt_size);
if (!fdt) {
- path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ path = qemu_find_file(QEMU_FILE_TYPE_DTB, BINARY_DEVICE_TREE_FILE);
if (path) {
fdt = load_device_tree(path, &fdt_size);
g_free(path);
@@ -239,6 +217,7 @@ static void virtex_init(MachineState *machine)
cpu_irq = qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT);
dev = qdev_new("xlnx.xps-intc");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_BIG);
qdev_prop_set_uint32(dev, "kind-of-intr", 0);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
@@ -252,6 +231,7 @@ static void virtex_init(MachineState *machine)
/* 2 timers at irq 2 @ 62 Mhz. */
dev = qdev_new("xlnx.xps-timer");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_BIG);
qdev_prop_set_uint32(dev, "one-timer-only", 0);
qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -264,8 +244,8 @@ static void virtex_init(MachineState *machine)
/* Boots a kernel elf binary. */
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
- &entry, NULL, &high, NULL, 1, PPC_ELF_MACHINE,
- 0, 0);
+ &entry, NULL, &high, NULL,
+ ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
boot_info.bootstrap_pc = entry & 0x00ffffff;
if (kernel_size < 0) {
diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c
index b5b6514..f14efa3 100644
--- a/hw/ppc/vof.c
+++ b/hw/ppc/vof.c
@@ -15,10 +15,10 @@
#include "qemu/units.h"
#include "qemu/log.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/ppc/vof.h"
#include "hw/ppc/fdt.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "qom/qom-qobject.h"
#include "trace.h"
diff --git a/hw/remote/iohub.c b/hw/remote/iohub.c
index 40dfee4..988d328 100644
--- a/hw/remote/iohub.c
+++ b/hw/remote/iohub.c
@@ -33,19 +33,6 @@ void remote_iohub_init(RemoteIOHubState *iohub)
}
}
-void remote_iohub_finalize(RemoteIOHubState *iohub)
-{
- int pirq;
-
- for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
- qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
- NULL, NULL, NULL);
- event_notifier_cleanup(&iohub->irqfds[pirq]);
- event_notifier_cleanup(&iohub->resamplefds[pirq]);
- qemu_mutex_destroy(&iohub->irq_level_lock[pirq]);
- }
-}
-
int remote_iohub_map_irq(PCIDevice *pci_dev, int intx)
{
return pci_dev->devfn;
diff --git a/hw/remote/iommu.c b/hw/remote/iommu.c
index 7c56aad..3e0758a 100644
--- a/hw/remote/iommu.c
+++ b/hw/remote/iommu.c
@@ -13,8 +13,8 @@
#include "hw/remote/iommu.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
+#include "system/memory.h"
+#include "system/address-spaces.h"
#include "trace.h"
/**
diff --git a/hw/remote/machine.c b/hw/remote/machine.c
index fdc6c44..e4b4783 100644
--- a/hw/remote/machine.c
+++ b/hw/remote/machine.c
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
#include "hw/remote/machine.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qapi/error.h"
#include "hw/pci/pci_host.h"
#include "hw/remote/iohub.h"
@@ -121,7 +121,7 @@ static void remote_machine_dev_unplug_cb(HotplugHandler *hotplug_dev,
}
}
-static void remote_machine_class_init(ObjectClass *oc, void *data)
+static void remote_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -146,7 +146,7 @@ static const TypeInfo remote_machine = {
.instance_size = sizeof(RemoteMachineState),
.instance_init = remote_machine_instance_init,
.class_init = remote_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
index 6d60da9..00193a5 100644
--- a/hw/remote/memory.c
+++ b/hw/remote/memory.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "hw/remote/memory.h"
-#include "exec/ram_addr.h"
+#include "system/ram_addr.h"
#include "qapi/error.h"
static void remote_sysmem_reset(void)
diff --git a/hw/remote/message.c b/hw/remote/message.c
index 38ae6c7..273f1e0 100644
--- a/hw/remote/message.c
+++ b/hw/remote/message.c
@@ -13,12 +13,12 @@
#include "io/channel.h"
#include "hw/remote/mpqemu-link.h"
#include "qapi/error.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/pci/pci.h"
#include "exec/memattrs.h"
#include "hw/remote/memory.h"
#include "hw/remote/iohub.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
MPQemuMsg *msg, Error **errp);
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
index 4394dc4..49885a1 100644
--- a/hw/remote/mpqemu-link.c
+++ b/hw/remote/mpqemu-link.c
@@ -17,7 +17,7 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "io/channel.h"
-#include "sysemu/iothread.h"
+#include "system/iothread.h"
#include "trace.h"
/*
@@ -110,7 +110,7 @@ static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, size_t len, int **fds,
bql_unlock();
}
- ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, errp);
+ ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, 0, errp);
if (drop_bql && !iothread && !qemu_in_coroutine()) {
bql_lock();
diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c
index a926f61..30ac749 100644
--- a/hw/remote/proxy-memory-listener.c
+++ b/hw/remote/proxy-memory-listener.c
@@ -10,9 +10,9 @@
#include "qemu/int128.h"
#include "qemu/range.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "exec/cpu-common.h"
-#include "exec/ram_addr.h"
+#include "system/ram_addr.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/remote/mpqemu-link.h"
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
index fbc85a8..b0165aa 100644
--- a/hw/remote/proxy.c
+++ b/hw/remote/proxy.c
@@ -21,7 +21,7 @@
#include "hw/remote/proxy-memory-listener.h"
#include "qom/object.h"
#include "qemu/event_notifier.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
static void probe_pci_info(PCIDevice *dev, Error **errp);
static void proxy_device_reset(DeviceState *dev);
@@ -191,12 +191,11 @@ static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val,
config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGWRITE);
}
-static Property proxy_properties[] = {
+static const Property proxy_properties[] = {
DEFINE_PROP_STRING("fd", PCIProxyDev, fd),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pci_proxy_dev_class_init(ObjectClass *klass, void *data)
+static void pci_proxy_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -206,7 +205,7 @@ static void pci_proxy_dev_class_init(ObjectClass *klass, void *data)
k->config_read = pci_proxy_read_config;
k->config_write = pci_proxy_write_config;
- dc->reset = proxy_device_reset;
+ device_class_set_legacy_reset(dc, proxy_device_reset);
device_class_set_props(dc, proxy_properties);
}
@@ -216,7 +215,7 @@ static const TypeInfo pci_proxy_dev_type_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIProxyDev),
.class_init = pci_proxy_dev_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c
index dc27cc8..8588290 100644
--- a/hw/remote/remote-obj.c
+++ b/hw/remote/remote-obj.c
@@ -17,7 +17,7 @@
#include "hw/remote/machine.h"
#include "io/channel-util.h"
#include "qapi/error.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/pci/pci.h"
#include "qemu/sockets.h"
#include "monitor/monitor.h"
@@ -163,7 +163,7 @@ static void remote_object_finalize(Object *obj)
g_free(o->devid);
}
-static void remote_object_class_init(ObjectClass *klass, void *data)
+static void remote_object_class_init(ObjectClass *klass, const void *data)
{
RemoteObjectClass *k = REMOTE_OBJECT_CLASS(klass);
@@ -188,7 +188,7 @@ static const TypeInfo remote_object_info = {
.instance_finalize = remote_object_finalize,
.class_size = sizeof(RemoteObjectClass),
.class_init = remote_object_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c
index 8dbafaf..ea6165e 100644
--- a/hw/remote/vfio-user-obj.c
+++ b/hw/remote/vfio-user-obj.c
@@ -43,7 +43,7 @@
#include "qom/object_interfaces.h"
#include "qemu/error-report.h"
#include "trace.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/boards.h"
#include "hw/remote/machine.h"
#include "qapi/error.h"
@@ -52,12 +52,12 @@
#include "qemu/notify.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "libvfio-user.h"
#include "hw/qdev-core.h"
#include "hw/pci/pci.h"
#include "qemu/timer.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/remote/vfio-user-obj.h"
@@ -358,7 +358,7 @@ static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset,
int access_size;
uint64_t val;
- if (memory_access_is_direct(mr, is_write)) {
+ if (memory_access_is_direct(mr, is_write, MEMTXATTRS_UNSPECIFIED)) {
/**
* Some devices expose a PCI expansion ROM, which could be buffer
* based as compared to other regions which are primarily based on
@@ -917,7 +917,7 @@ static void vfu_object_finalize(Object *obj)
}
}
-static void vfu_object_class_init(ObjectClass *klass, void *data)
+static void vfu_object_class_init(ObjectClass *klass, const void *data)
{
VfuObjectClass *k = VFU_OBJECT_CLASS(klass);
@@ -944,7 +944,7 @@ static const TypeInfo vfu_object_info = {
.instance_finalize = vfu_object_finalize,
.class_size = sizeof(VfuObjectClass),
.class_init = vfu_object_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index a2030e3..e6a0ac1 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -1,3 +1,6 @@
+config RISCV_IOMMU
+ bool
+
config RISCV_NUMA
bool
@@ -22,6 +25,14 @@ config MICROCHIP_PFSOC
select SIFIVE_PLIC
select UNIMP
+config MICROBLAZE_V
+ bool
+ default y
+ depends on RISCV32 || RISCV64
+ select XILINX
+ select XILINX_AXI
+ select XILINX_ETHLITE
+
config OPENTITAN
bool
default y
@@ -44,9 +55,10 @@ config RISCV_VIRT
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select RISCV_ACLINT
select RISCV_APLIC
+ select RISCV_IOMMU
select RISCV_IMSIC
select SIFIVE_PLIC
select SIFIVE_TEST
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index 47281ca..828a867 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -27,17 +27,17 @@
#include "hw/riscv/boot.h"
#include "hw/riscv/boot_opensbi.h"
#include "elf.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/qtest.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
+#include "system/device_tree.h"
+#include "system/qtest.h"
+#include "system/kvm.h"
+#include "system/reset.h"
#include <libfdt.h>
bool riscv_is_32bit(RISCVHartArrayState *harts)
{
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(&harts->harts[0]);
- return mcc->misa_mxl_max == MXL_RV32;
+ return mcc->def->misa_mxl_max == MXL_RV32;
}
/*
@@ -67,9 +67,16 @@ char *riscv_plic_hart_config_string(int hart_count)
return g_strjoinv(",", (char **)vals);
}
-target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts,
+void riscv_boot_info_init(RISCVBootInfo *info, RISCVHartArrayState *harts)
+{
+ info->kernel_size = 0;
+ info->initrd_size = 0;
+ info->is_32bit = riscv_is_32bit(harts);
+}
+
+target_ulong riscv_calc_kernel_start_addr(RISCVBootInfo *info,
target_ulong firmware_end_addr) {
- if (riscv_is_32bit(harts)) {
+ if (info->is_32bit) {
return QEMU_ALIGN_UP(firmware_end_addr, 4 * MiB);
} else {
return QEMU_ALIGN_UP(firmware_end_addr, 2 * MiB);
@@ -128,11 +135,11 @@ char *riscv_find_firmware(const char *firmware_filename,
target_ulong riscv_find_and_load_firmware(MachineState *machine,
const char *default_machine_firmware,
- hwaddr firmware_load_addr,
+ hwaddr *firmware_load_addr,
symbol_fn_t sym_cb)
{
char *firmware_filename;
- target_ulong firmware_end_addr = firmware_load_addr;
+ target_ulong firmware_end_addr = *firmware_load_addr;
firmware_filename = riscv_find_firmware(machine->firmware,
default_machine_firmware);
@@ -148,7 +155,7 @@ target_ulong riscv_find_and_load_firmware(MachineState *machine,
}
target_ulong riscv_load_firmware(const char *firmware_filename,
- hwaddr firmware_load_addr,
+ hwaddr *firmware_load_addr,
symbol_fn_t sym_cb)
{
uint64_t firmware_entry, firmware_end;
@@ -159,22 +166,23 @@ target_ulong riscv_load_firmware(const char *firmware_filename,
if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL,
&firmware_entry, NULL, &firmware_end, NULL,
0, EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) {
+ *firmware_load_addr = firmware_entry;
return firmware_end;
}
firmware_size = load_image_targphys_as(firmware_filename,
- firmware_load_addr,
+ *firmware_load_addr,
current_machine->ram_size, NULL);
if (firmware_size > 0) {
- return firmware_load_addr + firmware_size;
+ return *firmware_load_addr + firmware_size;
}
error_report("could not load firmware '%s'", firmware_filename);
exit(1);
}
-static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry)
+static void riscv_load_initrd(MachineState *machine, RISCVBootInfo *info)
{
const char *filename = machine->initrd_filename;
uint64_t mem_size = machine->ram_size;
@@ -195,7 +203,7 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry)
* halfway into RAM, and for boards with 1GB of RAM or more we put
* the initrd at 512MB.
*/
- start = kernel_entry + MIN(mem_size / 2, 512 * MiB);
+ start = info->image_low_addr + MIN(mem_size / 2, 512 * MiB);
size = load_ramdisk(filename, start, mem_size - start);
if (size == -1) {
@@ -206,6 +214,9 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry)
}
}
+ info->initrd_start = start;
+ info->initrd_size = size;
+
/* Some RISC-V machines (e.g. opentitan) don't have a fdt. */
if (fdt) {
end = start + size;
@@ -214,14 +225,14 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry)
}
}
-target_ulong riscv_load_kernel(MachineState *machine,
- RISCVHartArrayState *harts,
- target_ulong kernel_start_addr,
- bool load_initrd,
- symbol_fn_t sym_cb)
+void riscv_load_kernel(MachineState *machine,
+ RISCVBootInfo *info,
+ target_ulong kernel_start_addr,
+ bool load_initrd,
+ symbol_fn_t sym_cb)
{
const char *kernel_filename = machine->kernel_filename;
- uint64_t kernel_load_base, kernel_entry;
+ ssize_t kernel_size;
void *fdt = machine->fdt;
g_assert(kernel_filename != NULL);
@@ -233,21 +244,29 @@ target_ulong riscv_load_kernel(MachineState *machine,
* the (expected) load address load address. This allows kernels to have
* separate SBI and ELF entry points (used by FreeBSD, for example).
*/
- if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL,
- NULL, &kernel_load_base, NULL, NULL, 0,
- EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) {
- kernel_entry = kernel_load_base;
+ kernel_size = load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, NULL,
+ &info->image_low_addr, &info->image_high_addr,
+ NULL, ELFDATA2LSB, EM_RISCV,
+ 1, 0, NULL, true, sym_cb);
+ if (kernel_size > 0) {
+ info->kernel_size = kernel_size;
goto out;
}
- if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL,
- NULL, NULL, NULL) > 0) {
+ kernel_size = load_uimage_as(kernel_filename, &info->image_low_addr,
+ NULL, NULL, NULL, NULL, NULL);
+ if (kernel_size > 0) {
+ info->kernel_size = kernel_size;
+ info->image_high_addr = info->image_low_addr + kernel_size;
goto out;
}
- if (load_image_targphys_as(kernel_filename, kernel_start_addr,
- current_machine->ram_size, NULL) > 0) {
- kernel_entry = kernel_start_addr;
+ kernel_size = load_image_targphys_as(kernel_filename, kernel_start_addr,
+ current_machine->ram_size, NULL);
+ if (kernel_size > 0) {
+ info->kernel_size = kernel_size;
+ info->image_low_addr = kernel_start_addr;
+ info->image_high_addr = info->image_low_addr + kernel_size;
goto out;
}
@@ -256,23 +275,21 @@ target_ulong riscv_load_kernel(MachineState *machine,
out:
/*
- * For 32 bit CPUs 'kernel_entry' can be sign-extended by
+ * For 32 bit CPUs 'image_low_addr' can be sign-extended by
* load_elf_ram_sym().
*/
- if (riscv_is_32bit(harts)) {
- kernel_entry = extract64(kernel_entry, 0, 32);
+ if (info->is_32bit) {
+ info->image_low_addr = extract64(info->image_low_addr, 0, 32);
}
if (load_initrd && machine->initrd_filename) {
- riscv_load_initrd(machine, kernel_entry);
+ riscv_load_initrd(machine, info);
}
if (fdt && machine->kernel_cmdline && *machine->kernel_cmdline) {
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
machine->kernel_cmdline);
}
-
- return kernel_entry;
}
/*
@@ -292,11 +309,12 @@ out:
* The FDT is fdt_packed() during the calculation.
*/
uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size,
- MachineState *ms)
+ MachineState *ms, RISCVBootInfo *info)
{
int ret = fdt_pack(ms->fdt);
hwaddr dram_end, temp;
int fdtsize;
+ uint64_t dtb_start, dtb_start_limit;
/* Should only fail if we've built a corrupted tree */
g_assert(ret == 0);
@@ -307,6 +325,17 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size,
exit(1);
}
+ if (info->initrd_size) {
+ /* If initrd is successfully loaded, place DTB after it. */
+ dtb_start_limit = info->initrd_start + info->initrd_size;
+ } else if (info->kernel_size) {
+ /* If only kernel is successfully loaded, place DTB after it. */
+ dtb_start_limit = info->image_high_addr;
+ } else {
+ /* Otherwise, do not check DTB overlapping */
+ dtb_start_limit = 0;
+ }
+
/*
* A dram_size == 0, usually from a MemMapEntry[].size element,
* means that the DRAM block goes all the way to ms->ram_size.
@@ -316,13 +345,24 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size,
/*
* We should put fdt as far as possible to avoid kernel/initrd overwriting
- * its content. But it should be addressable by 32 bit system as well.
- * Thus, put it at an 2MB aligned address that less than fdt size from the
- * end of dram or 3GB whichever is lesser.
+ * its content. But it should be addressable by 32 bit system as well in RV32.
+ * Thus, put it near to the end of dram in RV64, and put it near to the end
+ * of dram or 3GB whichever is lesser in RV32.
*/
- temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end;
+ if (!info->is_32bit) {
+ temp = dram_end;
+ } else {
+ temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end;
+ }
- return QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB);
+ dtb_start = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB);
+
+ if (dtb_start_limit && (dtb_start < dtb_start_limit)) {
+ error_report("No enough memory to place DTB after kernel/initrd");
+ exit(1);
+ }
+
+ return dtb_start;
}
/*
@@ -334,35 +374,39 @@ void riscv_load_fdt(hwaddr fdt_addr, void *fdt)
uint32_t fdtsize = fdt_totalsize(fdt);
/* copy in the device tree */
- qemu_fdt_dumpdtb(fdt, fdtsize);
-
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
&address_space_memory);
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize));
}
-void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
- hwaddr rom_size, uint32_t reset_vec_size,
+void riscv_rom_copy_firmware_info(MachineState *machine,
+ RISCVHartArrayState *harts,
+ hwaddr rom_base, hwaddr rom_size,
+ uint32_t reset_vec_size,
uint64_t kernel_entry)
{
+ struct fw_dynamic_info32 dinfo32;
struct fw_dynamic_info dinfo;
size_t dinfo_len;
- if (sizeof(dinfo.magic) == 4) {
- dinfo.magic = cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
- dinfo.version = cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
- dinfo.next_mode = cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
- dinfo.next_addr = cpu_to_le32(kernel_entry);
+ if (riscv_is_32bit(harts)) {
+ dinfo32.magic = cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
+ dinfo32.version = cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
+ dinfo32.next_mode = cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
+ dinfo32.next_addr = cpu_to_le32(kernel_entry);
+ dinfo32.options = 0;
+ dinfo32.boot_hart = 0;
+ dinfo_len = sizeof(dinfo32);
} else {
dinfo.magic = cpu_to_le64(FW_DYNAMIC_INFO_MAGIC_VALUE);
dinfo.version = cpu_to_le64(FW_DYNAMIC_INFO_VERSION);
dinfo.next_mode = cpu_to_le64(FW_DYNAMIC_INFO_NEXT_MODE_S);
dinfo.next_addr = cpu_to_le64(kernel_entry);
+ dinfo.options = 0;
+ dinfo.boot_hart = 0;
+ dinfo_len = sizeof(dinfo);
}
- dinfo.options = 0;
- dinfo.boot_hart = 0;
- dinfo_len = sizeof(dinfo);
/**
* copy the dynamic firmware info. This information is specific to
@@ -374,7 +418,10 @@ void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
exit(1);
}
- rom_add_blob_fixed_as("mrom.finfo", &dinfo, dinfo_len,
+ rom_add_blob_fixed_as("mrom.finfo",
+ riscv_is_32bit(harts) ?
+ (void *)&dinfo32 : (void *)&dinfo,
+ dinfo_len,
rom_base + reset_vec_size,
&address_space_memory);
}
@@ -430,7 +477,9 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
}
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
rom_base, &address_space_memory);
- riscv_rom_copy_firmware_info(machine, rom_base, rom_size, sizeof(reset_vec),
+ riscv_rom_copy_firmware_info(machine, harts,
+ rom_base, rom_size,
+ sizeof(reset_vec),
kernel_entry);
}
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index f872674..c22f3a7 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -10,5 +10,8 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
+riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
+ 'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
+riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
hw_arch += {'riscv': riscv_ss}
diff --git a/hw/riscv/microblaze-v-generic.c b/hw/riscv/microblaze-v-generic.c
new file mode 100644
index 0000000..e863c50
--- /dev/null
+++ b/hw/riscv/microblaze-v-generic.c
@@ -0,0 +1,189 @@
+/*
+ * QEMU model of Microblaze V generic board.
+ *
+ * based on hw/microblaze/petalogix_ml605_mmu.c
+ *
+ * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (c) 2011 PetaLogix
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ * Copyright (C) 2024, Advanced Micro Devices, Inc.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Written by Sai Pavan Boddu <sai.pavan.boddu@amd.com
+ * and by Michal Simek <michal.simek@amd.com>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "hw/sysbus.h"
+#include "system/system.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/char/serial-mm.h"
+#include "system/address-spaces.h"
+#include "hw/char/xilinx_uartlite.h"
+#include "hw/misc/unimp.h"
+
+#define LMB_BRAM_SIZE (128 * KiB)
+#define MEMORY_BASEADDR 0x80000000
+#define INTC_BASEADDR 0x41200000
+#define TIMER_BASEADDR 0x41c00000
+#define TIMER_BASEADDR2 0x41c10000
+#define UARTLITE_BASEADDR 0x40600000
+#define ETHLITE_BASEADDR 0x40e00000
+#define UART16550_BASEADDR 0x44a10000
+#define AXIENET_BASEADDR 0x40c00000
+#define AXIDMA_BASEADDR 0x41e00000
+#define GPIO_BASEADDR 0x40000000
+#define GPIO_BASEADDR2 0x40010000
+#define GPIO_BASEADDR3 0x40020000
+#define I2C_BASEADDR 0x40800000
+#define QSPI_BASEADDR 0x44a00000
+
+#define TIMER_IRQ 0
+#define UARTLITE_IRQ 1
+#define UART16550_IRQ 4
+#define ETHLITE_IRQ 5
+#define TIMER_IRQ2 6
+#define AXIENET_IRQ 7
+#define AXIDMA_IRQ1 8
+#define AXIDMA_IRQ0 9
+
+static void mb_v_generic_init(MachineState *machine)
+{
+ ram_addr_t ram_size = machine->ram_size;
+ DeviceState *dev, *dma, *eth0;
+ Object *ds, *cs;
+ int i;
+ RISCVCPU *cpu;
+ hwaddr ddr_base = MEMORY_BASEADDR;
+ MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1);
+ MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+ qemu_irq irq[32];
+ MemoryRegion *sysmem = get_system_memory();
+
+ cpu = RISCV_CPU(object_new(machine->cpu_type));
+ object_property_set_bool(OBJECT(cpu), "h", false, NULL);
+ object_property_set_bool(OBJECT(cpu), "d", false, NULL);
+ qdev_realize(DEVICE(cpu), NULL, &error_abort);
+ /* Attach emulated BRAM through the LMB. */
+ memory_region_init_ram(phys_lmb_bram, NULL,
+ "mb_v.lmb_bram", LMB_BRAM_SIZE,
+ &error_fatal);
+ memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram);
+
+ memory_region_init_ram(phys_ram, NULL, "mb_v.ram",
+ ram_size, &error_fatal);
+ memory_region_add_subregion(sysmem, ddr_base, phys_ram);
+
+ dev = qdev_new("xlnx.xps-intc");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
+ qdev_prop_set_uint32(dev, "kind-of-intr",
+ 1 << UARTLITE_IRQ);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+ qdev_get_gpio_in(DEVICE(cpu), 11));
+ for (i = 0; i < 32; i++) {
+ irq[i] = qdev_get_gpio_in(dev, i);
+ }
+
+ /* Uartlite */
+ dev = qdev_new(TYPE_XILINX_UARTLITE);
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
+ qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, UARTLITE_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[UARTLITE_IRQ]);
+
+ /* Full uart */
+ serial_mm_init(sysmem, UART16550_BASEADDR + 0x1000, 2,
+ irq[UART16550_IRQ], 115200, serial_hd(1),
+ DEVICE_LITTLE_ENDIAN);
+
+ /* 2 timers at irq 0 @ 100 Mhz. */
+ dev = qdev_new("xlnx.xps-timer");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
+ qdev_prop_set_uint32(dev, "one-timer-only", 0);
+ qdev_prop_set_uint32(dev, "clock-frequency", 100000000);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
+
+ /* 2 timers at irq 3 @ 100 Mhz. */
+ dev = qdev_new("xlnx.xps-timer");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
+ qdev_prop_set_uint32(dev, "one-timer-only", 0);
+ qdev_prop_set_uint32(dev, "clock-frequency", 100000000);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR2);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ2]);
+
+ /* Emaclite */
+ dev = qdev_new("xlnx.xps-ethernetlite");
+ qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE);
+ qemu_configure_nic_device(dev, true, NULL);
+ qdev_prop_set_uint32(dev, "tx-ping-pong", 0);
+ qdev_prop_set_uint32(dev, "rx-ping-pong", 0);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]);
+
+ /* axi ethernet and dma initialization. */
+ eth0 = qdev_new("xlnx.axi-ethernet");
+ dma = qdev_new("xlnx.axi-dma");
+
+ /* FIXME: attach to the sysbus instead */
+ object_property_add_child(qdev_get_machine(), "xilinx-eth", OBJECT(eth0));
+ object_property_add_child(qdev_get_machine(), "xilinx-dma", OBJECT(dma));
+
+ ds = object_property_get_link(OBJECT(dma),
+ "axistream-connected-target", NULL);
+ cs = object_property_get_link(OBJECT(dma),
+ "axistream-control-connected-target", NULL);
+ qemu_configure_nic_device(eth0, true, NULL);
+ qdev_prop_set_uint32(eth0, "rxmem", 0x1000);
+ qdev_prop_set_uint32(eth0, "txmem", 0x1000);
+ object_property_set_link(OBJECT(eth0), "axistream-connected", ds,
+ &error_abort);
+ object_property_set_link(OBJECT(eth0), "axistream-control-connected", cs,
+ &error_abort);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(eth0), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(eth0), 0, irq[AXIENET_IRQ]);
+
+ ds = object_property_get_link(OBJECT(eth0),
+ "axistream-connected-target", NULL);
+ cs = object_property_get_link(OBJECT(eth0),
+ "axistream-control-connected-target", NULL);
+ qdev_prop_set_uint32(dma, "freqhz", 100000000);
+ object_property_set_link(OBJECT(dma), "axistream-connected", ds,
+ &error_abort);
+ object_property_set_link(OBJECT(dma), "axistream-control-connected", cs,
+ &error_abort);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dma), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dma), 0, irq[AXIDMA_IRQ0]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dma), 1, irq[AXIDMA_IRQ1]);
+
+ /* unimplemented devices */
+ create_unimplemented_device("gpio", GPIO_BASEADDR, 0x10000);
+ create_unimplemented_device("gpio2", GPIO_BASEADDR2, 0x10000);
+ create_unimplemented_device("gpio3", GPIO_BASEADDR3, 0x10000);
+ create_unimplemented_device("i2c", I2C_BASEADDR, 0x10000);
+ create_unimplemented_device("qspi", QSPI_BASEADDR, 0x10000);
+}
+
+static void mb_v_generic_machine_init(MachineClass *mc)
+{
+ mc->desc = "AMD Microblaze-V generic platform";
+ mc->init = mb_v_generic_init;
+ mc->min_cpus = 1;
+ mc->max_cpus = 1;
+ mc->default_cpu_type = TYPE_RISCV_CPU_BASE;
+ mc->default_cpus = 1;
+}
+
+DEFINE_MACHINE("amd-microblaze-v-generic", mb_v_generic_machine_init)
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 7725dfb..2e74783 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -39,6 +39,7 @@
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
+#include "qapi/visitor.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
@@ -51,8 +52,8 @@
#include "hw/riscv/microchip_pfsoc.h"
#include "hw/intc/riscv_aclint.h"
#include "hw/intc/sifive_plic.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
+#include "system/device_tree.h"
+#include "system/system.h"
/*
* The BIOS image used by this machine is called Hart Software Services (HSS).
@@ -61,9 +62,6 @@
#define BIOS_FILENAME "hss.bin"
#define RESET_VECTOR 0x20220000
-/* CLINT timebase frequency */
-#define CLINT_TIMEBASE_FREQ 1000000
-
/* GEM version */
#define GEM_REVISION 0x0107010c
@@ -193,6 +191,7 @@ static void microchip_pfsoc_soc_instance_init(Object *obj)
static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
+ MicrochipIcicleKitState *iks = MICROCHIP_ICICLE_KIT_MACHINE(ms);
MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev);
const MemMapEntry *memmap = microchip_pfsoc_memmap;
MemoryRegion *system_memory = get_system_memory();
@@ -253,7 +252,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus,
RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
- CLINT_TIMEBASE_FREQ, false);
+ iks->clint_timebase_freq, false);
/* L2 cache controller */
create_unimplemented_device("microchip.pfsoc.l2cc",
@@ -479,7 +478,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
qspi_xip_mem);
}
-static void microchip_pfsoc_soc_class_init(ObjectClass *oc, void *data)
+static void microchip_pfsoc_soc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -516,11 +515,11 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
uint64_t mem_low_size, mem_high_size;
hwaddr firmware_load_addr;
const char *firmware_name;
- bool kernel_as_payload = false;
target_ulong firmware_end_addr, kernel_start_addr;
uint64_t kernel_entry;
- uint32_t fdt_load_addr;
+ uint64_t fdt_load_addr;
DriveInfo *dinfo = drive_get(IF_SD, 0, 0);
+ RISCVBootInfo boot_info;
/* Sanity check on RAM size */
if (machine->ram_size < mc->default_ram_size) {
@@ -578,65 +577,135 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
}
/*
- * We follow the following table to select which payload we execute.
- *
- * -bios | -kernel | payload
- * -------+------------+--------
- * N | N | HSS
- * Y | don't care | HSS
- * N | Y | kernel
+ * We follow the following table to select which firmware we use.
*
- * This ensures backwards compatibility with how we used to expose -bios
- * to users but allows them to run through direct kernel booting as well.
- *
- * When -kernel is used for direct boot, -dtb must be present to provide
- * a valid device tree for the board, as we don't generate device tree.
+ * -bios | -kernel | firmware
+ * --------------+------------+--------
+ * none | N | error
+ * none | Y | kernel
+ * NULL, default | N | BIOS_FILENAME
+ * NULL, default | Y | RISCV64_BIOS_BIN
+ * other | don't care | other
*/
-
- if (machine->kernel_filename && machine->dtb) {
- int fdt_size;
- machine->fdt = load_device_tree(machine->dtb, &fdt_size);
- if (!machine->fdt) {
- error_report("load_device_tree() failed");
+ if (machine->firmware && !strcmp(machine->firmware, "none")) {
+ if (!machine->kernel_filename) {
+ error_report("for -bios none, a kernel is required");
exit(1);
}
- firmware_name = RISCV64_BIOS_BIN;
- firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
- kernel_as_payload = true;
- }
-
- if (!kernel_as_payload) {
- firmware_name = BIOS_FILENAME;
+ firmware_name = NULL;
+ firmware_load_addr = RESET_VECTOR;
+ } else if (!machine->firmware || !strcmp(machine->firmware, "default")) {
+ if (machine->kernel_filename) {
+ firmware_name = RISCV64_BIOS_BIN;
+ firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
+ } else {
+ firmware_name = BIOS_FILENAME;
+ firmware_load_addr = RESET_VECTOR;
+ }
+ } else {
+ firmware_name = machine->firmware;
firmware_load_addr = RESET_VECTOR;
}
- /* Load the firmware */
- firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
- firmware_load_addr, NULL);
+ /* Load the firmware if necessary */
+ firmware_end_addr = firmware_load_addr;
+ if (firmware_name) {
+ char *filename = riscv_find_firmware(firmware_name, NULL);
+ if (filename) {
+ firmware_end_addr = riscv_load_firmware(filename,
+ &firmware_load_addr, NULL);
+ g_free(filename);
+ }
+ }
- if (kernel_as_payload) {
- kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
+ riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
+ if (machine->kernel_filename) {
+ kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
firmware_end_addr);
- kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
- kernel_start_addr, true, NULL);
+ riscv_load_kernel(machine, &boot_info, kernel_start_addr,
+ true, NULL);
+ kernel_entry = boot_info.image_low_addr;
+
+ if (machine->dtb) {
+ int fdt_size;
+ machine->fdt = load_device_tree(machine->dtb, &fdt_size);
+ if (!machine->fdt) {
+ error_report("load_device_tree() failed");
+ exit(1);
+ }
+
+ /* Compute the FDT load address in DRAM */
+ hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
+ hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size;
+
+ if (kernel_entry - kernel_ram_base >= kernel_ram_size) {
+ kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base;
+ kernel_ram_size = mem_high_size;
+ }
+
+ fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size,
+ machine, &boot_info);
+ riscv_load_fdt(fdt_load_addr, machine->fdt);
+ } else {
+ warn_report_once("The QEMU microchip-icicle-kit machine does not "
+ "generate a device tree, so no device tree is "
+ "being provided to the guest.");
+ fdt_load_addr = 0;
+ }
- /* Compute the fdt load address in dram */
- fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base,
- memmap[MICROCHIP_PFSOC_DRAM_LO].size,
- machine);
- riscv_load_fdt(fdt_load_addr, machine->fdt);
+ hwaddr start_addr;
+ if (firmware_name) {
+ start_addr = firmware_load_addr;
+ } else {
+ start_addr = kernel_entry;
+ }
/* Load the reset vector */
- riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr,
+ riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, start_addr,
memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
memmap[MICROCHIP_PFSOC_ENVM_DATA].size,
kernel_entry, fdt_load_addr);
}
}
-static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)
+static void microchip_icicle_kit_set_clint_timebase_freq(Object *obj,
+ Visitor *v,
+ const char *name,
+ void *opaque,
+ Error **errp)
+{
+ MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj);
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ s->clint_timebase_freq = value;
+}
+
+static void microchip_icicle_kit_get_clint_timebase_freq(Object *obj,
+ Visitor *v,
+ const char *name,
+ void *opaque,
+ Error **errp)
+{
+ MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj);
+ uint32_t value = s->clint_timebase_freq;
+
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void microchip_icicle_kit_machine_instance_init(Object *obj)
+{
+ MicrochipIcicleKitState *m = MICROCHIP_ICICLE_KIT_MACHINE(obj);
+ m->clint_timebase_freq = 1000000;
+}
+
+static void microchip_icicle_kit_machine_class_init(ObjectClass *oc,
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -647,6 +716,7 @@ static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)
mc->min_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + 1;
mc->default_cpus = mc->min_cpus;
mc->default_ram_id = "microchip.icicle.kit.ram";
+ mc->auto_create_sdcard = true;
/*
* Map 513 MiB high memory, the minimum required high memory size, because
@@ -656,12 +726,20 @@ static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)
* See memory_tests() in mss_ddr.c in the HSS source code.
*/
mc->default_ram_size = 1537 * MiB;
+
+ object_class_property_add(oc, "clint-timebase-frequency", "uint32_t",
+ microchip_icicle_kit_get_clint_timebase_freq,
+ microchip_icicle_kit_set_clint_timebase_freq,
+ NULL, NULL);
+ object_class_property_set_description(oc, "clint-timebase-frequency",
+ "Set CLINT timebase frequency in Hz.");
}
static const TypeInfo microchip_icicle_kit_machine_typeinfo = {
.name = MACHINE_TYPE_NAME("microchip-icicle-kit"),
.parent = TYPE_MACHINE,
.class_init = microchip_icicle_kit_machine_class_init,
+ .instance_init = microchip_icicle_kit_machine_instance_init,
.instance_size = sizeof(MicrochipIcicleKitState),
};
diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c
index cf686f4..7a7b012 100644
--- a/hw/riscv/numa.c
+++ b/hw/riscv/numa.c
@@ -23,7 +23,7 @@
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "hw/riscv/numa.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
static bool numa_enabled(const MachineState *ms)
{
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 436503f..d369a8a 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -27,7 +27,8 @@
#include "hw/misc/unimp.h"
#include "hw/riscv/boot.h"
#include "qemu/units.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
+#include "system/address-spaces.h"
/*
* This version of the OpenTitan machine currently supports
@@ -81,6 +82,7 @@ static void opentitan_machine_init(MachineState *machine)
OpenTitanState *s = OPENTITAN_MACHINE(machine);
const MemMapEntry *memmap = ibex_memmap;
MemoryRegion *sys_mem = get_system_memory();
+ RISCVBootInfo boot_info;
if (machine->ram_size != mc->default_ram_size) {
char *sz = size_to_str(mc->default_ram_size);
@@ -98,17 +100,19 @@ static void opentitan_machine_init(MachineState *machine)
memmap[IBEX_DEV_RAM].base, machine->ram);
if (machine->firmware) {
- riscv_load_firmware(machine->firmware, memmap[IBEX_DEV_RAM].base, NULL);
+ hwaddr firmware_load_addr = memmap[IBEX_DEV_RAM].base;
+ riscv_load_firmware(machine->firmware, &firmware_load_addr, NULL);
}
+ riscv_boot_info_init(&boot_info, &s->soc.cpus);
if (machine->kernel_filename) {
- riscv_load_kernel(machine, &s->soc.cpus,
+ riscv_load_kernel(machine, &boot_info,
memmap[IBEX_DEV_RAM].base,
false, NULL);
}
}
-static void opentitan_machine_class_init(ObjectClass *oc, void *data)
+static void opentitan_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -305,12 +309,11 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
memmap[IBEX_DEV_IBEX_CFG].base, memmap[IBEX_DEV_IBEX_CFG].size);
}
-static Property lowrisc_ibex_soc_props[] = {
+static const Property lowrisc_ibex_soc_props[] = {
DEFINE_PROP_UINT32("resetvec", LowRISCIbexSoCState, resetvec, 0x20000400),
- DEFINE_PROP_END_OF_LIST()
};
-static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data)
+static void lowrisc_ibex_soc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h
new file mode 100644
index 0000000..1017d73
--- /dev/null
+++ b/hw/riscv/riscv-iommu-bits.h
@@ -0,0 +1,468 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright © 2022-2023 Rivos Inc.
+ * Copyright © 2023 FORTH-ICS/CARV
+ * Copyright © 2023 RISC-V IOMMU Task Group
+ *
+ * RISC-V IOMMU - Register Layout and Data Structures.
+ *
+ * Based on the IOMMU spec version 1.0, 3/2023
+ * https://github.com/riscv-non-isa/riscv-iommu
+ */
+
+#ifndef HW_RISCV_IOMMU_BITS_H
+#define HW_RISCV_IOMMU_BITS_H
+
+#define RISCV_IOMMU_SPEC_DOT_VER 0x010
+
+#ifndef GENMASK_ULL
+#define GENMASK_ULL(h, l) (((~0ULL) >> (63 - (h) + (l))) << (l))
+#endif
+
+/*
+ * struct riscv_iommu_fq_record - Fault/Event Queue Record
+ * See section 3.2 for more info.
+ */
+struct riscv_iommu_fq_record {
+ uint64_t hdr;
+ uint64_t _reserved;
+ uint64_t iotval;
+ uint64_t iotval2;
+};
+/* Header fields */
+#define RISCV_IOMMU_FQ_HDR_CAUSE GENMASK_ULL(11, 0)
+#define RISCV_IOMMU_FQ_HDR_PID GENMASK_ULL(31, 12)
+#define RISCV_IOMMU_FQ_HDR_PV BIT_ULL(32)
+#define RISCV_IOMMU_FQ_HDR_TTYPE GENMASK_ULL(39, 34)
+#define RISCV_IOMMU_FQ_HDR_DID GENMASK_ULL(63, 40)
+
+/*
+ * struct riscv_iommu_pq_record - PCIe Page Request record
+ * For more infos on the PCIe Page Request queue see chapter 3.3.
+ */
+struct riscv_iommu_pq_record {
+ uint64_t hdr;
+ uint64_t payload;
+};
+/* Header fields */
+#define RISCV_IOMMU_PREQ_HDR_PID GENMASK_ULL(31, 12)
+#define RISCV_IOMMU_PREQ_HDR_PV BIT_ULL(32)
+#define RISCV_IOMMU_PREQ_HDR_PRIV BIT_ULL(33)
+#define RISCV_IOMMU_PREQ_HDR_EXEC BIT_ULL(34)
+#define RISCV_IOMMU_PREQ_HDR_DID GENMASK_ULL(63, 40)
+
+/* Payload fields */
+#define RISCV_IOMMU_PREQ_PAYLOAD_R BIT_ULL(0)
+#define RISCV_IOMMU_PREQ_PAYLOAD_W BIT_ULL(1)
+#define RISCV_IOMMU_PREQ_PAYLOAD_L BIT_ULL(2)
+#define RISCV_IOMMU_PREQ_PAYLOAD_M GENMASK_ULL(2, 0)
+#define RISCV_IOMMU_PREQ_PRG_INDEX GENMASK_ULL(11, 3)
+#define RISCV_IOMMU_PREQ_UADDR GENMASK_ULL(63, 12)
+
+/* Common field positions */
+#define RISCV_IOMMU_PPN_FIELD GENMASK_ULL(53, 10)
+#define RISCV_IOMMU_QUEUE_LOGSZ_FIELD GENMASK_ULL(4, 0)
+#define RISCV_IOMMU_QUEUE_INDEX_FIELD GENMASK_ULL(31, 0)
+#define RISCV_IOMMU_QUEUE_ENABLE BIT(0)
+#define RISCV_IOMMU_QUEUE_INTR_ENABLE BIT(1)
+#define RISCV_IOMMU_QUEUE_MEM_FAULT BIT(8)
+#define RISCV_IOMMU_QUEUE_OVERFLOW BIT(9)
+#define RISCV_IOMMU_QUEUE_ACTIVE BIT(16)
+#define RISCV_IOMMU_QUEUE_BUSY BIT(17)
+#define RISCV_IOMMU_ATP_PPN_FIELD GENMASK_ULL(43, 0)
+#define RISCV_IOMMU_ATP_MODE_FIELD GENMASK_ULL(63, 60)
+
+/* 5.3 IOMMU Capabilities (64bits) */
+#define RISCV_IOMMU_REG_CAP 0x0000
+#define RISCV_IOMMU_CAP_VERSION GENMASK_ULL(7, 0)
+#define RISCV_IOMMU_CAP_SV32 BIT_ULL(8)
+#define RISCV_IOMMU_CAP_SV39 BIT_ULL(9)
+#define RISCV_IOMMU_CAP_SV48 BIT_ULL(10)
+#define RISCV_IOMMU_CAP_SV57 BIT_ULL(11)
+#define RISCV_IOMMU_CAP_SV32X4 BIT_ULL(16)
+#define RISCV_IOMMU_CAP_SV39X4 BIT_ULL(17)
+#define RISCV_IOMMU_CAP_SV48X4 BIT_ULL(18)
+#define RISCV_IOMMU_CAP_SV57X4 BIT_ULL(19)
+#define RISCV_IOMMU_CAP_MSI_FLAT BIT_ULL(22)
+#define RISCV_IOMMU_CAP_MSI_MRIF BIT_ULL(23)
+#define RISCV_IOMMU_CAP_ATS BIT_ULL(25)
+#define RISCV_IOMMU_CAP_T2GPA BIT_ULL(26)
+#define RISCV_IOMMU_CAP_IGS GENMASK_ULL(29, 28)
+#define RISCV_IOMMU_CAP_HPM BIT_ULL(30)
+#define RISCV_IOMMU_CAP_DBG BIT_ULL(31)
+#define RISCV_IOMMU_CAP_PAS GENMASK_ULL(37, 32)
+#define RISCV_IOMMU_CAP_PD8 BIT_ULL(38)
+#define RISCV_IOMMU_CAP_PD17 BIT_ULL(39)
+#define RISCV_IOMMU_CAP_PD20 BIT_ULL(40)
+
+enum riscv_iommu_igs_modes {
+ RISCV_IOMMU_CAP_IGS_MSI = 0,
+ RISCV_IOMMU_CAP_IGS_WSI,
+ RISCV_IOMMU_CAP_IGS_BOTH
+};
+
+/* 5.4 Features control register (32bits) */
+#define RISCV_IOMMU_REG_FCTL 0x0008
+#define RISCV_IOMMU_FCTL_BE BIT(0)
+#define RISCV_IOMMU_FCTL_WSI BIT(1)
+#define RISCV_IOMMU_FCTL_GXL BIT(2)
+
+/* 5.5 Device-directory-table pointer (64bits) */
+#define RISCV_IOMMU_REG_DDTP 0x0010
+#define RISCV_IOMMU_DDTP_MODE GENMASK_ULL(3, 0)
+#define RISCV_IOMMU_DDTP_BUSY BIT_ULL(4)
+#define RISCV_IOMMU_DDTP_PPN RISCV_IOMMU_PPN_FIELD
+
+enum riscv_iommu_ddtp_modes {
+ RISCV_IOMMU_DDTP_MODE_OFF = 0,
+ RISCV_IOMMU_DDTP_MODE_BARE = 1,
+ RISCV_IOMMU_DDTP_MODE_1LVL = 2,
+ RISCV_IOMMU_DDTP_MODE_2LVL = 3,
+ RISCV_IOMMU_DDTP_MODE_3LVL = 4,
+ RISCV_IOMMU_DDTP_MODE_MAX = 4
+};
+
+/* 5.6 Command Queue Base (64bits) */
+#define RISCV_IOMMU_REG_CQB 0x0018
+#define RISCV_IOMMU_CQB_LOG2SZ RISCV_IOMMU_QUEUE_LOGSZ_FIELD
+#define RISCV_IOMMU_CQB_PPN RISCV_IOMMU_PPN_FIELD
+
+/* 5.7 Command Queue head (32bits) */
+#define RISCV_IOMMU_REG_CQH 0x0020
+
+/* 5.8 Command Queue tail (32bits) */
+#define RISCV_IOMMU_REG_CQT 0x0024
+
+/* 5.9 Fault Queue Base (64bits) */
+#define RISCV_IOMMU_REG_FQB 0x0028
+#define RISCV_IOMMU_FQB_LOG2SZ RISCV_IOMMU_QUEUE_LOGSZ_FIELD
+#define RISCV_IOMMU_FQB_PPN RISCV_IOMMU_PPN_FIELD
+
+/* 5.10 Fault Queue Head (32bits) */
+#define RISCV_IOMMU_REG_FQH 0x0030
+
+/* 5.11 Fault Queue tail (32bits) */
+#define RISCV_IOMMU_REG_FQT 0x0034
+
+/* 5.12 Page Request Queue base (64bits) */
+#define RISCV_IOMMU_REG_PQB 0x0038
+#define RISCV_IOMMU_PQB_LOG2SZ RISCV_IOMMU_QUEUE_LOGSZ_FIELD
+#define RISCV_IOMMU_PQB_PPN RISCV_IOMMU_PPN_FIELD
+
+/* 5.13 Page Request Queue head (32bits) */
+#define RISCV_IOMMU_REG_PQH 0x0040
+
+/* 5.14 Page Request Queue tail (32bits) */
+#define RISCV_IOMMU_REG_PQT 0x0044
+
+/* 5.15 Command Queue CSR (32bits) */
+#define RISCV_IOMMU_REG_CQCSR 0x0048
+#define RISCV_IOMMU_CQCSR_CQEN RISCV_IOMMU_QUEUE_ENABLE
+#define RISCV_IOMMU_CQCSR_CIE RISCV_IOMMU_QUEUE_INTR_ENABLE
+#define RISCV_IOMMU_CQCSR_CQMF RISCV_IOMMU_QUEUE_MEM_FAULT
+#define RISCV_IOMMU_CQCSR_CMD_TO BIT(9)
+#define RISCV_IOMMU_CQCSR_CMD_ILL BIT(10)
+#define RISCV_IOMMU_CQCSR_FENCE_W_IP BIT(11)
+#define RISCV_IOMMU_CQCSR_CQON RISCV_IOMMU_QUEUE_ACTIVE
+#define RISCV_IOMMU_CQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
+
+/* 5.16 Fault Queue CSR (32bits) */
+#define RISCV_IOMMU_REG_FQCSR 0x004C
+#define RISCV_IOMMU_FQCSR_FQEN RISCV_IOMMU_QUEUE_ENABLE
+#define RISCV_IOMMU_FQCSR_FIE RISCV_IOMMU_QUEUE_INTR_ENABLE
+#define RISCV_IOMMU_FQCSR_FQMF RISCV_IOMMU_QUEUE_MEM_FAULT
+#define RISCV_IOMMU_FQCSR_FQOF RISCV_IOMMU_QUEUE_OVERFLOW
+#define RISCV_IOMMU_FQCSR_FQON RISCV_IOMMU_QUEUE_ACTIVE
+#define RISCV_IOMMU_FQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
+
+/* 5.17 Page Request Queue CSR (32bits) */
+#define RISCV_IOMMU_REG_PQCSR 0x0050
+#define RISCV_IOMMU_PQCSR_PQEN RISCV_IOMMU_QUEUE_ENABLE
+#define RISCV_IOMMU_PQCSR_PIE RISCV_IOMMU_QUEUE_INTR_ENABLE
+#define RISCV_IOMMU_PQCSR_PQMF RISCV_IOMMU_QUEUE_MEM_FAULT
+#define RISCV_IOMMU_PQCSR_PQOF RISCV_IOMMU_QUEUE_OVERFLOW
+#define RISCV_IOMMU_PQCSR_PQON RISCV_IOMMU_QUEUE_ACTIVE
+#define RISCV_IOMMU_PQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY
+
+/* 5.18 Interrupt Pending Status (32bits) */
+#define RISCV_IOMMU_REG_IPSR 0x0054
+#define RISCV_IOMMU_IPSR_CIP BIT(0)
+#define RISCV_IOMMU_IPSR_FIP BIT(1)
+#define RISCV_IOMMU_IPSR_PIP BIT(3)
+
+enum {
+ RISCV_IOMMU_INTR_CQ,
+ RISCV_IOMMU_INTR_FQ,
+ RISCV_IOMMU_INTR_PM,
+ RISCV_IOMMU_INTR_PQ,
+ RISCV_IOMMU_INTR_COUNT
+};
+
+#define RISCV_IOMMU_IOCOUNT_NUM 31
+
+/* 5.19 Performance monitoring counter overflow status (32bits) */
+#define RISCV_IOMMU_REG_IOCOUNTOVF 0x0058
+#define RISCV_IOMMU_IOCOUNTOVF_CY BIT(0)
+
+/* 5.20 Performance monitoring counter inhibits (32bits) */
+#define RISCV_IOMMU_REG_IOCOUNTINH 0x005C
+#define RISCV_IOMMU_IOCOUNTINH_CY BIT(0)
+
+/* 5.21 Performance monitoring cycles counter (64bits) */
+#define RISCV_IOMMU_REG_IOHPMCYCLES 0x0060
+#define RISCV_IOMMU_IOHPMCYCLES_COUNTER GENMASK_ULL(62, 0)
+#define RISCV_IOMMU_IOHPMCYCLES_OVF BIT_ULL(63)
+
+/* 5.22 Performance monitoring event counters (31 * 64bits) */
+#define RISCV_IOMMU_REG_IOHPMCTR_BASE 0x0068
+#define RISCV_IOMMU_REG_IOHPMCTR(_n) \
+ (RISCV_IOMMU_REG_IOHPMCTR_BASE + (_n * 0x8))
+
+/* 5.23 Performance monitoring event selectors (31 * 64bits) */
+#define RISCV_IOMMU_REG_IOHPMEVT_BASE 0x0160
+#define RISCV_IOMMU_REG_IOHPMEVT(_n) \
+ (RISCV_IOMMU_REG_IOHPMEVT_BASE + (_n * 0x8))
+#define RISCV_IOMMU_IOHPMEVT_EVENT_ID GENMASK_ULL(14, 0)
+#define RISCV_IOMMU_IOHPMEVT_DMASK BIT_ULL(15)
+#define RISCV_IOMMU_IOHPMEVT_PID_PSCID GENMASK_ULL(35, 16)
+#define RISCV_IOMMU_IOHPMEVT_DID_GSCID GENMASK_ULL(59, 36)
+#define RISCV_IOMMU_IOHPMEVT_PV_PSCV BIT_ULL(60)
+#define RISCV_IOMMU_IOHPMEVT_DV_GSCV BIT_ULL(61)
+#define RISCV_IOMMU_IOHPMEVT_IDT BIT_ULL(62)
+#define RISCV_IOMMU_IOHPMEVT_OF BIT_ULL(63)
+
+enum RISCV_IOMMU_HPMEVENT_id {
+ RISCV_IOMMU_HPMEVENT_INVALID = 0,
+ RISCV_IOMMU_HPMEVENT_URQ = 1,
+ RISCV_IOMMU_HPMEVENT_TRQ = 2,
+ RISCV_IOMMU_HPMEVENT_ATS_RQ = 3,
+ RISCV_IOMMU_HPMEVENT_TLB_MISS = 4,
+ RISCV_IOMMU_HPMEVENT_DD_WALK = 5,
+ RISCV_IOMMU_HPMEVENT_PD_WALK = 6,
+ RISCV_IOMMU_HPMEVENT_S_VS_WALKS = 7,
+ RISCV_IOMMU_HPMEVENT_G_WALKS = 8,
+ RISCV_IOMMU_HPMEVENT_MAX = 9
+};
+
+/* 5.24 Translation request IOVA (64bits) */
+#define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258
+
+/* 5.25 Translation request control (64bits) */
+#define RISCV_IOMMU_REG_TR_REQ_CTL 0x0260
+#define RISCV_IOMMU_TR_REQ_CTL_GO_BUSY BIT_ULL(0)
+#define RISCV_IOMMU_TR_REQ_CTL_NW BIT_ULL(3)
+#define RISCV_IOMMU_TR_REQ_CTL_PID GENMASK_ULL(31, 12)
+#define RISCV_IOMMU_TR_REQ_CTL_DID GENMASK_ULL(63, 40)
+
+/* 5.26 Translation request response (64bits) */
+#define RISCV_IOMMU_REG_TR_RESPONSE 0x0268
+#define RISCV_IOMMU_TR_RESPONSE_FAULT BIT_ULL(0)
+#define RISCV_IOMMU_TR_RESPONSE_S BIT_ULL(9)
+#define RISCV_IOMMU_TR_RESPONSE_PPN RISCV_IOMMU_PPN_FIELD
+
+/* 5.27 Interrupt cause to vector (64bits) */
+#define RISCV_IOMMU_REG_ICVEC 0x02F8
+#define RISCV_IOMMU_ICVEC_CIV GENMASK_ULL(3, 0)
+#define RISCV_IOMMU_ICVEC_FIV GENMASK_ULL(7, 4)
+#define RISCV_IOMMU_ICVEC_PMIV GENMASK_ULL(11, 8)
+#define RISCV_IOMMU_ICVEC_PIV GENMASK_ULL(15, 12)
+
+/* 5.28 MSI Configuration table (32 * 64bits) */
+#define RISCV_IOMMU_REG_MSI_CONFIG 0x0300
+
+#define RISCV_IOMMU_REG_SIZE 0x1000
+
+#define RISCV_IOMMU_DDTE_VALID BIT_ULL(0)
+#define RISCV_IOMMU_DDTE_PPN RISCV_IOMMU_PPN_FIELD
+
+/* Struct riscv_iommu_dc - Device Context - section 2.1 */
+struct riscv_iommu_dc {
+ uint64_t tc;
+ uint64_t iohgatp;
+ uint64_t ta;
+ uint64_t fsc;
+ uint64_t msiptp;
+ uint64_t msi_addr_mask;
+ uint64_t msi_addr_pattern;
+ uint64_t _reserved;
+};
+
+/* Translation control fields */
+#define RISCV_IOMMU_DC_TC_V BIT_ULL(0)
+#define RISCV_IOMMU_DC_TC_EN_ATS BIT_ULL(1)
+#define RISCV_IOMMU_DC_TC_EN_PRI BIT_ULL(2)
+#define RISCV_IOMMU_DC_TC_T2GPA BIT_ULL(3)
+#define RISCV_IOMMU_DC_TC_DTF BIT_ULL(4)
+#define RISCV_IOMMU_DC_TC_PDTV BIT_ULL(5)
+#define RISCV_IOMMU_DC_TC_PRPR BIT_ULL(6)
+#define RISCV_IOMMU_DC_TC_GADE BIT_ULL(7)
+#define RISCV_IOMMU_DC_TC_SADE BIT_ULL(8)
+#define RISCV_IOMMU_DC_TC_DPE BIT_ULL(9)
+#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
+#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
+
+/* Second-stage (aka G-stage) context fields */
+#define RISCV_IOMMU_DC_IOHGATP_PPN RISCV_IOMMU_ATP_PPN_FIELD
+#define RISCV_IOMMU_DC_IOHGATP_GSCID GENMASK_ULL(59, 44)
+#define RISCV_IOMMU_DC_IOHGATP_MODE RISCV_IOMMU_ATP_MODE_FIELD
+
+enum riscv_iommu_dc_iohgatp_modes {
+ RISCV_IOMMU_DC_IOHGATP_MODE_BARE = 0,
+ RISCV_IOMMU_DC_IOHGATP_MODE_SV32X4 = 8,
+ RISCV_IOMMU_DC_IOHGATP_MODE_SV39X4 = 8,
+ RISCV_IOMMU_DC_IOHGATP_MODE_SV48X4 = 9,
+ RISCV_IOMMU_DC_IOHGATP_MODE_SV57X4 = 10
+};
+
+/* Translation attributes fields */
+#define RISCV_IOMMU_DC_TA_PSCID GENMASK_ULL(31, 12)
+
+/* First-stage context fields */
+#define RISCV_IOMMU_DC_FSC_PPN RISCV_IOMMU_ATP_PPN_FIELD
+#define RISCV_IOMMU_DC_FSC_MODE RISCV_IOMMU_ATP_MODE_FIELD
+
+/* Generic I/O MMU command structure - check section 3.1 */
+struct riscv_iommu_command {
+ uint64_t dword0;
+ uint64_t dword1;
+};
+
+#define RISCV_IOMMU_CMD_OPCODE GENMASK_ULL(6, 0)
+#define RISCV_IOMMU_CMD_FUNC GENMASK_ULL(9, 7)
+
+#define RISCV_IOMMU_CMD_IOTINVAL_OPCODE 1
+#define RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA 0
+#define RISCV_IOMMU_CMD_IOTINVAL_FUNC_GVMA 1
+#define RISCV_IOMMU_CMD_IOTINVAL_AV BIT_ULL(10)
+#define RISCV_IOMMU_CMD_IOTINVAL_PSCID GENMASK_ULL(31, 12)
+#define RISCV_IOMMU_CMD_IOTINVAL_PSCV BIT_ULL(32)
+#define RISCV_IOMMU_CMD_IOTINVAL_GV BIT_ULL(33)
+#define RISCV_IOMMU_CMD_IOTINVAL_GSCID GENMASK_ULL(59, 44)
+
+#define RISCV_IOMMU_CMD_IOFENCE_OPCODE 2
+#define RISCV_IOMMU_CMD_IOFENCE_FUNC_C 0
+#define RISCV_IOMMU_CMD_IOFENCE_AV BIT_ULL(10)
+#define RISCV_IOMMU_CMD_IOFENCE_DATA GENMASK_ULL(63, 32)
+
+#define RISCV_IOMMU_CMD_IODIR_OPCODE 3
+#define RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT 0
+#define RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_PDT 1
+#define RISCV_IOMMU_CMD_IODIR_PID GENMASK_ULL(31, 12)
+#define RISCV_IOMMU_CMD_IODIR_DV BIT_ULL(33)
+#define RISCV_IOMMU_CMD_IODIR_DID GENMASK_ULL(63, 40)
+
+/* 3.1.4 I/O MMU PCIe ATS */
+#define RISCV_IOMMU_CMD_ATS_OPCODE 4
+#define RISCV_IOMMU_CMD_ATS_FUNC_INVAL 0
+#define RISCV_IOMMU_CMD_ATS_FUNC_PRGR 1
+#define RISCV_IOMMU_CMD_ATS_PID GENMASK_ULL(31, 12)
+#define RISCV_IOMMU_CMD_ATS_PV BIT_ULL(32)
+#define RISCV_IOMMU_CMD_ATS_DSV BIT_ULL(33)
+#define RISCV_IOMMU_CMD_ATS_RID GENMASK_ULL(55, 40)
+#define RISCV_IOMMU_CMD_ATS_DSEG GENMASK_ULL(63, 56)
+/* dword1 is the ATS payload, two different payload types for INVAL and PRGR */
+
+/* ATS.PRGR payload */
+#define RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE GENMASK_ULL(47, 44)
+
+enum riscv_iommu_dc_fsc_atp_modes {
+ RISCV_IOMMU_DC_FSC_MODE_BARE = 0,
+ RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV32 = 8,
+ RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39 = 8,
+ RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48 = 9,
+ RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57 = 10,
+ RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8 = 1,
+ RISCV_IOMMU_DC_FSC_PDTP_MODE_PD17 = 2,
+ RISCV_IOMMU_DC_FSC_PDTP_MODE_PD20 = 3
+};
+
+enum riscv_iommu_fq_causes {
+ RISCV_IOMMU_FQ_CAUSE_INST_FAULT = 1,
+ RISCV_IOMMU_FQ_CAUSE_RD_ADDR_MISALIGNED = 4,
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT = 5,
+ RISCV_IOMMU_FQ_CAUSE_WR_ADDR_MISALIGNED = 6,
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT = 7,
+ RISCV_IOMMU_FQ_CAUSE_INST_FAULT_S = 12,
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S = 13,
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S = 15,
+ RISCV_IOMMU_FQ_CAUSE_INST_FAULT_VS = 20,
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS = 21,
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS = 23,
+ RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED = 256,
+ RISCV_IOMMU_FQ_CAUSE_DDT_LOAD_FAULT = 257,
+ RISCV_IOMMU_FQ_CAUSE_DDT_INVALID = 258,
+ RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED = 259,
+ RISCV_IOMMU_FQ_CAUSE_TTYPE_BLOCKED = 260,
+ RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT = 261,
+ RISCV_IOMMU_FQ_CAUSE_MSI_INVALID = 262,
+ RISCV_IOMMU_FQ_CAUSE_MSI_MISCONFIGURED = 263,
+ RISCV_IOMMU_FQ_CAUSE_MRIF_FAULT = 264,
+ RISCV_IOMMU_FQ_CAUSE_PDT_LOAD_FAULT = 265,
+ RISCV_IOMMU_FQ_CAUSE_PDT_INVALID = 266,
+ RISCV_IOMMU_FQ_CAUSE_PDT_MISCONFIGURED = 267,
+ RISCV_IOMMU_FQ_CAUSE_DDT_CORRUPTED = 268,
+ RISCV_IOMMU_FQ_CAUSE_PDT_CORRUPTED = 269,
+ RISCV_IOMMU_FQ_CAUSE_MSI_PT_CORRUPTED = 270,
+ RISCV_IOMMU_FQ_CAUSE_MRIF_CORRUIPTED = 271,
+ RISCV_IOMMU_FQ_CAUSE_INTERNAL_DP_ERROR = 272,
+ RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT = 273,
+ RISCV_IOMMU_FQ_CAUSE_PT_CORRUPTED = 274
+};
+
+/* MSI page table pointer */
+#define RISCV_IOMMU_DC_MSIPTP_PPN RISCV_IOMMU_ATP_PPN_FIELD
+#define RISCV_IOMMU_DC_MSIPTP_MODE RISCV_IOMMU_ATP_MODE_FIELD
+#define RISCV_IOMMU_DC_MSIPTP_MODE_OFF 0
+#define RISCV_IOMMU_DC_MSIPTP_MODE_FLAT 1
+
+/* 2.2 Process Directory Table */
+#define RISCV_IOMMU_PDTE_VALID BIT_ULL(0)
+#define RISCV_IOMMU_PDTE_PPN RISCV_IOMMU_PPN_FIELD
+
+/* Translation attributes fields */
+#define RISCV_IOMMU_PC_TA_V BIT_ULL(0)
+#define RISCV_IOMMU_PC_TA_RESERVED GENMASK_ULL(63, 32)
+
+/* First stage context fields */
+#define RISCV_IOMMU_PC_FSC_PPN RISCV_IOMMU_ATP_PPN_FIELD
+#define RISCV_IOMMU_PC_FSC_RESERVED GENMASK_ULL(59, 44)
+
+enum riscv_iommu_fq_ttypes {
+ RISCV_IOMMU_FQ_TTYPE_NONE = 0,
+ RISCV_IOMMU_FQ_TTYPE_UADDR_INST_FETCH = 1,
+ RISCV_IOMMU_FQ_TTYPE_UADDR_RD = 2,
+ RISCV_IOMMU_FQ_TTYPE_UADDR_WR = 3,
+ RISCV_IOMMU_FQ_TTYPE_TADDR_INST_FETCH = 5,
+ RISCV_IOMMU_FQ_TTYPE_TADDR_RD = 6,
+ RISCV_IOMMU_FQ_TTYPE_TADDR_WR = 7,
+ RISCV_IOMMU_FQ_TTYPE_PCIE_ATS_REQ = 8,
+ RISCV_IOMMU_FW_TTYPE_PCIE_MSG_REQ = 9,
+};
+
+/*
+ * struct riscv_iommu_msi_pte - MSI Page Table Entry
+ */
+struct riscv_iommu_msi_pte {
+ uint64_t pte;
+ uint64_t mrif_info;
+};
+
+/* Fields on pte */
+#define RISCV_IOMMU_MSI_PTE_V BIT_ULL(0)
+#define RISCV_IOMMU_MSI_PTE_M GENMASK_ULL(2, 1)
+
+#define RISCV_IOMMU_MSI_PTE_M_MRIF 1
+#define RISCV_IOMMU_MSI_PTE_M_BASIC 3
+
+/* When M == 1 (MRIF mode) */
+#define RISCV_IOMMU_MSI_PTE_MRIF_ADDR GENMASK_ULL(53, 7)
+/* When M == 3 (basic mode) */
+#define RISCV_IOMMU_MSI_PTE_PPN RISCV_IOMMU_PPN_FIELD
+#define RISCV_IOMMU_MSI_PTE_C BIT_ULL(63)
+
+/* Fields on mrif_info */
+#define RISCV_IOMMU_MSI_MRIF_NID GENMASK_ULL(9, 0)
+#define RISCV_IOMMU_MSI_MRIF_NPPN RISCV_IOMMU_PPN_FIELD
+#define RISCV_IOMMU_MSI_MRIF_NID_MSB BIT_ULL(60)
+
+#endif /* _RISCV_IOMMU_BITS_H_ */
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
new file mode 100644
index 0000000..c5034bf
--- /dev/null
+++ b/hw/riscv/riscv-iommu-hpm.c
@@ -0,0 +1,381 @@
+/*
+ * RISC-V IOMMU - Hardware Performance Monitor (HPM) helpers
+ *
+ * Copyright (C) 2022-2023 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "cpu_bits.h"
+#include "riscv-iommu-hpm.h"
+#include "riscv-iommu.h"
+#include "riscv-iommu-bits.h"
+#include "trace.h"
+
+/* For now we assume IOMMU HPM frequency to be 1GHz so 1-cycle is of 1-ns. */
+static inline uint64_t get_cycles(void)
+{
+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s)
+{
+ const uint64_t cycle = riscv_iommu_reg_get64(
+ s, RISCV_IOMMU_REG_IOHPMCYCLES);
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+ const uint64_t ctr_prev = s->hpmcycle_prev;
+ const uint64_t ctr_val = s->hpmcycle_val;
+
+ trace_riscv_iommu_hpm_read(cycle, inhibit, ctr_prev, ctr_val);
+
+ if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
+ /*
+ * Counter should not increment if inhibit bit is set. We can't really
+ * stop the QEMU_CLOCK_VIRTUAL, so we just return the last updated
+ * counter value to indicate that counter was not incremented.
+ */
+ return (ctr_val & RISCV_IOMMU_IOHPMCYCLES_COUNTER) |
+ (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
+ }
+
+ return (ctr_val + get_cycles() - ctr_prev) |
+ (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
+}
+
+static void hpm_incr_ctr(RISCVIOMMUState *s, uint32_t ctr_idx)
+{
+ const uint32_t off = ctr_idx << 3;
+ uint64_t cntr_val;
+
+ cntr_val = ldq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off]);
+ stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off], cntr_val + 1);
+
+ trace_riscv_iommu_hpm_incr_ctr(cntr_val);
+
+ /* Handle the overflow scenario. */
+ if (cntr_val == UINT64_MAX) {
+ /*
+ * Generate interrupt only if OF bit is clear. +1 to offset the cycle
+ * register OF bit.
+ */
+ const uint32_t ovf =
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF,
+ BIT(ctr_idx + 1), 0);
+ if (!get_field(ovf, BIT(ctr_idx + 1))) {
+ riscv_iommu_reg_mod64(s,
+ RISCV_IOMMU_REG_IOHPMEVT_BASE + off,
+ RISCV_IOMMU_IOHPMEVT_OF,
+ 0);
+ riscv_iommu_notify(s, RISCV_IOMMU_INTR_PM);
+ }
+ }
+}
+
+void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
+ unsigned event_id)
+{
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+ uint32_t did_gscid;
+ uint32_t pid_pscid;
+ uint32_t ctr_idx;
+ gpointer value;
+ uint32_t ctrs;
+ uint64_t evt;
+
+ if (!(s->cap & RISCV_IOMMU_CAP_HPM)) {
+ return;
+ }
+
+ value = g_hash_table_lookup(s->hpm_event_ctr_map,
+ GUINT_TO_POINTER(event_id));
+ if (value == NULL) {
+ return;
+ }
+
+ for (ctrs = GPOINTER_TO_UINT(value); ctrs != 0; ctrs &= ctrs - 1) {
+ ctr_idx = ctz32(ctrs);
+ if (get_field(inhibit, BIT(ctr_idx + 1))) {
+ continue;
+ }
+
+ evt = riscv_iommu_reg_get64(s,
+ RISCV_IOMMU_REG_IOHPMEVT_BASE + (ctr_idx << 3));
+
+ /*
+ * It's quite possible that event ID has been changed in counter
+ * but hashtable hasn't been updated yet. We don't want to increment
+ * counter for the old event ID.
+ */
+ if (event_id != get_field(evt, RISCV_IOMMU_IOHPMEVT_EVENT_ID)) {
+ continue;
+ }
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_IDT)) {
+ did_gscid = get_field(ctx->gatp, RISCV_IOMMU_DC_IOHGATP_GSCID);
+ pid_pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID);
+ } else {
+ did_gscid = ctx->devid;
+ pid_pscid = ctx->process_id;
+ }
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_PV_PSCV)) {
+ /*
+ * If the transaction does not have a valid process_id, counter
+ * increments if device_id matches DID_GSCID. If the transaction
+ * has a valid process_id, counter increments if device_id
+ * matches DID_GSCID and process_id matches PID_PSCID. See
+ * IOMMU Specification, Chapter 5.23. Performance-monitoring
+ * event selector.
+ */
+ if (ctx->process_id &&
+ get_field(evt, RISCV_IOMMU_IOHPMEVT_PID_PSCID) != pid_pscid) {
+ continue;
+ }
+ }
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_DV_GSCV)) {
+ uint32_t mask = ~0;
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_DMASK)) {
+ /*
+ * 1001 1011 mask = GSCID
+ * 0000 0111 mask = mask ^ (mask + 1)
+ * 1111 1000 mask = ~mask;
+ */
+ mask = get_field(evt, RISCV_IOMMU_IOHPMEVT_DID_GSCID);
+ mask = mask ^ (mask + 1);
+ mask = ~mask;
+ }
+
+ if ((get_field(evt, RISCV_IOMMU_IOHPMEVT_DID_GSCID) & mask) !=
+ (did_gscid & mask)) {
+ continue;
+ }
+ }
+
+ hpm_incr_ctr(s, ctr_idx);
+ }
+}
+
+/* Timer callback for cycle counter overflow. */
+void riscv_iommu_hpm_timer_cb(void *priv)
+{
+ RISCVIOMMUState *s = priv;
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+ uint32_t ovf;
+
+ if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
+ return;
+ }
+
+ if (s->irq_overflow_left > 0) {
+ uint64_t irq_trigger_at =
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->irq_overflow_left;
+ timer_mod_anticipate_ns(s->hpm_timer, irq_trigger_at);
+ s->irq_overflow_left = 0;
+ return;
+ }
+
+ ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF);
+ if (!get_field(ovf, RISCV_IOMMU_IOCOUNTOVF_CY)) {
+ /*
+ * We don't need to set hpmcycle_val to zero and update hpmcycle_prev to
+ * current clock value. The way we calculate iohpmcycs will overflow
+ * and return the correct value. This avoids the need to synchronize
+ * timer callback and write callback.
+ */
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF,
+ RISCV_IOMMU_IOCOUNTOVF_CY, 0);
+ riscv_iommu_reg_mod64(s, RISCV_IOMMU_REG_IOHPMCYCLES,
+ RISCV_IOMMU_IOHPMCYCLES_OVF, 0);
+ riscv_iommu_notify(s, RISCV_IOMMU_INTR_PM);
+ }
+}
+
+static void hpm_setup_timer(RISCVIOMMUState *s, uint64_t value)
+{
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+ uint64_t overflow_at, overflow_ns;
+
+ if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
+ return;
+ }
+
+ /*
+ * We are using INT64_MAX here instead to UINT64_MAX because cycle counter
+ * has 63-bit precision and INT64_MAX is the maximum it can store.
+ */
+ if (value) {
+ overflow_ns = INT64_MAX - value + 1;
+ } else {
+ overflow_ns = INT64_MAX;
+ }
+
+ overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + overflow_ns;
+
+ if (overflow_at > INT64_MAX) {
+ s->irq_overflow_left = overflow_at - INT64_MAX;
+ overflow_at = INT64_MAX;
+ }
+
+ timer_mod_anticipate_ns(s->hpm_timer, overflow_at);
+}
+
+/* Updates the internal cycle counter state when iocntinh:CY is changed. */
+void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh)
+{
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ /* We only need to process CY bit toggle. */
+ if (!(inhibit ^ prev_cy_inh)) {
+ return;
+ }
+
+ trace_riscv_iommu_hpm_iocntinh_cy(prev_cy_inh);
+
+ if (!(inhibit & RISCV_IOMMU_IOCOUNTINH_CY)) {
+ /*
+ * Cycle counter is enabled. Just start the timer again and update
+ * the clock snapshot value to point to the current time to make
+ * sure iohpmcycles read is correct.
+ */
+ s->hpmcycle_prev = get_cycles();
+ hpm_setup_timer(s, s->hpmcycle_val);
+ } else {
+ /*
+ * Cycle counter is disabled. Stop the timer and update the cycle
+ * counter to record the current value which is last programmed
+ * value + the cycles passed so far.
+ */
+ s->hpmcycle_val = s->hpmcycle_val + (get_cycles() - s->hpmcycle_prev);
+ timer_del(s->hpm_timer);
+ }
+}
+
+void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState *s)
+{
+ const uint64_t val = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_IOHPMCYCLES);
+ const uint32_t ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF);
+
+ trace_riscv_iommu_hpm_cycle_write(ovf, val);
+
+ /*
+ * Clear OF bit in IOCNTOVF if it's being cleared in IOHPMCYCLES register.
+ */
+ if (get_field(ovf, RISCV_IOMMU_IOCOUNTOVF_CY) &&
+ !get_field(val, RISCV_IOMMU_IOHPMCYCLES_OVF)) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF, 0,
+ RISCV_IOMMU_IOCOUNTOVF_CY);
+ }
+
+ s->hpmcycle_val = val & ~RISCV_IOMMU_IOHPMCYCLES_OVF;
+ s->hpmcycle_prev = get_cycles();
+ hpm_setup_timer(s, s->hpmcycle_val);
+}
+
+static inline bool check_valid_event_id(unsigned event_id)
+{
+ return event_id > RISCV_IOMMU_HPMEVENT_INVALID &&
+ event_id < RISCV_IOMMU_HPMEVENT_MAX;
+}
+
+static gboolean hpm_event_equal(gpointer key, gpointer value, gpointer udata)
+{
+ uint32_t *pair = udata;
+
+ if (GPOINTER_TO_UINT(value) & (1 << pair[0])) {
+ pair[1] = GPOINTER_TO_UINT(key);
+ return true;
+ }
+
+ return false;
+}
+
+/* Caller must check ctr_idx against hpm_ctrs to see if its supported or not. */
+static void update_event_map(RISCVIOMMUState *s, uint64_t value,
+ uint32_t ctr_idx)
+{
+ unsigned event_id = get_field(value, RISCV_IOMMU_IOHPMEVT_EVENT_ID);
+ uint32_t pair[2] = { ctr_idx, RISCV_IOMMU_HPMEVENT_INVALID };
+ uint32_t new_value = 1 << ctr_idx;
+ gpointer data;
+
+ /*
+ * If EventID field is RISCV_IOMMU_HPMEVENT_INVALID
+ * remove the current mapping.
+ */
+ if (event_id == RISCV_IOMMU_HPMEVENT_INVALID) {
+ data = g_hash_table_find(s->hpm_event_ctr_map, hpm_event_equal, pair);
+
+ new_value = GPOINTER_TO_UINT(data) & ~(new_value);
+ if (new_value != 0) {
+ g_hash_table_replace(s->hpm_event_ctr_map,
+ GUINT_TO_POINTER(pair[1]),
+ GUINT_TO_POINTER(new_value));
+ } else {
+ g_hash_table_remove(s->hpm_event_ctr_map,
+ GUINT_TO_POINTER(pair[1]));
+ }
+
+ return;
+ }
+
+ /* Update the counter mask if the event is already enabled. */
+ if (g_hash_table_lookup_extended(s->hpm_event_ctr_map,
+ GUINT_TO_POINTER(event_id),
+ NULL,
+ &data)) {
+ new_value |= GPOINTER_TO_UINT(data);
+ }
+
+ g_hash_table_insert(s->hpm_event_ctr_map,
+ GUINT_TO_POINTER(event_id),
+ GUINT_TO_POINTER(new_value));
+}
+
+void riscv_iommu_process_hpmevt_write(RISCVIOMMUState *s, uint32_t evt_reg)
+{
+ const uint32_t ctr_idx = (evt_reg - RISCV_IOMMU_REG_IOHPMEVT_BASE) >> 3;
+ const uint32_t ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF);
+ uint64_t val = riscv_iommu_reg_get64(s, evt_reg);
+
+ if (ctr_idx >= s->hpm_cntrs) {
+ return;
+ }
+
+ trace_riscv_iommu_hpm_evt_write(ctr_idx, ovf, val);
+
+ /* Clear OF bit in IOCNTOVF if it's being cleared in IOHPMEVT register. */
+ if (get_field(ovf, BIT(ctr_idx + 1)) &&
+ !get_field(val, RISCV_IOMMU_IOHPMEVT_OF)) {
+ /* +1 to offset CYCLE register OF bit. */
+ riscv_iommu_reg_mod32(
+ s, RISCV_IOMMU_REG_IOCOUNTOVF, 0, BIT(ctr_idx + 1));
+ }
+
+ if (!check_valid_event_id(get_field(val, RISCV_IOMMU_IOHPMEVT_EVENT_ID))) {
+ /* Reset EventID (WARL) field to invalid. */
+ val = set_field(val, RISCV_IOMMU_IOHPMEVT_EVENT_ID,
+ RISCV_IOMMU_HPMEVENT_INVALID);
+ riscv_iommu_reg_set64(s, evt_reg, val);
+ }
+
+ update_event_map(s, val, ctr_idx);
+}
diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
new file mode 100644
index 0000000..5fc4ef2
--- /dev/null
+++ b/hw/riscv/riscv-iommu-hpm.h
@@ -0,0 +1,33 @@
+/*
+ * RISC-V IOMMU - Hardware Performance Monitor (HPM) helpers
+ *
+ * Copyright (C) 2022-2023 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_RISCV_IOMMU_HPM_H
+#define HW_RISCV_IOMMU_HPM_H
+
+#include "qom/object.h"
+#include "hw/riscv/riscv-iommu.h"
+
+uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s);
+void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
+ unsigned event_id);
+void riscv_iommu_hpm_timer_cb(void *priv);
+void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh);
+void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState *s);
+void riscv_iommu_process_hpmevt_write(RISCVIOMMUState *s, uint32_t evt_reg);
+
+#endif
diff --git a/hw/riscv/riscv-iommu-pci.c b/hw/riscv/riscv-iommu-pci.c
new file mode 100644
index 0000000..cdb4a7a
--- /dev/null
+++ b/hw/riscv/riscv-iommu-pci.c
@@ -0,0 +1,217 @@
+/*
+ * QEMU emulation of an RISC-V IOMMU
+ *
+ * Copyright (C) 2022-2023 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "exec/target_page.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/msix.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/qdev-properties.h"
+#include "hw/riscv/riscv_hart.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/host-utils.h"
+#include "qom/object.h"
+
+#include "cpu_bits.h"
+#include "riscv-iommu.h"
+#include "riscv-iommu-bits.h"
+#include "trace.h"
+
+/* RISC-V IOMMU PCI Device Emulation */
+#define RISCV_PCI_CLASS_SYSTEM_IOMMU 0x0806
+
+/*
+ * 4 MSIx vectors for ICVEC, one for MRIF. The spec mentions in
+ * the "Placement and data flow" section that:
+ *
+ * "The interfaces related to recording an incoming MSI in a memory-resident
+ * interrupt file (MRIF) are implementation-specific. The partitioning of
+ * responsibility between the IOMMU and the IO bridge for recording the
+ * incoming MSI in an MRIF and generating the associated notice MSI are
+ * implementation-specific."
+ *
+ * We're making a design decision to create the MSIx for MRIF in the
+ * IOMMU MSIx emulation.
+ */
+#define RISCV_IOMMU_PCI_MSIX_VECTORS 5
+
+/*
+ * 4 vectors that can be used by civ, fiv, pmiv and piv. Number of
+ * vectors is represented by 2^N, where N = number of writable bits
+ * in each cause. For 4 vectors we'll write 0b11 (3) in each reg.
+ */
+#define RISCV_IOMMU_PCI_ICVEC_VECTORS 0x3333
+
+typedef struct RISCVIOMMUStatePci {
+ PCIDevice pci; /* Parent PCIe device state */
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint8_t revision;
+ MemoryRegion bar0; /* PCI BAR (including MSI-x config) */
+ RISCVIOMMUState iommu; /* common IOMMU state */
+} RISCVIOMMUStatePci;
+
+/* interrupt delivery callback */
+static void riscv_iommu_pci_notify(RISCVIOMMUState *iommu, unsigned vector)
+{
+ RISCVIOMMUStatePci *s = container_of(iommu, RISCVIOMMUStatePci, iommu);
+
+ if (msix_enabled(&(s->pci))) {
+ msix_notify(&(s->pci), vector);
+ }
+}
+
+static void riscv_iommu_pci_realize(PCIDevice *dev, Error **errp)
+{
+ RISCVIOMMUStatePci *s = DO_UPCAST(RISCVIOMMUStatePci, pci, dev);
+ RISCVIOMMUState *iommu = &s->iommu;
+ uint8_t *pci_conf = dev->config;
+ Error *err = NULL;
+
+ pci_set_word(pci_conf + PCI_VENDOR_ID, s->vendor_id);
+ pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, s->vendor_id);
+ pci_set_word(pci_conf + PCI_DEVICE_ID, s->device_id);
+ pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, s->device_id);
+ pci_set_byte(pci_conf + PCI_REVISION_ID, s->revision);
+
+ /* Set device id for trace / debug */
+ DEVICE(iommu)->id = g_strdup_printf("%02x:%02x.%01x",
+ pci_dev_bus_num(dev), PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ qdev_realize(DEVICE(iommu), NULL, errp);
+
+ memory_region_init(&s->bar0, OBJECT(s), "riscv-iommu-bar0",
+ QEMU_ALIGN_UP(memory_region_size(&iommu->regs_mr), TARGET_PAGE_SIZE));
+ memory_region_add_subregion(&s->bar0, 0, &iommu->regs_mr);
+
+ pcie_endpoint_cap_init(dev, 0);
+
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64, &s->bar0);
+
+ int ret = msix_init(dev, RISCV_IOMMU_PCI_MSIX_VECTORS,
+ &s->bar0, 0, RISCV_IOMMU_REG_MSI_CONFIG,
+ &s->bar0, 0, RISCV_IOMMU_REG_MSI_CONFIG + 256, 0, &err);
+
+ if (ret == -ENOTSUP) {
+ /*
+ * MSI-x is not supported by the platform.
+ * Driver should use timer/polling based notification handlers.
+ */
+ warn_report_err(err);
+ } else if (ret < 0) {
+ error_propagate(errp, err);
+ return;
+ } else {
+ /* Mark all ICVEC MSIx vectors as used */
+ for (int i = 0; i < RISCV_IOMMU_PCI_MSIX_VECTORS; i++) {
+ msix_vector_use(dev, i);
+ }
+
+ iommu->notify = riscv_iommu_pci_notify;
+ }
+
+ PCIBus *bus = pci_device_root_bus(dev);
+ if (!bus) {
+ error_setg(errp, "can't find PCIe root port for %02x:%02x.%x",
+ pci_bus_num(pci_get_bus(dev)), PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+ return;
+ }
+
+ riscv_iommu_pci_setup_iommu(iommu, bus, errp);
+}
+
+static void riscv_iommu_pci_exit(PCIDevice *pci_dev)
+{
+ pci_setup_iommu(pci_device_root_bus(pci_dev), NULL, NULL);
+}
+
+static const VMStateDescription riscv_iommu_vmstate = {
+ .name = "riscv-iommu",
+ .unmigratable = 1
+};
+
+static void riscv_iommu_pci_init(Object *obj)
+{
+ RISCVIOMMUStatePci *s = RISCV_IOMMU_PCI(obj);
+ RISCVIOMMUState *iommu = &s->iommu;
+
+ object_initialize_child(obj, "iommu", iommu, TYPE_RISCV_IOMMU);
+ qdev_alias_all_properties(DEVICE(iommu), obj);
+
+ iommu->icvec_avail_vectors = RISCV_IOMMU_PCI_ICVEC_VECTORS;
+ riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_MSI);
+}
+
+static const Property riscv_iommu_pci_properties[] = {
+ DEFINE_PROP_UINT16("vendor-id", RISCVIOMMUStatePci, vendor_id,
+ PCI_VENDOR_ID_REDHAT),
+ DEFINE_PROP_UINT16("device-id", RISCVIOMMUStatePci, device_id,
+ PCI_DEVICE_ID_REDHAT_RISCV_IOMMU),
+ DEFINE_PROP_UINT8("revision", RISCVIOMMUStatePci, revision, 0x01),
+};
+
+static void riscv_iommu_pci_reset_hold(Object *obj, ResetType type)
+{
+ RISCVIOMMUStatePci *pci = RISCV_IOMMU_PCI(obj);
+ RISCVIOMMUState *iommu = &pci->iommu;
+
+ riscv_iommu_reset(iommu);
+
+ trace_riscv_iommu_pci_reset_hold(type);
+}
+
+static void riscv_iommu_pci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = riscv_iommu_pci_reset_hold;
+
+ k->realize = riscv_iommu_pci_realize;
+ k->exit = riscv_iommu_pci_exit;
+ k->class_id = RISCV_PCI_CLASS_SYSTEM_IOMMU;
+ dc->desc = "RISCV-IOMMU DMA Remapping device";
+ dc->vmsd = &riscv_iommu_vmstate;
+ dc->hotpluggable = false;
+ dc->user_creatable = true;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ device_class_set_props(dc, riscv_iommu_pci_properties);
+}
+
+static const TypeInfo riscv_iommu_pci = {
+ .name = TYPE_RISCV_IOMMU_PCI,
+ .parent = TYPE_PCI_DEVICE,
+ .class_init = riscv_iommu_pci_class_init,
+ .instance_init = riscv_iommu_pci_init,
+ .instance_size = sizeof(RISCVIOMMUStatePci),
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { },
+ },
+};
+
+static void riscv_iommu_register_pci_types(void)
+{
+ type_register_static(&riscv_iommu_pci);
+}
+
+type_init(riscv_iommu_register_pci_types);
diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c
new file mode 100644
index 0000000..e34d00a
--- /dev/null
+++ b/hw/riscv/riscv-iommu-sys.c
@@ -0,0 +1,248 @@
+/*
+ * QEMU emulation of an RISC-V IOMMU Platform Device
+ *
+ * Copyright (C) 2022-2023 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/host-utils.h"
+#include "qemu/module.h"
+#include "qom/object.h"
+#include "trace.h"
+
+#include "riscv-iommu.h"
+
+#define RISCV_IOMMU_SYSDEV_ICVEC_VECTORS 0x3333
+
+#define RISCV_IOMMU_PCI_MSIX_VECTORS 5
+
+/* RISC-V IOMMU System Platform Device Emulation */
+
+struct RISCVIOMMUStateSys {
+ SysBusDevice parent;
+ uint64_t addr;
+ uint32_t base_irq;
+ DeviceState *irqchip;
+ RISCVIOMMUState iommu;
+
+ /* Wired int support */
+ qemu_irq irqs[RISCV_IOMMU_INTR_COUNT];
+
+ /* Memory Regions for MSIX table and pending bit entries. */
+ MemoryRegion msix_table_mmio;
+ MemoryRegion msix_pba_mmio;
+ uint8_t *msix_table;
+ uint8_t *msix_pba;
+};
+
+static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ RISCVIOMMUStateSys *s = opaque;
+
+ g_assert(addr + size <= RISCV_IOMMU_PCI_MSIX_VECTORS * PCI_MSIX_ENTRY_SIZE);
+ return pci_get_long(s->msix_table + addr);
+}
+
+static void msix_table_mmio_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ RISCVIOMMUStateSys *s = opaque;
+
+ g_assert(addr + size <= RISCV_IOMMU_PCI_MSIX_VECTORS * PCI_MSIX_ENTRY_SIZE);
+ pci_set_long(s->msix_table + addr, val);
+}
+
+static const MemoryRegionOps msix_table_mmio_ops = {
+ .read = msix_table_mmio_read,
+ .write = msix_table_mmio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .max_access_size = 4,
+ },
+};
+
+static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ RISCVIOMMUStateSys *s = opaque;
+
+ return pci_get_long(s->msix_pba + addr);
+}
+
+static void msix_pba_mmio_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+}
+
+static const MemoryRegionOps msix_pba_mmio_ops = {
+ .read = msix_pba_mmio_read,
+ .write = msix_pba_mmio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .max_access_size = 4,
+ },
+};
+
+static void riscv_iommu_sysdev_init_msi(RISCVIOMMUStateSys *s,
+ uint32_t n_vectors)
+{
+ RISCVIOMMUState *iommu = &s->iommu;
+ uint32_t table_size = n_vectors * PCI_MSIX_ENTRY_SIZE;
+ uint32_t table_offset = RISCV_IOMMU_REG_MSI_CONFIG;
+ uint32_t pba_size = QEMU_ALIGN_UP(n_vectors, 64) / 8;
+ uint32_t pba_offset = RISCV_IOMMU_REG_MSI_CONFIG + 256;
+
+ s->msix_table = g_malloc0(table_size);
+ s->msix_pba = g_malloc0(pba_size);
+
+ memory_region_init_io(&s->msix_table_mmio, OBJECT(s), &msix_table_mmio_ops,
+ s, "msix-table", table_size);
+ memory_region_add_subregion(&iommu->regs_mr, table_offset,
+ &s->msix_table_mmio);
+
+ memory_region_init_io(&s->msix_pba_mmio, OBJECT(s), &msix_pba_mmio_ops, s,
+ "msix-pba", pba_size);
+ memory_region_add_subregion(&iommu->regs_mr, pba_offset,
+ &s->msix_pba_mmio);
+}
+
+static void riscv_iommu_sysdev_send_MSI(RISCVIOMMUStateSys *s,
+ uint32_t vector)
+{
+ uint8_t *table_entry = s->msix_table + vector * PCI_MSIX_ENTRY_SIZE;
+ uint64_t msi_addr = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
+ uint32_t msi_data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
+ MemTxResult result;
+
+ address_space_stl_le(&address_space_memory, msi_addr,
+ msi_data, MEMTXATTRS_UNSPECIFIED, &result);
+ trace_riscv_iommu_sys_msi_sent(vector, msi_addr, msi_data, result);
+}
+
+static void riscv_iommu_sysdev_notify(RISCVIOMMUState *iommu,
+ unsigned vector)
+{
+ RISCVIOMMUStateSys *s = container_of(iommu, RISCVIOMMUStateSys, iommu);
+ uint32_t fctl = riscv_iommu_reg_get32(iommu, RISCV_IOMMU_REG_FCTL);
+
+ if (fctl & RISCV_IOMMU_FCTL_WSI) {
+ qemu_irq_pulse(s->irqs[vector]);
+ trace_riscv_iommu_sys_irq_sent(vector);
+ return;
+ }
+
+ riscv_iommu_sysdev_send_MSI(s, vector);
+}
+
+static void riscv_iommu_sys_realize(DeviceState *dev, Error **errp)
+{
+ RISCVIOMMUStateSys *s = RISCV_IOMMU_SYS(dev);
+ SysBusDevice *sysdev = SYS_BUS_DEVICE(s);
+ PCIBus *pci_bus;
+ qemu_irq irq;
+
+ qdev_realize(DEVICE(&s->iommu), NULL, errp);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iommu.regs_mr);
+ if (s->addr) {
+ sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, s->addr);
+ }
+
+ pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL);
+ if (pci_bus) {
+ riscv_iommu_pci_setup_iommu(&s->iommu, pci_bus, errp);
+ }
+
+ s->iommu.notify = riscv_iommu_sysdev_notify;
+
+ /* 4 IRQs are defined starting from s->base_irq */
+ for (int i = 0; i < RISCV_IOMMU_INTR_COUNT; i++) {
+ sysbus_init_irq(sysdev, &s->irqs[i]);
+ irq = qdev_get_gpio_in(s->irqchip, s->base_irq + i);
+ sysbus_connect_irq(sysdev, i, irq);
+ }
+
+ riscv_iommu_sysdev_init_msi(s, RISCV_IOMMU_PCI_MSIX_VECTORS);
+}
+
+static void riscv_iommu_sys_init(Object *obj)
+{
+ RISCVIOMMUStateSys *s = RISCV_IOMMU_SYS(obj);
+ RISCVIOMMUState *iommu = &s->iommu;
+
+ object_initialize_child(obj, "iommu", iommu, TYPE_RISCV_IOMMU);
+ qdev_alias_all_properties(DEVICE(iommu), obj);
+
+ iommu->icvec_avail_vectors = RISCV_IOMMU_SYSDEV_ICVEC_VECTORS;
+ riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_BOTH);
+}
+
+static const Property riscv_iommu_sys_properties[] = {
+ DEFINE_PROP_UINT64("addr", RISCVIOMMUStateSys, addr, 0),
+ DEFINE_PROP_UINT32("base-irq", RISCVIOMMUStateSys, base_irq, 0),
+ DEFINE_PROP_LINK("irqchip", RISCVIOMMUStateSys, irqchip,
+ TYPE_DEVICE, DeviceState *),
+};
+
+static void riscv_iommu_sys_reset_hold(Object *obj, ResetType type)
+{
+ RISCVIOMMUStateSys *sys = RISCV_IOMMU_SYS(obj);
+ RISCVIOMMUState *iommu = &sys->iommu;
+
+ riscv_iommu_reset(iommu);
+
+ trace_riscv_iommu_sys_reset_hold(type);
+}
+
+static void riscv_iommu_sys_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = riscv_iommu_sys_reset_hold;
+
+ dc->realize = riscv_iommu_sys_realize;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ device_class_set_props(dc, riscv_iommu_sys_properties);
+}
+
+static const TypeInfo riscv_iommu_sys = {
+ .name = TYPE_RISCV_IOMMU_SYS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = riscv_iommu_sys_class_init,
+ .instance_init = riscv_iommu_sys_init,
+ .instance_size = sizeof(RISCVIOMMUStateSys),
+};
+
+static void riscv_iommu_register_sys(void)
+{
+ type_register_static(&riscv_iommu_sys);
+}
+
+type_init(riscv_iommu_register_sys)
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
new file mode 100644
index 0000000..a877e5d
--- /dev/null
+++ b/hw/riscv/riscv-iommu.c
@@ -0,0 +1,2679 @@
+/*
+ * QEMU emulation of an RISC-V IOMMU
+ *
+ * Copyright (C) 2021-2023, Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qom/object.h"
+#include "exec/target_page.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_device.h"
+#include "hw/qdev-properties.h"
+#include "hw/riscv/riscv_hart.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/timer.h"
+
+#include "cpu_bits.h"
+#include "riscv-iommu.h"
+#include "riscv-iommu-bits.h"
+#include "riscv-iommu-hpm.h"
+#include "trace.h"
+
+#define LIMIT_CACHE_CTX (1U << 7)
+#define LIMIT_CACHE_IOT (1U << 20)
+
+/* Physical page number coversions */
+#define PPN_PHYS(ppn) ((ppn) << TARGET_PAGE_BITS)
+#define PPN_DOWN(phy) ((phy) >> TARGET_PAGE_BITS)
+
+typedef struct RISCVIOMMUEntry RISCVIOMMUEntry;
+
+/* Device assigned I/O address space */
+struct RISCVIOMMUSpace {
+ IOMMUMemoryRegion iova_mr; /* IOVA memory region for attached device */
+ AddressSpace iova_as; /* IOVA address space for attached device */
+ RISCVIOMMUState *iommu; /* Managing IOMMU device state */
+ uint32_t devid; /* Requester identifier, AKA device_id */
+ bool notifier; /* IOMMU unmap notifier enabled */
+ QLIST_ENTRY(RISCVIOMMUSpace) list;
+};
+
+typedef enum RISCVIOMMUTransTag {
+ RISCV_IOMMU_TRANS_TAG_BY, /* Bypass */
+ RISCV_IOMMU_TRANS_TAG_SS, /* Single Stage */
+ RISCV_IOMMU_TRANS_TAG_VG, /* G-stage only */
+ RISCV_IOMMU_TRANS_TAG_VN, /* Nested translation */
+} RISCVIOMMUTransTag;
+
+/* Address translation cache entry */
+struct RISCVIOMMUEntry {
+ RISCVIOMMUTransTag tag; /* Translation Tag */
+ uint64_t iova:44; /* IOVA Page Number */
+ uint64_t pscid:20; /* Process Soft-Context identifier */
+ uint64_t phys:44; /* Physical Page Number */
+ uint64_t gscid:16; /* Guest Soft-Context identifier */
+ uint64_t perm:2; /* IOMMU_RW flags */
+};
+
+/* IOMMU index for transactions without process_id specified. */
+#define RISCV_IOMMU_NOPROCID 0
+
+static uint8_t riscv_iommu_get_icvec_vector(uint32_t icvec, uint32_t vec_type)
+{
+ switch (vec_type) {
+ case RISCV_IOMMU_INTR_CQ:
+ return icvec & RISCV_IOMMU_ICVEC_CIV;
+ case RISCV_IOMMU_INTR_FQ:
+ return (icvec & RISCV_IOMMU_ICVEC_FIV) >> 4;
+ case RISCV_IOMMU_INTR_PM:
+ return (icvec & RISCV_IOMMU_ICVEC_PMIV) >> 8;
+ case RISCV_IOMMU_INTR_PQ:
+ return (icvec & RISCV_IOMMU_ICVEC_PIV) >> 12;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type)
+{
+ uint32_t ipsr, icvec, vector;
+
+ if (!s->notify) {
+ return;
+ }
+
+ icvec = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_ICVEC);
+ ipsr = riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IPSR, (1 << vec_type), 0);
+
+ if (!(ipsr & (1 << vec_type))) {
+ vector = riscv_iommu_get_icvec_vector(icvec, vec_type);
+ s->notify(s, vector);
+ trace_riscv_iommu_notify_int_vector(vec_type, vector);
+ }
+}
+
+static void riscv_iommu_fault(RISCVIOMMUState *s,
+ struct riscv_iommu_fq_record *ev)
+{
+ uint32_t ctrl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_FQCSR);
+ uint32_t head = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_FQH) & s->fq_mask;
+ uint32_t tail = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_FQT) & s->fq_mask;
+ uint32_t next = (tail + 1) & s->fq_mask;
+ uint32_t devid = get_field(ev->hdr, RISCV_IOMMU_FQ_HDR_DID);
+
+ trace_riscv_iommu_flt(s->parent_obj.id, PCI_BUS_NUM(devid), PCI_SLOT(devid),
+ PCI_FUNC(devid), ev->hdr, ev->iotval);
+
+ if (!(ctrl & RISCV_IOMMU_FQCSR_FQON) ||
+ !!(ctrl & (RISCV_IOMMU_FQCSR_FQOF | RISCV_IOMMU_FQCSR_FQMF))) {
+ return;
+ }
+
+ if (head == next) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_FQCSR,
+ RISCV_IOMMU_FQCSR_FQOF, 0);
+ } else {
+ dma_addr_t addr = s->fq_addr + tail * sizeof(*ev);
+ if (dma_memory_write(s->target_as, addr, ev, sizeof(*ev),
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_FQCSR,
+ RISCV_IOMMU_FQCSR_FQMF, 0);
+ } else {
+ riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_FQT, next);
+ }
+ }
+
+ if (ctrl & RISCV_IOMMU_FQCSR_FIE) {
+ riscv_iommu_notify(s, RISCV_IOMMU_INTR_FQ);
+ }
+}
+
+static void riscv_iommu_pri(RISCVIOMMUState *s,
+ struct riscv_iommu_pq_record *pr)
+{
+ uint32_t ctrl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_PQCSR);
+ uint32_t head = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_PQH) & s->pq_mask;
+ uint32_t tail = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_PQT) & s->pq_mask;
+ uint32_t next = (tail + 1) & s->pq_mask;
+ uint32_t devid = get_field(pr->hdr, RISCV_IOMMU_PREQ_HDR_DID);
+
+ trace_riscv_iommu_pri(s->parent_obj.id, PCI_BUS_NUM(devid), PCI_SLOT(devid),
+ PCI_FUNC(devid), pr->payload);
+
+ if (!(ctrl & RISCV_IOMMU_PQCSR_PQON) ||
+ !!(ctrl & (RISCV_IOMMU_PQCSR_PQOF | RISCV_IOMMU_PQCSR_PQMF))) {
+ return;
+ }
+
+ if (head == next) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_PQCSR,
+ RISCV_IOMMU_PQCSR_PQOF, 0);
+ } else {
+ dma_addr_t addr = s->pq_addr + tail * sizeof(*pr);
+ if (dma_memory_write(s->target_as, addr, pr, sizeof(*pr),
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_PQCSR,
+ RISCV_IOMMU_PQCSR_PQMF, 0);
+ } else {
+ riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_PQT, next);
+ }
+ }
+
+ if (ctrl & RISCV_IOMMU_PQCSR_PIE) {
+ riscv_iommu_notify(s, RISCV_IOMMU_INTR_PQ);
+ }
+}
+
+/*
+ * Discards all bits from 'val' whose matching bits in the same
+ * positions in the mask 'ext' are zeros, and packs the remaining
+ * bits from 'val' contiguously at the least-significant end of the
+ * result, keeping the same bit order as 'val' and filling any
+ * other bits at the most-significant end of the result with zeros.
+ *
+ * For example, for the following 'val' and 'ext', the return 'ret'
+ * will be:
+ *
+ * val = a b c d e f g h
+ * ext = 1 0 1 0 0 1 1 0
+ * ret = 0 0 0 0 a c f g
+ *
+ * This function, taken from the riscv-iommu 1.0 spec, section 2.3.3
+ * "Process to translate addresses of MSIs", is similar to bit manip
+ * function PEXT (Parallel bits extract) from x86.
+ */
+static uint64_t riscv_iommu_pext_u64(uint64_t val, uint64_t ext)
+{
+ uint64_t ret = 0;
+ uint64_t rot = 1;
+
+ while (ext) {
+ if (ext & 1) {
+ if (val & 1) {
+ ret |= rot;
+ }
+ rot <<= 1;
+ }
+ val >>= 1;
+ ext >>= 1;
+ }
+
+ return ret;
+}
+
+/* Check if GPA matches MSI/MRIF pattern. */
+static bool riscv_iommu_msi_check(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
+ dma_addr_t gpa)
+{
+ if (!s->enable_msi) {
+ return false;
+ }
+
+ if (get_field(ctx->msiptp, RISCV_IOMMU_DC_MSIPTP_MODE) !=
+ RISCV_IOMMU_DC_MSIPTP_MODE_FLAT) {
+ return false; /* Invalid MSI/MRIF mode */
+ }
+
+ if ((PPN_DOWN(gpa) ^ ctx->msi_addr_pattern) & ~ctx->msi_addr_mask) {
+ return false; /* GPA not in MSI range defined by AIA IMSIC rules. */
+ }
+
+ return true;
+}
+
+/*
+ * RISCV IOMMU Address Translation Lookup - Page Table Walk
+ *
+ * Note: Code is based on get_physical_address() from target/riscv/cpu_helper.c
+ * Both implementation can be merged into single helper function in future.
+ * Keeping them separate for now, as error reporting and flow specifics are
+ * sufficiently different for separate implementation.
+ *
+ * @s : IOMMU Device State
+ * @ctx : Translation context for device id and process address space id.
+ * @iotlb : translation data: physical address and access mode.
+ * @return : success or fault cause code.
+ */
+static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
+ IOMMUTLBEntry *iotlb)
+{
+ dma_addr_t addr, base;
+ uint64_t satp, gatp, pte;
+ bool en_s, en_g;
+ struct {
+ unsigned char step;
+ unsigned char levels;
+ unsigned char ptidxbits;
+ unsigned char ptesize;
+ } sc[2];
+ /* Translation stage phase */
+ enum {
+ S_STAGE = 0,
+ G_STAGE = 1,
+ } pass;
+ MemTxResult ret;
+
+ satp = get_field(ctx->satp, RISCV_IOMMU_ATP_MODE_FIELD);
+ gatp = get_field(ctx->gatp, RISCV_IOMMU_ATP_MODE_FIELD);
+
+ en_s = satp != RISCV_IOMMU_DC_FSC_MODE_BARE;
+ en_g = gatp != RISCV_IOMMU_DC_IOHGATP_MODE_BARE;
+
+ /*
+ * Early check for MSI address match when IOVA == GPA.
+ * Note that the (!en_s) condition means that the MSI
+ * page table may only be used when guest pages are
+ * mapped using the g-stage page table, whether single-
+ * or two-stage paging is enabled. It's unavoidable though,
+ * because the spec mandates that we do a first-stage
+ * translation before we check the MSI page table, which
+ * means we can't do an early MSI check unless we have
+ * strictly !en_s.
+ */
+ if (!en_s && (iotlb->perm & IOMMU_WO) &&
+ riscv_iommu_msi_check(s, ctx, iotlb->iova)) {
+ iotlb->target_as = &s->trap_as;
+ iotlb->translated_addr = iotlb->iova;
+ iotlb->addr_mask = ~TARGET_PAGE_MASK;
+ return 0;
+ }
+
+ /* Exit early for pass-through mode. */
+ if (!(en_s || en_g)) {
+ iotlb->translated_addr = iotlb->iova;
+ iotlb->addr_mask = ~TARGET_PAGE_MASK;
+ /* Allow R/W in pass-through mode */
+ iotlb->perm = IOMMU_RW;
+ return 0;
+ }
+
+ /* S/G translation parameters. */
+ for (pass = 0; pass < 2; pass++) {
+ uint32_t sv_mode;
+
+ sc[pass].step = 0;
+ if (pass ? (s->fctl & RISCV_IOMMU_FCTL_GXL) :
+ (ctx->tc & RISCV_IOMMU_DC_TC_SXL)) {
+ /* 32bit mode for GXL/SXL == 1 */
+ switch (pass ? gatp : satp) {
+ case RISCV_IOMMU_DC_IOHGATP_MODE_BARE:
+ sc[pass].levels = 0;
+ sc[pass].ptidxbits = 0;
+ sc[pass].ptesize = 0;
+ break;
+ case RISCV_IOMMU_DC_IOHGATP_MODE_SV32X4:
+ sv_mode = pass ? RISCV_IOMMU_CAP_SV32X4 : RISCV_IOMMU_CAP_SV32;
+ if (!(s->cap & sv_mode)) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+ sc[pass].levels = 2;
+ sc[pass].ptidxbits = 10;
+ sc[pass].ptesize = 4;
+ break;
+ default:
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+ } else {
+ /* 64bit mode for GXL/SXL == 0 */
+ switch (pass ? gatp : satp) {
+ case RISCV_IOMMU_DC_IOHGATP_MODE_BARE:
+ sc[pass].levels = 0;
+ sc[pass].ptidxbits = 0;
+ sc[pass].ptesize = 0;
+ break;
+ case RISCV_IOMMU_DC_IOHGATP_MODE_SV39X4:
+ sv_mode = pass ? RISCV_IOMMU_CAP_SV39X4 : RISCV_IOMMU_CAP_SV39;
+ if (!(s->cap & sv_mode)) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+ sc[pass].levels = 3;
+ sc[pass].ptidxbits = 9;
+ sc[pass].ptesize = 8;
+ break;
+ case RISCV_IOMMU_DC_IOHGATP_MODE_SV48X4:
+ sv_mode = pass ? RISCV_IOMMU_CAP_SV48X4 : RISCV_IOMMU_CAP_SV48;
+ if (!(s->cap & sv_mode)) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+ sc[pass].levels = 4;
+ sc[pass].ptidxbits = 9;
+ sc[pass].ptesize = 8;
+ break;
+ case RISCV_IOMMU_DC_IOHGATP_MODE_SV57X4:
+ sv_mode = pass ? RISCV_IOMMU_CAP_SV57X4 : RISCV_IOMMU_CAP_SV57;
+ if (!(s->cap & sv_mode)) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+ sc[pass].levels = 5;
+ sc[pass].ptidxbits = 9;
+ sc[pass].ptesize = 8;
+ break;
+ default:
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+ }
+ };
+
+ /* S/G stages translation tables root pointers */
+ gatp = PPN_PHYS(get_field(ctx->gatp, RISCV_IOMMU_ATP_PPN_FIELD));
+ satp = PPN_PHYS(get_field(ctx->satp, RISCV_IOMMU_ATP_PPN_FIELD));
+ addr = (en_s && en_g) ? satp : iotlb->iova;
+ base = en_g ? gatp : satp;
+ pass = en_g ? G_STAGE : S_STAGE;
+
+ do {
+ const unsigned widened = (pass && !sc[pass].step) ? 2 : 0;
+ const unsigned va_bits = widened + sc[pass].ptidxbits;
+ const unsigned va_skip = TARGET_PAGE_BITS + sc[pass].ptidxbits *
+ (sc[pass].levels - 1 - sc[pass].step);
+ const unsigned idx = (addr >> va_skip) & ((1 << va_bits) - 1);
+ const dma_addr_t pte_addr = base + idx * sc[pass].ptesize;
+ const bool ade =
+ ctx->tc & (pass ? RISCV_IOMMU_DC_TC_GADE : RISCV_IOMMU_DC_TC_SADE);
+
+ /* Address range check before first level lookup */
+ if (!sc[pass].step) {
+ const uint64_t va_len = va_skip + va_bits;
+ const uint64_t va_mask = (1ULL << va_len) - 1;
+
+ if (pass == S_STAGE && va_len > 32) {
+ target_ulong mask, masked_msbs;
+
+ mask = (1L << (TARGET_LONG_BITS - (va_len - 1))) - 1;
+ masked_msbs = (addr >> (va_len - 1)) & mask;
+
+ if (masked_msbs != 0 && masked_msbs != mask) {
+ return (iotlb->perm & IOMMU_WO) ?
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S :
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S;
+ }
+ } else {
+ if ((addr & va_mask) != addr) {
+ return (iotlb->perm & IOMMU_WO) ?
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS :
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS;
+ }
+ }
+ }
+
+
+ if (pass == S_STAGE) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_S_VS_WALKS);
+ } else {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_G_WALKS);
+ }
+
+ /* Read page table entry */
+ if (sc[pass].ptesize == 4) {
+ uint32_t pte32 = 0;
+ ret = ldl_le_dma(s->target_as, pte_addr, &pte32,
+ MEMTXATTRS_UNSPECIFIED);
+ pte = pte32;
+ } else {
+ ret = ldq_le_dma(s->target_as, pte_addr, &pte,
+ MEMTXATTRS_UNSPECIFIED);
+ }
+ if (ret != MEMTX_OK) {
+ return (iotlb->perm & IOMMU_WO) ? RISCV_IOMMU_FQ_CAUSE_WR_FAULT
+ : RISCV_IOMMU_FQ_CAUSE_RD_FAULT;
+ }
+
+ sc[pass].step++;
+ hwaddr ppn = pte >> PTE_PPN_SHIFT;
+
+ if (!(pte & PTE_V)) {
+ break; /* Invalid PTE */
+ } else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
+ base = PPN_PHYS(ppn); /* Inner PTE, continue walking */
+ } else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) {
+ break; /* Reserved leaf PTE flags: PTE_W */
+ } else if ((pte & (PTE_R | PTE_W | PTE_X)) == (PTE_W | PTE_X)) {
+ break; /* Reserved leaf PTE flags: PTE_W + PTE_X */
+ } else if (ppn & ((1ULL << (va_skip - TARGET_PAGE_BITS)) - 1)) {
+ break; /* Misaligned PPN */
+ } else if ((iotlb->perm & IOMMU_RO) && !(pte & PTE_R)) {
+ break; /* Read access check failed */
+ } else if ((iotlb->perm & IOMMU_WO) && !(pte & PTE_W)) {
+ break; /* Write access check failed */
+ } else if ((iotlb->perm & IOMMU_RO) && !ade && !(pte & PTE_A)) {
+ break; /* Access bit not set */
+ } else if ((iotlb->perm & IOMMU_WO) && !ade && !(pte & PTE_D)) {
+ break; /* Dirty bit not set */
+ } else {
+ /* Leaf PTE, translation completed. */
+ sc[pass].step = sc[pass].levels;
+ base = PPN_PHYS(ppn) | (addr & ((1ULL << va_skip) - 1));
+ /* Update address mask based on smallest translation granularity */
+ iotlb->addr_mask &= (1ULL << va_skip) - 1;
+ /* Continue with S-Stage translation? */
+ if (pass && sc[0].step != sc[0].levels) {
+ pass = S_STAGE;
+ addr = iotlb->iova;
+ continue;
+ }
+ /* Translation phase completed (GPA or SPA) */
+ iotlb->translated_addr = base;
+ iotlb->perm = (pte & PTE_W) ? ((pte & PTE_R) ? IOMMU_RW : IOMMU_WO)
+ : IOMMU_RO;
+
+ /* Check MSI GPA address match */
+ if (pass == S_STAGE && (iotlb->perm & IOMMU_WO) &&
+ riscv_iommu_msi_check(s, ctx, base)) {
+ /* Trap MSI writes and return GPA address. */
+ iotlb->target_as = &s->trap_as;
+ iotlb->addr_mask = ~TARGET_PAGE_MASK;
+ return 0;
+ }
+
+ /* Continue with G-Stage translation? */
+ if (!pass && en_g) {
+ pass = G_STAGE;
+ addr = base;
+ base = gatp;
+ sc[pass].step = 0;
+ continue;
+ }
+
+ return 0;
+ }
+
+ if (sc[pass].step == sc[pass].levels) {
+ break; /* Can't find leaf PTE */
+ }
+
+ /* Continue with G-Stage translation? */
+ if (!pass && en_g) {
+ pass = G_STAGE;
+ addr = base;
+ base = gatp;
+ sc[pass].step = 0;
+ }
+ } while (1);
+
+ return (iotlb->perm & IOMMU_WO) ?
+ (pass ? RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS :
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S) :
+ (pass ? RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS :
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S);
+}
+
+static void riscv_iommu_report_fault(RISCVIOMMUState *s,
+ RISCVIOMMUContext *ctx,
+ uint32_t fault_type, uint32_t cause,
+ bool pv,
+ uint64_t iotval, uint64_t iotval2)
+{
+ struct riscv_iommu_fq_record ev = { 0 };
+
+ if (ctx->tc & RISCV_IOMMU_DC_TC_DTF) {
+ switch (cause) {
+ case RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED:
+ case RISCV_IOMMU_FQ_CAUSE_DDT_LOAD_FAULT:
+ case RISCV_IOMMU_FQ_CAUSE_DDT_INVALID:
+ case RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED:
+ case RISCV_IOMMU_FQ_CAUSE_DDT_CORRUPTED:
+ case RISCV_IOMMU_FQ_CAUSE_INTERNAL_DP_ERROR:
+ case RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT:
+ break;
+ default:
+ /* DTF prevents reporting a fault for this given cause */
+ return;
+ }
+ }
+
+ ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_CAUSE, cause);
+ ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_TTYPE, fault_type);
+ ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_DID, ctx->devid);
+ ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_PV, true);
+
+ if (pv) {
+ ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_PID, ctx->process_id);
+ }
+
+ ev.iotval = iotval;
+ ev.iotval2 = iotval2;
+
+ riscv_iommu_fault(s, &ev);
+}
+
+/* Redirect MSI write for given GPA. */
+static MemTxResult riscv_iommu_msi_write(RISCVIOMMUState *s,
+ RISCVIOMMUContext *ctx, uint64_t gpa, uint64_t data,
+ unsigned size, MemTxAttrs attrs)
+{
+ MemTxResult res;
+ dma_addr_t addr;
+ uint64_t intn;
+ uint32_t n190;
+ uint64_t pte[2];
+ int fault_type = RISCV_IOMMU_FQ_TTYPE_UADDR_WR;
+ int cause;
+
+ /* Interrupt File Number */
+ intn = riscv_iommu_pext_u64(PPN_DOWN(gpa), ctx->msi_addr_mask);
+ if (intn >= 256) {
+ /* Interrupt file number out of range */
+ res = MEMTX_ACCESS_ERROR;
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
+ goto err;
+ }
+
+ /* fetch MSI PTE */
+ addr = PPN_PHYS(get_field(ctx->msiptp, RISCV_IOMMU_DC_MSIPTP_PPN));
+ addr = addr | (intn * sizeof(pte));
+ res = dma_memory_read(s->target_as, addr, &pte, sizeof(pte),
+ MEMTXATTRS_UNSPECIFIED);
+ if (res != MEMTX_OK) {
+ if (res == MEMTX_DECODE_ERROR) {
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_PT_CORRUPTED;
+ } else {
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
+ }
+ goto err;
+ }
+
+ le64_to_cpus(&pte[0]);
+ le64_to_cpus(&pte[1]);
+
+ if (!(pte[0] & RISCV_IOMMU_MSI_PTE_V) || (pte[0] & RISCV_IOMMU_MSI_PTE_C)) {
+ /*
+ * The spec mentions that: "If msipte.C == 1, then further
+ * processing to interpret the PTE is implementation
+ * defined.". We'll abort with cause = 262 for this
+ * case too.
+ */
+ res = MEMTX_ACCESS_ERROR;
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_INVALID;
+ goto err;
+ }
+
+ switch (get_field(pte[0], RISCV_IOMMU_MSI_PTE_M)) {
+ case RISCV_IOMMU_MSI_PTE_M_BASIC:
+ /* MSI Pass-through mode */
+ addr = PPN_PHYS(get_field(pte[0], RISCV_IOMMU_MSI_PTE_PPN));
+
+ trace_riscv_iommu_msi(s->parent_obj.id, PCI_BUS_NUM(ctx->devid),
+ PCI_SLOT(ctx->devid), PCI_FUNC(ctx->devid),
+ gpa, addr);
+
+ res = dma_memory_write(s->target_as, addr, &data, size, attrs);
+ if (res != MEMTX_OK) {
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT;
+ goto err;
+ }
+
+ return MEMTX_OK;
+ case RISCV_IOMMU_MSI_PTE_M_MRIF:
+ /* MRIF mode, continue. */
+ break;
+ default:
+ res = MEMTX_ACCESS_ERROR;
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_MISCONFIGURED;
+ goto err;
+ }
+
+ /*
+ * Report an error for interrupt identities exceeding the maximum allowed
+ * for an IMSIC interrupt file (2047) or destination address is not 32-bit
+ * aligned. See IOMMU Specification, Chapter 2.3. MSI page tables.
+ */
+ if ((data > 2047) || (gpa & 3)) {
+ res = MEMTX_ACCESS_ERROR;
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_MISCONFIGURED;
+ goto err;
+ }
+
+ /* MSI MRIF mode, non atomic pending bit update */
+
+ /* MRIF pending bit address */
+ addr = get_field(pte[0], RISCV_IOMMU_MSI_PTE_MRIF_ADDR) << 9;
+ addr = addr | ((data & 0x7c0) >> 3);
+
+ trace_riscv_iommu_msi(s->parent_obj.id, PCI_BUS_NUM(ctx->devid),
+ PCI_SLOT(ctx->devid), PCI_FUNC(ctx->devid),
+ gpa, addr);
+
+ /* MRIF pending bit mask */
+ data = 1ULL << (data & 0x03f);
+ res = dma_memory_read(s->target_as, addr, &intn, sizeof(intn), attrs);
+ if (res != MEMTX_OK) {
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
+ goto err;
+ }
+
+ intn = intn | data;
+ res = dma_memory_write(s->target_as, addr, &intn, sizeof(intn), attrs);
+ if (res != MEMTX_OK) {
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT;
+ goto err;
+ }
+
+ /* Get MRIF enable bits */
+ addr = addr + sizeof(intn);
+ res = dma_memory_read(s->target_as, addr, &intn, sizeof(intn), attrs);
+ if (res != MEMTX_OK) {
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT;
+ goto err;
+ }
+
+ if (!(intn & data)) {
+ /* notification disabled, MRIF update completed. */
+ return MEMTX_OK;
+ }
+
+ /* Send notification message */
+ addr = PPN_PHYS(get_field(pte[1], RISCV_IOMMU_MSI_MRIF_NPPN));
+ n190 = get_field(pte[1], RISCV_IOMMU_MSI_MRIF_NID) |
+ (get_field(pte[1], RISCV_IOMMU_MSI_MRIF_NID_MSB) << 10);
+
+ res = dma_memory_write(s->target_as, addr, &n190, sizeof(n190), attrs);
+ if (res != MEMTX_OK) {
+ cause = RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT;
+ goto err;
+ }
+
+ trace_riscv_iommu_mrif_notification(s->parent_obj.id, n190, addr);
+
+ return MEMTX_OK;
+
+err:
+ riscv_iommu_report_fault(s, ctx, fault_type, cause,
+ !!ctx->process_id, 0, 0);
+ return res;
+}
+
+/*
+ * Check device context configuration as described by the
+ * riscv-iommu spec section "Device-context configuration
+ * checks".
+ */
+static bool riscv_iommu_validate_device_ctx(RISCVIOMMUState *s,
+ RISCVIOMMUContext *ctx)
+{
+ uint32_t fsc_mode, msi_mode;
+ uint64_t gatp;
+
+ if (!(s->cap & RISCV_IOMMU_CAP_ATS) &&
+ (ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS ||
+ ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI ||
+ ctx->tc & RISCV_IOMMU_DC_TC_PRPR)) {
+ return false;
+ }
+
+ if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS) &&
+ (ctx->tc & RISCV_IOMMU_DC_TC_T2GPA ||
+ ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI)) {
+ return false;
+ }
+
+ if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI) &&
+ ctx->tc & RISCV_IOMMU_DC_TC_PRPR) {
+ return false;
+ }
+
+ if (!(s->cap & RISCV_IOMMU_CAP_T2GPA) &&
+ ctx->tc & RISCV_IOMMU_DC_TC_T2GPA) {
+ return false;
+ }
+
+ if (s->cap & RISCV_IOMMU_CAP_MSI_FLAT) {
+ msi_mode = get_field(ctx->msiptp, RISCV_IOMMU_DC_MSIPTP_MODE);
+
+ if (msi_mode != RISCV_IOMMU_DC_MSIPTP_MODE_OFF &&
+ msi_mode != RISCV_IOMMU_DC_MSIPTP_MODE_FLAT) {
+ return false;
+ }
+ }
+
+ gatp = get_field(ctx->gatp, RISCV_IOMMU_ATP_MODE_FIELD);
+ if (ctx->tc & RISCV_IOMMU_DC_TC_T2GPA &&
+ gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE) {
+ return false;
+ }
+
+ fsc_mode = get_field(ctx->satp, RISCV_IOMMU_DC_FSC_MODE);
+
+ if (ctx->tc & RISCV_IOMMU_DC_TC_PDTV) {
+ switch (fsc_mode) {
+ case RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8:
+ if (!(s->cap & RISCV_IOMMU_CAP_PD8)) {
+ return false;
+ }
+ break;
+ case RISCV_IOMMU_DC_FSC_PDTP_MODE_PD17:
+ if (!(s->cap & RISCV_IOMMU_CAP_PD17)) {
+ return false;
+ }
+ break;
+ case RISCV_IOMMU_DC_FSC_PDTP_MODE_PD20:
+ if (!(s->cap & RISCV_IOMMU_CAP_PD20)) {
+ return false;
+ }
+ break;
+ }
+ } else {
+ /* DC.tc.PDTV is 0 */
+ if (ctx->tc & RISCV_IOMMU_DC_TC_DPE) {
+ return false;
+ }
+
+ if (ctx->tc & RISCV_IOMMU_DC_TC_SXL) {
+ if (fsc_mode == RISCV_IOMMU_CAP_SV32 &&
+ !(s->cap & RISCV_IOMMU_CAP_SV32)) {
+ return false;
+ }
+ } else {
+ switch (fsc_mode) {
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39:
+ if (!(s->cap & RISCV_IOMMU_CAP_SV39)) {
+ return false;
+ }
+ break;
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48:
+ if (!(s->cap & RISCV_IOMMU_CAP_SV48)) {
+ return false;
+ }
+ break;
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57:
+ if (!(s->cap & RISCV_IOMMU_CAP_SV57)) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+
+ /*
+ * CAP_END is always zero (only one endianess). FCTL_BE is
+ * always zero (little-endian accesses). Thus TC_SBE must
+ * always be LE, i.e. zero.
+ */
+ if (ctx->tc & RISCV_IOMMU_DC_TC_SBE) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Validate process context (PC) according to section
+ * "Process-context configuration checks".
+ */
+static bool riscv_iommu_validate_process_ctx(RISCVIOMMUState *s,
+ RISCVIOMMUContext *ctx)
+{
+ uint32_t mode;
+
+ if (get_field(ctx->ta, RISCV_IOMMU_PC_TA_RESERVED)) {
+ return false;
+ }
+
+ if (get_field(ctx->satp, RISCV_IOMMU_PC_FSC_RESERVED)) {
+ return false;
+ }
+
+ mode = get_field(ctx->satp, RISCV_IOMMU_DC_FSC_MODE);
+ switch (mode) {
+ case RISCV_IOMMU_DC_FSC_MODE_BARE:
+ /* sv39 and sv32 modes have the same value (8) */
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57:
+ break;
+ default:
+ return false;
+ }
+
+ if (ctx->tc & RISCV_IOMMU_DC_TC_SXL) {
+ if (mode == RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV32 &&
+ !(s->cap & RISCV_IOMMU_CAP_SV32)) {
+ return false;
+ }
+ } else {
+ switch (mode) {
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39:
+ if (!(s->cap & RISCV_IOMMU_CAP_SV39)) {
+ return false;
+ }
+ break;
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48:
+ if (!(s->cap & RISCV_IOMMU_CAP_SV48)) {
+ return false;
+ }
+ break;
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57:
+ if (!(s->cap & RISCV_IOMMU_CAP_SV57)) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+/*
+ * RISC-V IOMMU Device Context Loopkup - Device Directory Tree Walk
+ *
+ * @s : IOMMU Device State
+ * @ctx : Device Translation Context with devid and process_id set.
+ * @return : success or fault code.
+ */
+static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
+{
+ const uint64_t ddtp = s->ddtp;
+ unsigned mode = get_field(ddtp, RISCV_IOMMU_DDTP_MODE);
+ dma_addr_t addr = PPN_PHYS(get_field(ddtp, RISCV_IOMMU_DDTP_PPN));
+ struct riscv_iommu_dc dc;
+ /* Device Context format: 0: extended (64 bytes) | 1: base (32 bytes) */
+ const int dc_fmt = !s->enable_msi;
+ const size_t dc_len = sizeof(dc) >> dc_fmt;
+ int depth;
+ uint64_t de;
+
+ switch (mode) {
+ case RISCV_IOMMU_DDTP_MODE_OFF:
+ return RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED;
+
+ case RISCV_IOMMU_DDTP_MODE_BARE:
+ /* mock up pass-through translation context */
+ ctx->gatp = set_field(0, RISCV_IOMMU_ATP_MODE_FIELD,
+ RISCV_IOMMU_DC_IOHGATP_MODE_BARE);
+ ctx->satp = set_field(0, RISCV_IOMMU_ATP_MODE_FIELD,
+ RISCV_IOMMU_DC_FSC_MODE_BARE);
+
+ ctx->tc = RISCV_IOMMU_DC_TC_V;
+ if (s->enable_ats) {
+ ctx->tc |= RISCV_IOMMU_DC_TC_EN_ATS;
+ }
+
+ ctx->ta = 0;
+ ctx->msiptp = 0;
+ return 0;
+
+ case RISCV_IOMMU_DDTP_MODE_1LVL:
+ depth = 0;
+ break;
+
+ case RISCV_IOMMU_DDTP_MODE_2LVL:
+ depth = 1;
+ break;
+
+ case RISCV_IOMMU_DDTP_MODE_3LVL:
+ depth = 2;
+ break;
+
+ default:
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+
+ /*
+ * Check supported device id width (in bits).
+ * See IOMMU Specification, Chapter 6. Software guidelines.
+ * - if extended device-context format is used:
+ * 1LVL: 6, 2LVL: 15, 3LVL: 24
+ * - if base device-context format is used:
+ * 1LVL: 7, 2LVL: 16, 3LVL: 24
+ */
+ if (ctx->devid >= (1 << (depth * 9 + 6 + (dc_fmt && depth != 2)))) {
+ return RISCV_IOMMU_FQ_CAUSE_TTYPE_BLOCKED;
+ }
+
+ /* Device directory tree walk */
+ for (; depth-- > 0; ) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_DD_WALK);
+ /*
+ * Select device id index bits based on device directory tree level
+ * and device context format.
+ * See IOMMU Specification, Chapter 2. Data Structures.
+ * - if extended device-context format is used:
+ * device index: [23:15][14:6][5:0]
+ * - if base device-context format is used:
+ * device index: [23:16][15:7][6:0]
+ */
+ const int split = depth * 9 + 6 + dc_fmt;
+ addr |= ((ctx->devid >> split) << 3) & ~TARGET_PAGE_MASK;
+ if (dma_memory_read(s->target_as, addr, &de, sizeof(de),
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_LOAD_FAULT;
+ }
+ le64_to_cpus(&de);
+ if (!(de & RISCV_IOMMU_DDTE_VALID)) {
+ /* invalid directory entry */
+ return RISCV_IOMMU_FQ_CAUSE_DDT_INVALID;
+ }
+ if (de & ~(RISCV_IOMMU_DDTE_PPN | RISCV_IOMMU_DDTE_VALID)) {
+ /* reserved bits set */
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+ addr = PPN_PHYS(get_field(de, RISCV_IOMMU_DDTE_PPN));
+ }
+
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_DD_WALK);
+
+ /* index into device context entry page */
+ addr |= (ctx->devid * dc_len) & ~TARGET_PAGE_MASK;
+
+ memset(&dc, 0, sizeof(dc));
+ if (dma_memory_read(s->target_as, addr, &dc, dc_len,
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_LOAD_FAULT;
+ }
+
+ /* Set translation context. */
+ ctx->tc = le64_to_cpu(dc.tc);
+ ctx->gatp = le64_to_cpu(dc.iohgatp);
+ ctx->satp = le64_to_cpu(dc.fsc);
+ ctx->ta = le64_to_cpu(dc.ta);
+ ctx->msiptp = le64_to_cpu(dc.msiptp);
+ ctx->msi_addr_mask = le64_to_cpu(dc.msi_addr_mask);
+ ctx->msi_addr_pattern = le64_to_cpu(dc.msi_addr_pattern);
+
+ if (!(ctx->tc & RISCV_IOMMU_DC_TC_V)) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_INVALID;
+ }
+
+ if (!riscv_iommu_validate_device_ctx(s, ctx)) {
+ return RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED;
+ }
+
+ /* FSC field checks */
+ mode = get_field(ctx->satp, RISCV_IOMMU_DC_FSC_MODE);
+ addr = PPN_PHYS(get_field(ctx->satp, RISCV_IOMMU_DC_FSC_PPN));
+
+ if (!(ctx->tc & RISCV_IOMMU_DC_TC_PDTV)) {
+ if (ctx->process_id != RISCV_IOMMU_NOPROCID) {
+ /* PID is disabled */
+ return RISCV_IOMMU_FQ_CAUSE_TTYPE_BLOCKED;
+ }
+ if (mode > RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57) {
+ /* Invalid translation mode */
+ return RISCV_IOMMU_FQ_CAUSE_DDT_INVALID;
+ }
+ return 0;
+ }
+
+ if (ctx->process_id == RISCV_IOMMU_NOPROCID) {
+ if (!(ctx->tc & RISCV_IOMMU_DC_TC_DPE)) {
+ /* No default process_id enabled, set BARE mode */
+ ctx->satp = 0ULL;
+ return 0;
+ } else {
+ /* Use default process_id #0 */
+ ctx->process_id = 0;
+ }
+ }
+
+ if (mode == RISCV_IOMMU_DC_FSC_MODE_BARE) {
+ /* No S-Stage translation, done. */
+ return 0;
+ }
+
+ /* FSC.TC.PDTV enabled */
+ if (mode > RISCV_IOMMU_DC_FSC_PDTP_MODE_PD20) {
+ /* Invalid PDTP.MODE */
+ return RISCV_IOMMU_FQ_CAUSE_PDT_MISCONFIGURED;
+ }
+
+ for (depth = mode - RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8; depth-- > 0; ) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_PD_WALK);
+
+ /*
+ * Select process id index bits based on process directory tree
+ * level. See IOMMU Specification, 2.2. Process-Directory-Table.
+ */
+ const int split = depth * 9 + 8;
+ addr |= ((ctx->process_id >> split) << 3) & ~TARGET_PAGE_MASK;
+ if (dma_memory_read(s->target_as, addr, &de, sizeof(de),
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ return RISCV_IOMMU_FQ_CAUSE_PDT_LOAD_FAULT;
+ }
+ le64_to_cpus(&de);
+ if (!(de & RISCV_IOMMU_PDTE_VALID)) {
+ return RISCV_IOMMU_FQ_CAUSE_PDT_INVALID;
+ }
+ addr = PPN_PHYS(get_field(de, RISCV_IOMMU_PDTE_PPN));
+ }
+
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_PD_WALK);
+
+ /* Leaf entry in PDT */
+ addr |= (ctx->process_id << 4) & ~TARGET_PAGE_MASK;
+ if (dma_memory_read(s->target_as, addr, &dc.ta, sizeof(uint64_t) * 2,
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ return RISCV_IOMMU_FQ_CAUSE_PDT_LOAD_FAULT;
+ }
+
+ /* Use FSC and TA from process directory entry. */
+ ctx->ta = le64_to_cpu(dc.ta);
+ ctx->satp = le64_to_cpu(dc.fsc);
+
+ if (!(ctx->ta & RISCV_IOMMU_PC_TA_V)) {
+ return RISCV_IOMMU_FQ_CAUSE_PDT_INVALID;
+ }
+
+ if (!riscv_iommu_validate_process_ctx(s, ctx)) {
+ return RISCV_IOMMU_FQ_CAUSE_PDT_MISCONFIGURED;
+ }
+
+ return 0;
+}
+
+/* Translation Context cache support */
+static gboolean riscv_iommu_ctx_equal(gconstpointer v1, gconstpointer v2)
+{
+ RISCVIOMMUContext *c1 = (RISCVIOMMUContext *) v1;
+ RISCVIOMMUContext *c2 = (RISCVIOMMUContext *) v2;
+ return c1->devid == c2->devid &&
+ c1->process_id == c2->process_id;
+}
+
+static guint riscv_iommu_ctx_hash(gconstpointer v)
+{
+ RISCVIOMMUContext *ctx = (RISCVIOMMUContext *) v;
+ /*
+ * Generate simple hash of (process_id, devid)
+ * assuming 24-bit wide devid.
+ */
+ return (guint)(ctx->devid) + ((guint)(ctx->process_id) << 24);
+}
+
+static void riscv_iommu_ctx_inval_devid_procid(gpointer key, gpointer value,
+ gpointer data)
+{
+ RISCVIOMMUContext *ctx = (RISCVIOMMUContext *) value;
+ RISCVIOMMUContext *arg = (RISCVIOMMUContext *) data;
+ if (ctx->tc & RISCV_IOMMU_DC_TC_V &&
+ ctx->devid == arg->devid &&
+ ctx->process_id == arg->process_id) {
+ ctx->tc &= ~RISCV_IOMMU_DC_TC_V;
+ }
+}
+
+static void riscv_iommu_ctx_inval_devid(gpointer key, gpointer value,
+ gpointer data)
+{
+ RISCVIOMMUContext *ctx = (RISCVIOMMUContext *) value;
+ RISCVIOMMUContext *arg = (RISCVIOMMUContext *) data;
+ if (ctx->tc & RISCV_IOMMU_DC_TC_V &&
+ ctx->devid == arg->devid) {
+ ctx->tc &= ~RISCV_IOMMU_DC_TC_V;
+ }
+}
+
+static void riscv_iommu_ctx_inval_all(gpointer key, gpointer value,
+ gpointer data)
+{
+ RISCVIOMMUContext *ctx = (RISCVIOMMUContext *) value;
+ if (ctx->tc & RISCV_IOMMU_DC_TC_V) {
+ ctx->tc &= ~RISCV_IOMMU_DC_TC_V;
+ }
+}
+
+static void riscv_iommu_ctx_inval(RISCVIOMMUState *s, GHFunc func,
+ uint32_t devid, uint32_t process_id)
+{
+ GHashTable *ctx_cache;
+ RISCVIOMMUContext key = {
+ .devid = devid,
+ .process_id = process_id,
+ };
+ ctx_cache = g_hash_table_ref(s->ctx_cache);
+ g_hash_table_foreach(ctx_cache, func, &key);
+ g_hash_table_unref(ctx_cache);
+}
+
+/* Find or allocate translation context for a given {device_id, process_id} */
+static RISCVIOMMUContext *riscv_iommu_ctx(RISCVIOMMUState *s,
+ unsigned devid, unsigned process_id,
+ void **ref)
+{
+ GHashTable *ctx_cache;
+ RISCVIOMMUContext *ctx;
+ RISCVIOMMUContext key = {
+ .devid = devid,
+ .process_id = process_id,
+ };
+
+ ctx_cache = g_hash_table_ref(s->ctx_cache);
+ ctx = g_hash_table_lookup(ctx_cache, &key);
+
+ if (ctx && (ctx->tc & RISCV_IOMMU_DC_TC_V)) {
+ *ref = ctx_cache;
+ return ctx;
+ }
+
+ ctx = g_new0(RISCVIOMMUContext, 1);
+ ctx->devid = devid;
+ ctx->process_id = process_id;
+
+ int fault = riscv_iommu_ctx_fetch(s, ctx);
+ if (!fault) {
+ if (g_hash_table_size(ctx_cache) >= LIMIT_CACHE_CTX) {
+ g_hash_table_unref(ctx_cache);
+ ctx_cache = g_hash_table_new_full(riscv_iommu_ctx_hash,
+ riscv_iommu_ctx_equal,
+ g_free, NULL);
+ g_hash_table_ref(ctx_cache);
+ g_hash_table_unref(qatomic_xchg(&s->ctx_cache, ctx_cache));
+ }
+ g_hash_table_add(ctx_cache, ctx);
+ *ref = ctx_cache;
+ return ctx;
+ }
+
+ g_hash_table_unref(ctx_cache);
+ *ref = NULL;
+
+ riscv_iommu_report_fault(s, ctx, RISCV_IOMMU_FQ_TTYPE_UADDR_RD,
+ fault, !!process_id, 0, 0);
+
+ g_free(ctx);
+ return NULL;
+}
+
+static void riscv_iommu_ctx_put(RISCVIOMMUState *s, void *ref)
+{
+ if (ref) {
+ g_hash_table_unref((GHashTable *)ref);
+ }
+}
+
+/* Find or allocate address space for a given device */
+static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid)
+{
+ RISCVIOMMUSpace *as;
+
+ /* FIXME: PCIe bus remapping for attached endpoints. */
+ devid |= s->bus << 8;
+
+ QLIST_FOREACH(as, &s->spaces, list) {
+ if (as->devid == devid) {
+ break;
+ }
+ }
+
+ if (as == NULL) {
+ char name[64];
+ as = g_new0(RISCVIOMMUSpace, 1);
+
+ as->iommu = s;
+ as->devid = devid;
+
+ snprintf(name, sizeof(name), "riscv-iommu-%04x:%02x.%d-iova",
+ PCI_BUS_NUM(as->devid), PCI_SLOT(as->devid), PCI_FUNC(as->devid));
+
+ /* IOVA address space, untranslated addresses */
+ memory_region_init_iommu(&as->iova_mr, sizeof(as->iova_mr),
+ TYPE_RISCV_IOMMU_MEMORY_REGION,
+ OBJECT(as), "riscv_iommu", UINT64_MAX);
+ address_space_init(&as->iova_as, MEMORY_REGION(&as->iova_mr), name);
+
+ QLIST_INSERT_HEAD(&s->spaces, as, list);
+
+ trace_riscv_iommu_new(s->parent_obj.id, PCI_BUS_NUM(as->devid),
+ PCI_SLOT(as->devid), PCI_FUNC(as->devid));
+ }
+ return &as->iova_as;
+}
+
+/* Translation Object cache support */
+static gboolean riscv_iommu_iot_equal(gconstpointer v1, gconstpointer v2)
+{
+ RISCVIOMMUEntry *t1 = (RISCVIOMMUEntry *) v1;
+ RISCVIOMMUEntry *t2 = (RISCVIOMMUEntry *) v2;
+ return t1->gscid == t2->gscid && t1->pscid == t2->pscid &&
+ t1->iova == t2->iova && t1->tag == t2->tag;
+}
+
+static guint riscv_iommu_iot_hash(gconstpointer v)
+{
+ RISCVIOMMUEntry *t = (RISCVIOMMUEntry *) v;
+ return (guint)t->iova;
+}
+
+/* GV: 0 AV: 0 PSCV: 0 GVMA: 0 */
+/* GV: 0 AV: 0 GVMA: 1 */
+static
+void riscv_iommu_iot_inval_all(gpointer key, gpointer value, gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* GV: 0 AV: 0 PSCV: 1 GVMA: 0 */
+static
+void riscv_iommu_iot_inval_pscid(gpointer key, gpointer value, gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag &&
+ iot->pscid == arg->pscid) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* GV: 0 AV: 1 PSCV: 0 GVMA: 0 */
+static
+void riscv_iommu_iot_inval_iova(gpointer key, gpointer value, gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag &&
+ iot->iova == arg->iova) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* GV: 0 AV: 1 PSCV: 1 GVMA: 0 */
+static void riscv_iommu_iot_inval_pscid_iova(gpointer key, gpointer value,
+ gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag &&
+ iot->pscid == arg->pscid &&
+ iot->iova == arg->iova) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* GV: 1 AV: 0 PSCV: 0 GVMA: 0 */
+/* GV: 1 AV: 0 GVMA: 1 */
+static
+void riscv_iommu_iot_inval_gscid(gpointer key, gpointer value, gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag &&
+ iot->gscid == arg->gscid) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* GV: 1 AV: 0 PSCV: 1 GVMA: 0 */
+static void riscv_iommu_iot_inval_gscid_pscid(gpointer key, gpointer value,
+ gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag &&
+ iot->gscid == arg->gscid &&
+ iot->pscid == arg->pscid) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* GV: 1 AV: 1 PSCV: 0 GVMA: 0 */
+/* GV: 1 AV: 1 GVMA: 1 */
+static void riscv_iommu_iot_inval_gscid_iova(gpointer key, gpointer value,
+ gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag &&
+ iot->gscid == arg->gscid &&
+ iot->iova == arg->iova) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* GV: 1 AV: 1 PSCV: 1 GVMA: 0 */
+static void riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key, gpointer value,
+ gpointer data)
+{
+ RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
+ RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
+ if (iot->tag == arg->tag &&
+ iot->gscid == arg->gscid &&
+ iot->pscid == arg->pscid &&
+ iot->iova == arg->iova) {
+ iot->perm = IOMMU_NONE;
+ }
+}
+
+/* caller should keep ref-count for iot_cache object */
+static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext *ctx,
+ GHashTable *iot_cache, hwaddr iova, RISCVIOMMUTransTag transtag)
+{
+ RISCVIOMMUEntry key = {
+ .tag = transtag,
+ .gscid = get_field(ctx->gatp, RISCV_IOMMU_DC_IOHGATP_GSCID),
+ .pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID),
+ .iova = PPN_DOWN(iova),
+ };
+ return g_hash_table_lookup(iot_cache, &key);
+}
+
+/* caller should keep ref-count for iot_cache object */
+static void riscv_iommu_iot_update(RISCVIOMMUState *s,
+ GHashTable *iot_cache, RISCVIOMMUEntry *iot)
+{
+ if (!s->iot_limit) {
+ return;
+ }
+
+ if (g_hash_table_size(s->iot_cache) >= s->iot_limit) {
+ iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
+ riscv_iommu_iot_equal,
+ g_free, NULL);
+ g_hash_table_unref(qatomic_xchg(&s->iot_cache, iot_cache));
+ }
+ g_hash_table_add(iot_cache, iot);
+}
+
+static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func,
+ uint32_t gscid, uint32_t pscid, hwaddr iova, RISCVIOMMUTransTag transtag)
+{
+ GHashTable *iot_cache;
+ RISCVIOMMUEntry key = {
+ .tag = transtag,
+ .gscid = gscid,
+ .pscid = pscid,
+ .iova = PPN_DOWN(iova),
+ };
+
+ iot_cache = g_hash_table_ref(s->iot_cache);
+ g_hash_table_foreach(iot_cache, func, &key);
+ g_hash_table_unref(iot_cache);
+}
+
+static RISCVIOMMUTransTag riscv_iommu_get_transtag(RISCVIOMMUContext *ctx)
+{
+ uint64_t satp = get_field(ctx->satp, RISCV_IOMMU_ATP_MODE_FIELD);
+ uint64_t gatp = get_field(ctx->gatp, RISCV_IOMMU_ATP_MODE_FIELD);
+
+ if (satp == RISCV_IOMMU_DC_FSC_MODE_BARE) {
+ return (gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE) ?
+ RISCV_IOMMU_TRANS_TAG_BY : RISCV_IOMMU_TRANS_TAG_VG;
+ } else {
+ return (gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE) ?
+ RISCV_IOMMU_TRANS_TAG_SS : RISCV_IOMMU_TRANS_TAG_VN;
+ }
+}
+
+static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
+ IOMMUTLBEntry *iotlb, bool enable_cache)
+{
+ RISCVIOMMUTransTag transtag = riscv_iommu_get_transtag(ctx);
+ RISCVIOMMUEntry *iot;
+ IOMMUAccessFlags perm;
+ bool enable_pid;
+ bool enable_pri;
+ GHashTable *iot_cache;
+ int fault;
+
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_URQ);
+
+ iot_cache = g_hash_table_ref(s->iot_cache);
+ /*
+ * TC[32] is reserved for custom extensions, used here to temporarily
+ * enable automatic page-request generation for ATS queries.
+ */
+ enable_pri = (iotlb->perm == IOMMU_NONE) && (ctx->tc & BIT_ULL(32));
+ enable_pid = (ctx->tc & RISCV_IOMMU_DC_TC_PDTV);
+
+ /* Check for ATS request. */
+ if (iotlb->perm == IOMMU_NONE) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_ATS_RQ);
+ /* Check if ATS is disabled. */
+ if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS)) {
+ enable_pri = false;
+ fault = RISCV_IOMMU_FQ_CAUSE_TTYPE_BLOCKED;
+ goto done;
+ }
+ }
+
+ iot = riscv_iommu_iot_lookup(ctx, iot_cache, iotlb->iova, transtag);
+ perm = iot ? iot->perm : IOMMU_NONE;
+ if (perm != IOMMU_NONE) {
+ iotlb->translated_addr = PPN_PHYS(iot->phys);
+ iotlb->addr_mask = ~TARGET_PAGE_MASK;
+ iotlb->perm = perm;
+ fault = 0;
+ goto done;
+ }
+
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_TLB_MISS);
+
+ /* Translate using device directory / page table information. */
+ fault = riscv_iommu_spa_fetch(s, ctx, iotlb);
+
+ if (!fault && iotlb->target_as == &s->trap_as) {
+ /* Do not cache trapped MSI translations */
+ goto done;
+ }
+
+ /*
+ * We made an implementation choice to not cache identity-mapped
+ * translations, as allowed by the specification, to avoid
+ * translation cache evictions for other devices sharing the
+ * IOMMU hardware model.
+ */
+ if (!fault && iotlb->translated_addr != iotlb->iova && enable_cache) {
+ iot = g_new0(RISCVIOMMUEntry, 1);
+ iot->iova = PPN_DOWN(iotlb->iova);
+ iot->phys = PPN_DOWN(iotlb->translated_addr);
+ iot->gscid = get_field(ctx->gatp, RISCV_IOMMU_DC_IOHGATP_GSCID);
+ iot->pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID);
+ iot->perm = iotlb->perm;
+ iot->tag = transtag;
+ riscv_iommu_iot_update(s, iot_cache, iot);
+ }
+
+done:
+ g_hash_table_unref(iot_cache);
+
+ if (enable_pri && fault) {
+ struct riscv_iommu_pq_record pr = {0};
+ if (enable_pid) {
+ pr.hdr = set_field(RISCV_IOMMU_PREQ_HDR_PV,
+ RISCV_IOMMU_PREQ_HDR_PID, ctx->process_id);
+ }
+ pr.hdr = set_field(pr.hdr, RISCV_IOMMU_PREQ_HDR_DID, ctx->devid);
+ pr.payload = (iotlb->iova & TARGET_PAGE_MASK) |
+ RISCV_IOMMU_PREQ_PAYLOAD_M;
+ riscv_iommu_pri(s, &pr);
+ return fault;
+ }
+
+ if (fault) {
+ unsigned ttype = RISCV_IOMMU_FQ_TTYPE_PCIE_ATS_REQ;
+
+ if (iotlb->perm & IOMMU_RW) {
+ ttype = RISCV_IOMMU_FQ_TTYPE_UADDR_WR;
+ } else if (iotlb->perm & IOMMU_RO) {
+ ttype = RISCV_IOMMU_FQ_TTYPE_UADDR_RD;
+ }
+
+ riscv_iommu_report_fault(s, ctx, ttype, fault, enable_pid,
+ iotlb->iova, iotlb->translated_addr);
+ return fault;
+ }
+
+ return 0;
+}
+
+/* IOMMU Command Interface */
+static MemTxResult riscv_iommu_iofence(RISCVIOMMUState *s, bool notify,
+ uint64_t addr, uint32_t data)
+{
+ /*
+ * ATS processing in this implementation of the IOMMU is synchronous,
+ * no need to wait for completions here.
+ */
+ if (!notify) {
+ return MEMTX_OK;
+ }
+
+ return dma_memory_write(s->target_as, addr, &data, sizeof(data),
+ MEMTXATTRS_UNSPECIFIED);
+}
+
+static void riscv_iommu_ats(RISCVIOMMUState *s,
+ struct riscv_iommu_command *cmd, IOMMUNotifierFlag flag,
+ IOMMUAccessFlags perm,
+ void (*trace_fn)(const char *id))
+{
+ RISCVIOMMUSpace *as = NULL;
+ IOMMUNotifier *n;
+ IOMMUTLBEvent event;
+ uint32_t pid;
+ uint32_t devid;
+ const bool pv = cmd->dword0 & RISCV_IOMMU_CMD_ATS_PV;
+
+ if (cmd->dword0 & RISCV_IOMMU_CMD_ATS_DSV) {
+ /* Use device segment and requester id */
+ devid = get_field(cmd->dword0,
+ RISCV_IOMMU_CMD_ATS_DSEG | RISCV_IOMMU_CMD_ATS_RID);
+ } else {
+ devid = get_field(cmd->dword0, RISCV_IOMMU_CMD_ATS_RID);
+ }
+
+ pid = get_field(cmd->dword0, RISCV_IOMMU_CMD_ATS_PID);
+
+ QLIST_FOREACH(as, &s->spaces, list) {
+ if (as->devid == devid) {
+ break;
+ }
+ }
+
+ if (!as || !as->notifier) {
+ return;
+ }
+
+ event.type = flag;
+ event.entry.perm = perm;
+ event.entry.target_as = s->target_as;
+
+ IOMMU_NOTIFIER_FOREACH(n, &as->iova_mr) {
+ if (!pv || n->iommu_idx == pid) {
+ event.entry.iova = n->start;
+ event.entry.addr_mask = n->end - n->start;
+ trace_fn(as->iova_mr.parent_obj.name);
+ memory_region_notify_iommu_one(n, &event);
+ }
+ }
+}
+
+static void riscv_iommu_ats_inval(RISCVIOMMUState *s,
+ struct riscv_iommu_command *cmd)
+{
+ return riscv_iommu_ats(s, cmd, IOMMU_NOTIFIER_DEVIOTLB_UNMAP, IOMMU_NONE,
+ trace_riscv_iommu_ats_inval);
+}
+
+static void riscv_iommu_ats_prgr(RISCVIOMMUState *s,
+ struct riscv_iommu_command *cmd)
+{
+ unsigned resp_code = get_field(cmd->dword1,
+ RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE);
+
+ /* Using the access flag to carry response code information */
+ IOMMUAccessFlags perm = resp_code ? IOMMU_NONE : IOMMU_RW;
+ return riscv_iommu_ats(s, cmd, IOMMU_NOTIFIER_MAP, perm,
+ trace_riscv_iommu_ats_prgr);
+}
+
+static void riscv_iommu_process_ddtp(RISCVIOMMUState *s)
+{
+ uint64_t old_ddtp = s->ddtp;
+ uint64_t new_ddtp = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_DDTP);
+ unsigned new_mode = get_field(new_ddtp, RISCV_IOMMU_DDTP_MODE);
+ unsigned old_mode = get_field(old_ddtp, RISCV_IOMMU_DDTP_MODE);
+ bool ok = false;
+
+ /*
+ * Check for allowed DDTP.MODE transitions:
+ * {OFF, BARE} -> {OFF, BARE, 1LVL, 2LVL, 3LVL}
+ * {1LVL, 2LVL, 3LVL} -> {OFF, BARE}
+ */
+ if (new_mode == old_mode ||
+ new_mode == RISCV_IOMMU_DDTP_MODE_OFF ||
+ new_mode == RISCV_IOMMU_DDTP_MODE_BARE) {
+ ok = true;
+ } else if (new_mode == RISCV_IOMMU_DDTP_MODE_1LVL ||
+ new_mode == RISCV_IOMMU_DDTP_MODE_2LVL ||
+ new_mode == RISCV_IOMMU_DDTP_MODE_3LVL) {
+ ok = old_mode == RISCV_IOMMU_DDTP_MODE_OFF ||
+ old_mode == RISCV_IOMMU_DDTP_MODE_BARE;
+ }
+
+ if (ok) {
+ /* clear reserved and busy bits, report back sanitized version */
+ new_ddtp = set_field(new_ddtp & RISCV_IOMMU_DDTP_PPN,
+ RISCV_IOMMU_DDTP_MODE, new_mode);
+ } else {
+ new_ddtp = old_ddtp;
+ }
+ s->ddtp = new_ddtp;
+
+ riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_DDTP, new_ddtp);
+}
+
+/* Command function and opcode field. */
+#define RISCV_IOMMU_CMD(func, op) (((func) << 7) | (op))
+
+static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
+{
+ struct riscv_iommu_command cmd;
+ MemTxResult res;
+ dma_addr_t addr;
+ uint32_t tail, head, ctrl;
+ uint64_t cmd_opcode;
+ GHFunc func;
+
+ ctrl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR);
+ tail = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQT) & s->cq_mask;
+ head = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQH) & s->cq_mask;
+
+ /* Check for pending error or queue processing disabled */
+ if (!(ctrl & RISCV_IOMMU_CQCSR_CQON) ||
+ !!(ctrl & (RISCV_IOMMU_CQCSR_CMD_ILL | RISCV_IOMMU_CQCSR_CQMF))) {
+ return;
+ }
+
+ while (tail != head) {
+ addr = s->cq_addr + head * sizeof(cmd);
+ res = dma_memory_read(s->target_as, addr, &cmd, sizeof(cmd),
+ MEMTXATTRS_UNSPECIFIED);
+
+ if (res != MEMTX_OK) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_CQCSR,
+ RISCV_IOMMU_CQCSR_CQMF, 0);
+ goto fault;
+ }
+
+ trace_riscv_iommu_cmd(s->parent_obj.id, cmd.dword0, cmd.dword1);
+
+ cmd_opcode = get_field(cmd.dword0,
+ RISCV_IOMMU_CMD_OPCODE | RISCV_IOMMU_CMD_FUNC);
+
+ switch (cmd_opcode) {
+ case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IOFENCE_FUNC_C,
+ RISCV_IOMMU_CMD_IOFENCE_OPCODE):
+ res = riscv_iommu_iofence(s,
+ cmd.dword0 & RISCV_IOMMU_CMD_IOFENCE_AV, cmd.dword1 << 2,
+ get_field(cmd.dword0, RISCV_IOMMU_CMD_IOFENCE_DATA));
+
+ if (res != MEMTX_OK) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_CQCSR,
+ RISCV_IOMMU_CQCSR_CQMF, 0);
+ goto fault;
+ }
+ break;
+
+ case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IOTINVAL_FUNC_GVMA,
+ RISCV_IOMMU_CMD_IOTINVAL_OPCODE):
+ {
+ bool gv = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV);
+ bool av = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV);
+ bool pscv = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV);
+ uint32_t gscid = get_field(cmd.dword0,
+ RISCV_IOMMU_CMD_IOTINVAL_GSCID);
+ uint32_t pscid = get_field(cmd.dword0,
+ RISCV_IOMMU_CMD_IOTINVAL_PSCID);
+ hwaddr iova = (cmd.dword1 << 2) & TARGET_PAGE_MASK;
+
+ if (pscv) {
+ /* illegal command arguments IOTINVAL.GVMA & PSCV == 1 */
+ goto cmd_ill;
+ }
+
+ func = riscv_iommu_iot_inval_all;
+
+ if (gv) {
+ func = (av) ? riscv_iommu_iot_inval_gscid_iova :
+ riscv_iommu_iot_inval_gscid;
+ }
+
+ riscv_iommu_iot_inval(
+ s, func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VG);
+
+ riscv_iommu_iot_inval(
+ s, func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VN);
+ break;
+ }
+
+ case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA,
+ RISCV_IOMMU_CMD_IOTINVAL_OPCODE):
+ {
+ bool gv = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV);
+ bool av = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV);
+ bool pscv = !!(cmd.dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV);
+ uint32_t gscid = get_field(cmd.dword0,
+ RISCV_IOMMU_CMD_IOTINVAL_GSCID);
+ uint32_t pscid = get_field(cmd.dword0,
+ RISCV_IOMMU_CMD_IOTINVAL_PSCID);
+ hwaddr iova = (cmd.dword1 << 2) & TARGET_PAGE_MASK;
+ RISCVIOMMUTransTag transtag;
+
+ if (gv) {
+ transtag = RISCV_IOMMU_TRANS_TAG_VN;
+ if (pscv) {
+ func = (av) ? riscv_iommu_iot_inval_gscid_pscid_iova :
+ riscv_iommu_iot_inval_gscid_pscid;
+ } else {
+ func = (av) ? riscv_iommu_iot_inval_gscid_iova :
+ riscv_iommu_iot_inval_gscid;
+ }
+ } else {
+ transtag = RISCV_IOMMU_TRANS_TAG_SS;
+ if (pscv) {
+ func = (av) ? riscv_iommu_iot_inval_pscid_iova :
+ riscv_iommu_iot_inval_pscid;
+ } else {
+ func = (av) ? riscv_iommu_iot_inval_iova :
+ riscv_iommu_iot_inval_all;
+ }
+ }
+
+ riscv_iommu_iot_inval(s, func, gscid, pscid, iova, transtag);
+ break;
+ }
+
+ case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT,
+ RISCV_IOMMU_CMD_IODIR_OPCODE):
+ if (!(cmd.dword0 & RISCV_IOMMU_CMD_IODIR_DV)) {
+ /* invalidate all device context cache mappings */
+ func = riscv_iommu_ctx_inval_all;
+ } else {
+ /* invalidate all device context matching DID */
+ func = riscv_iommu_ctx_inval_devid;
+ }
+ riscv_iommu_ctx_inval(s, func,
+ get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID), 0);
+ break;
+
+ case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_PDT,
+ RISCV_IOMMU_CMD_IODIR_OPCODE):
+ if (!(cmd.dword0 & RISCV_IOMMU_CMD_IODIR_DV)) {
+ /* illegal command arguments IODIR_PDT & DV == 0 */
+ goto cmd_ill;
+ } else {
+ func = riscv_iommu_ctx_inval_devid_procid;
+ }
+ riscv_iommu_ctx_inval(s, func,
+ get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID),
+ get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_PID));
+ break;
+
+ /* ATS commands */
+ case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_ATS_FUNC_INVAL,
+ RISCV_IOMMU_CMD_ATS_OPCODE):
+ if (!s->enable_ats) {
+ goto cmd_ill;
+ }
+
+ riscv_iommu_ats_inval(s, &cmd);
+ break;
+
+ case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_ATS_FUNC_PRGR,
+ RISCV_IOMMU_CMD_ATS_OPCODE):
+ if (!s->enable_ats) {
+ goto cmd_ill;
+ }
+
+ riscv_iommu_ats_prgr(s, &cmd);
+ break;
+
+ default:
+ cmd_ill:
+ /* Invalid instruction, do not advance instruction index. */
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_CQCSR,
+ RISCV_IOMMU_CQCSR_CMD_ILL, 0);
+ goto fault;
+ }
+
+ /* Advance and update head pointer after command completes. */
+ head = (head + 1) & s->cq_mask;
+ riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_CQH, head);
+ }
+ return;
+
+fault:
+ if (ctrl & RISCV_IOMMU_CQCSR_CIE) {
+ riscv_iommu_notify(s, RISCV_IOMMU_INTR_CQ);
+ }
+}
+
+static void riscv_iommu_process_cq_control(RISCVIOMMUState *s)
+{
+ uint64_t base;
+ uint32_t ctrl_set = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR);
+ uint32_t ctrl_clr;
+ bool enable = !!(ctrl_set & RISCV_IOMMU_CQCSR_CQEN);
+ bool active = !!(ctrl_set & RISCV_IOMMU_CQCSR_CQON);
+
+ if (enable && !active) {
+ base = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_CQB);
+ s->cq_mask = (2ULL << get_field(base, RISCV_IOMMU_CQB_LOG2SZ)) - 1;
+ s->cq_addr = PPN_PHYS(get_field(base, RISCV_IOMMU_CQB_PPN));
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_CQT], ~s->cq_mask);
+ stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_CQH], 0);
+ stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_CQT], 0);
+ ctrl_set = RISCV_IOMMU_CQCSR_CQON;
+ ctrl_clr = RISCV_IOMMU_CQCSR_BUSY | RISCV_IOMMU_CQCSR_CQMF |
+ RISCV_IOMMU_CQCSR_CMD_ILL | RISCV_IOMMU_CQCSR_CMD_TO |
+ RISCV_IOMMU_CQCSR_FENCE_W_IP;
+ } else if (!enable && active) {
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_CQT], ~0);
+ ctrl_set = 0;
+ ctrl_clr = RISCV_IOMMU_CQCSR_BUSY | RISCV_IOMMU_CQCSR_CQON;
+ } else {
+ ctrl_set = 0;
+ ctrl_clr = RISCV_IOMMU_CQCSR_BUSY;
+ }
+
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_CQCSR, ctrl_set, ctrl_clr);
+}
+
+static void riscv_iommu_process_fq_control(RISCVIOMMUState *s)
+{
+ uint64_t base;
+ uint32_t ctrl_set = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_FQCSR);
+ uint32_t ctrl_clr;
+ bool enable = !!(ctrl_set & RISCV_IOMMU_FQCSR_FQEN);
+ bool active = !!(ctrl_set & RISCV_IOMMU_FQCSR_FQON);
+
+ if (enable && !active) {
+ base = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_FQB);
+ s->fq_mask = (2ULL << get_field(base, RISCV_IOMMU_FQB_LOG2SZ)) - 1;
+ s->fq_addr = PPN_PHYS(get_field(base, RISCV_IOMMU_FQB_PPN));
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_FQH], ~s->fq_mask);
+ stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_FQH], 0);
+ stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_FQT], 0);
+ ctrl_set = RISCV_IOMMU_FQCSR_FQON;
+ ctrl_clr = RISCV_IOMMU_FQCSR_BUSY | RISCV_IOMMU_FQCSR_FQMF |
+ RISCV_IOMMU_FQCSR_FQOF;
+ } else if (!enable && active) {
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_FQH], ~0);
+ ctrl_set = 0;
+ ctrl_clr = RISCV_IOMMU_FQCSR_BUSY | RISCV_IOMMU_FQCSR_FQON;
+ } else {
+ ctrl_set = 0;
+ ctrl_clr = RISCV_IOMMU_FQCSR_BUSY;
+ }
+
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_FQCSR, ctrl_set, ctrl_clr);
+}
+
+static void riscv_iommu_process_pq_control(RISCVIOMMUState *s)
+{
+ uint64_t base;
+ uint32_t ctrl_set = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_PQCSR);
+ uint32_t ctrl_clr;
+ bool enable = !!(ctrl_set & RISCV_IOMMU_PQCSR_PQEN);
+ bool active = !!(ctrl_set & RISCV_IOMMU_PQCSR_PQON);
+
+ if (enable && !active) {
+ base = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_PQB);
+ s->pq_mask = (2ULL << get_field(base, RISCV_IOMMU_PQB_LOG2SZ)) - 1;
+ s->pq_addr = PPN_PHYS(get_field(base, RISCV_IOMMU_PQB_PPN));
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_PQH], ~s->pq_mask);
+ stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_PQH], 0);
+ stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_PQT], 0);
+ ctrl_set = RISCV_IOMMU_PQCSR_PQON;
+ ctrl_clr = RISCV_IOMMU_PQCSR_BUSY | RISCV_IOMMU_PQCSR_PQMF |
+ RISCV_IOMMU_PQCSR_PQOF;
+ } else if (!enable && active) {
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_PQH], ~0);
+ ctrl_set = 0;
+ ctrl_clr = RISCV_IOMMU_PQCSR_BUSY | RISCV_IOMMU_PQCSR_PQON;
+ } else {
+ ctrl_set = 0;
+ ctrl_clr = RISCV_IOMMU_PQCSR_BUSY;
+ }
+
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_PQCSR, ctrl_set, ctrl_clr);
+}
+
+static void riscv_iommu_process_dbg(RISCVIOMMUState *s)
+{
+ uint64_t iova = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_TR_REQ_IOVA);
+ uint64_t ctrl = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_TR_REQ_CTL);
+ unsigned devid = get_field(ctrl, RISCV_IOMMU_TR_REQ_CTL_DID);
+ unsigned pid = get_field(ctrl, RISCV_IOMMU_TR_REQ_CTL_PID);
+ RISCVIOMMUContext *ctx;
+ void *ref;
+
+ if (!(ctrl & RISCV_IOMMU_TR_REQ_CTL_GO_BUSY)) {
+ return;
+ }
+
+ ctx = riscv_iommu_ctx(s, devid, pid, &ref);
+ if (ctx == NULL) {
+ riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_TR_RESPONSE,
+ RISCV_IOMMU_TR_RESPONSE_FAULT |
+ (RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED << 10));
+ } else {
+ IOMMUTLBEntry iotlb = {
+ .iova = iova,
+ .perm = ctrl & RISCV_IOMMU_TR_REQ_CTL_NW ? IOMMU_RO : IOMMU_RW,
+ .addr_mask = ~0,
+ .target_as = NULL,
+ };
+ int fault = riscv_iommu_translate(s, ctx, &iotlb, false);
+ if (fault) {
+ iova = RISCV_IOMMU_TR_RESPONSE_FAULT | (((uint64_t) fault) << 10);
+ } else {
+ iova = iotlb.translated_addr & ~iotlb.addr_mask;
+ iova >>= TARGET_PAGE_BITS;
+ iova &= RISCV_IOMMU_TR_RESPONSE_PPN;
+
+ /* We do not support superpages (> 4kbs) for now */
+ iova &= ~RISCV_IOMMU_TR_RESPONSE_S;
+ }
+ riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_TR_RESPONSE, iova);
+ }
+
+ riscv_iommu_reg_mod64(s, RISCV_IOMMU_REG_TR_REQ_CTL, 0,
+ RISCV_IOMMU_TR_REQ_CTL_GO_BUSY);
+ riscv_iommu_ctx_put(s, ref);
+}
+
+typedef void riscv_iommu_process_fn(RISCVIOMMUState *s);
+
+static void riscv_iommu_update_icvec(RISCVIOMMUState *s, uint64_t data)
+{
+ uint64_t icvec = 0;
+
+ icvec |= MIN(data & RISCV_IOMMU_ICVEC_CIV,
+ s->icvec_avail_vectors & RISCV_IOMMU_ICVEC_CIV);
+
+ icvec |= MIN(data & RISCV_IOMMU_ICVEC_FIV,
+ s->icvec_avail_vectors & RISCV_IOMMU_ICVEC_FIV);
+
+ icvec |= MIN(data & RISCV_IOMMU_ICVEC_PMIV,
+ s->icvec_avail_vectors & RISCV_IOMMU_ICVEC_PMIV);
+
+ icvec |= MIN(data & RISCV_IOMMU_ICVEC_PIV,
+ s->icvec_avail_vectors & RISCV_IOMMU_ICVEC_PIV);
+
+ trace_riscv_iommu_icvec_write(data, icvec);
+
+ riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_ICVEC, icvec);
+}
+
+static void riscv_iommu_update_ipsr(RISCVIOMMUState *s, uint64_t data)
+{
+ uint32_t cqcsr, fqcsr, pqcsr;
+ uint32_t ipsr_set = 0;
+ uint32_t ipsr_clr = 0;
+
+ if (data & RISCV_IOMMU_IPSR_CIP) {
+ cqcsr = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR);
+
+ if (cqcsr & RISCV_IOMMU_CQCSR_CIE &&
+ (cqcsr & RISCV_IOMMU_CQCSR_FENCE_W_IP ||
+ cqcsr & RISCV_IOMMU_CQCSR_CMD_ILL ||
+ cqcsr & RISCV_IOMMU_CQCSR_CMD_TO ||
+ cqcsr & RISCV_IOMMU_CQCSR_CQMF)) {
+ ipsr_set |= RISCV_IOMMU_IPSR_CIP;
+ } else {
+ ipsr_clr |= RISCV_IOMMU_IPSR_CIP;
+ }
+ } else {
+ ipsr_clr |= RISCV_IOMMU_IPSR_CIP;
+ }
+
+ if (data & RISCV_IOMMU_IPSR_FIP) {
+ fqcsr = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_FQCSR);
+
+ if (fqcsr & RISCV_IOMMU_FQCSR_FIE &&
+ (fqcsr & RISCV_IOMMU_FQCSR_FQOF ||
+ fqcsr & RISCV_IOMMU_FQCSR_FQMF)) {
+ ipsr_set |= RISCV_IOMMU_IPSR_FIP;
+ } else {
+ ipsr_clr |= RISCV_IOMMU_IPSR_FIP;
+ }
+ } else {
+ ipsr_clr |= RISCV_IOMMU_IPSR_FIP;
+ }
+
+ if (data & RISCV_IOMMU_IPSR_PIP) {
+ pqcsr = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_PQCSR);
+
+ if (pqcsr & RISCV_IOMMU_PQCSR_PIE &&
+ (pqcsr & RISCV_IOMMU_PQCSR_PQOF ||
+ pqcsr & RISCV_IOMMU_PQCSR_PQMF)) {
+ ipsr_set |= RISCV_IOMMU_IPSR_PIP;
+ } else {
+ ipsr_clr |= RISCV_IOMMU_IPSR_PIP;
+ }
+ } else {
+ ipsr_clr |= RISCV_IOMMU_IPSR_PIP;
+ }
+
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IPSR, ipsr_set, ipsr_clr);
+}
+
+static void riscv_iommu_process_hpm_writes(RISCVIOMMUState *s,
+ uint32_t regb,
+ bool prev_cy_inh)
+{
+ switch (regb) {
+ case RISCV_IOMMU_REG_IOCOUNTINH:
+ riscv_iommu_process_iocntinh_cy(s, prev_cy_inh);
+ break;
+
+ case RISCV_IOMMU_REG_IOHPMCYCLES:
+ case RISCV_IOMMU_REG_IOHPMCYCLES + 4:
+ riscv_iommu_process_hpmcycle_write(s);
+ break;
+
+ case RISCV_IOMMU_REG_IOHPMEVT_BASE ...
+ RISCV_IOMMU_REG_IOHPMEVT(RISCV_IOMMU_IOCOUNT_NUM) + 4:
+ riscv_iommu_process_hpmevt_write(s, regb & ~7);
+ break;
+ }
+}
+
+/*
+ * Write the resulting value of 'data' for the reg specified
+ * by 'reg_addr', after considering read-only/read-write/write-clear
+ * bits, in the pointer 'dest'.
+ *
+ * The result is written in little-endian.
+ */
+static void riscv_iommu_write_reg_val(RISCVIOMMUState *s,
+ void *dest, hwaddr reg_addr,
+ int size, uint64_t data)
+{
+ uint64_t ro = ldn_le_p(&s->regs_ro[reg_addr], size);
+ uint64_t wc = ldn_le_p(&s->regs_wc[reg_addr], size);
+ uint64_t rw = ldn_le_p(&s->regs_rw[reg_addr], size);
+
+ stn_le_p(dest, size, ((rw & ro) | (data & ~ro)) & ~(data & wc));
+}
+
+static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size,
+ MemTxAttrs attrs)
+{
+ riscv_iommu_process_fn *process_fn = NULL;
+ RISCVIOMMUState *s = opaque;
+ uint32_t regb = addr & ~3;
+ uint32_t busy = 0;
+ uint64_t val = 0;
+ bool cy_inh = false;
+
+ if ((addr & (size - 1)) != 0) {
+ /* Unsupported MMIO alignment or access size */
+ return MEMTX_ERROR;
+ }
+
+ if (addr + size > RISCV_IOMMU_REG_MSI_CONFIG) {
+ /* Unsupported MMIO access location. */
+ return MEMTX_ACCESS_ERROR;
+ }
+
+ /* Track actionable MMIO write. */
+ switch (regb) {
+ case RISCV_IOMMU_REG_DDTP:
+ case RISCV_IOMMU_REG_DDTP + 4:
+ process_fn = riscv_iommu_process_ddtp;
+ regb = RISCV_IOMMU_REG_DDTP;
+ busy = RISCV_IOMMU_DDTP_BUSY;
+ break;
+
+ case RISCV_IOMMU_REG_CQT:
+ process_fn = riscv_iommu_process_cq_tail;
+ break;
+
+ case RISCV_IOMMU_REG_CQCSR:
+ process_fn = riscv_iommu_process_cq_control;
+ busy = RISCV_IOMMU_CQCSR_BUSY;
+ break;
+
+ case RISCV_IOMMU_REG_FQCSR:
+ process_fn = riscv_iommu_process_fq_control;
+ busy = RISCV_IOMMU_FQCSR_BUSY;
+ break;
+
+ case RISCV_IOMMU_REG_PQCSR:
+ process_fn = riscv_iommu_process_pq_control;
+ busy = RISCV_IOMMU_PQCSR_BUSY;
+ break;
+
+ case RISCV_IOMMU_REG_ICVEC:
+ case RISCV_IOMMU_REG_IPSR:
+ /*
+ * ICVEC and IPSR have special read/write procedures. We'll
+ * call their respective helpers and exit.
+ */
+ riscv_iommu_write_reg_val(s, &val, addr, size, data);
+
+ /*
+ * 'val' is stored as LE. Switch to host endianess
+ * before using it.
+ */
+ val = le64_to_cpu(val);
+
+ if (regb == RISCV_IOMMU_REG_ICVEC) {
+ riscv_iommu_update_icvec(s, val);
+ } else {
+ riscv_iommu_update_ipsr(s, val);
+ }
+
+ return MEMTX_OK;
+
+ case RISCV_IOMMU_REG_TR_REQ_CTL:
+ process_fn = riscv_iommu_process_dbg;
+ regb = RISCV_IOMMU_REG_TR_REQ_CTL;
+ busy = RISCV_IOMMU_TR_REQ_CTL_GO_BUSY;
+ break;
+
+ case RISCV_IOMMU_REG_IOCOUNTINH:
+ if (addr != RISCV_IOMMU_REG_IOCOUNTINH) {
+ break;
+ }
+ /* Store previous value of CY bit. */
+ cy_inh = !!(riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTINH) &
+ RISCV_IOMMU_IOCOUNTINH_CY);
+ break;
+
+
+ default:
+ break;
+ }
+
+ /*
+ * Registers update might be not synchronized with core logic.
+ * If system software updates register when relevant BUSY bit
+ * is set IOMMU behavior of additional writes to the register
+ * is UNSPECIFIED.
+ */
+ riscv_iommu_write_reg_val(s, &s->regs_rw[addr], addr, size, data);
+
+ /* Busy flag update, MSB 4-byte register. */
+ if (busy) {
+ uint32_t rw = ldl_le_p(&s->regs_rw[regb]);
+ stl_le_p(&s->regs_rw[regb], rw | busy);
+ }
+
+ /* Process HPM writes and update any internal state if needed. */
+ if (regb >= RISCV_IOMMU_REG_IOCOUNTOVF &&
+ regb <= (RISCV_IOMMU_REG_IOHPMEVT(RISCV_IOMMU_IOCOUNT_NUM) + 4)) {
+ riscv_iommu_process_hpm_writes(s, regb, cy_inh);
+ }
+
+ if (process_fn) {
+ process_fn(s);
+ }
+
+ return MEMTX_OK;
+}
+
+static MemTxResult riscv_iommu_mmio_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size, MemTxAttrs attrs)
+{
+ RISCVIOMMUState *s = opaque;
+ uint64_t val = -1;
+ uint8_t *ptr;
+
+ if ((addr & (size - 1)) != 0) {
+ /* Unsupported MMIO alignment. */
+ return MEMTX_ERROR;
+ }
+
+ if (addr + size > RISCV_IOMMU_REG_MSI_CONFIG) {
+ return MEMTX_ACCESS_ERROR;
+ }
+
+ /* Compute cycle register value. */
+ if ((addr & ~7) == RISCV_IOMMU_REG_IOHPMCYCLES) {
+ val = riscv_iommu_hpmcycle_read(s);
+ ptr = (uint8_t *)&val + (addr & 7);
+ } else if ((addr & ~3) == RISCV_IOMMU_REG_IOCOUNTOVF) {
+ /*
+ * Software can read RISCV_IOMMU_REG_IOCOUNTOVF before timer
+ * callback completes. In which case CY_OF bit in
+ * RISCV_IOMMU_IOHPMCYCLES_OVF would be 0. Here we take the
+ * CY_OF bit state from RISCV_IOMMU_REG_IOHPMCYCLES register as
+ * it's not dependent over the timer callback and is computed
+ * from cycle overflow.
+ */
+ val = ldq_le_p(&s->regs_rw[addr]);
+ val |= (riscv_iommu_hpmcycle_read(s) & RISCV_IOMMU_IOHPMCYCLES_OVF)
+ ? RISCV_IOMMU_IOCOUNTOVF_CY
+ : 0;
+ ptr = (uint8_t *)&val + (addr & 3);
+ } else {
+ ptr = &s->regs_rw[addr];
+ }
+
+ val = ldn_le_p(ptr, size);
+
+ *data = val;
+
+ return MEMTX_OK;
+}
+
+static const MemoryRegionOps riscv_iommu_mmio_ops = {
+ .read_with_attrs = riscv_iommu_mmio_read,
+ .write_with_attrs = riscv_iommu_mmio_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ .unaligned = false,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ }
+};
+
+/*
+ * Translations matching MSI pattern check are redirected to "riscv-iommu-trap"
+ * memory region as untranslated address, for additional MSI/MRIF interception
+ * by IOMMU interrupt remapping implementation.
+ * Note: Device emulation code generating an MSI is expected to provide a valid
+ * memory transaction attributes with requested_id set.
+ */
+static MemTxResult riscv_iommu_trap_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size, MemTxAttrs attrs)
+{
+ RISCVIOMMUState* s = (RISCVIOMMUState *)opaque;
+ RISCVIOMMUContext *ctx;
+ MemTxResult res;
+ void *ref;
+ uint32_t devid = attrs.requester_id;
+
+ if (attrs.unspecified) {
+ return MEMTX_ACCESS_ERROR;
+ }
+
+ /* FIXME: PCIe bus remapping for attached endpoints. */
+ devid |= s->bus << 8;
+
+ ctx = riscv_iommu_ctx(s, devid, 0, &ref);
+ if (ctx == NULL) {
+ res = MEMTX_ACCESS_ERROR;
+ } else {
+ res = riscv_iommu_msi_write(s, ctx, addr, data, size, attrs);
+ }
+ riscv_iommu_ctx_put(s, ref);
+ return res;
+}
+
+static MemTxResult riscv_iommu_trap_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size, MemTxAttrs attrs)
+{
+ return MEMTX_ACCESS_ERROR;
+}
+
+static const MemoryRegionOps riscv_iommu_trap_ops = {
+ .read_with_attrs = riscv_iommu_trap_read,
+ .write_with_attrs = riscv_iommu_trap_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ .unaligned = true,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ }
+};
+
+void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode)
+{
+ s->cap = set_field(s->cap, RISCV_IOMMU_CAP_IGS, mode);
+}
+
+static void riscv_iommu_instance_init(Object *obj)
+{
+ RISCVIOMMUState *s = RISCV_IOMMU(obj);
+
+ /* Enable translation debug interface */
+ s->cap = RISCV_IOMMU_CAP_DBG;
+
+ /* Report QEMU target physical address space limits */
+ s->cap = set_field(s->cap, RISCV_IOMMU_CAP_PAS,
+ TARGET_PHYS_ADDR_SPACE_BITS);
+
+ /* TODO: method to report supported PID bits */
+ s->pid_bits = 8; /* restricted to size of MemTxAttrs.pid */
+ s->cap |= RISCV_IOMMU_CAP_PD8;
+
+ /* register storage */
+ s->regs_rw = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
+ s->regs_ro = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
+ s->regs_wc = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
+
+ /* Mark all registers read-only */
+ memset(s->regs_ro, 0xff, RISCV_IOMMU_REG_SIZE);
+
+ /* Device translation context cache */
+ s->ctx_cache = g_hash_table_new_full(riscv_iommu_ctx_hash,
+ riscv_iommu_ctx_equal,
+ g_free, NULL);
+
+ s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
+ riscv_iommu_iot_equal,
+ g_free, NULL);
+
+ s->iommus.le_next = NULL;
+ s->iommus.le_prev = NULL;
+ QLIST_INIT(&s->spaces);
+}
+
+static void riscv_iommu_realize(DeviceState *dev, Error **errp)
+{
+ RISCVIOMMUState *s = RISCV_IOMMU(dev);
+
+ s->cap |= s->version & RISCV_IOMMU_CAP_VERSION;
+ if (s->enable_msi) {
+ s->cap |= RISCV_IOMMU_CAP_MSI_FLAT | RISCV_IOMMU_CAP_MSI_MRIF;
+ }
+ if (s->enable_ats) {
+ s->cap |= RISCV_IOMMU_CAP_ATS;
+ }
+ if (s->enable_s_stage) {
+ s->cap |= RISCV_IOMMU_CAP_SV32 | RISCV_IOMMU_CAP_SV39 |
+ RISCV_IOMMU_CAP_SV48 | RISCV_IOMMU_CAP_SV57;
+ }
+ if (s->enable_g_stage) {
+ s->cap |= RISCV_IOMMU_CAP_SV32X4 | RISCV_IOMMU_CAP_SV39X4 |
+ RISCV_IOMMU_CAP_SV48X4 | RISCV_IOMMU_CAP_SV57X4;
+ }
+
+ if (s->hpm_cntrs > 0) {
+ /* Clip number of HPM counters to maximum supported (31). */
+ if (s->hpm_cntrs > RISCV_IOMMU_IOCOUNT_NUM) {
+ s->hpm_cntrs = RISCV_IOMMU_IOCOUNT_NUM;
+ }
+ /* Enable hardware performance monitor interface */
+ s->cap |= RISCV_IOMMU_CAP_HPM;
+ }
+
+ /* Out-of-reset translation mode: OFF (DMA disabled) BARE (passthrough) */
+ s->ddtp = set_field(0, RISCV_IOMMU_DDTP_MODE, s->enable_off ?
+ RISCV_IOMMU_DDTP_MODE_OFF : RISCV_IOMMU_DDTP_MODE_BARE);
+
+ /*
+ * Register complete MMIO space, including MSI/PBA registers.
+ * Note, PCIDevice implementation will add overlapping MR for MSI/PBA,
+ * managed directly by the PCIDevice implementation.
+ */
+ memory_region_init_io(&s->regs_mr, OBJECT(dev), &riscv_iommu_mmio_ops, s,
+ "riscv-iommu-regs", RISCV_IOMMU_REG_SIZE);
+
+ /* Set power-on register state */
+ stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_CAP], s->cap);
+ stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_FCTL], 0);
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_FCTL],
+ ~(RISCV_IOMMU_FCTL_BE | RISCV_IOMMU_FCTL_WSI));
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_DDTP],
+ ~(RISCV_IOMMU_DDTP_PPN | RISCV_IOMMU_DDTP_MODE));
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_CQB],
+ ~(RISCV_IOMMU_CQB_LOG2SZ | RISCV_IOMMU_CQB_PPN));
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_FQB],
+ ~(RISCV_IOMMU_FQB_LOG2SZ | RISCV_IOMMU_FQB_PPN));
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_PQB],
+ ~(RISCV_IOMMU_PQB_LOG2SZ | RISCV_IOMMU_PQB_PPN));
+ stl_le_p(&s->regs_wc[RISCV_IOMMU_REG_CQCSR], RISCV_IOMMU_CQCSR_CQMF |
+ RISCV_IOMMU_CQCSR_CMD_TO | RISCV_IOMMU_CQCSR_CMD_ILL);
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_CQCSR], RISCV_IOMMU_CQCSR_CQON |
+ RISCV_IOMMU_CQCSR_BUSY);
+ stl_le_p(&s->regs_wc[RISCV_IOMMU_REG_FQCSR], RISCV_IOMMU_FQCSR_FQMF |
+ RISCV_IOMMU_FQCSR_FQOF);
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_FQCSR], RISCV_IOMMU_FQCSR_FQON |
+ RISCV_IOMMU_FQCSR_BUSY);
+ stl_le_p(&s->regs_wc[RISCV_IOMMU_REG_PQCSR], RISCV_IOMMU_PQCSR_PQMF |
+ RISCV_IOMMU_PQCSR_PQOF);
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_PQCSR], RISCV_IOMMU_PQCSR_PQON |
+ RISCV_IOMMU_PQCSR_BUSY);
+ stl_le_p(&s->regs_wc[RISCV_IOMMU_REG_IPSR], ~0);
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_ICVEC], 0);
+ stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_DDTP], s->ddtp);
+ /* If debug registers enabled. */
+ if (s->cap & RISCV_IOMMU_CAP_DBG) {
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_TR_REQ_IOVA], 0);
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_TR_REQ_CTL],
+ RISCV_IOMMU_TR_REQ_CTL_GO_BUSY);
+ }
+
+ /* If HPM registers are enabled. */
+ if (s->cap & RISCV_IOMMU_CAP_HPM) {
+ /* +1 for cycle counter bit. */
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_IOCOUNTINH],
+ ~((2 << s->hpm_cntrs) - 1));
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_IOHPMCYCLES], 0);
+ memset(&s->regs_ro[RISCV_IOMMU_REG_IOHPMCTR_BASE],
+ 0x00, s->hpm_cntrs * 8);
+ memset(&s->regs_ro[RISCV_IOMMU_REG_IOHPMEVT_BASE],
+ 0x00, s->hpm_cntrs * 8);
+ }
+
+ /* Memory region for downstream access, if specified. */
+ if (s->target_mr) {
+ s->target_as = g_new0(AddressSpace, 1);
+ address_space_init(s->target_as, s->target_mr,
+ "riscv-iommu-downstream");
+ } else {
+ /* Fallback to global system memory. */
+ s->target_as = &address_space_memory;
+ }
+
+ /* Memory region for untranslated MRIF/MSI writes */
+ memory_region_init_io(&s->trap_mr, OBJECT(dev), &riscv_iommu_trap_ops, s,
+ "riscv-iommu-trap", ~0ULL);
+ address_space_init(&s->trap_as, &s->trap_mr, "riscv-iommu-trap-as");
+
+ if (s->cap & RISCV_IOMMU_CAP_HPM) {
+ s->hpm_timer =
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, riscv_iommu_hpm_timer_cb, s);
+ s->hpm_event_ctr_map = g_hash_table_new(g_direct_hash, g_direct_equal);
+ }
+}
+
+static void riscv_iommu_unrealize(DeviceState *dev)
+{
+ RISCVIOMMUState *s = RISCV_IOMMU(dev);
+
+ g_hash_table_unref(s->iot_cache);
+ g_hash_table_unref(s->ctx_cache);
+
+ if (s->cap & RISCV_IOMMU_CAP_HPM) {
+ g_hash_table_unref(s->hpm_event_ctr_map);
+ timer_free(s->hpm_timer);
+ }
+}
+
+void riscv_iommu_reset(RISCVIOMMUState *s)
+{
+ uint32_t reg_clr;
+ int ddtp_mode;
+
+ /*
+ * Clear DDTP while setting DDTP_mode back to user
+ * initial setting.
+ */
+ ddtp_mode = s->enable_off ?
+ RISCV_IOMMU_DDTP_MODE_OFF : RISCV_IOMMU_DDTP_MODE_BARE;
+ s->ddtp = set_field(0, RISCV_IOMMU_DDTP_MODE, ddtp_mode);
+ riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_DDTP, s->ddtp);
+
+ reg_clr = RISCV_IOMMU_CQCSR_CQEN | RISCV_IOMMU_CQCSR_CIE |
+ RISCV_IOMMU_CQCSR_CQON | RISCV_IOMMU_CQCSR_BUSY;
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_CQCSR, 0, reg_clr);
+
+ reg_clr = RISCV_IOMMU_FQCSR_FQEN | RISCV_IOMMU_FQCSR_FIE |
+ RISCV_IOMMU_FQCSR_FQON | RISCV_IOMMU_FQCSR_BUSY;
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_FQCSR, 0, reg_clr);
+
+ reg_clr = RISCV_IOMMU_PQCSR_PQEN | RISCV_IOMMU_PQCSR_PIE |
+ RISCV_IOMMU_PQCSR_PQON | RISCV_IOMMU_PQCSR_BUSY;
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_PQCSR, 0, reg_clr);
+
+ riscv_iommu_reg_mod64(s, RISCV_IOMMU_REG_TR_REQ_CTL, 0,
+ RISCV_IOMMU_TR_REQ_CTL_GO_BUSY);
+
+ riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_IPSR, 0);
+
+ g_hash_table_remove_all(s->ctx_cache);
+ g_hash_table_remove_all(s->iot_cache);
+}
+
+static const Property riscv_iommu_properties[] = {
+ DEFINE_PROP_UINT32("version", RISCVIOMMUState, version,
+ RISCV_IOMMU_SPEC_DOT_VER),
+ DEFINE_PROP_UINT32("bus", RISCVIOMMUState, bus, 0x0),
+ DEFINE_PROP_UINT32("ioatc-limit", RISCVIOMMUState, iot_limit,
+ LIMIT_CACHE_IOT),
+ DEFINE_PROP_BOOL("intremap", RISCVIOMMUState, enable_msi, TRUE),
+ DEFINE_PROP_BOOL("ats", RISCVIOMMUState, enable_ats, TRUE),
+ DEFINE_PROP_BOOL("off", RISCVIOMMUState, enable_off, TRUE),
+ DEFINE_PROP_BOOL("s-stage", RISCVIOMMUState, enable_s_stage, TRUE),
+ DEFINE_PROP_BOOL("g-stage", RISCVIOMMUState, enable_g_stage, TRUE),
+ DEFINE_PROP_LINK("downstream-mr", RISCVIOMMUState, target_mr,
+ TYPE_MEMORY_REGION, MemoryRegion *),
+ DEFINE_PROP_UINT8("hpm-counters", RISCVIOMMUState, hpm_cntrs,
+ RISCV_IOMMU_IOCOUNT_NUM),
+};
+
+static void riscv_iommu_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ /* internal device for riscv-iommu-{pci/sys}, not user-creatable */
+ dc->user_creatable = false;
+ dc->realize = riscv_iommu_realize;
+ dc->unrealize = riscv_iommu_unrealize;
+ device_class_set_props(dc, riscv_iommu_properties);
+}
+
+static const TypeInfo riscv_iommu_info = {
+ .name = TYPE_RISCV_IOMMU,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(RISCVIOMMUState),
+ .instance_init = riscv_iommu_instance_init,
+ .class_init = riscv_iommu_class_init,
+};
+
+static const char *IOMMU_FLAG_STR[] = {
+ "NA",
+ "RO",
+ "WR",
+ "RW",
+};
+
+/* RISC-V IOMMU Memory Region - Address Translation Space */
+static IOMMUTLBEntry riscv_iommu_memory_region_translate(
+ IOMMUMemoryRegion *iommu_mr, hwaddr addr,
+ IOMMUAccessFlags flag, int iommu_idx)
+{
+ RISCVIOMMUSpace *as = container_of(iommu_mr, RISCVIOMMUSpace, iova_mr);
+ RISCVIOMMUContext *ctx;
+ void *ref;
+ IOMMUTLBEntry iotlb = {
+ .iova = addr,
+ .target_as = as->iommu->target_as,
+ .addr_mask = ~0ULL,
+ .perm = flag,
+ };
+
+ ctx = riscv_iommu_ctx(as->iommu, as->devid, iommu_idx, &ref);
+ if (ctx == NULL) {
+ /* Translation disabled or invalid. */
+ iotlb.addr_mask = 0;
+ iotlb.perm = IOMMU_NONE;
+ } else if (riscv_iommu_translate(as->iommu, ctx, &iotlb, true)) {
+ /* Translation disabled or fault reported. */
+ iotlb.addr_mask = 0;
+ iotlb.perm = IOMMU_NONE;
+ }
+
+ /* Trace all dma translations with original access flags. */
+ trace_riscv_iommu_dma(as->iommu->parent_obj.id, PCI_BUS_NUM(as->devid),
+ PCI_SLOT(as->devid), PCI_FUNC(as->devid), iommu_idx,
+ IOMMU_FLAG_STR[flag & IOMMU_RW], iotlb.iova,
+ iotlb.translated_addr);
+
+ riscv_iommu_ctx_put(as->iommu, ref);
+
+ return iotlb;
+}
+
+static int riscv_iommu_memory_region_notify(
+ IOMMUMemoryRegion *iommu_mr, IOMMUNotifierFlag old,
+ IOMMUNotifierFlag new, Error **errp)
+{
+ RISCVIOMMUSpace *as = container_of(iommu_mr, RISCVIOMMUSpace, iova_mr);
+
+ if (old == IOMMU_NOTIFIER_NONE) {
+ as->notifier = true;
+ trace_riscv_iommu_notifier_add(iommu_mr->parent_obj.name);
+ } else if (new == IOMMU_NOTIFIER_NONE) {
+ as->notifier = false;
+ trace_riscv_iommu_notifier_del(iommu_mr->parent_obj.name);
+ }
+
+ return 0;
+}
+
+static inline bool pci_is_iommu(PCIDevice *pdev)
+{
+ return pci_get_word(pdev->config + PCI_CLASS_DEVICE) == 0x0806;
+}
+
+static AddressSpace *riscv_iommu_find_as(PCIBus *bus, void *opaque, int devfn)
+{
+ RISCVIOMMUState *s = (RISCVIOMMUState *) opaque;
+ PCIDevice *pdev = pci_find_device(bus, pci_bus_num(bus), devfn);
+ AddressSpace *as = NULL;
+
+ if (pdev && pci_is_iommu(pdev)) {
+ return s->target_as;
+ }
+
+ /* Find first registered IOMMU device */
+ while (s->iommus.le_prev) {
+ s = *(s->iommus.le_prev);
+ }
+
+ /* Find first matching IOMMU */
+ while (s != NULL && as == NULL) {
+ as = riscv_iommu_space(s, PCI_BUILD_BDF(pci_bus_num(bus), devfn));
+ s = s->iommus.le_next;
+ }
+
+ return as ? as : &address_space_memory;
+}
+
+static const PCIIOMMUOps riscv_iommu_ops = {
+ .get_address_space = riscv_iommu_find_as,
+};
+
+void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
+ Error **errp)
+{
+ if (bus->iommu_ops &&
+ bus->iommu_ops->get_address_space == riscv_iommu_find_as) {
+ /* Allow multiple IOMMUs on the same PCIe bus, link known devices */
+ RISCVIOMMUState *last = (RISCVIOMMUState *)bus->iommu_opaque;
+ QLIST_INSERT_AFTER(last, iommu, iommus);
+ } else if (!bus->iommu_ops && !bus->iommu_opaque) {
+ pci_setup_iommu(bus, &riscv_iommu_ops, iommu);
+ } else {
+ error_setg(errp, "can't register secondary IOMMU for PCI bus #%d",
+ pci_bus_num(bus));
+ }
+}
+
+static int riscv_iommu_memory_region_index(IOMMUMemoryRegion *iommu_mr,
+ MemTxAttrs attrs)
+{
+ return attrs.unspecified ? RISCV_IOMMU_NOPROCID : (int)attrs.pid;
+}
+
+static int riscv_iommu_memory_region_index_len(IOMMUMemoryRegion *iommu_mr)
+{
+ RISCVIOMMUSpace *as = container_of(iommu_mr, RISCVIOMMUSpace, iova_mr);
+ return 1 << as->iommu->pid_bits;
+}
+
+static void riscv_iommu_memory_region_init(ObjectClass *klass, const void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = riscv_iommu_memory_region_translate;
+ imrc->notify_flag_changed = riscv_iommu_memory_region_notify;
+ imrc->attrs_to_index = riscv_iommu_memory_region_index;
+ imrc->num_indexes = riscv_iommu_memory_region_index_len;
+}
+
+static const TypeInfo riscv_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_RISCV_IOMMU_MEMORY_REGION,
+ .class_init = riscv_iommu_memory_region_init,
+};
+
+static void riscv_iommu_register_mr_types(void)
+{
+ type_register_static(&riscv_iommu_memory_region_info);
+ type_register_static(&riscv_iommu_info);
+}
+
+type_init(riscv_iommu_register_mr_types);
diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
new file mode 100644
index 0000000..a31aa62
--- /dev/null
+++ b/hw/riscv/riscv-iommu.h
@@ -0,0 +1,157 @@
+/*
+ * QEMU emulation of an RISC-V IOMMU
+ *
+ * Copyright (C) 2022-2023 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_RISCV_IOMMU_STATE_H
+#define HW_RISCV_IOMMU_STATE_H
+
+#include "qom/object.h"
+#include "hw/qdev-properties.h"
+#include "system/dma.h"
+#include "hw/riscv/iommu.h"
+#include "hw/riscv/riscv-iommu-bits.h"
+
+typedef enum riscv_iommu_igs_modes riscv_iommu_igs_mode;
+
+struct RISCVIOMMUState {
+ /*< private >*/
+ DeviceState parent_obj;
+
+ /*< public >*/
+ uint32_t version; /* Reported interface version number */
+ uint32_t pid_bits; /* process identifier width */
+ uint32_t bus; /* PCI bus mapping for non-root endpoints */
+
+ uint64_t cap; /* IOMMU supported capabilities */
+ uint64_t fctl; /* IOMMU enabled features */
+ uint64_t icvec_avail_vectors; /* Available interrupt vectors in ICVEC */
+
+ bool enable_off; /* Enable out-of-reset OFF mode (DMA disabled) */
+ bool enable_msi; /* Enable MSI remapping */
+ bool enable_ats; /* Enable ATS support */
+ bool enable_s_stage; /* Enable S/VS-Stage translation */
+ bool enable_g_stage; /* Enable G-Stage translation */
+
+ /* IOMMU Internal State */
+ uint64_t ddtp; /* Validated Device Directory Tree Root Pointer */
+
+ dma_addr_t cq_addr; /* Command queue base physical address */
+ dma_addr_t fq_addr; /* Fault/event queue base physical address */
+ dma_addr_t pq_addr; /* Page request queue base physical address */
+
+ uint32_t cq_mask; /* Command queue index bit mask */
+ uint32_t fq_mask; /* Fault/event queue index bit mask */
+ uint32_t pq_mask; /* Page request queue index bit mask */
+
+ /* interrupt notifier */
+ void (*notify)(RISCVIOMMUState *iommu, unsigned vector);
+
+ /* IOMMU target address space */
+ AddressSpace *target_as;
+ MemoryRegion *target_mr;
+
+ /* MSI / MRIF access trap */
+ AddressSpace trap_as;
+ MemoryRegion trap_mr;
+
+ GHashTable *ctx_cache; /* Device translation Context Cache */
+
+ GHashTable *iot_cache; /* IO Translated Address Cache */
+ unsigned iot_limit; /* IO Translation Cache size limit */
+
+ /* MMIO Hardware Interface */
+ MemoryRegion regs_mr;
+ uint8_t *regs_rw; /* register state (user write) */
+ uint8_t *regs_wc; /* write-1-to-clear mask */
+ uint8_t *regs_ro; /* read-only mask */
+
+ QLIST_ENTRY(RISCVIOMMUState) iommus;
+ QLIST_HEAD(, RISCVIOMMUSpace) spaces;
+
+ /* HPM cycle counter */
+ QEMUTimer *hpm_timer;
+ uint64_t hpmcycle_val; /* Current value of cycle register */
+ uint64_t hpmcycle_prev; /* Saved value of QEMU_CLOCK_VIRTUAL clock */
+ uint64_t irq_overflow_left; /* Value beyond INT64_MAX after overflow */
+
+ /* HPM event counters */
+ GHashTable *hpm_event_ctr_map; /* Mapping of events to counters */
+ uint8_t hpm_cntrs;
+};
+
+void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
+ Error **errp);
+void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
+void riscv_iommu_reset(RISCVIOMMUState *s);
+void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
+
+typedef struct RISCVIOMMUContext RISCVIOMMUContext;
+/* Device translation context state. */
+struct RISCVIOMMUContext {
+ uint64_t devid:24; /* Requester Id, AKA device_id */
+ uint64_t process_id:20; /* Process ID. PASID for PCIe */
+ uint64_t tc; /* Translation Control */
+ uint64_t ta; /* Translation Attributes */
+ uint64_t satp; /* S-Stage address translation and protection */
+ uint64_t gatp; /* G-Stage address translation and protection */
+ uint64_t msi_addr_mask; /* MSI filtering - address mask */
+ uint64_t msi_addr_pattern; /* MSI filtering - address pattern */
+ uint64_t msiptp; /* MSI redirection page table pointer */
+};
+
+/* private helpers */
+
+/* Register helper functions */
+static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
+ unsigned idx, uint32_t set, uint32_t clr)
+{
+ uint32_t val = ldl_le_p(s->regs_rw + idx);
+ stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
+ return val;
+}
+
+static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
+ uint32_t set)
+{
+ stl_le_p(s->regs_rw + idx, set);
+}
+
+static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
+{
+ return ldl_le_p(s->regs_rw + idx);
+}
+
+static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
+ uint64_t set, uint64_t clr)
+{
+ uint64_t val = ldq_le_p(s->regs_rw + idx);
+ stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
+ return val;
+}
+
+static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
+ uint64_t set)
+{
+ stq_le_p(s->regs_rw + idx, set);
+}
+
+static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
+ unsigned idx)
+{
+ return ldq_le_p(s->regs_rw + idx);
+}
+#endif
diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c
index 613ea2a..7f26760 100644
--- a/hw/riscv/riscv_hart.c
+++ b/hw/riscv/riscv_hart.c
@@ -21,19 +21,38 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
+#include "system/qtest.h"
+#include "qemu/cutils.h"
#include "hw/sysbus.h"
#include "target/riscv/cpu.h"
#include "hw/qdev-properties.h"
#include "hw/riscv/riscv_hart.h"
+#include "qemu/error-report.h"
-static Property riscv_harts_props[] = {
+static const Property riscv_harts_props[] = {
DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1),
DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0),
DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
DEFINE_PROP_UINT64("resetvec", RISCVHartArrayState, resetvec,
DEFAULT_RSTVEC),
- DEFINE_PROP_END_OF_LIST(),
+
+ /*
+ * Smrnmi implementation-defined interrupt and exception trap handlers.
+ *
+ * When an RNMI interrupt is detected, the hart then enters M-mode and
+ * jumps to the address defined by "rnmi-interrupt-vector".
+ *
+ * When the hart encounters an exception while executing in M-mode with
+ * the mnstatus.NMIE bit clear, the hart then jumps to the address
+ * defined by "rnmi-exception-vector".
+ */
+ DEFINE_PROP_ARRAY("rnmi-interrupt-vector", RISCVHartArrayState,
+ num_rnmi_irqvec, rnmi_irqvec, qdev_prop_uint64,
+ uint64_t),
+ DEFINE_PROP_ARRAY("rnmi-exception-vector", RISCVHartArrayState,
+ num_rnmi_excpvec, rnmi_excpvec, qdev_prop_uint64,
+ uint64_t),
};
static void riscv_harts_cpu_reset(void *opaque)
@@ -42,11 +61,85 @@ static void riscv_harts_cpu_reset(void *opaque)
cpu_reset(CPU(cpu));
}
+#ifndef CONFIG_USER_ONLY
+static void csr_call(char *cmd, uint64_t cpu_num, int csrno, uint64_t *val)
+{
+ RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(cpu_num));
+ CPURISCVState *env = &cpu->env;
+
+ int ret = RISCV_EXCP_NONE;
+ if (strcmp(cmd, "get_csr") == 0) {
+ ret = riscv_csrr(env, csrno, (target_ulong *)val);
+ } else if (strcmp(cmd, "set_csr") == 0) {
+ ret = riscv_csrrw(env, csrno, NULL, *(target_ulong *)val,
+ MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
+ }
+
+ g_assert(ret == RISCV_EXCP_NONE);
+}
+
+static bool csr_qtest_callback(CharBackend *chr, gchar **words)
+{
+ if (strcmp(words[0], "csr") == 0) {
+
+ uint64_t cpu;
+ uint64_t val;
+ int rc, csr;
+
+ rc = qemu_strtou64(words[2], NULL, 0, &cpu);
+ g_assert(rc == 0);
+ rc = qemu_strtoi(words[3], NULL, 0, &csr);
+ g_assert(rc == 0);
+ rc = qemu_strtou64(words[4], NULL, 0, &val);
+ g_assert(rc == 0);
+ csr_call(words[1], cpu, csr, &val);
+
+ qtest_sendf(chr, "OK 0 "TARGET_FMT_lx"\n", (target_ulong)val);
+
+ return true;
+ }
+
+ return false;
+}
+
+static void riscv_cpu_register_csr_qtest_callback(void)
+{
+ static bool first = true;
+ if (first) {
+ first = false;
+ qtest_set_command_cb(csr_qtest_callback);
+ }
+}
+#endif
+
static bool riscv_hart_realize(RISCVHartArrayState *s, int idx,
char *cpu_type, Error **errp)
{
object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type);
qdev_prop_set_uint64(DEVICE(&s->harts[idx]), "resetvec", s->resetvec);
+
+ if (s->harts[idx].cfg.ext_smrnmi) {
+ if (idx < s->num_rnmi_irqvec) {
+ qdev_prop_set_uint64(DEVICE(&s->harts[idx]),
+ "rnmi-interrupt-vector", s->rnmi_irqvec[idx]);
+ }
+
+ if (idx < s->num_rnmi_excpvec) {
+ qdev_prop_set_uint64(DEVICE(&s->harts[idx]),
+ "rnmi-exception-vector", s->rnmi_excpvec[idx]);
+ }
+ } else {
+ if (s->num_rnmi_irqvec > 0) {
+ warn_report_once("rnmi-interrupt-vector property is ignored "
+ "because Smrnmi extension is not enabled.");
+ }
+
+ if (s->num_rnmi_excpvec > 0) {
+ warn_report_once("rnmi-exception-vector property is ignored "
+ "because Smrnmi extension is not enabled.");
+ }
+ }
+
s->harts[idx].env.mhartid = s->hartid_base + idx;
qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp);
@@ -59,6 +152,10 @@ static void riscv_harts_realize(DeviceState *dev, Error **errp)
s->harts = g_new0(RISCVCPU, s->num_harts);
+#ifndef CONFIG_USER_ONLY
+ riscv_cpu_register_csr_qtest_callback();
+#endif
+
for (n = 0; n < s->num_harts; n++) {
if (!riscv_hart_realize(s, n, s->cpu_type, errp)) {
return;
@@ -66,7 +163,7 @@ static void riscv_harts_realize(DeviceState *dev, Error **errp)
}
}
-static void riscv_harts_class_init(ObjectClass *klass, void *data)
+static void riscv_harts_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c
index 3888034..3e7f441 100644
--- a/hw/riscv/shakti_c.c
+++ b/hw/riscv/shakti_c.c
@@ -23,9 +23,9 @@
#include "qemu/error-report.h"
#include "hw/intc/sifive_plic.h"
#include "hw/intc/riscv_aclint.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/qdev-properties.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/riscv/boot.h"
static const struct MemmapEntry {
@@ -45,6 +45,7 @@ static void shakti_c_machine_state_init(MachineState *mstate)
{
ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate);
MemoryRegion *system_memory = get_system_memory();
+ hwaddr firmware_load_addr = shakti_c_memmap[SHAKTI_C_RAM].base;
/* Initialize SoC */
object_initialize_child(OBJECT(mstate), "soc", &sms->soc,
@@ -56,23 +57,21 @@ static void shakti_c_machine_state_init(MachineState *mstate)
shakti_c_memmap[SHAKTI_C_RAM].base,
mstate->ram);
+ if (mstate->firmware) {
+ riscv_load_firmware(mstate->firmware, &firmware_load_addr, NULL);
+ }
+
/* ROM reset vector */
- riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus,
- shakti_c_memmap[SHAKTI_C_RAM].base,
+ riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, firmware_load_addr,
shakti_c_memmap[SHAKTI_C_ROM].base,
shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0);
- if (mstate->firmware) {
- riscv_load_firmware(mstate->firmware,
- shakti_c_memmap[SHAKTI_C_RAM].base,
- NULL);
- }
}
static void shakti_c_machine_instance_init(Object *obj)
{
}
-static void shakti_c_machine_class_init(ObjectClass *klass, void *data)
+static void shakti_c_machine_class_init(ObjectClass *klass, const void *data)
{
MachineClass *mc = MACHINE_CLASS(klass);
static const char * const valid_cpu_types[] = {
@@ -143,7 +142,7 @@ static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp)
shakti_c_memmap[SHAKTI_C_ROM].base, &sss->rom);
}
-static void shakti_c_soc_class_init(ObjectClass *klass, void *data)
+static void shakti_c_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = shakti_c_soc_state_realize;
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index 87d9602..7baed19 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -35,7 +35,6 @@
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
#include "hw/misc/unimp.h"
#include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h"
@@ -47,7 +46,7 @@
#include "hw/misc/sifive_e_prci.h"
#include "hw/misc/sifive_e_aon.h"
#include "chardev/char.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static const MemMapEntry sifive_e_memmap[] = {
[SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 },
@@ -79,6 +78,7 @@ static void sifive_e_machine_init(MachineState *machine)
SiFiveEState *s = RISCV_E_MACHINE(machine);
MemoryRegion *sys_mem = get_system_memory();
int i;
+ RISCVBootInfo boot_info;
if (machine->ram_size != mc->default_ram_size) {
char *sz = size_to_str(mc->default_ram_size);
@@ -114,8 +114,9 @@ static void sifive_e_machine_init(MachineState *machine)
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
memmap[SIFIVE_E_DEV_MROM].base, &address_space_memory);
+ riscv_boot_info_init(&boot_info, &s->soc.cpus);
if (machine->kernel_filename) {
- riscv_load_kernel(machine, &s->soc.cpus,
+ riscv_load_kernel(machine, &boot_info,
memmap[SIFIVE_E_DEV_DTIM].base,
false, NULL);
}
@@ -142,7 +143,7 @@ static void sifive_e_machine_instance_init(Object *obj)
s->revb = false;
}
-static void sifive_e_machine_class_init(ObjectClass *oc, void *data)
+static void sifive_e_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -283,7 +284,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
&s->xip_mem);
}
-static void sifive_e_soc_class_init(ObjectClass *oc, void *data)
+static void sifive_e_soc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index af5f923..d69f942 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -43,7 +43,6 @@
#include "hw/irq.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
#include "hw/cpu/cluster.h"
#include "hw/misc/unimp.h"
#include "hw/sd/sd.h"
@@ -57,9 +56,9 @@
#include "hw/intc/sifive_plic.h"
#include "chardev/char.h"
#include "net/eth.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/device_tree.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include <libfdt.h>
@@ -515,17 +514,19 @@ static void sifive_u_machine_init(MachineState *machine)
SiFiveUState *s = RISCV_U_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *flash0 = g_new(MemoryRegion, 1);
- target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
+ hwaddr start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr;
const char *firmware_name;
uint32_t start_addr_hi32 = 0x00000000;
+ uint32_t fdt_load_addr_hi32 = 0x00000000;
int i;
- uint32_t fdt_load_addr;
+ uint64_t fdt_load_addr;
uint64_t kernel_entry;
DriveInfo *dinfo;
BlockBackend *blk;
DeviceState *flash_dev, *sd_dev, *card_dev;
qemu_irq flash_cs, sd_cs;
+ RISCVBootInfo boot_info;
/* Initialize SoC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC);
@@ -589,14 +590,15 @@ static void sifive_u_machine_init(MachineState *machine)
firmware_name = riscv_default_firmware_name(&s->soc.u_cpus);
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
- start_addr, NULL);
+ &start_addr, NULL);
+ riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
if (machine->kernel_filename) {
- kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
+ kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
firmware_end_addr);
-
- kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
- kernel_start_addr, true, NULL);
+ riscv_load_kernel(machine, &boot_info, kernel_start_addr,
+ true, NULL);
+ kernel_entry = boot_info.image_low_addr;
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
@@ -607,11 +609,12 @@ static void sifive_u_machine_init(MachineState *machine)
fdt_load_addr = riscv_compute_fdt_addr(memmap[SIFIVE_U_DEV_DRAM].base,
memmap[SIFIVE_U_DEV_DRAM].size,
- machine);
+ machine, &boot_info);
riscv_load_fdt(fdt_load_addr, machine->fdt);
if (!riscv_is_32bit(&s->soc.u_cpus)) {
start_addr_hi32 = (uint64_t)start_addr >> 32;
+ fdt_load_addr_hi32 = fdt_load_addr >> 32;
}
/* reset vector */
@@ -626,7 +629,7 @@ static void sifive_u_machine_init(MachineState *machine)
start_addr, /* start: .dword */
start_addr_hi32,
fdt_load_addr, /* fdt_laddr: .dword */
- 0x00000000,
+ fdt_load_addr_hi32,
0x00000000,
/* fw_dyn: */
};
@@ -646,7 +649,8 @@ static void sifive_u_machine_init(MachineState *machine)
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
memmap[SIFIVE_U_DEV_MROM].base, &address_space_memory);
- riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base,
+ riscv_rom_copy_firmware_info(machine, &s->soc.u_cpus,
+ memmap[SIFIVE_U_DEV_MROM].base,
memmap[SIFIVE_U_DEV_MROM].size,
sizeof(reset_vec), kernel_entry);
@@ -709,7 +713,7 @@ static void sifive_u_machine_instance_init(Object *obj)
object_property_set_description(obj, "serial", "Board serial number");
}
-static void sifive_u_machine_class_init(ObjectClass *oc, void *data)
+static void sifive_u_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -720,6 +724,7 @@ static void sifive_u_machine_class_init(ObjectClass *oc, void *data)
mc->default_cpu_type = SIFIVE_U_CPU;
mc->default_cpus = mc->min_cpus;
mc->default_ram_id = "riscv.sifive.u.ram";
+ mc->auto_create_sdcard = true;
object_class_property_add_bool(oc, "start-in-flash",
sifive_u_machine_get_start_in_flash,
@@ -936,13 +941,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI2_IRQ));
}
-static Property sifive_u_soc_props[] = {
+static const Property sifive_u_soc_props[] = {
DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL),
DEFINE_PROP_STRING("cpu-type", SiFiveUSoCState, cpu_type),
- DEFINE_PROP_END_OF_LIST()
};
-static void sifive_u_soc_class_init(ObjectClass *oc, void *data)
+static void sifive_u_soc_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 6407439..641aae8 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -36,8 +36,8 @@
#include "hw/char/riscv_htif.h"
#include "hw/intc/riscv_aclint.h"
#include "chardev/char.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
+#include "system/device_tree.h"
+#include "system/system.h"
#include <libfdt.h>
@@ -198,13 +198,15 @@ static void spike_board_init(MachineState *machine)
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
target_ulong firmware_end_addr = memmap[SPIKE_DRAM].base;
+ hwaddr firmware_load_addr = memmap[SPIKE_DRAM].base;
target_ulong kernel_start_addr;
char *firmware_name;
- uint32_t fdt_load_addr;
+ uint64_t fdt_load_addr;
uint64_t kernel_entry;
char *soc_name;
int i, base_hartid, hart_count;
bool htif_custom_base = false;
+ RISCVBootInfo boot_info;
/* Check socket count limit */
if (SPIKE_SOCKETS_MAX < riscv_socket_count(machine)) {
@@ -290,7 +292,7 @@ static void spike_board_init(MachineState *machine)
/* Load firmware */
if (firmware_name) {
firmware_end_addr = riscv_load_firmware(firmware_name,
- memmap[SPIKE_DRAM].base,
+ &firmware_load_addr,
htif_symbol_callback);
g_free(firmware_name);
}
@@ -299,13 +301,14 @@ static void spike_board_init(MachineState *machine)
create_fdt(s, memmap, riscv_is_32bit(&s->soc[0]), htif_custom_base);
/* Load kernel */
+ riscv_boot_info_init(&boot_info, &s->soc[0]);
if (machine->kernel_filename) {
- kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
+ kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
firmware_end_addr);
- kernel_entry = riscv_load_kernel(machine, &s->soc[0],
- kernel_start_addr,
- true, htif_symbol_callback);
+ riscv_load_kernel(machine, &boot_info, kernel_start_addr,
+ true, htif_symbol_callback);
+ kernel_entry = boot_info.image_low_addr;
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
@@ -316,11 +319,11 @@ static void spike_board_init(MachineState *machine)
fdt_load_addr = riscv_compute_fdt_addr(memmap[SPIKE_DRAM].base,
memmap[SPIKE_DRAM].size,
- machine);
+ machine, &boot_info);
riscv_load_fdt(fdt_load_addr, machine->fdt);
/* load the reset vector */
- riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base,
+ riscv_setup_rom_reset_vec(machine, &s->soc[0], firmware_load_addr,
memmap[SPIKE_MROM].base,
memmap[SPIKE_MROM].size, kernel_entry,
fdt_load_addr);
@@ -339,7 +342,7 @@ static void spike_machine_instance_init(Object *obj)
{
}
-static void spike_machine_class_init(ObjectClass *oc, void *data)
+static void spike_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events
new file mode 100644
index 0000000..b50b14a
--- /dev/null
+++ b/hw/riscv/trace-events
@@ -0,0 +1,26 @@
+# See documentation at docs/devel/tracing.rst
+
+# riscv-iommu.c
+riscv_iommu_new(const char *id, unsigned b, unsigned d, unsigned f) "%s: device attached %04x:%02x.%d"
+riscv_iommu_flt(const char *id, unsigned b, unsigned d, unsigned f, uint64_t reason, uint64_t iova) "%s: fault %04x:%02x.%u reason: 0x%"PRIx64" iova: 0x%"PRIx64
+riscv_iommu_pri(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova) "%s: page request %04x:%02x.%u iova: 0x%"PRIx64
+riscv_iommu_dma(const char *id, unsigned b, unsigned d, unsigned f, unsigned pasid, const char *dir, uint64_t iova, uint64_t phys) "%s: translate %04x:%02x.%u #%u %s 0x%"PRIx64" -> 0x%"PRIx64
+riscv_iommu_msi(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova, uint64_t phys) "%s: translate %04x:%02x.%u MSI 0x%"PRIx64" -> 0x%"PRIx64
+riscv_iommu_mrif_notification(const char *id, uint32_t nid, uint64_t phys) "%s: sent MRIF notification 0x%x to 0x%"PRIx64
+riscv_iommu_cmd(const char *id, uint64_t l, uint64_t u) "%s: command 0x%"PRIx64" 0x%"PRIx64
+riscv_iommu_notifier_add(const char *id) "%s: dev-iotlb notifier added"
+riscv_iommu_notifier_del(const char *id) "%s: dev-iotlb notifier removed"
+riscv_iommu_notify_int_vector(uint32_t cause, uint32_t vector) "Interrupt cause 0x%x sent via vector 0x%x"
+riscv_iommu_icvec_write(uint32_t orig, uint32_t actual) "ICVEC write: incoming 0x%x actual 0x%x"
+riscv_iommu_ats(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova) "%s: translate request %04x:%02x.%u iova: 0x%"PRIx64
+riscv_iommu_ats_inval(const char *id) "%s: dev-iotlb invalidate"
+riscv_iommu_ats_prgr(const char *id) "%s: dev-iotlb page request group response"
+riscv_iommu_sys_irq_sent(uint32_t vector) "IRQ sent to vector %u"
+riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%"PRIx64" msi_data 0x%x result %u"
+riscv_iommu_sys_reset_hold(int reset_type) "reset type %d"
+riscv_iommu_pci_reset_hold(int reset_type) "reset type %d"
+riscv_iommu_hpm_read(uint64_t cycle, uint32_t inhibit, uint64_t ctr_prev, uint64_t ctr_val) "cycle 0x%"PRIx64" inhibit 0x%x ctr_prev 0x%"PRIx64" ctr_val 0x%"PRIx64
+riscv_iommu_hpm_incr_ctr(uint64_t cntr_val) "cntr_val 0x%"PRIx64
+riscv_iommu_hpm_iocntinh_cy(bool prev_cy_inh) "prev_cy_inh %d"
+riscv_iommu_hpm_cycle_write(uint32_t ovf, uint64_t val) "ovf 0x%x val 0x%"PRIx64
+riscv_iommu_hpm_evt_write(uint32_t ctr_idx, uint32_t ovf, uint64_t val) "ctr_idx 0x%x ovf 0x%x val 0x%"PRIx64
diff --git a/hw/riscv/trace.h b/hw/riscv/trace.h
new file mode 100644
index 0000000..8c0e3ca
--- /dev/null
+++ b/hw/riscv/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-hw_riscv.h"
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 36d6a3a..8b5683d 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -38,7 +38,7 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#define ACPI_BUILD_TABLE_SIZE 0x20000
#define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index))
@@ -199,15 +199,42 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
}
/*
+ * Add DSDT entry for the IOMMU platform device.
+ * ACPI ID for IOMMU is defined in the section 6.2 of RISC-V BRS spec.
+ * https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.8/riscv-brs-spec.pdf
+ */
+static void acpi_dsdt_add_iommu_sys(Aml *scope, const MemMapEntry *iommu_memmap,
+ uint32_t iommu_irq)
+{
+ uint32_t i;
+
+ Aml *dev = aml_device("IMU0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0004")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(iommu_memmap->base,
+ iommu_memmap->size, AML_READ_WRITE));
+ for (i = iommu_irq; i < iommu_irq + 4; i++) {
+ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_LOW,
+ AML_EXCLUSIVE, &i, 1));
+ }
+
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
+/*
* Serial Port Console Redirection Table (SPCR)
- * Rev: 1.07
+ * Rev: 1.10
*/
static void
spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
{
+ const char name[] = ".";
AcpiSpcrData serial = {
- .interface_type = 0, /* 16550 compatible */
+ .interface_type = 0x12, /* 16550 compatible */
.base_addr.id = AML_AS_SYSTEM_MEMORY,
.base_addr.width = 32,
.base_addr.offset = 0,
@@ -229,9 +256,14 @@ spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
.pci_function = 0,
.pci_flags = 0,
.pci_segment = 0,
+ .uart_clk_freq = 0,
+ .precise_baudrate = 0,
+ .namespace_string_length = sizeof(name),
+ .namespace_string_offset = 88,
};
- build_spcr(table_data, linker, &serial, 2, s->oem_id, s->oem_table_id);
+ build_spcr(table_data, linker, &serial, 4, s->oem_id, s->oem_table_id,
+ name);
}
/* RHCT Node[N] starts at offset 56 */
@@ -255,7 +287,7 @@ static void build_rhct(GArray *table_data,
uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0;
RISCVCPU *cpu = &s->soc[0].harts[0];
uint32_t mmu_offset = 0;
- uint8_t satp_mode_max;
+ bool rv32 = riscv_cpu_is_32bit(cpu);
g_autofree char *isa = NULL;
AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id,
@@ -275,7 +307,7 @@ static void build_rhct(GArray *table_data,
num_rhct_nodes++;
}
- if (cpu->cfg.satp_mode.supported != 0) {
+ if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) {
num_rhct_nodes++;
}
@@ -335,22 +367,21 @@ static void build_rhct(GArray *table_data,
}
/* MMU node structure */
- if (cpu->cfg.satp_mode.supported != 0) {
- satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
+ if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) {
mmu_offset = table_data->len - table.table_offset;
build_append_int_noprefix(table_data, 2, 2); /* Type */
build_append_int_noprefix(table_data, 8, 2); /* Length */
build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
build_append_int_noprefix(table_data, 0, 1); /* Reserved */
/* MMU Type */
- if (satp_mode_max == VM_1_10_SV57) {
+ if (cpu->cfg.max_satp_mode == VM_1_10_SV57) {
build_append_int_noprefix(table_data, 2, 1); /* Sv57 */
- } else if (satp_mode_max == VM_1_10_SV48) {
+ } else if (cpu->cfg.max_satp_mode == VM_1_10_SV48) {
build_append_int_noprefix(table_data, 1, 1); /* Sv48 */
- } else if (satp_mode_max == VM_1_10_SV39) {
+ } else if (cpu->cfg.max_satp_mode == VM_1_10_SV39) {
build_append_int_noprefix(table_data, 0, 1); /* Sv39 */
} else {
- assert(1);
+ g_assert_not_reached();
}
}
@@ -444,6 +475,9 @@ static void build_dsdt(GArray *table_data,
}
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
+ if (virt_is_iommu_sys_enabled(s)) {
+ acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ);
+ }
if (socket_count == 1) {
virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
@@ -596,6 +630,187 @@ static void build_madt(GArray *table_data,
acpi_table_end(linker, &table);
}
+#define ID_MAPPING_ENTRY_SIZE 20
+#define IOMMU_ENTRY_SIZE 40
+#define RISCV_INTERRUPT_WIRE_OFFSSET 40
+#define ROOT_COMPLEX_ENTRY_SIZE 20
+#define RIMT_NODE_OFFSET 48
+
+/*
+ * ID Mapping Structure
+ */
+static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base,
+ uint32_t num_ids, uint32_t dest_id_base)
+{
+ /* Source ID Base */
+ build_append_int_noprefix(table_data, source_id_base, 4);
+ /* Number of IDs */
+ build_append_int_noprefix(table_data, num_ids, 4);
+ /* Destination Device ID Base */
+ build_append_int_noprefix(table_data, source_id_base, 4);
+ /* Destination IOMMU Offset */
+ build_append_int_noprefix(table_data, dest_id_base, 4);
+ /* Flags */
+ build_append_int_noprefix(table_data, 0, 4);
+}
+
+struct AcpiRimtIdMapping {
+ uint32_t source_id_base;
+ uint32_t num_ids;
+};
+typedef struct AcpiRimtIdMapping AcpiRimtIdMapping;
+
+/* Build the rimt ID mapping to IOMMU for a given PCI host bridge */
+static int rimt_host_bridges(Object *obj, void *opaque)
+{
+ GArray *idmap_blob = opaque;
+
+ if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
+ PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
+
+ if (bus && !pci_bus_bypass_iommu(bus)) {
+ int min_bus, max_bus;
+
+ pci_bus_range(bus, &min_bus, &max_bus);
+
+ AcpiRimtIdMapping idmap = {
+ .source_id_base = min_bus << 8,
+ .num_ids = (max_bus - min_bus + 1) << 8,
+ };
+ g_array_append_val(idmap_blob, idmap);
+ }
+ }
+
+ return 0;
+}
+
+static int rimt_idmap_compare(gconstpointer a, gconstpointer b)
+{
+ AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a;
+ AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b;
+
+ return idmap_a->source_id_base - idmap_b->source_id_base;
+}
+
+/*
+ * RISC-V IO Mapping Table (RIMT)
+ * https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf
+ */
+static void build_rimt(GArray *table_data, BIOSLinker *linker,
+ RISCVVirtState *s)
+{
+ int i, nb_nodes, rc_mapping_count;
+ size_t node_size, iommu_offset = 0;
+ uint32_t id = 0;
+ g_autoptr(GArray) iommu_idmaps = g_array_new(false, true,
+ sizeof(AcpiRimtIdMapping));
+
+ AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id,
+ .oem_table_id = s->oem_table_id };
+
+ acpi_table_begin(&table, table_data);
+
+ object_child_foreach_recursive(object_get_root(),
+ rimt_host_bridges, iommu_idmaps);
+
+ /* Sort the ID mapping by Source ID Base*/
+ g_array_sort(iommu_idmaps, rimt_idmap_compare);
+
+ nb_nodes = 2; /* RC, IOMMU */
+ rc_mapping_count = iommu_idmaps->len;
+ /* Number of RIMT Nodes */
+ build_append_int_noprefix(table_data, nb_nodes, 4);
+
+ /* Offset to Array of RIMT Nodes */
+ build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4);
+ build_append_int_noprefix(table_data, 0, 4); /* Reserved */
+
+ iommu_offset = table_data->len - table.table_offset;
+ /* IOMMU Device Structure */
+ build_append_int_noprefix(table_data, 0, 1); /* Type - IOMMU*/
+ build_append_int_noprefix(table_data, 1, 1); /* Revision */
+ node_size = IOMMU_ENTRY_SIZE;
+ build_append_int_noprefix(table_data, node_size, 2); /* Length */
+ build_append_int_noprefix(table_data, 0, 2); /* Reserved */
+ build_append_int_noprefix(table_data, id++, 2); /* ID */
+ if (virt_is_iommu_sys_enabled(s)) {
+ /* Hardware ID */
+ build_append_int_noprefix(table_data, 'R', 1);
+ build_append_int_noprefix(table_data, 'S', 1);
+ build_append_int_noprefix(table_data, 'C', 1);
+ build_append_int_noprefix(table_data, 'V', 1);
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '4', 1);
+ /* Base Address */
+ build_append_int_noprefix(table_data,
+ s->memmap[VIRT_IOMMU_SYS].base, 8);
+ build_append_int_noprefix(table_data, 0, 4); /* Flags */
+ } else {
+ /* Hardware ID */
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '1', 1);
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '0', 1);
+ build_append_int_noprefix(table_data, '1', 1);
+ build_append_int_noprefix(table_data, '4', 1);
+
+ build_append_int_noprefix(table_data, 0, 8); /* Base Address */
+ build_append_int_noprefix(table_data, 1, 4); /* Flags */
+ }
+
+ build_append_int_noprefix(table_data, 0, 4); /* Proximity Domain */
+ build_append_int_noprefix(table_data, 0, 2); /* PCI Segment number */
+ /* PCIe B/D/F */
+ if (virt_is_iommu_sys_enabled(s)) {
+ build_append_int_noprefix(table_data, 0, 2);
+ } else {
+ build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2);
+ }
+ /* Number of interrupt wires */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Interrupt wire array offset */
+ build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2);
+
+ /* PCIe Root Complex Node */
+ build_append_int_noprefix(table_data, 1, 1); /* Type */
+ build_append_int_noprefix(table_data, 1, 1); /* Revision */
+ node_size = ROOT_COMPLEX_ENTRY_SIZE +
+ ID_MAPPING_ENTRY_SIZE * rc_mapping_count;
+ build_append_int_noprefix(table_data, node_size, 2); /* Length */
+ build_append_int_noprefix(table_data, 0, 2); /* Reserved */
+ build_append_int_noprefix(table_data, id++, 2); /* ID */
+ build_append_int_noprefix(table_data, 0, 4); /* Flags */
+ build_append_int_noprefix(table_data, 0, 2); /* Reserved */
+ /* PCI Segment number */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* ID mapping array offset */
+ build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2);
+ /* Number of ID mappings */
+ build_append_int_noprefix(table_data, rc_mapping_count, 2);
+
+ /* Output Reference */
+ AcpiRimtIdMapping *range;
+
+ /* ID mapping array */
+ for (i = 0; i < iommu_idmaps->len; i++) {
+ range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i);
+ if (virt_is_iommu_sys_enabled(s)) {
+ range->source_id_base = 0;
+ } else {
+ range->source_id_base = s->pci_iommu_bdf + 1;
+ }
+ range->num_ids = 0xffff - s->pci_iommu_bdf;
+ build_rimt_id_mapping(table_data, range->source_id_base,
+ range->num_ids, iommu_offset);
+ }
+
+ acpi_table_end(linker, &table);
+}
+
/*
* ACPI spec, Revision 6.5+
* 5.2.16 System Resource Affinity Table (SRAT)
@@ -673,6 +888,11 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
build_rhct(tables_blob, tables->linker, s);
+ if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) {
+ acpi_add_table(table_offsets, tables_blob);
+ build_rimt(tables_blob, tables->linker, s);
+ }
+
acpi_add_table(table_offsets, tables_blob);
spcr_setup(tables_blob, tables->linker, s);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index cef41c1..cf280a9 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -27,11 +27,13 @@
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/qdev-properties.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "target/riscv/cpu.h"
#include "hw/core/sysbus-fdt.h"
#include "target/riscv/pmu.h"
#include "hw/riscv/riscv_hart.h"
+#include "hw/riscv/iommu.h"
+#include "hw/riscv/riscv-iommu-bits.h"
#include "hw/riscv/virt.h"
#include "hw/riscv/boot.h"
#include "hw/riscv/numa.h"
@@ -43,23 +45,33 @@
#include "hw/misc/sifive_test.h"
#include "hw/platform-bus.h"
#include "chardev/char.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/tcg.h"
-#include "sysemu/kvm.h"
-#include "sysemu/tpm.h"
-#include "sysemu/qtest.h"
+#include "system/device_tree.h"
+#include "system/system.h"
+#include "system/tcg.h"
+#include "system/kvm.h"
+#include "system/tpm.h"
+#include "system/qtest.h"
#include "hw/pci/pci.h"
#include "hw/pci-host/gpex.h"
#include "hw/display/ramfb.h"
#include "hw/acpi/aml-build.h"
#include "qapi/qapi-visit-common.h"
#include "hw/virtio/virtio-iommu.h"
+#include "hw/uefi/var-service-api.h"
/* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */
-static bool virt_use_kvm_aia(RISCVVirtState *s)
+static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type)
{
- return kvm_irqchip_in_kernel() && s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC;
+ bool msimode = aia_type == VIRT_AIA_TYPE_APLIC_IMSIC;
+
+ return riscv_is_kvm_aia_aplic_imsic(msimode);
+}
+
+static bool virt_use_emulated_aplic(RISCVVirtAIAType aia_type)
+{
+ bool msimode = aia_type == VIRT_AIA_TYPE_APLIC_IMSIC;
+
+ return riscv_use_emulated_aplic(msimode);
}
static bool virt_aclint_allowed(void)
@@ -75,6 +87,7 @@ static const MemMapEntry virt_memmap[] = {
[VIRT_CLINT] = { 0x2000000, 0x10000 },
[VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 },
[VIRT_PCIE_PIO] = { 0x3000000, 0x10000 },
+ [VIRT_IOMMU_SYS] = { 0x3010000, 0x1000 },
[VIRT_PLATFORM_BUS] = { 0x4000000, 0x2000000 },
[VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
[VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) },
@@ -153,8 +166,8 @@ static void virt_flash_map1(PFlashCFI01 *flash,
static void virt_flash_map(RISCVVirtState *s,
MemoryRegion *sysmem)
{
- hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
- hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
+ hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
+ hwaddr flashbase = s->memmap[VIRT_FLASH].base;
virt_flash_map1(s->flash[0], flashbase, flashsize,
sysmem);
@@ -167,7 +180,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
{
int pin, dev;
uint32_t irq_map_stride = 0;
- uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
FDT_MAX_INT_MAP_WIDTH] = {};
uint32_t *irq_map = full_irq_map;
@@ -179,11 +192,11 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
* possible slot) seeing the interrupt-map-mask will allow the table
* to wrap to any number of devices.
*/
- for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+ for (dev = 0; dev < PCI_NUM_PINS; dev++) {
int devfn = dev * 0x8;
- for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
- int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+ for (pin = 0; pin < PCI_NUM_PINS; pin++) {
+ int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
int i = 0;
/* Fill PCI address cells */
@@ -209,7 +222,7 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
}
qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
- GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ PCI_NUM_PINS * PCI_NUM_PINS *
irq_map_stride * sizeof(uint32_t));
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
@@ -224,10 +237,10 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
uint32_t cpu_phandle;
MachineState *ms = MACHINE(s);
bool is_32_bit = riscv_is_32bit(&s->soc[0]);
- uint8_t satp_mode_max;
for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu];
+ int8_t satp_mode_max = cpu_ptr->cfg.max_satp_mode;
g_autofree char *cpu_name = NULL;
g_autofree char *core_name = NULL;
g_autofree char *intc_name = NULL;
@@ -239,8 +252,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
s->soc[socket].hartid_base + cpu);
qemu_fdt_add_subnode(ms->fdt, cpu_name);
- if (cpu_ptr->cfg.satp_mode.supported != 0) {
- satp_mode_max = satp_mode_max_from_map(cpu_ptr->cfg.satp_mode.map);
+ if (satp_mode_max != -1) {
sv_name = g_strdup_printf("riscv,%s",
satp_mode_str(satp_mode_max, is_32_bit));
qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name);
@@ -288,16 +300,16 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
}
}
-static void create_fdt_socket_memory(RISCVVirtState *s,
- const MemMapEntry *memmap, int socket)
+static void create_fdt_socket_memory(RISCVVirtState *s, int socket)
{
g_autofree char *mem_name = NULL;
- uint64_t addr, size;
+ hwaddr addr;
+ uint64_t size;
MachineState *ms = MACHINE(s);
- addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket);
+ addr = s->memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket);
size = riscv_socket_mem_size(ms, socket);
- mem_name = g_strdup_printf("/memory@%lx", (long)addr);
+ mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr);
qemu_fdt_add_subnode(ms->fdt, mem_name);
qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg",
addr >> 32, addr, size >> 32, size);
@@ -306,7 +318,7 @@ static void create_fdt_socket_memory(RISCVVirtState *s,
}
static void create_fdt_socket_clint(RISCVVirtState *s,
- const MemMapEntry *memmap, int socket,
+ int socket,
uint32_t *intc_phandles)
{
int cpu;
@@ -327,21 +339,22 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
}
- clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
+ clint_addr = s->memmap[VIRT_CLINT].base +
+ (s->memmap[VIRT_CLINT].size * socket);
clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
qemu_fdt_add_subnode(ms->fdt, clint_name);
qemu_fdt_setprop_string_array(ms->fdt, clint_name, "compatible",
(char **)&clint_compat,
ARRAY_SIZE(clint_compat));
qemu_fdt_setprop_cells(ms->fdt, clint_name, "reg",
- 0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
+ 0x0, clint_addr, 0x0, s->memmap[VIRT_CLINT].size);
qemu_fdt_setprop(ms->fdt, clint_name, "interrupts-extended",
clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
riscv_socket_fdt_write_id(ms, clint_name, socket);
}
static void create_fdt_socket_aclint(RISCVVirtState *s,
- const MemMapEntry *memmap, int socket,
+ int socket,
uint32_t *intc_phandles)
{
int cpu;
@@ -368,8 +381,10 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2;
if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
- addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
+ addr = s->memmap[VIRT_CLINT].base +
+ (s->memmap[VIRT_CLINT].size * socket);
name = g_strdup_printf("/soc/mswi@%lx", addr);
+
qemu_fdt_add_subnode(ms->fdt, name);
qemu_fdt_setprop_string(ms->fdt, name, "compatible",
"riscv,aclint-mswi");
@@ -384,13 +399,13 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
}
if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
- addr = memmap[VIRT_CLINT].base +
+ addr = s->memmap[VIRT_CLINT].base +
(RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket);
size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
} else {
- addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
- (memmap[VIRT_CLINT].size * socket);
- size = memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
+ addr = s->memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
+ (s->memmap[VIRT_CLINT].size * socket);
+ size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
}
name = g_strdup_printf("/soc/mtimer@%lx", addr);
qemu_fdt_add_subnode(ms->fdt, name);
@@ -407,14 +422,15 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
g_free(name);
if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
- addr = memmap[VIRT_ACLINT_SSWI].base +
- (memmap[VIRT_ACLINT_SSWI].size * socket);
+ addr = s->memmap[VIRT_ACLINT_SSWI].base +
+ (s->memmap[VIRT_ACLINT_SSWI].size * socket);
+
name = g_strdup_printf("/soc/sswi@%lx", addr);
qemu_fdt_add_subnode(ms->fdt, name);
qemu_fdt_setprop_string(ms->fdt, name, "compatible",
"riscv,aclint-sswi");
qemu_fdt_setprop_cells(ms->fdt, name, "reg",
- 0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size);
+ 0x0, addr, 0x0, s->memmap[VIRT_ACLINT_SSWI].size);
qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
aclint_sswi_cells, aclint_cells_size);
qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0);
@@ -425,7 +441,7 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
}
static void create_fdt_socket_plic(RISCVVirtState *s,
- const MemMapEntry *memmap, int socket,
+ int socket,
uint32_t *phandle, uint32_t *intc_phandles,
uint32_t *plic_phandles)
{
@@ -439,7 +455,8 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
};
plic_phandles[socket] = (*phandle)++;
- plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
+ plic_addr = s->memmap[VIRT_PLIC].base +
+ (s->memmap[VIRT_PLIC].size * socket);
plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
qemu_fdt_add_subnode(ms->fdt, plic_name);
qemu_fdt_setprop_cell(ms->fdt, plic_name,
@@ -478,7 +495,7 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
}
qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg",
- 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
+ 0x0, plic_addr, 0x0, s->memmap[VIRT_PLIC].size);
qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev",
VIRT_IRQCHIP_NUM_SOURCES - 1);
riscv_socket_fdt_write_id(ms, plic_name, socket);
@@ -487,8 +504,8 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
if (!socket) {
platform_bus_add_all_fdt_nodes(ms->fdt, plic_name,
- memmap[VIRT_PLATFORM_BUS].base,
- memmap[VIRT_PLATFORM_BUS].size,
+ s->memmap[VIRT_PLATFORM_BUS].base,
+ s->memmap[VIRT_PLATFORM_BUS].size,
VIRT_PLATFORM_BUS_IRQ);
}
}
@@ -575,7 +592,7 @@ static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr,
qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", msi_phandle);
}
-static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap,
+static void create_fdt_imsic(RISCVVirtState *s,
uint32_t *phandle, uint32_t *intc_phandles,
uint32_t *msi_m_phandle, uint32_t *msi_s_phandle)
{
@@ -584,12 +601,12 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap,
if (!kvm_enabled()) {
/* M-level IMSIC node */
- create_fdt_one_imsic(s, memmap[VIRT_IMSIC_M].base, intc_phandles,
+ create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_M].base, intc_phandles,
*msi_m_phandle, true, 0);
}
/* S-level IMSIC node */
- create_fdt_one_imsic(s, memmap[VIRT_IMSIC_S].base, intc_phandles,
+ create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_S].base, intc_phandles,
*msi_s_phandle, false,
imsic_num_bits(s->aia_guests + 1));
@@ -666,7 +683,7 @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket,
}
static void create_fdt_socket_aplic(RISCVVirtState *s,
- const MemMapEntry *memmap, int socket,
+ int socket,
uint32_t msi_m_phandle,
uint32_t msi_s_phandle,
uint32_t *phandle,
@@ -683,18 +700,19 @@ static void create_fdt_socket_aplic(RISCVVirtState *s,
if (!kvm_enabled()) {
/* M-level APLIC node */
- aplic_addr = memmap[VIRT_APLIC_M].base +
- (memmap[VIRT_APLIC_M].size * socket);
- create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_M].size,
+ aplic_addr = s->memmap[VIRT_APLIC_M].base +
+ (s->memmap[VIRT_APLIC_M].size * socket);
+ create_fdt_one_aplic(s, socket, aplic_addr,
+ s->memmap[VIRT_APLIC_M].size,
msi_m_phandle, intc_phandles,
aplic_m_phandle, aplic_s_phandle,
true, num_harts);
}
/* S-level APLIC node */
- aplic_addr = memmap[VIRT_APLIC_S].base +
- (memmap[VIRT_APLIC_S].size * socket);
- create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_S].size,
+ aplic_addr = s->memmap[VIRT_APLIC_S].base +
+ (s->memmap[VIRT_APLIC_S].size * socket);
+ create_fdt_one_aplic(s, socket, aplic_addr, s->memmap[VIRT_APLIC_S].size,
msi_s_phandle, intc_phandles,
aplic_s_phandle, 0,
false, num_harts);
@@ -702,8 +720,8 @@ static void create_fdt_socket_aplic(RISCVVirtState *s,
if (!socket) {
g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name,
- memmap[VIRT_PLATFORM_BUS].base,
- memmap[VIRT_PLATFORM_BUS].size,
+ s->memmap[VIRT_PLATFORM_BUS].base,
+ s->memmap[VIRT_PLATFORM_BUS].size,
VIRT_PLATFORM_BUS_IRQ);
}
@@ -721,7 +739,7 @@ static void create_fdt_pmu(RISCVVirtState *s)
riscv_pmu_generate_fdt_node(ms->fdt, hart.pmu_avail_ctrs, pmu_name);
}
-static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
+static void create_fdt_sockets(RISCVVirtState *s,
uint32_t *phandle,
uint32_t *irq_mmio_phandle,
uint32_t *irq_pcie_phandle,
@@ -738,7 +756,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
qemu_fdt_add_subnode(ms->fdt, "/cpus");
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "timebase-frequency",
kvm_enabled() ?
- kvm_riscv_get_timebase_frequency(first_cpu) :
+ kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
@@ -757,53 +775,54 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
create_fdt_socket_cpus(s, socket, clust_name, phandle,
&intc_phandles[phandle_pos]);
- create_fdt_socket_memory(s, memmap, socket);
+ create_fdt_socket_memory(s, socket);
if (virt_aclint_allowed() && s->have_aclint) {
- create_fdt_socket_aclint(s, memmap, socket,
+ create_fdt_socket_aclint(s, socket,
&intc_phandles[phandle_pos]);
} else if (tcg_enabled()) {
- create_fdt_socket_clint(s, memmap, socket,
+ create_fdt_socket_clint(s, socket,
&intc_phandles[phandle_pos]);
}
}
if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
- create_fdt_imsic(s, memmap, phandle, intc_phandles,
- &msi_m_phandle, &msi_s_phandle);
+ create_fdt_imsic(s, phandle, intc_phandles,
+ &msi_m_phandle, &msi_s_phandle);
*msi_pcie_phandle = msi_s_phandle;
}
- /* KVM AIA only has one APLIC instance */
- if (kvm_enabled() && virt_use_kvm_aia(s)) {
- create_fdt_socket_aplic(s, memmap, 0,
+ /*
+ * With KVM AIA aplic-imsic, using an irqchip without split
+ * mode, we'll use only one APLIC instance.
+ */
+ if (!virt_use_emulated_aplic(s->aia_type)) {
+ create_fdt_socket_aplic(s, 0,
msi_m_phandle, msi_s_phandle, phandle,
&intc_phandles[0], xplic_phandles,
ms->smp.cpus);
+
+ *irq_mmio_phandle = xplic_phandles[0];
+ *irq_virtio_phandle = xplic_phandles[0];
+ *irq_pcie_phandle = xplic_phandles[0];
} else {
phandle_pos = ms->smp.cpus;
for (socket = (socket_count - 1); socket >= 0; socket--) {
phandle_pos -= s->soc[socket].num_harts;
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
- create_fdt_socket_plic(s, memmap, socket, phandle,
+ create_fdt_socket_plic(s, socket, phandle,
&intc_phandles[phandle_pos],
xplic_phandles);
} else {
- create_fdt_socket_aplic(s, memmap, socket,
+ create_fdt_socket_aplic(s, socket,
msi_m_phandle, msi_s_phandle, phandle,
&intc_phandles[phandle_pos],
xplic_phandles,
s->soc[socket].num_harts);
}
}
- }
- if (kvm_enabled() && virt_use_kvm_aia(s)) {
- *irq_mmio_phandle = xplic_phandles[0];
- *irq_virtio_phandle = xplic_phandles[0];
- *irq_pcie_phandle = xplic_phandles[0];
- } else {
for (socket = 0; socket < socket_count; socket++) {
if (socket == 0) {
*irq_mmio_phandle = xplic_phandles[socket];
@@ -823,21 +842,24 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
riscv_socket_fdt_write_distance_matrix(ms);
}
-static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
- uint32_t irq_virtio_phandle)
+static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle)
{
int i;
MachineState *ms = MACHINE(s);
+ hwaddr virtio_base = s->memmap[VIRT_VIRTIO].base;
for (i = 0; i < VIRTIO_COUNT; i++) {
- g_autofree char *name = g_strdup_printf("/soc/virtio_mmio@%lx",
- (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
+ g_autofree char *name = NULL;
+ uint64_t size = s->memmap[VIRT_VIRTIO].size;
+ hwaddr addr = virtio_base + i * size;
+
+ name = g_strdup_printf("/soc/virtio_mmio@%"HWADDR_PRIx, addr);
qemu_fdt_add_subnode(ms->fdt, name);
qemu_fdt_setprop_string(ms->fdt, name, "compatible", "virtio,mmio");
qemu_fdt_setprop_cells(ms->fdt, name, "reg",
- 0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
- 0x0, memmap[VIRT_VIRTIO].size);
+ 0x0, addr,
+ 0x0, size);
qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
irq_virtio_phandle);
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
@@ -850,15 +872,16 @@ static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
}
}
-static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
+static void create_fdt_pcie(RISCVVirtState *s,
uint32_t irq_pcie_phandle,
- uint32_t msi_pcie_phandle)
+ uint32_t msi_pcie_phandle,
+ uint32_t iommu_sys_phandle)
{
g_autofree char *name = NULL;
MachineState *ms = MACHINE(s);
- name = g_strdup_printf("/soc/pci@%lx",
- (long) memmap[VIRT_PCIE_ECAM].base);
+ name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
+ s->memmap[VIRT_PCIE_ECAM].base);
qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells",
FDT_PCI_ADDR_CELLS);
qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells",
@@ -869,36 +892,41 @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci");
qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0);
qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0,
- memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
+ s->memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0);
if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle);
}
qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0,
- memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size);
+ s->memmap[VIRT_PCIE_ECAM].base, 0, s->memmap[VIRT_PCIE_ECAM].size);
qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges",
1, FDT_PCI_RANGE_IOPORT, 2, 0,
- 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
+ 2, s->memmap[VIRT_PCIE_PIO].base, 2, s->memmap[VIRT_PCIE_PIO].size,
1, FDT_PCI_RANGE_MMIO,
- 2, memmap[VIRT_PCIE_MMIO].base,
- 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size,
+ 2, s->memmap[VIRT_PCIE_MMIO].base,
+ 2, s->memmap[VIRT_PCIE_MMIO].base, 2, s->memmap[VIRT_PCIE_MMIO].size,
1, FDT_PCI_RANGE_MMIO_64BIT,
2, virt_high_pcie_memmap.base,
2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
+ if (virt_is_iommu_sys_enabled(s)) {
+ qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
+ 0, iommu_sys_phandle, 0, 0, 0,
+ iommu_sys_phandle, 0, 0xffff);
+ }
+
create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
}
-static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
- uint32_t *phandle)
+static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle)
{
char *name;
uint32_t test_phandle;
MachineState *ms = MACHINE(s);
test_phandle = (*phandle)++;
- name = g_strdup_printf("/soc/test@%lx",
- (long)memmap[VIRT_TEST].base);
+ name = g_strdup_printf("/soc/test@%"HWADDR_PRIx,
+ s->memmap[VIRT_TEST].base);
qemu_fdt_add_subnode(ms->fdt, name);
{
static const char * const compat[3] = {
@@ -908,7 +936,7 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
(char **)&compat, ARRAY_SIZE(compat));
}
qemu_fdt_setprop_cells(ms->fdt, name, "reg",
- 0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size);
+ 0x0, s->memmap[VIRT_TEST].base, 0x0, s->memmap[VIRT_TEST].size);
qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle);
test_phandle = qemu_fdt_get_phandle(ms->fdt, name);
g_free(name);
@@ -930,18 +958,19 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
g_free(name);
}
-static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
+static void create_fdt_uart(RISCVVirtState *s,
uint32_t irq_mmio_phandle)
{
g_autofree char *name = NULL;
MachineState *ms = MACHINE(s);
- name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base);
+ name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx,
+ s->memmap[VIRT_UART0].base);
qemu_fdt_add_subnode(ms->fdt, name);
qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a");
qemu_fdt_setprop_cells(ms->fdt, name, "reg",
- 0x0, memmap[VIRT_UART0].base,
- 0x0, memmap[VIRT_UART0].size);
+ 0x0, s->memmap[VIRT_UART0].base,
+ 0x0, s->memmap[VIRT_UART0].size);
qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400);
qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle);
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
@@ -951,20 +980,22 @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
}
qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
+ qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
}
-static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
+static void create_fdt_rtc(RISCVVirtState *s,
uint32_t irq_mmio_phandle)
{
g_autofree char *name = NULL;
MachineState *ms = MACHINE(s);
- name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
+ name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
+ s->memmap[VIRT_RTC].base);
qemu_fdt_add_subnode(ms->fdt, name);
qemu_fdt_setprop_string(ms->fdt, name, "compatible",
"google,goldfish-rtc");
qemu_fdt_setprop_cells(ms->fdt, name, "reg",
- 0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
+ 0x0, s->memmap[VIRT_RTC].base, 0x0, s->memmap[VIRT_RTC].size);
qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
irq_mmio_phandle);
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
@@ -974,11 +1005,11 @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
}
}
-static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
+static void create_fdt_flash(RISCVVirtState *s)
{
MachineState *ms = MACHINE(s);
- hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
- hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
+ hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
+ hwaddr flashbase = s->memmap[VIRT_FLASH].base;
g_autofree char *name = g_strdup_printf("/flash@%" PRIx64, flashbase);
qemu_fdt_add_subnode(ms->fdt, name);
@@ -989,11 +1020,11 @@ static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4);
}
-static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap)
+static void create_fdt_fw_cfg(RISCVVirtState *s)
{
MachineState *ms = MACHINE(s);
- hwaddr base = memmap[VIRT_FW_CFG].base;
- hwaddr size = memmap[VIRT_FW_CFG].size;
+ hwaddr base = s->memmap[VIRT_FW_CFG].base;
+ hwaddr size = s->memmap[VIRT_FW_CFG].size;
g_autofree char *nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
qemu_fdt_add_subnode(ms->fdt, nodename);
@@ -1012,8 +1043,8 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf)
g_autofree char *iommu_node = NULL;
g_autofree char *pci_node = NULL;
- pci_node = g_strdup_printf("/soc/pci@%lx",
- (long) virt_memmap[VIRT_PCIE_ECAM].base);
+ pci_node = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
+ s->memmap[VIRT_PCIE_ECAM].base);
iommu_node = g_strdup_printf("%s/virtio_iommu@%x,%x", pci_node,
PCI_SLOT(bdf), PCI_FUNC(bdf));
iommu_phandle = qemu_fdt_alloc_phandle(fdt);
@@ -1032,27 +1063,99 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf)
bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf);
}
+static void create_fdt_iommu_sys(RISCVVirtState *s, uint32_t irq_chip,
+ uint32_t msi_phandle,
+ uint32_t *iommu_sys_phandle)
+{
+ const char comp[] = "riscv,iommu";
+ void *fdt = MACHINE(s)->fdt;
+ uint32_t iommu_phandle;
+ g_autofree char *iommu_node = NULL;
+ hwaddr addr = s->memmap[VIRT_IOMMU_SYS].base;
+ hwaddr size = s->memmap[VIRT_IOMMU_SYS].size;
+ uint32_t iommu_irq_map[RISCV_IOMMU_INTR_COUNT] = {
+ IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_CQ,
+ IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_FQ,
+ IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PM,
+ IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PQ,
+ };
+
+ iommu_node = g_strdup_printf("/soc/iommu@%x",
+ (unsigned int) s->memmap[VIRT_IOMMU_SYS].base);
+ iommu_phandle = qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_add_subnode(fdt, iommu_node);
+
+ qemu_fdt_setprop(fdt, iommu_node, "compatible", comp, sizeof(comp));
+ qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
+ qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle);
+
+ qemu_fdt_setprop_cells(fdt, iommu_node, "reg",
+ addr >> 32, addr, size >> 32, size);
+ qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent", irq_chip);
+
+ qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts",
+ iommu_irq_map[0], FDT_IRQ_TYPE_EDGE_LOW,
+ iommu_irq_map[1], FDT_IRQ_TYPE_EDGE_LOW,
+ iommu_irq_map[2], FDT_IRQ_TYPE_EDGE_LOW,
+ iommu_irq_map[3], FDT_IRQ_TYPE_EDGE_LOW);
+
+ qemu_fdt_setprop_cell(fdt, iommu_node, "msi-parent", msi_phandle);
+
+ *iommu_sys_phandle = iommu_phandle;
+}
+
+static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf)
+{
+ const char comp[] = "riscv,pci-iommu";
+ void *fdt = MACHINE(s)->fdt;
+ uint32_t iommu_phandle;
+ g_autofree char *iommu_node = NULL;
+ g_autofree char *pci_node = NULL;
+
+ pci_node = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
+ s->memmap[VIRT_PCIE_ECAM].base);
+ iommu_node = g_strdup_printf("%s/iommu@%x", pci_node, bdf);
+ iommu_phandle = qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_add_subnode(fdt, iommu_node);
+
+ qemu_fdt_setprop(fdt, iommu_node, "compatible", comp, sizeof(comp));
+ qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
+ qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle);
+ qemu_fdt_setprop_cells(fdt, iommu_node, "reg",
+ bdf << 8, 0, 0, 0, 0);
+ qemu_fdt_setprop_cells(fdt, pci_node, "iommu-map",
+ 0, iommu_phandle, 0, bdf,
+ bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf);
+ s->pci_iommu_bdf = bdf;
+}
+
static void finalize_fdt(RISCVVirtState *s)
{
uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1;
uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
+ uint32_t iommu_sys_phandle = 1;
- create_fdt_sockets(s, virt_memmap, &phandle, &irq_mmio_phandle,
+ create_fdt_sockets(s, &phandle, &irq_mmio_phandle,
&irq_pcie_phandle, &irq_virtio_phandle,
&msi_pcie_phandle);
- create_fdt_virtio(s, virt_memmap, irq_virtio_phandle);
+ create_fdt_virtio(s, irq_virtio_phandle);
- create_fdt_pcie(s, virt_memmap, irq_pcie_phandle, msi_pcie_phandle);
+ if (virt_is_iommu_sys_enabled(s)) {
+ create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle,
+ &iommu_sys_phandle);
+ }
+ create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
+ iommu_sys_phandle);
- create_fdt_reset(s, virt_memmap, &phandle);
+ create_fdt_reset(s, &phandle);
- create_fdt_uart(s, virt_memmap, irq_mmio_phandle);
+ create_fdt_uart(s, irq_mmio_phandle);
- create_fdt_rtc(s, virt_memmap, irq_mmio_phandle);
+ create_fdt_rtc(s, irq_mmio_phandle);
}
-static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap)
+static void create_fdt(RISCVVirtState *s)
{
MachineState *ms = MACHINE(s);
uint8_t rng_seed[32];
@@ -1079,7 +1182,8 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap)
* The "/soc/pci@..." node is needed for PCIE hotplugs
* that might happen before finalize_fdt().
*/
- name = g_strdup_printf("/soc/pci@%lx", (long) memmap[VIRT_PCIE_ECAM].base);
+ name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
+ s->memmap[VIRT_PCIE_ECAM].base);
qemu_fdt_add_subnode(ms->fdt, name);
qemu_fdt_add_subnode(ms->fdt, "/chosen");
@@ -1089,8 +1193,10 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap)
qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed",
rng_seed, sizeof(rng_seed));
- create_fdt_flash(s, memmap);
- create_fdt_fw_cfg(s, memmap);
+ qemu_fdt_add_subnode(ms->fdt, "/aliases");
+
+ create_fdt_flash(s);
+ create_fdt_fw_cfg(s);
create_fdt_pmu(s);
}
@@ -1115,23 +1221,21 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
dev = qdev_new(TYPE_GPEX_HOST);
/* Set GPEX object properties for the virt machine */
- object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_BASE,
+ object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
ecam_base, NULL);
- object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_SIZE,
+ object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
ecam_size, NULL);
- object_property_set_uint(OBJECT(GPEX_HOST(dev)),
- PCI_HOST_BELOW_4G_MMIO_BASE,
+ object_property_set_uint(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_BASE,
mmio_base, NULL);
- object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_BELOW_4G_MMIO_SIZE,
+ object_property_set_int(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_SIZE,
mmio_size, NULL);
- object_property_set_uint(OBJECT(GPEX_HOST(dev)),
- PCI_HOST_ABOVE_4G_MMIO_BASE,
+ object_property_set_uint(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_BASE,
high_mmio_base, NULL);
- object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ABOVE_4G_MMIO_SIZE,
+ object_property_set_int(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_SIZE,
high_mmio_size, NULL);
- object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_BASE,
+ object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
pio_base, NULL);
- object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_SIZE,
+ object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
pio_size, NULL);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -1157,20 +1261,19 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
}
- GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(GPEX_HOST(dev))->bus;
+ GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
return dev;
}
-static FWCfgState *create_fw_cfg(const MachineState *ms)
+static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr base)
{
- hwaddr base = virt_memmap[VIRT_FW_CFG].base;
FWCfgState *fw_cfg;
fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16,
@@ -1183,27 +1286,22 @@ static FWCfgState *create_fw_cfg(const MachineState *ms)
static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket,
int base_hartid, int hart_count)
{
- DeviceState *ret;
g_autofree char *plic_hart_config = NULL;
/* Per-socket PLIC hart topology configuration string */
plic_hart_config = riscv_plic_hart_config_string(hart_count);
/* Per-socket PLIC */
- ret = sifive_plic_create(
- memmap[VIRT_PLIC].base + socket * memmap[VIRT_PLIC].size,
- plic_hart_config, hart_count, base_hartid,
- VIRT_IRQCHIP_NUM_SOURCES,
- ((1U << VIRT_IRQCHIP_NUM_PRIO_BITS) - 1),
- VIRT_PLIC_PRIORITY_BASE,
- VIRT_PLIC_PENDING_BASE,
- VIRT_PLIC_ENABLE_BASE,
- VIRT_PLIC_ENABLE_STRIDE,
- VIRT_PLIC_CONTEXT_BASE,
- VIRT_PLIC_CONTEXT_STRIDE,
- memmap[VIRT_PLIC].size);
-
- return ret;
+ return sifive_plic_create(
+ memmap[VIRT_PLIC].base + socket * memmap[VIRT_PLIC].size,
+ plic_hart_config, hart_count, base_hartid,
+ VIRT_IRQCHIP_NUM_SOURCES,
+ ((1U << VIRT_IRQCHIP_NUM_PRIO_BITS) - 1),
+ VIRT_PLIC_PRIORITY_BASE, VIRT_PLIC_PENDING_BASE,
+ VIRT_PLIC_ENABLE_BASE, VIRT_PLIC_ENABLE_STRIDE,
+ VIRT_PLIC_CONTEXT_BASE,
+ VIRT_PLIC_CONTEXT_STRIDE,
+ memmap[VIRT_PLIC].size);
}
static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests,
@@ -1211,7 +1309,7 @@ static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests,
int base_hartid, int hart_count)
{
int i;
- hwaddr addr;
+ hwaddr addr = 0;
uint32_t guest_bits;
DeviceState *aplic_s = NULL;
DeviceState *aplic_m = NULL;
@@ -1261,6 +1359,10 @@ static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests,
VIRT_IRQCHIP_NUM_PRIO_BITS,
msimode, false, aplic_m);
+ if (kvm_enabled() && msimode) {
+ riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s), addr);
+ }
+
return kvm_enabled() ? aplic_s : aplic_m;
}
@@ -1268,14 +1370,13 @@ static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
{
DeviceState *dev;
SysBusDevice *sysbus;
- const MemMapEntry *memmap = virt_memmap;
int i;
MemoryRegion *sysmem = get_system_memory();
dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS);
- qdev_prop_set_uint32(dev, "mmio_size", memmap[VIRT_PLATFORM_BUS].size);
+ qdev_prop_set_uint32(dev, "mmio_size", s->memmap[VIRT_PLATFORM_BUS].size);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
s->platform_bus_dev = dev;
@@ -1286,7 +1387,7 @@ static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
}
memory_region_add_subregion(sysmem,
- memmap[VIRT_PLATFORM_BUS].base,
+ s->memmap[VIRT_PLATFORM_BUS].base,
sysbus_mmio_get_region(sysbus, 0));
}
@@ -1333,14 +1434,14 @@ static void virt_machine_done(Notifier *notifier, void *data)
{
RISCVVirtState *s = container_of(notifier, RISCVVirtState,
machine_done);
- const MemMapEntry *memmap = virt_memmap;
MachineState *machine = MACHINE(s);
- target_ulong start_addr = memmap[VIRT_DRAM].base;
+ hwaddr start_addr = s->memmap[VIRT_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr;
const char *firmware_name = riscv_default_firmware_name(&s->soc[0]);
uint64_t fdt_load_addr;
uint64_t kernel_entry = 0;
BlockBackend *pflash_blk0;
+ RISCVBootInfo boot_info;
/*
* An user provided dtb must include everything, including
@@ -1367,7 +1468,7 @@ static void virt_machine_done(Notifier *notifier, void *data)
}
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
- start_addr, NULL);
+ &start_addr, NULL);
pflash_blk0 = pflash_cfi01_get_blk(s->flash[0]);
if (pflash_blk0) {
@@ -1378,34 +1479,36 @@ static void virt_machine_done(Notifier *notifier, void *data)
* let's overwrite the address we jump to after reset to
* the base of the flash.
*/
- start_addr = virt_memmap[VIRT_FLASH].base;
+ start_addr = s->memmap[VIRT_FLASH].base;
} else {
/*
* Pflash was supplied but either KVM guest or bios is not none.
* In this case, base of the flash would contain S-mode payload.
*/
riscv_setup_firmware_boot(machine);
- kernel_entry = virt_memmap[VIRT_FLASH].base;
+ kernel_entry = s->memmap[VIRT_FLASH].base;
}
}
+ riscv_boot_info_init(&boot_info, &s->soc[0]);
+
if (machine->kernel_filename && !kernel_entry) {
- kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
+ kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
firmware_end_addr);
-
- kernel_entry = riscv_load_kernel(machine, &s->soc[0],
- kernel_start_addr, true, NULL);
+ riscv_load_kernel(machine, &boot_info, kernel_start_addr,
+ true, NULL);
+ kernel_entry = boot_info.image_low_addr;
}
- fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base,
- memmap[VIRT_DRAM].size,
- machine);
+ fdt_load_addr = riscv_compute_fdt_addr(s->memmap[VIRT_DRAM].base,
+ s->memmap[VIRT_DRAM].size,
+ machine, &boot_info);
riscv_load_fdt(fdt_load_addr, machine->fdt);
/* load the reset vector */
riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr,
- virt_memmap[VIRT_MROM].base,
- virt_memmap[VIRT_MROM].size, kernel_entry,
+ s->memmap[VIRT_MROM].base,
+ s->memmap[VIRT_MROM].size, kernel_entry,
fdt_load_addr);
/*
@@ -1426,7 +1529,6 @@ static void virt_machine_done(Notifier *notifier, void *data)
static void virt_machine_init(MachineState *machine)
{
- const MemMapEntry *memmap = virt_memmap;
RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
@@ -1434,6 +1536,8 @@ static void virt_machine_init(MachineState *machine)
int i, base_hartid, hart_count;
int socket_count = riscv_socket_count(machine);
+ s->memmap = virt_memmap;
+
/* Check socket count limit */
if (VIRT_SOCKETS_MAX < socket_count) {
error_report("number of sockets/nodes should be less than %d",
@@ -1481,7 +1585,7 @@ static void virt_machine_init(MachineState *machine)
if (virt_aclint_allowed() && s->have_aclint) {
if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
/* Per-socket ACLINT MTIMER */
- riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base +
+ riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base +
i * RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
base_hartid, hart_count,
@@ -1490,28 +1594,28 @@ static void virt_machine_init(MachineState *machine)
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
} else {
/* Per-socket ACLINT MSWI, MTIMER, and SSWI */
- riscv_aclint_swi_create(memmap[VIRT_CLINT].base +
- i * memmap[VIRT_CLINT].size,
+ riscv_aclint_swi_create(s->memmap[VIRT_CLINT].base +
+ i * s->memmap[VIRT_CLINT].size,
base_hartid, hart_count, false);
- riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base +
- i * memmap[VIRT_CLINT].size +
+ riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base +
+ i * s->memmap[VIRT_CLINT].size +
RISCV_ACLINT_SWI_SIZE,
RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
base_hartid, hart_count,
RISCV_ACLINT_DEFAULT_MTIMECMP,
RISCV_ACLINT_DEFAULT_MTIME,
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
- riscv_aclint_swi_create(memmap[VIRT_ACLINT_SSWI].base +
- i * memmap[VIRT_ACLINT_SSWI].size,
+ riscv_aclint_swi_create(s->memmap[VIRT_ACLINT_SSWI].base +
+ i * s->memmap[VIRT_ACLINT_SSWI].size,
base_hartid, hart_count, true);
}
} else if (tcg_enabled()) {
/* Per-socket SiFive CLINT */
riscv_aclint_swi_create(
- memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
+ s->memmap[VIRT_CLINT].base + i * s->memmap[VIRT_CLINT].size,
base_hartid, hart_count, false);
- riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base +
- i * memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE,
+ riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base +
+ i * s->memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE,
RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count,
RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
@@ -1519,11 +1623,11 @@ static void virt_machine_init(MachineState *machine)
/* Per-socket interrupt controller */
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
- s->irqchip[i] = virt_create_plic(memmap, i,
+ s->irqchip[i] = virt_create_plic(s->memmap, i,
base_hartid, hart_count);
} else {
s->irqchip[i] = virt_create_aia(s->aia_type, s->aia_guests,
- memmap, i, base_hartid,
+ s->memmap, i, base_hartid,
hart_count);
}
@@ -1542,11 +1646,11 @@ static void virt_machine_init(MachineState *machine)
}
}
- if (kvm_enabled() && virt_use_kvm_aia(s)) {
+ if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) {
kvm_riscv_aia_create(machine, IMSIC_MMIO_GROUP_MIN_SHIFT,
VIRT_IRQCHIP_NUM_SOURCES, VIRT_IRQCHIP_NUM_MSIS,
- memmap[VIRT_APLIC_S].base,
- memmap[VIRT_IMSIC_S].base,
+ s->memmap[VIRT_APLIC_S].base,
+ s->memmap[VIRT_IMSIC_S].base,
s->aia_guests);
}
@@ -1562,37 +1666,36 @@ static void virt_machine_init(MachineState *machine)
virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE;
} else {
virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE;
- virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size;
+ virt_high_pcie_memmap.base = s->memmap[VIRT_DRAM].base +
+ machine->ram_size;
virt_high_pcie_memmap.base =
ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size);
}
- s->memmap = virt_memmap;
-
/* register system main memory (actual RAM) */
- memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base,
- machine->ram);
+ memory_region_add_subregion(system_memory, s->memmap[VIRT_DRAM].base,
+ machine->ram);
/* boot rom */
memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom",
- memmap[VIRT_MROM].size, &error_fatal);
- memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
+ s->memmap[VIRT_MROM].size, &error_fatal);
+ memory_region_add_subregion(system_memory, s->memmap[VIRT_MROM].base,
mask_rom);
/*
* Init fw_cfg. Must be done before riscv_load_fdt, otherwise the
* device tree cannot be altered and we get FDT_ERR_NOSPACE.
*/
- s->fw_cfg = create_fw_cfg(machine);
+ s->fw_cfg = create_fw_cfg(machine, s->memmap[VIRT_FW_CFG].base);
rom_set_fw(s->fw_cfg);
/* SiFive Test MMIO device */
- sifive_test_create(memmap[VIRT_TEST].base);
+ sifive_test_create(s->memmap[VIRT_TEST].base);
/* VirtIO MMIO devices */
for (i = 0; i < VIRTIO_COUNT; i++) {
sysbus_create_simple("virtio-mmio",
- memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
+ s->memmap[VIRT_VIRTIO].base + i * s->memmap[VIRT_VIRTIO].size,
qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i));
}
@@ -1600,11 +1703,11 @@ static void virt_machine_init(MachineState *machine)
create_platform_bus(s, mmio_irqchip);
- serial_mm_init(system_memory, memmap[VIRT_UART0].base,
+ serial_mm_init(system_memory, s->memmap[VIRT_UART0].base,
0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193,
serial_hd(0), DEVICE_LITTLE_ENDIAN);
- sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base,
+ sysbus_create_simple("goldfish_rtc", s->memmap[VIRT_RTC].base,
qdev_get_gpio_in(mmio_irqchip, RTC_IRQ));
for (i = 0; i < ARRAY_SIZE(s->flash); i++) {
@@ -1622,7 +1725,23 @@ static void virt_machine_init(MachineState *machine)
exit(1);
}
} else {
- create_fdt(s, memmap);
+ create_fdt(s);
+ }
+
+ if (virt_is_iommu_sys_enabled(s)) {
+ DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
+
+ object_property_set_uint(OBJECT(iommu_sys), "addr",
+ s->memmap[VIRT_IOMMU_SYS].base,
+ &error_fatal);
+ object_property_set_uint(OBJECT(iommu_sys), "base-irq",
+ IOMMU_SYS_IRQ,
+ &error_fatal);
+ object_property_set_link(OBJECT(iommu_sys), "irqchip",
+ OBJECT(mmio_irqchip),
+ &error_fatal);
+
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
}
s->machine_done.notify = virt_machine_done;
@@ -1638,6 +1757,7 @@ static void virt_machine_instance_init(Object *obj)
s->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
s->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
s->acpi = ON_OFF_AUTO_AUTO;
+ s->iommu_sys = ON_OFF_AUTO_AUTO;
}
static char *virt_get_aia_guests(Object *obj, Error **errp)
@@ -1710,6 +1830,28 @@ static void virt_set_aclint(Object *obj, bool value, Error **errp)
s->have_aclint = value;
}
+bool virt_is_iommu_sys_enabled(RISCVVirtState *s)
+{
+ return s->iommu_sys == ON_OFF_AUTO_ON;
+}
+
+static void virt_get_iommu_sys(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
+ OnOffAuto iommu_sys = s->iommu_sys;
+
+ visit_type_OnOffAuto(v, name, &iommu_sys, errp);
+}
+
+static void virt_set_iommu_sys(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
+
+ visit_type_OnOffAuto(v, name, &s->iommu_sys, errp);
+}
+
bool virt_is_acpi_enabled(RISCVVirtState *s)
{
return s->acpi != ON_OFF_AUTO_OFF;
@@ -1736,11 +1878,15 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
DeviceState *dev)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
+ RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
if (device_is_dynamic_sysbus(mc, dev) ||
- object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
+ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_RISCV_IOMMU_PCI)) {
+ s->iommu_sys = ON_OFF_AUTO_OFF;
return HOTPLUG_HANDLER(machine);
}
+
return NULL;
}
@@ -1761,9 +1907,14 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
create_fdt_virtio_iommu(s, pci_get_bdf(PCI_DEVICE(dev)));
}
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_IOMMU_PCI)) {
+ create_fdt_iommu(s, pci_get_bdf(PCI_DEVICE(dev)));
+ s->iommu_sys = ON_OFF_AUTO_OFF;
+ }
}
-static void virt_machine_class_init(ObjectClass *oc, void *data)
+static void virt_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -1788,6 +1939,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
hc->plug = virt_machine_device_plug_cb;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
@@ -1822,6 +1974,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, "acpi",
"Enable ACPI");
+
+ object_class_property_add(oc, "iommu-sys", "OnOffAuto",
+ virt_get_iommu_sys, virt_set_iommu_sys,
+ NULL, NULL);
+ object_class_property_set_description(oc, "iommu-sys",
+ "Enable IOMMU platform device");
}
static const TypeInfo virt_machine_typeinfo = {
@@ -1830,7 +1988,7 @@ static const TypeInfo virt_machine_typeinfo = {
.class_init = virt_machine_class_init,
.instance_init = virt_machine_instance_init,
.instance_size = sizeof(RISCVVirtState),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
},
diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
index d0d8dda..315b0e4 100644
--- a/hw/rtc/Kconfig
+++ b/hw/rtc/Kconfig
@@ -14,10 +14,6 @@ config M48T59
config PL031
bool
-config TWL92230
- bool
- depends on I2C
-
config MC146818RTC
depends on ISA_BUS
bool
@@ -30,3 +26,8 @@ config GOLDFISH_RTC
config LS7A_RTC
bool
+
+config RS5C372_RTC
+ bool
+ depends on I2C
+ default y if I2C_DEVICES
diff --git a/hw/rtc/allwinner-rtc.c b/hw/rtc/allwinner-rtc.c
index 2ac50b3..a747bff 100644
--- a/hw/rtc/allwinner-rtc.c
+++ b/hw/rtc/allwinner-rtc.c
@@ -25,7 +25,7 @@
#include "qemu/module.h"
#include "hw/qdev-properties.h"
#include "hw/rtc/allwinner-rtc.h"
-#include "sysemu/rtc.h"
+#include "system/rtc.h"
#include "trace.h"
/* RTC registers */
@@ -259,7 +259,7 @@ static void allwinner_rtc_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_rtc_ops = {
.read = allwinner_rtc_read,
.write = allwinner_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -311,16 +311,15 @@ static const VMStateDescription allwinner_rtc_vmstate = {
}
};
-static Property allwinner_rtc_properties[] = {
+static const Property allwinner_rtc_properties[] = {
DEFINE_PROP_INT32("base-year", AwRtcState, base_year, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void allwinner_rtc_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_rtc_reset;
+ device_class_set_legacy_reset(dc, allwinner_rtc_reset);
dc->vmsd = &allwinner_rtc_vmstate;
device_class_set_props(dc, allwinner_rtc_properties);
}
@@ -331,7 +330,7 @@ static void allwinner_rtc_sun4i_init(Object *obj)
s->base_year = 2010;
}
-static void allwinner_rtc_sun4i_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_sun4i_class_init(ObjectClass *klass, const void *data)
{
AwRtcClass *arc = AW_RTC_CLASS(klass);
@@ -347,7 +346,7 @@ static void allwinner_rtc_sun6i_init(Object *obj)
s->base_year = 1970;
}
-static void allwinner_rtc_sun6i_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_sun6i_class_init(ObjectClass *klass, const void *data)
{
AwRtcClass *arc = AW_RTC_CLASS(klass);
@@ -363,7 +362,7 @@ static void allwinner_rtc_sun7i_init(Object *obj)
s->base_year = 1970;
}
-static void allwinner_rtc_sun7i_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_sun7i_class_init(ObjectClass *klass, const void *data)
{
AwRtcClass *arc = AW_RTC_CLASS(klass);
allwinner_rtc_sun4i_class_init(klass, arc);
diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c
index 589d9a5..c4feea2 100644
--- a/hw/rtc/aspeed_rtc.c
+++ b/hw/rtc/aspeed_rtc.c
@@ -11,7 +11,7 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/timer.h"
-#include "sysemu/rtc.h"
+#include "system/rtc.h"
#include "trace.h"
@@ -156,13 +156,13 @@ static void aspeed_rtc_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
+static void aspeed_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_rtc_realize;
dc->vmsd = &vmstate_aspeed_rtc;
- dc->reset = aspeed_rtc_reset;
+ device_class_set_legacy_reset(dc, aspeed_rtc_reset);
}
static const TypeInfo aspeed_rtc_info = {
diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c
index e479661..5f1ee2e 100644
--- a/hw/rtc/ds1338.c
+++ b/hw/rtc/ds1338.c
@@ -14,9 +14,9 @@
#include "hw/i2c/i2c.h"
#include "migration/vmstate.h"
#include "qemu/bcd.h"
-#include "qemu/module.h"
#include "qom/object.h"
-#include "sysemu/rtc.h"
+#include "system/rtc.h"
+#include "trace.h"
/* Size of NVRAM including both the user-accessible area and the
* secondary register area.
@@ -126,6 +126,9 @@ static uint8_t ds1338_recv(I2CSlave *i2c)
uint8_t res;
res = s->nvram[s->ptr];
+
+ trace_ds1338_recv(s->ptr, res);
+
inc_regptr(s);
return res;
}
@@ -134,6 +137,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
{
DS1338State *s = DS1338(i2c);
+ trace_ds1338_send(s->ptr, data);
+
if (s->addr_byte) {
s->ptr = data & (NVRAM_SIZE - 1);
s->addr_byte = false;
@@ -215,7 +220,7 @@ static void ds1338_reset(DeviceState *dev)
s->addr_byte = false;
}
-static void ds1338_class_init(ObjectClass *klass, void *data)
+static void ds1338_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -223,20 +228,17 @@ static void ds1338_class_init(ObjectClass *klass, void *data)
k->event = ds1338_event;
k->recv = ds1338_recv;
k->send = ds1338_send;
- dc->reset = ds1338_reset;
+ device_class_set_legacy_reset(dc, ds1338_reset);
dc->vmsd = &vmstate_ds1338;
}
-static const TypeInfo ds1338_info = {
- .name = TYPE_DS1338,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(DS1338State),
- .class_init = ds1338_class_init,
+static const TypeInfo ds1338_types[] = {
+ {
+ .name = TYPE_DS1338,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(DS1338State),
+ .class_init = ds1338_class_init,
+ },
};
-static void ds1338_register_types(void)
-{
- type_register_static(&ds1338_info);
-}
-
-type_init(ds1338_register_types)
+DEFINE_TYPES(ds1338_types)
diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c
index 319371f..624b4f6 100644
--- a/hw/rtc/exynos4210_rtc.c
+++ b/hw/rtc/exynos4210_rtc.c
@@ -38,7 +38,7 @@
#include "hw/arm/exynos4210.h"
#include "qom/object.h"
-#include "sysemu/rtc.h"
+#include "system/rtc.h"
#define DEBUG_RTC 0
@@ -592,11 +592,11 @@ static void exynos4210_rtc_finalize(Object *obj)
ptimer_free(s->ptimer_1Hz);
}
-static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
+static void exynos4210_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_rtc_reset;
+ device_class_set_legacy_reset(dc, exynos4210_rtc_reset);
dc->vmsd = &vmstate_exynos4210_rtc_state;
}
diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c
index 01acf30..78df031 100644
--- a/hw/rtc/goldfish_rtc.c
+++ b/hw/rtc/goldfish_rtc.c
@@ -27,8 +27,8 @@
#include "hw/sysbus.h"
#include "qemu/bitops.h"
#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
+#include "system/system.h"
+#include "system/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
@@ -178,38 +178,21 @@ static void goldfish_rtc_write(void *opaque, hwaddr offset,
trace_goldfish_rtc_write(offset, value);
}
-static int goldfish_rtc_pre_save(void *opaque)
-{
- uint64_t delta;
- GoldfishRTCState *s = opaque;
-
- /*
- * We want to migrate this offset, which sounds straightforward.
- * Unfortunately, we cannot directly pass tick_offset because
- * rtc_clock on destination Host might not be same source Host.
- *
- * To tackle, this we pass tick_offset relative to vm_clock from
- * source Host and make it relative to rtc_clock at destination Host.
- */
- delta = qemu_clock_get_ns(rtc_clock) -
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->tick_offset_vmstate = s->tick_offset + delta;
-
- return 0;
-}
-
static int goldfish_rtc_post_load(void *opaque, int version_id)
{
- uint64_t delta;
GoldfishRTCState *s = opaque;
- /*
- * We extract tick_offset from tick_offset_vmstate by doing
- * reverse math compared to pre_save() function.
- */
- delta = qemu_clock_get_ns(rtc_clock) -
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->tick_offset = s->tick_offset_vmstate - delta;
+ if (version_id < 3) {
+ /*
+ * Previous versions didn't migrate tick_offset directly. Instead, they
+ * migrated tick_offset_vmstate, which is a recalculation based on
+ * QEMU_CLOCK_VIRTUAL. We use tick_offset_vmstate when migrating from
+ * older versions.
+ */
+ uint64_t delta = qemu_clock_get_ns(rtc_clock) -
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ s->tick_offset = s->tick_offset_vmstate - delta;
+ }
goldfish_rtc_set_alarm(s);
@@ -239,8 +222,7 @@ static const MemoryRegionOps goldfish_rtc_ops[2] = {
static const VMStateDescription goldfish_rtc_vmstate = {
.name = TYPE_GOLDFISH_RTC,
- .version_id = 2,
- .pre_save = goldfish_rtc_pre_save,
+ .version_id = 3,
.post_load = goldfish_rtc_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState),
@@ -249,6 +231,7 @@ static const VMStateDescription goldfish_rtc_vmstate = {
VMSTATE_UINT32(irq_pending, GoldfishRTCState),
VMSTATE_UINT32(irq_enabled, GoldfishRTCState),
VMSTATE_UINT32(time_high, GoldfishRTCState),
+ VMSTATE_UINT64_V(tick_offset, GoldfishRTCState, 3),
VMSTATE_END_OF_LIST()
}
};
@@ -256,15 +239,8 @@ static const VMStateDescription goldfish_rtc_vmstate = {
static void goldfish_rtc_reset(DeviceState *dev)
{
GoldfishRTCState *s = GOLDFISH_RTC(dev);
- struct tm tm;
timer_del(s->timer);
-
- qemu_get_timedate(&tm, 0);
- s->tick_offset = mktimegm(&tm);
- s->tick_offset *= NANOSECONDS_PER_SECOND;
- s->tick_offset -= qemu_clock_get_ns(rtc_clock);
- s->tick_offset_vmstate = 0;
s->alarm_next = 0;
s->alarm_running = 0;
s->irq_pending = 0;
@@ -275,6 +251,7 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp)
{
SysBusDevice *dev = SYS_BUS_DEVICE(d);
GoldfishRTCState *s = GOLDFISH_RTC(d);
+ struct tm tm;
memory_region_init_io(&s->iomem, OBJECT(s),
&goldfish_rtc_ops[s->big_endian], s,
@@ -284,21 +261,25 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp)
sysbus_init_irq(dev, &s->irq);
s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s);
+
+ qemu_get_timedate(&tm, 0);
+ s->tick_offset = mktimegm(&tm);
+ s->tick_offset *= NANOSECONDS_PER_SECOND;
+ s->tick_offset -= qemu_clock_get_ns(rtc_clock);
}
-static Property goldfish_rtc_properties[] = {
+static const Property goldfish_rtc_properties[] = {
DEFINE_PROP_BOOL("big-endian", GoldfishRTCState, big_endian,
false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void goldfish_rtc_class_init(ObjectClass *klass, void *data)
+static void goldfish_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, goldfish_rtc_properties);
dc->realize = goldfish_rtc_realize;
- dc->reset = goldfish_rtc_reset;
+ device_class_set_legacy_reset(dc, goldfish_rtc_reset);
dc->vmsd = &goldfish_rtc_vmstate;
}
diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c
index 3226b61..10097b2 100644
--- a/hw/rtc/ls7a_rtc.c
+++ b/hw/rtc/ls7a_rtc.c
@@ -10,12 +10,12 @@
#include "hw/irq.h"
#include "hw/register.h"
#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "migration/vmstate.h"
#include "hw/misc/unimp.h"
-#include "sysemu/rtc.h"
+#include "system/rtc.h"
#include "hw/registerfields.h"
#define SYS_TOYTRIM 0x20
@@ -464,12 +464,12 @@ static const VMStateDescription vmstate_ls7a_rtc = {
}
};
-static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
+static void ls7a_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_ls7a_rtc;
dc->realize = ls7a_rtc_realize;
- dc->reset = ls7a_rtc_reset;
+ device_class_set_legacy_reset(dc, ls7a_rtc_reset);
dc->desc = "ls7a rtc";
}
diff --git a/hw/rtc/m41t80.c b/hw/rtc/m41t80.c
index e045c86..c631ec3 100644
--- a/hw/rtc/m41t80.c
+++ b/hw/rtc/m41t80.c
@@ -14,7 +14,7 @@
#include "qemu/bcd.h"
#include "hw/i2c/i2c.h"
#include "qom/object.h"
-#include "sysemu/rtc.h"
+#include "system/rtc.h"
#define TYPE_M41T80 "m41t80"
OBJECT_DECLARE_SIMPLE_TYPE(M41t80State, M41T80)
@@ -94,7 +94,7 @@ static int m41t80_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static void m41t80_class_init(ObjectClass *klass, void *data)
+static void m41t80_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
diff --git a/hw/rtc/m48t59-isa.c b/hw/rtc/m48t59-isa.c
index 5bb46f2..9e2f656 100644
--- a/hw/rtc/m48t59-isa.c
+++ b/hw/rtc/m48t59-isa.c
@@ -77,11 +77,10 @@ static void m48txx_isa_toggle_lock(Nvram *obj, int lock)
m48t59_toggle_lock(&d->state, lock);
}
-static Property m48t59_isa_properties[] = {
+static const Property m48t59_isa_properties[] = {
DEFINE_PROP_INT32("base-year", M48txxISAState, state.base_year, 0),
DEFINE_PROP_UINT32("iobase", M48txxISAState, io_base, 0x74),
DEFINE_PROP_UINT8("irq", M48txxISAState, isairq, 8),
- DEFINE_PROP_END_OF_LIST(),
};
static void m48t59_reset_isa(DeviceState *d)
@@ -114,23 +113,23 @@ static void m48t59_isa_realize(DeviceState *dev, Error **errp)
}
}
-static void m48txx_isa_class_init(ObjectClass *klass, void *data)
+static void m48txx_isa_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
NvramClass *nc = NVRAM_CLASS(klass);
dc->realize = m48t59_isa_realize;
- dc->reset = m48t59_reset_isa;
+ device_class_set_legacy_reset(dc, m48t59_reset_isa);
device_class_set_props(dc, m48t59_isa_properties);
nc->read = m48txx_isa_read;
nc->write = m48txx_isa_write;
nc->toggle_lock = m48txx_isa_toggle_lock;
}
-static void m48txx_isa_concrete_class_init(ObjectClass *klass, void *data)
+static void m48txx_isa_concrete_class_init(ObjectClass *klass, const void *data)
{
M48txxISADeviceClass *u = M48TXX_ISA_CLASS(klass);
- M48txxInfo *info = data;
+ const M48txxInfo *info = data;
u->info = *info;
}
@@ -141,7 +140,7 @@ static const TypeInfo m48txx_isa_type_info = {
.instance_size = sizeof(M48txxISAState),
.abstract = true,
.class_init = m48txx_isa_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NVRAM },
{ }
}
@@ -161,7 +160,7 @@ static void m48t59_isa_register_types(void)
for (i = 0; i < ARRAY_SIZE(m48txx_isa_info); i++) {
isa_type_info.name = m48txx_isa_info[i].bus_name;
isa_type_info.class_data = &m48txx_isa_info[i];
- type_register(&isa_type_info);
+ type_register_static(&isa_type_info);
}
}
diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c
index 1585a2d..68be2da 100644
--- a/hw/rtc/m48t59.c
+++ b/hw/rtc/m48t59.c
@@ -28,15 +28,15 @@
#include "hw/qdev-properties.h"
#include "hw/rtc/m48t59.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
-#include "sysemu/rtc.h"
-#include "sysemu/sysemu.h"
+#include "system/runstate.h"
+#include "system/rtc.h"
+#include "system/system.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
#include "qemu/bcd.h"
#include "qemu/module.h"
#include "trace.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "m48t59-internal.h"
#include "migration/vmstate.h"
@@ -618,18 +618,17 @@ static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
m48t59_toggle_lock(&d->state, lock);
}
-static Property m48t59_sysbus_properties[] = {
+static const Property m48t59_sysbus_properties[] = {
DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
+static void m48txx_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
NvramClass *nc = NVRAM_CLASS(klass);
dc->realize = m48t59_realize;
- dc->reset = m48t59_reset_sysbus;
+ device_class_set_legacy_reset(dc, m48t59_reset_sysbus);
device_class_set_props(dc, m48t59_sysbus_properties);
dc->vmsd = &vmstate_m48t59;
nc->read = m48txx_sysbus_read;
@@ -637,10 +636,11 @@ static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
nc->toggle_lock = m48txx_sysbus_toggle_lock;
}
-static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
+static void m48txx_sysbus_concrete_class_init(ObjectClass *klass,
+ const void *data)
{
M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
- M48txxInfo *info = data;
+ const M48txxInfo *info = data;
u->info = *info;
}
@@ -658,7 +658,7 @@ static const TypeInfo m48txx_sysbus_type_info = {
.instance_init = m48t59_init1,
.abstract = true,
.class_init = m48txx_sysbus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NVRAM },
{ }
}
@@ -679,7 +679,7 @@ static void m48t59_register_types(void)
for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) {
sysbus_type_info.name = m48txx_sysbus_info[i].bus_name;
sysbus_type_info.class_data = &m48txx_sysbus_info[i];
- type_register(&sysbus_type_info);
+ type_register_static(&sysbus_type_info);
}
}
diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index 8ccee9a..f9f5cf3 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -32,11 +32,11 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/replay.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/rtc.h"
+#include "system/system.h"
+#include "system/replay.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/rtc.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h"
@@ -819,7 +819,7 @@ static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = {
static const VMStateDescription vmstate_rtc = {
.name = "mc146818rtc",
.version_id = 3,
- .minimum_version_id = 1,
+ .minimum_version_id = 3,
.pre_save = rtc_pre_save,
.post_load = rtc_post_load,
.fields = (const VMStateField[]) {
@@ -829,13 +829,13 @@ static const VMStateDescription vmstate_rtc = {
VMSTATE_TIMER_PTR(periodic_timer, MC146818RtcState),
VMSTATE_INT64(next_periodic_time, MC146818RtcState),
VMSTATE_UNUSED(3*8),
- VMSTATE_UINT32_V(irq_coalesced, MC146818RtcState, 2),
- VMSTATE_UINT32_V(period, MC146818RtcState, 2),
- VMSTATE_UINT64_V(base_rtc, MC146818RtcState, 3),
- VMSTATE_UINT64_V(last_update, MC146818RtcState, 3),
- VMSTATE_INT64_V(offset, MC146818RtcState, 3),
- VMSTATE_TIMER_PTR_V(update_timer, MC146818RtcState, 3),
- VMSTATE_UINT64_V(next_alarm_time, MC146818RtcState, 3),
+ VMSTATE_UINT32(irq_coalesced, MC146818RtcState),
+ VMSTATE_UINT32(period, MC146818RtcState),
+ VMSTATE_UINT64(base_rtc, MC146818RtcState),
+ VMSTATE_UINT64(last_update, MC146818RtcState),
+ VMSTATE_INT64(offset, MC146818RtcState),
+ VMSTATE_TIMER_PTR(update_timer, MC146818RtcState),
+ VMSTATE_UINT64(next_alarm_time, MC146818RtcState),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
@@ -929,8 +929,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->io, 0, &s->coalesced_io);
memory_region_add_coalescing(&s->coalesced_io, 0, 1);
- qdev_set_legacy_instance_id(dev, s->io_base, 3);
-
object_property_add_tm(OBJECT(s), "date", rtc_get_date);
qdev_init_gpio_out(dev, &s->irq, 1);
@@ -960,13 +958,12 @@ MC146818RtcState *mc146818_rtc_init(ISABus *bus, int base_year,
return s;
}
-static Property mc146818rtc_properties[] = {
+static const Property mc146818rtc_properties[] = {
DEFINE_PROP_INT32("base_year", MC146818RtcState, base_year, 1980),
DEFINE_PROP_UINT16("iobase", MC146818RtcState, io_base, RTC_ISA_BASE),
DEFINE_PROP_UINT8("irq", MC146818RtcState, isairq, RTC_ISA_IRQ),
DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", MC146818RtcState,
lost_tick_policy, LOST_TICK_POLICY_DISCARD),
- DEFINE_PROP_END_OF_LIST(),
};
static void rtc_reset_enter(Object *obj, ResetType type)
@@ -1019,7 +1016,7 @@ static void rtc_build_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(scope, dev);
}
-static void rtc_class_initfn(ObjectClass *klass, void *data)
+static void rtc_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -1039,7 +1036,7 @@ static const TypeInfo mc146818rtc_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(MC146818RtcState),
.class_init = rtc_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
index 3ea2aff..6c87864 100644
--- a/hw/rtc/meson.build
+++ b/hw/rtc/meson.build
@@ -3,7 +3,6 @@ system_ss.add(when: 'CONFIG_DS1338', if_true: files('ds1338.c'))
system_ss.add(when: 'CONFIG_M41T80', if_true: files('m41t80.c'))
system_ss.add(when: 'CONFIG_M48T59', if_true: files('m48t59.c'))
system_ss.add(when: 'CONFIG_PL031', if_true: files('pl031.c'))
-system_ss.add(when: 'CONFIG_TWL92230', if_true: files('twl92230.c'))
system_ss.add(when: ['CONFIG_ISA_BUS', 'CONFIG_M48T59'], if_true: files('m48t59-isa.c'))
system_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-rtc.c'))
@@ -14,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
+system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c
index 563bb4b..e545b9d 100644
--- a/hw/rtc/pl031.c
+++ b/hw/rtc/pl031.c
@@ -18,8 +18,8 @@
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
+#include "system/system.h"
+#include "system/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -319,7 +319,7 @@ static const VMStateDescription vmstate_pl031 = {
}
};
-static Property pl031_properties[] = {
+static const Property pl031_properties[] = {
/*
* True to correctly migrate the tick offset of the RTC. False to
* obtain backward migration compatibility with older QEMU versions,
@@ -330,10 +330,9 @@ static Property pl031_properties[] = {
*/
DEFINE_PROP_BOOL("migrate-tick-offset",
PL031State, migrate_tick_offset, true),
- DEFINE_PROP_END_OF_LIST()
};
-static void pl031_class_init(ObjectClass *klass, void *data)
+static void pl031_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
new file mode 100644
index 0000000..bb92453
--- /dev/null
+++ b/hw/rtc/rs5c372.c
@@ -0,0 +1,236 @@
+/*
+ * Ricoh RS5C372, R222x I2C RTC
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * Based on hw/rtc/ds1338.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/i2c/i2c.h"
+#include "hw/qdev-properties.h"
+#include "hw/resettable.h"
+#include "migration/vmstate.h"
+#include "qemu/bcd.h"
+#include "qom/object.h"
+#include "system/rtc.h"
+#include "trace.h"
+
+#define NVRAM_SIZE 0x10
+
+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_PM 0x20
+#define CTRL2_24 0x20
+
+#define TYPE_RS5C372 "rs5c372"
+OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
+
+struct RS5C372State {
+ I2CSlave parent_obj;
+
+ int64_t offset;
+ uint8_t wday_offset;
+ uint8_t nvram[NVRAM_SIZE];
+ uint8_t ptr;
+ uint8_t tx_format;
+ bool addr_byte;
+};
+
+static void capture_current_time(RS5C372State *s)
+{
+ /*
+ * Capture the current time into the secondary registers which will be
+ * actually read by the data transfer operation.
+ */
+ struct tm now;
+ qemu_get_timedate(&now, s->offset);
+ s->nvram[0] = to_bcd(now.tm_sec);
+ s->nvram[1] = to_bcd(now.tm_min);
+ if (s->nvram[0xf] & CTRL2_24) {
+ s->nvram[2] = to_bcd(now.tm_hour);
+ } else {
+ int tmp = now.tm_hour;
+ if (tmp % 12 == 0) {
+ tmp += 12;
+ }
+ if (tmp <= 12) {
+ s->nvram[2] = to_bcd(tmp);
+ } else {
+ s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
+ }
+ }
+ s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
+ s->nvram[4] = to_bcd(now.tm_mday);
+ s->nvram[5] = to_bcd(now.tm_mon + 1);
+ s->nvram[6] = to_bcd(now.tm_year - 100);
+}
+
+static void inc_regptr(RS5C372State *s)
+{
+ s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
+}
+
+static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
+{
+ RS5C372State *s = RS5C372(i2c);
+
+ switch (event) {
+ case I2C_START_RECV:
+ /*
+ * In h/w, capture happens on any START condition, not just a
+ * START_RECV, but there is no need to actually capture on
+ * START_SEND, because the guest can't get at that data
+ * without going through a START_RECV which would overwrite it.
+ */
+ capture_current_time(s);
+ s->ptr = 0xf;
+ break;
+ case I2C_START_SEND:
+ s->addr_byte = true;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static uint8_t rs5c372_recv(I2CSlave *i2c)
+{
+ RS5C372State *s = RS5C372(i2c);
+ uint8_t res;
+
+ res = s->nvram[s->ptr];
+
+ trace_rs5c372_recv(s->ptr, res);
+
+ inc_regptr(s);
+ return res;
+}
+
+static int rs5c372_send(I2CSlave *i2c, uint8_t data)
+{
+ RS5C372State *s = RS5C372(i2c);
+
+ if (s->addr_byte) {
+ s->ptr = data >> 4;
+ s->tx_format = data & 0xf;
+ s->addr_byte = false;
+ return 0;
+ }
+
+ trace_rs5c372_send(s->ptr, data);
+
+ if (s->ptr < 7) {
+ /* Time register. */
+ struct tm now;
+ qemu_get_timedate(&now, s->offset);
+ switch (s->ptr) {
+ case 0:
+ now.tm_sec = from_bcd(data & 0x7f);
+ break;
+ case 1:
+ now.tm_min = from_bcd(data & 0x7f);
+ break;
+ case 2:
+ if (s->nvram[0xf] & CTRL2_24) {
+ now.tm_hour = from_bcd(data & 0x3f);
+ } else {
+ int tmp = from_bcd(data & (HOURS_PM - 1));
+ if (data & HOURS_PM) {
+ tmp += 12;
+ }
+ if (tmp % 12 == 0) {
+ tmp -= 12;
+ }
+ now.tm_hour = tmp;
+ }
+ break;
+ case 3:
+ {
+ /*
+ * The day field is supposed to contain a value in the range
+ * 1-7. Otherwise behavior is undefined.
+ */
+ int user_wday = (data & 7) - 1;
+ s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
+ }
+ break;
+ case 4:
+ now.tm_mday = from_bcd(data & 0x3f);
+ break;
+ case 5:
+ now.tm_mon = from_bcd(data & 0x1f) - 1;
+ break;
+ case 6:
+ now.tm_year = from_bcd(data) + 100;
+ break;
+ }
+ s->offset = qemu_timedate_diff(&now);
+ } else {
+ s->nvram[s->ptr] = data;
+ }
+ inc_regptr(s);
+ return 0;
+}
+
+static void rs5c372_reset_hold(Object *obj, ResetType type)
+{
+ RS5C372State *s = RS5C372(obj);
+
+ /* The clock is running and synchronized with the host */
+ s->offset = 0;
+ s->wday_offset = 0;
+ memset(s->nvram, 0, NVRAM_SIZE);
+ s->ptr = 0;
+ s->addr_byte = false;
+}
+
+static const VMStateDescription rs5c372_vmstate = {
+ .name = "rs5c372",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
+ VMSTATE_INT64(offset, RS5C372State),
+ VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
+ VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
+ VMSTATE_UINT8(ptr, RS5C372State),
+ VMSTATE_UINT8(tx_format, RS5C372State),
+ VMSTATE_BOOL(addr_byte, RS5C372State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void rs5c372_init(Object *obj)
+{
+ qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
+}
+
+static void rs5c372_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ k->event = rs5c372_event;
+ k->recv = rs5c372_recv;
+ k->send = rs5c372_send;
+ dc->vmsd = &rs5c372_vmstate;
+ rc->phases.hold = rs5c372_reset_hold;
+}
+
+static const TypeInfo rs5c372_types[] = {
+ {
+ .name = TYPE_RS5C372,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(RS5C372State),
+ .instance_init = rs5c372_init,
+ .class_init = rs5c372_class_init,
+ },
+};
+
+DEFINE_TYPES(rs5c372_types)
diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c
index ffcc0aa..29e24ef 100644
--- a/hw/rtc/sun4v-rtc.c
+++ b/hw/rtc/sun4v-rtc.c
@@ -75,7 +75,7 @@ static void sun4v_rtc_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void sun4v_rtc_class_init(ObjectClass *klass, void *data)
+static void sun4v_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
index ebb311a..b9f2852 100644
--- a/hw/rtc/trace-events
+++ b/hw/rtc/trace-events
@@ -22,6 +22,10 @@ pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks"
aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
+# ds1338.c
+ds1338_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
+ds1338_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
+
# m48t59.c
m48txx_nvram_io_read(uint64_t addr, uint64_t value) "io read addr:0x%04" PRIx64 " value:0x%02" PRIx64
m48txx_nvram_io_write(uint64_t addr, uint64_t value) "io write addr:0x%04" PRIx64 " value:0x%02" PRIx64
@@ -31,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
# goldfish_rtc.c
goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
+
+# rs5c372.c
+rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
+rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
diff --git a/hw/rtc/twl92230.c b/hw/rtc/twl92230.c
deleted file mode 100644
index efd19a7..0000000
--- a/hw/rtc/twl92230.c
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- * TI TWL92230C energy-management companion device for the OMAP24xx.
- * Aka. Menelaus (N4200 MENELAUS1_V2.2)
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "migration/qemu-file-types.h"
-#include "migration/vmstate.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
-#include "qemu/bcd.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define VERBOSE 1
-
-#define TYPE_TWL92230 "twl92230"
-OBJECT_DECLARE_SIMPLE_TYPE(MenelausState, TWL92230)
-
-struct MenelausState {
- I2CSlave parent_obj;
-
- int firstbyte;
- uint8_t reg;
-
- uint8_t vcore[5];
- uint8_t dcdc[3];
- uint8_t ldo[8];
- uint8_t sleep[2];
- uint8_t osc;
- uint8_t detect;
- uint16_t mask;
- uint16_t status;
- uint8_t dir;
- uint8_t inputs;
- uint8_t outputs;
- uint8_t bbsms;
- uint8_t pull[4];
- uint8_t mmc_ctrl[3];
- uint8_t mmc_debounce;
- struct {
- uint8_t ctrl;
- uint16_t comp;
- QEMUTimer *hz_tm;
- int64_t next;
- struct tm tm;
- struct tm new;
- struct tm alm;
- int64_t sec_offset;
- int64_t alm_sec;
- int next_comp;
- } rtc;
- uint16_t rtc_next_vmstate;
- qemu_irq out[4];
- uint8_t pwrbtn_state;
-};
-
-static inline void menelaus_update(MenelausState *s)
-{
- qemu_set_irq(s->out[3], s->status & ~s->mask);
-}
-
-static inline void menelaus_rtc_start(MenelausState *s)
-{
- s->rtc.next += qemu_clock_get_ms(rtc_clock);
- timer_mod(s->rtc.hz_tm, s->rtc.next);
-}
-
-static inline void menelaus_rtc_stop(MenelausState *s)
-{
- timer_del(s->rtc.hz_tm);
- s->rtc.next -= qemu_clock_get_ms(rtc_clock);
- if (s->rtc.next < 1)
- s->rtc.next = 1;
-}
-
-static void menelaus_rtc_update(MenelausState *s)
-{
- qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset);
-}
-
-static void menelaus_alm_update(MenelausState *s)
-{
- if ((s->rtc.ctrl & 3) == 3)
- s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset;
-}
-
-static void menelaus_rtc_hz(void *opaque)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- s->rtc.next_comp --;
- s->rtc.alm_sec --;
- s->rtc.next += 1000;
- timer_mod(s->rtc.hz_tm, s->rtc.next);
- if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */
- menelaus_rtc_update(s);
- if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
- s->status |= 1 << 8; /* RTCTMR */
- else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
- s->status |= 1 << 8; /* RTCTMR */
- else if (!s->rtc.tm.tm_hour)
- s->status |= 1 << 8; /* RTCTMR */
- } else
- s->status |= 1 << 8; /* RTCTMR */
- if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */
- if (s->rtc.alm_sec == 0)
- s->status |= 1 << 9; /* RTCALM */
- /* TODO: wake-up */
- }
- if (s->rtc.next_comp <= 0) {
- s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
- s->rtc.next_comp = 3600;
- }
- menelaus_update(s);
-}
-
-static void menelaus_reset(I2CSlave *i2c)
-{
- MenelausState *s = TWL92230(i2c);
-
- s->reg = 0x00;
-
- s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */
- s->vcore[1] = 0x05;
- s->vcore[2] = 0x02;
- s->vcore[3] = 0x0c;
- s->vcore[4] = 0x03;
- s->dcdc[0] = 0x33; /* Depends on wiring */
- s->dcdc[1] = 0x03;
- s->dcdc[2] = 0x00;
- s->ldo[0] = 0x95;
- s->ldo[1] = 0x7e;
- s->ldo[2] = 0x00;
- s->ldo[3] = 0x00; /* Depends on wiring */
- s->ldo[4] = 0x03; /* Depends on wiring */
- s->ldo[5] = 0x00;
- s->ldo[6] = 0x00;
- s->ldo[7] = 0x00;
- s->sleep[0] = 0x00;
- s->sleep[1] = 0x00;
- s->osc = 0x01;
- s->detect = 0x09;
- s->mask = 0x0fff;
- s->status = 0;
- s->dir = 0x07;
- s->outputs = 0x00;
- s->bbsms = 0x00;
- s->pull[0] = 0x00;
- s->pull[1] = 0x00;
- s->pull[2] = 0x00;
- s->pull[3] = 0x00;
- s->mmc_ctrl[0] = 0x03;
- s->mmc_ctrl[1] = 0xc0;
- s->mmc_ctrl[2] = 0x00;
- s->mmc_debounce = 0x05;
-
- if (s->rtc.ctrl & 1)
- menelaus_rtc_stop(s);
- s->rtc.ctrl = 0x00;
- s->rtc.comp = 0x0000;
- s->rtc.next = 1000;
- s->rtc.sec_offset = 0;
- s->rtc.next_comp = 1800;
- s->rtc.alm_sec = 1800;
- s->rtc.alm.tm_sec = 0x00;
- s->rtc.alm.tm_min = 0x00;
- s->rtc.alm.tm_hour = 0x00;
- s->rtc.alm.tm_mday = 0x01;
- s->rtc.alm.tm_mon = 0x00;
- s->rtc.alm.tm_year = 2004;
- menelaus_update(s);
-}
-
-static void menelaus_gpio_set(void *opaque, int line, int level)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- if (line < 3) {
- /* No interrupt generated */
- s->inputs &= ~(1 << line);
- s->inputs |= level << line;
- return;
- }
-
- if (!s->pwrbtn_state && level) {
- s->status |= 1 << 11; /* PSHBTN */
- menelaus_update(s);
- }
- s->pwrbtn_state = level;
-}
-
-#define MENELAUS_REV 0x01
-#define MENELAUS_VCORE_CTRL1 0x02
-#define MENELAUS_VCORE_CTRL2 0x03
-#define MENELAUS_VCORE_CTRL3 0x04
-#define MENELAUS_VCORE_CTRL4 0x05
-#define MENELAUS_VCORE_CTRL5 0x06
-#define MENELAUS_DCDC_CTRL1 0x07
-#define MENELAUS_DCDC_CTRL2 0x08
-#define MENELAUS_DCDC_CTRL3 0x09
-#define MENELAUS_LDO_CTRL1 0x0a
-#define MENELAUS_LDO_CTRL2 0x0b
-#define MENELAUS_LDO_CTRL3 0x0c
-#define MENELAUS_LDO_CTRL4 0x0d
-#define MENELAUS_LDO_CTRL5 0x0e
-#define MENELAUS_LDO_CTRL6 0x0f
-#define MENELAUS_LDO_CTRL7 0x10
-#define MENELAUS_LDO_CTRL8 0x11
-#define MENELAUS_SLEEP_CTRL1 0x12
-#define MENELAUS_SLEEP_CTRL2 0x13
-#define MENELAUS_DEVICE_OFF 0x14
-#define MENELAUS_OSC_CTRL 0x15
-#define MENELAUS_DETECT_CTRL 0x16
-#define MENELAUS_INT_MASK1 0x17
-#define MENELAUS_INT_MASK2 0x18
-#define MENELAUS_INT_STATUS1 0x19
-#define MENELAUS_INT_STATUS2 0x1a
-#define MENELAUS_INT_ACK1 0x1b
-#define MENELAUS_INT_ACK2 0x1c
-#define MENELAUS_GPIO_CTRL 0x1d
-#define MENELAUS_GPIO_IN 0x1e
-#define MENELAUS_GPIO_OUT 0x1f
-#define MENELAUS_BBSMS 0x20
-#define MENELAUS_RTC_CTRL 0x21
-#define MENELAUS_RTC_UPDATE 0x22
-#define MENELAUS_RTC_SEC 0x23
-#define MENELAUS_RTC_MIN 0x24
-#define MENELAUS_RTC_HR 0x25
-#define MENELAUS_RTC_DAY 0x26
-#define MENELAUS_RTC_MON 0x27
-#define MENELAUS_RTC_YR 0x28
-#define MENELAUS_RTC_WKDAY 0x29
-#define MENELAUS_RTC_AL_SEC 0x2a
-#define MENELAUS_RTC_AL_MIN 0x2b
-#define MENELAUS_RTC_AL_HR 0x2c
-#define MENELAUS_RTC_AL_DAY 0x2d
-#define MENELAUS_RTC_AL_MON 0x2e
-#define MENELAUS_RTC_AL_YR 0x2f
-#define MENELAUS_RTC_COMP_MSB 0x30
-#define MENELAUS_RTC_COMP_LSB 0x31
-#define MENELAUS_S1_PULL_EN 0x32
-#define MENELAUS_S1_PULL_DIR 0x33
-#define MENELAUS_S2_PULL_EN 0x34
-#define MENELAUS_S2_PULL_DIR 0x35
-#define MENELAUS_MCT_CTRL1 0x36
-#define MENELAUS_MCT_CTRL2 0x37
-#define MENELAUS_MCT_CTRL3 0x38
-#define MENELAUS_MCT_PIN_ST 0x39
-#define MENELAUS_DEBOUNCE1 0x3a
-
-static uint8_t menelaus_read(void *opaque, uint8_t addr)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- switch (addr) {
- case MENELAUS_REV:
- return 0x22;
-
- case MENELAUS_VCORE_CTRL1 ... MENELAUS_VCORE_CTRL5:
- return s->vcore[addr - MENELAUS_VCORE_CTRL1];
-
- case MENELAUS_DCDC_CTRL1 ... MENELAUS_DCDC_CTRL3:
- return s->dcdc[addr - MENELAUS_DCDC_CTRL1];
-
- case MENELAUS_LDO_CTRL1 ... MENELAUS_LDO_CTRL8:
- return s->ldo[addr - MENELAUS_LDO_CTRL1];
-
- case MENELAUS_SLEEP_CTRL1:
- case MENELAUS_SLEEP_CTRL2:
- return s->sleep[addr - MENELAUS_SLEEP_CTRL1];
-
- case MENELAUS_DEVICE_OFF:
- return 0;
-
- case MENELAUS_OSC_CTRL:
- return s->osc | (1 << 7); /* CLK32K_GOOD */
-
- case MENELAUS_DETECT_CTRL:
- return s->detect;
-
- case MENELAUS_INT_MASK1:
- return (s->mask >> 0) & 0xff;
- case MENELAUS_INT_MASK2:
- return (s->mask >> 8) & 0xff;
-
- case MENELAUS_INT_STATUS1:
- return (s->status >> 0) & 0xff;
- case MENELAUS_INT_STATUS2:
- return (s->status >> 8) & 0xff;
-
- case MENELAUS_INT_ACK1:
- case MENELAUS_INT_ACK2:
- return 0;
-
- case MENELAUS_GPIO_CTRL:
- return s->dir;
- case MENELAUS_GPIO_IN:
- return s->inputs | (~s->dir & s->outputs);
- case MENELAUS_GPIO_OUT:
- return s->outputs;
-
- case MENELAUS_BBSMS:
- return s->bbsms;
-
- case MENELAUS_RTC_CTRL:
- return s->rtc.ctrl;
- case MENELAUS_RTC_UPDATE:
- return 0x00;
- case MENELAUS_RTC_SEC:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_sec);
- case MENELAUS_RTC_MIN:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_min);
- case MENELAUS_RTC_HR:
- menelaus_rtc_update(s);
- if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
- return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
- (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */
- else
- return to_bcd(s->rtc.tm.tm_hour);
- case MENELAUS_RTC_DAY:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_mday);
- case MENELAUS_RTC_MON:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_mon + 1);
- case MENELAUS_RTC_YR:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_year - 2000);
- case MENELAUS_RTC_WKDAY:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_wday);
- case MENELAUS_RTC_AL_SEC:
- return to_bcd(s->rtc.alm.tm_sec);
- case MENELAUS_RTC_AL_MIN:
- return to_bcd(s->rtc.alm.tm_min);
- case MENELAUS_RTC_AL_HR:
- if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
- return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
- (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
- else
- return to_bcd(s->rtc.alm.tm_hour);
- case MENELAUS_RTC_AL_DAY:
- return to_bcd(s->rtc.alm.tm_mday);
- case MENELAUS_RTC_AL_MON:
- return to_bcd(s->rtc.alm.tm_mon + 1);
- case MENELAUS_RTC_AL_YR:
- return to_bcd(s->rtc.alm.tm_year - 2000);
- case MENELAUS_RTC_COMP_MSB:
- return (s->rtc.comp >> 8) & 0xff;
- case MENELAUS_RTC_COMP_LSB:
- return (s->rtc.comp >> 0) & 0xff;
-
- case MENELAUS_S1_PULL_EN:
- return s->pull[0];
- case MENELAUS_S1_PULL_DIR:
- return s->pull[1];
- case MENELAUS_S2_PULL_EN:
- return s->pull[2];
- case MENELAUS_S2_PULL_DIR:
- return s->pull[3];
-
- case MENELAUS_MCT_CTRL1 ... MENELAUS_MCT_CTRL3:
- return s->mmc_ctrl[addr - MENELAUS_MCT_CTRL1];
- case MENELAUS_MCT_PIN_ST:
- /* TODO: return the real Card Detect */
- return 0;
- case MENELAUS_DEBOUNCE1:
- return s->mmc_debounce;
-
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __func__, addr);
-#endif
- break;
- }
- return 0;
-}
-
-static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
-{
- MenelausState *s = (MenelausState *) opaque;
- int line;
- struct tm tm;
-
- switch (addr) {
- case MENELAUS_VCORE_CTRL1:
- s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL2:
- s->vcore[1] = value;
- break;
- case MENELAUS_VCORE_CTRL3:
- s->vcore[2] = MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL4:
- s->vcore[3] = MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL5:
- s->vcore[4] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
-
- case MENELAUS_DCDC_CTRL1:
- s->dcdc[0] = value & 0x3f;
- break;
- case MENELAUS_DCDC_CTRL2:
- s->dcdc[1] = value & 0x07;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_DCDC_CTRL3:
- s->dcdc[2] = value & 0x07;
- break;
-
- case MENELAUS_LDO_CTRL1:
- s->ldo[0] = value;
- break;
- case MENELAUS_LDO_CTRL2:
- s->ldo[1] = value & 0x7f;
- /* XXX
- * auto set to 0x7e on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL3:
- s->ldo[2] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL4:
- s->ldo[3] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL5:
- s->ldo[4] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL6:
- s->ldo[5] = value & 3;
- break;
- case MENELAUS_LDO_CTRL7:
- s->ldo[6] = value & 3;
- break;
- case MENELAUS_LDO_CTRL8:
- s->ldo[7] = value & 3;
- break;
-
- case MENELAUS_SLEEP_CTRL1:
- case MENELAUS_SLEEP_CTRL2:
- s->sleep[addr - MENELAUS_SLEEP_CTRL1] = value;
- break;
-
- case MENELAUS_DEVICE_OFF:
- if (value & 1) {
- menelaus_reset(I2C_SLAVE(s));
- }
- break;
-
- case MENELAUS_OSC_CTRL:
- s->osc = value & 7;
- break;
-
- case MENELAUS_DETECT_CTRL:
- s->detect = value & 0x7f;
- break;
-
- case MENELAUS_INT_MASK1:
- s->mask &= 0xf00;
- s->mask |= value << 0;
- menelaus_update(s);
- break;
- case MENELAUS_INT_MASK2:
- s->mask &= 0x0ff;
- s->mask |= value << 8;
- menelaus_update(s);
- break;
-
- case MENELAUS_INT_ACK1:
- s->status &= ~(((uint16_t) value) << 0);
- menelaus_update(s);
- break;
- case MENELAUS_INT_ACK2:
- s->status &= ~(((uint16_t) value) << 8);
- menelaus_update(s);
- break;
-
- case MENELAUS_GPIO_CTRL:
- for (line = 0; line < 3; line ++) {
- if (((s->dir ^ value) >> line) & 1) {
- qemu_set_irq(s->out[line],
- ((s->outputs & ~s->dir) >> line) & 1);
- }
- }
- s->dir = value & 0x67;
- break;
- case MENELAUS_GPIO_OUT:
- for (line = 0; line < 3; line ++) {
- if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
- qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
- }
- }
- s->outputs = value & 0x07;
- break;
-
- case MENELAUS_BBSMS:
- s->bbsms = 0x0d;
- break;
-
- case MENELAUS_RTC_CTRL:
- if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */
- if (value & 1)
- menelaus_rtc_start(s);
- else
- menelaus_rtc_stop(s);
- }
- s->rtc.ctrl = value & 0x1f;
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_UPDATE:
- menelaus_rtc_update(s);
- memcpy(&tm, &s->rtc.tm, sizeof(tm));
- switch (value & 0xf) {
- case 0:
- break;
- case 1:
- tm.tm_sec = s->rtc.new.tm_sec;
- break;
- case 2:
- tm.tm_min = s->rtc.new.tm_min;
- break;
- case 3:
- if (s->rtc.new.tm_hour > 23)
- goto rtc_badness;
- tm.tm_hour = s->rtc.new.tm_hour;
- break;
- case 4:
- if (s->rtc.new.tm_mday < 1)
- goto rtc_badness;
- /* TODO check range */
- tm.tm_mday = s->rtc.new.tm_mday;
- break;
- case 5:
- if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
- goto rtc_badness;
- tm.tm_mon = s->rtc.new.tm_mon;
- break;
- case 6:
- tm.tm_year = s->rtc.new.tm_year;
- break;
- case 7:
- /* TODO set .tm_mday instead */
- tm.tm_wday = s->rtc.new.tm_wday;
- break;
- case 8:
- if (s->rtc.new.tm_hour > 23)
- goto rtc_badness;
- if (s->rtc.new.tm_mday < 1)
- goto rtc_badness;
- if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
- goto rtc_badness;
- tm.tm_sec = s->rtc.new.tm_sec;
- tm.tm_min = s->rtc.new.tm_min;
- tm.tm_hour = s->rtc.new.tm_hour;
- tm.tm_mday = s->rtc.new.tm_mday;
- tm.tm_mon = s->rtc.new.tm_mon;
- tm.tm_year = s->rtc.new.tm_year;
- break;
- rtc_badness:
- default:
- fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
- __func__, value);
- s->status |= 1 << 10; /* RTCERR */
- menelaus_update(s);
- }
- s->rtc.sec_offset = qemu_timedate_diff(&tm);
- break;
- case MENELAUS_RTC_SEC:
- s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
- break;
- case MENELAUS_RTC_MIN:
- s->rtc.tm.tm_min = from_bcd(value & 0x7f);
- break;
- case MENELAUS_RTC_HR:
- s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
- MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
- from_bcd(value & 0x3f);
- break;
- case MENELAUS_RTC_DAY:
- s->rtc.tm.tm_mday = from_bcd(value);
- break;
- case MENELAUS_RTC_MON:
- s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
- break;
- case MENELAUS_RTC_YR:
- s->rtc.tm.tm_year = 2000 + from_bcd(value);
- break;
- case MENELAUS_RTC_WKDAY:
- s->rtc.tm.tm_mday = from_bcd(value);
- break;
- case MENELAUS_RTC_AL_SEC:
- s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_MIN:
- s->rtc.alm.tm_min = from_bcd(value & 0x7f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_HR:
- s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
- MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
- from_bcd(value & 0x3f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_DAY:
- s->rtc.alm.tm_mday = from_bcd(value);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_MON:
- s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_YR:
- s->rtc.alm.tm_year = 2000 + from_bcd(value);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_COMP_MSB:
- s->rtc.comp &= 0xff;
- s->rtc.comp |= value << 8;
- break;
- case MENELAUS_RTC_COMP_LSB:
- s->rtc.comp &= 0xff << 8;
- s->rtc.comp |= value;
- break;
-
- case MENELAUS_S1_PULL_EN:
- s->pull[0] = value;
- break;
- case MENELAUS_S1_PULL_DIR:
- s->pull[1] = value & 0x1f;
- break;
- case MENELAUS_S2_PULL_EN:
- s->pull[2] = value;
- break;
- case MENELAUS_S2_PULL_DIR:
- s->pull[3] = value & 0x1f;
- break;
-
- case MENELAUS_MCT_CTRL1:
- s->mmc_ctrl[0] = value & 0x7f;
- break;
- case MENELAUS_MCT_CTRL2:
- s->mmc_ctrl[1] = value;
- /* TODO update Card Detect interrupts */
- break;
- case MENELAUS_MCT_CTRL3:
- s->mmc_ctrl[2] = value & 0xf;
- break;
- case MENELAUS_DEBOUNCE1:
- s->mmc_debounce = value & 0x3f;
- break;
-
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __func__, addr);
-#endif
- break;
- }
-}
-
-static int menelaus_event(I2CSlave *i2c, enum i2c_event event)
-{
- MenelausState *s = TWL92230(i2c);
-
- if (event == I2C_START_SEND)
- s->firstbyte = 1;
-
- return 0;
-}
-
-static int menelaus_tx(I2CSlave *i2c, uint8_t data)
-{
- MenelausState *s = TWL92230(i2c);
-
- /* Interpret register address byte */
- if (s->firstbyte) {
- s->reg = data;
- s->firstbyte = 0;
- } else
- menelaus_write(s, s->reg ++, data);
-
- return 0;
-}
-
-static uint8_t menelaus_rx(I2CSlave *i2c)
-{
- MenelausState *s = TWL92230(i2c);
-
- return menelaus_read(s, s->reg ++);
-}
-
-/* Save restore 32 bit int as uint16_t
- This is a Big hack, but it is how the old state did it.
- Or we broke compatibility in the state, or we can't use struct tm
- */
-
-static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size,
- const VMStateField *field)
-{
- int *v = pv;
- *v = qemu_get_be16(f);
- return 0;
-}
-
-static int put_int32_as_uint16(QEMUFile *f, void *pv, size_t size,
- const VMStateField *field, JSONWriter *vmdesc)
-{
- int *v = pv;
- qemu_put_be16(f, *v);
-
- return 0;
-}
-
-static const VMStateInfo vmstate_hack_int32_as_uint16 = {
- .name = "int32_as_uint16",
- .get = get_int32_as_uint16,
- .put = put_int32_as_uint16,
-};
-
-#define VMSTATE_UINT16_HACK(_f, _s) \
- VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t)
-
-
-static const VMStateDescription vmstate_menelaus_tm = {
- .name = "menelaus_tm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT16_HACK(tm_sec, struct tm),
- VMSTATE_UINT16_HACK(tm_min, struct tm),
- VMSTATE_UINT16_HACK(tm_hour, struct tm),
- VMSTATE_UINT16_HACK(tm_mday, struct tm),
- VMSTATE_UINT16_HACK(tm_min, struct tm),
- VMSTATE_UINT16_HACK(tm_year, struct tm),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int menelaus_pre_save(void *opaque)
-{
- MenelausState *s = opaque;
- /* Should be <= 1000 */
- s->rtc_next_vmstate = s->rtc.next - qemu_clock_get_ms(rtc_clock);
-
- return 0;
-}
-
-static int menelaus_post_load(void *opaque, int version_id)
-{
- MenelausState *s = opaque;
-
- if (s->rtc.ctrl & 1) /* RTC_EN */
- menelaus_rtc_stop(s);
-
- s->rtc.next = s->rtc_next_vmstate;
-
- menelaus_alm_update(s);
- menelaus_update(s);
- if (s->rtc.ctrl & 1) /* RTC_EN */
- menelaus_rtc_start(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_menelaus = {
- .name = "menelaus",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = menelaus_pre_save,
- .post_load = menelaus_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(firstbyte, MenelausState),
- VMSTATE_UINT8(reg, MenelausState),
- VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5),
- VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3),
- VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8),
- VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2),
- VMSTATE_UINT8(osc, MenelausState),
- VMSTATE_UINT8(detect, MenelausState),
- VMSTATE_UINT16(mask, MenelausState),
- VMSTATE_UINT16(status, MenelausState),
- VMSTATE_UINT8(dir, MenelausState),
- VMSTATE_UINT8(inputs, MenelausState),
- VMSTATE_UINT8(outputs, MenelausState),
- VMSTATE_UINT8(bbsms, MenelausState),
- VMSTATE_UINT8_ARRAY(pull, MenelausState, 4),
- VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3),
- VMSTATE_UINT8(mmc_debounce, MenelausState),
- VMSTATE_UINT8(rtc.ctrl, MenelausState),
- VMSTATE_UINT16(rtc.comp, MenelausState),
- VMSTATE_UINT16(rtc_next_vmstate, MenelausState),
- VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm,
- struct tm),
- VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm,
- struct tm),
- VMSTATE_UINT8(pwrbtn_state, MenelausState),
- VMSTATE_I2C_SLAVE(parent_obj, MenelausState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void twl92230_realize(DeviceState *dev, Error **errp)
-{
- MenelausState *s = TWL92230(dev);
-
- s->rtc.hz_tm = timer_new_ms(rtc_clock, menelaus_rtc_hz, s);
- /* Three output pins plus one interrupt pin. */
- qdev_init_gpio_out(dev, s->out, 4);
-
- /* Three input pins plus one power-button pin. */
- qdev_init_gpio_in(dev, menelaus_gpio_set, 4);
-
- menelaus_reset(I2C_SLAVE(dev));
-}
-
-static void twl92230_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
-
- dc->realize = twl92230_realize;
- sc->event = menelaus_event;
- sc->recv = menelaus_rx;
- sc->send = menelaus_tx;
- dc->vmsd = &vmstate_menelaus;
-}
-
-static const TypeInfo twl92230_info = {
- .name = TYPE_TWL92230,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(MenelausState),
- .class_init = twl92230_class_init,
-};
-
-static void twl92230_register_types(void)
-{
- type_register_static(&twl92230_info);
-}
-
-type_init(twl92230_register_types)
diff --git a/hw/rtc/xlnx-zynqmp-rtc.c b/hw/rtc/xlnx-zynqmp-rtc.c
index 613c640..500982a 100644
--- a/hw/rtc/xlnx-zynqmp-rtc.c
+++ b/hw/rtc/xlnx-zynqmp-rtc.c
@@ -32,8 +32,8 @@
#include "qemu/module.h"
#include "hw/irq.h"
#include "qemu/cutils.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
+#include "system/system.h"
+#include "system/rtc.h"
#include "trace.h"
#include "hw/rtc/xlnx-zynqmp-rtc.h"
#include "migration/vmstate.h"
@@ -251,11 +251,11 @@ static const VMStateDescription vmstate_rtc = {
}
};
-static void rtc_class_init(ObjectClass *klass, void *data)
+static void rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = rtc_reset;
+ device_class_set_legacy_reset(dc, rtc_reset);
dc->vmsd = &vmstate_rtc;
}
diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c
index bb4746c..5b9004e 100644
--- a/hw/rx/rx-gdbsim.c
+++ b/hw/rx/rx-gdbsim.c
@@ -24,9 +24,9 @@
#include "qapi/error.h"
#include "hw/loader.h"
#include "hw/rx/rx62n.h"
-#include "sysemu/qtest.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/reset.h"
+#include "system/qtest.h"
+#include "system/device_tree.h"
+#include "system/reset.h"
#include "hw/boards.h"
#include "qom/object.h"
@@ -110,9 +110,6 @@ static void rx_gdbsim_init(MachineState *machine)
if (!kernel_filename) {
if (machine->firmware) {
rom_add_file_fixed(machine->firmware, RX62N_CFLASH_BASE, 0);
- } else if (!qtest_enabled()) {
- error_report("No bios or kernel specified");
- exit(1);
}
}
@@ -127,7 +124,7 @@ static void rx_gdbsim_init(MachineState *machine)
* the latter half of the SDRAM space.
*/
kernel_offset = machine->ram_size / 2;
- rx_load_image(RX_CPU(first_cpu), kernel_filename,
+ rx_load_image(&s->mcu.cpu, kernel_filename,
SDRAM_BASE + kernel_offset, kernel_offset);
if (dtb_filename) {
ram_addr_t dtb_offset;
@@ -153,12 +150,12 @@ static void rx_gdbsim_init(MachineState *machine)
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
rom_ptr(SDRAM_BASE + dtb_offset, dtb_size));
/* Set dtb address to R1 */
- RX_CPU(first_cpu)->env.regs[1] = SDRAM_BASE + dtb_offset;
+ s->mcu.cpu.env.regs[1] = SDRAM_BASE + dtb_offset;
}
}
}
-static void rx_gdbsim_class_init(ObjectClass *oc, void *data)
+static void rx_gdbsim_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -168,7 +165,7 @@ static void rx_gdbsim_class_init(ObjectClass *oc, void *data)
mc->default_ram_id = "ext-sdram";
}
-static void rx62n7_class_init(ObjectClass *oc, void *data)
+static void rx62n7_class_init(ObjectClass *oc, const void *data)
{
RxGdbSimMachineClass *rxc = RX_GDBSIM_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
@@ -178,7 +175,7 @@ static void rx62n7_class_init(ObjectClass *oc, void *data)
mc->desc = "gdb simulator (R5F562N7 MCU and external RAM)";
};
-static void rx62n8_class_init(ObjectClass *oc, void *data)
+static void rx62n8_class_init(ObjectClass *oc, const void *data)
{
RxGdbSimMachineClass *rxc = RX_GDBSIM_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c
index 560f53a..a2a243a 100644
--- a/hw/rx/rx62n.c
+++ b/hw/rx/rx62n.c
@@ -28,8 +28,8 @@
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/qdev-properties.h"
-#include "sysemu/sysemu.h"
-#include "qapi/qmp/qlist.h"
+#include "system/system.h"
+#include "qobject/qlist.h"
#include "qom/object.h"
/*
@@ -257,15 +257,14 @@ static void rx62n_realize(DeviceState *dev, Error **errp)
register_sci(s, 0);
}
-static Property rx62n_properties[] = {
+static const Property rx62n_properties[] = {
DEFINE_PROP_LINK("main-bus", RX62NState, sysmem, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_BOOL("load-kernel", RX62NState, kernel, false),
DEFINE_PROP_UINT32("xtal-frequency-hz", RX62NState, xtal_freq_hz, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void rx62n_class_init(ObjectClass *klass, void *data)
+static void rx62n_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -273,7 +272,7 @@ static void rx62n_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, rx62n_properties);
}
-static void r5f562n7_class_init(ObjectClass *oc, void *data)
+static void r5f562n7_class_init(ObjectClass *oc, const void *data)
{
RX62NClass *rxc = RX62N_MCU_CLASS(oc);
@@ -282,7 +281,7 @@ static void r5f562n7_class_init(ObjectClass *oc, void *data)
rxc->data_flash_size = 32 * KiB;
};
-static void r5f562n8_class_init(ObjectClass *oc, void *data)
+static void r5f562n8_class_init(ObjectClass *oc, const void *data)
{
RX62NClass *rxc = RX62N_MCU_CLASS(oc);
diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c
index 69e6783..3f0d384 100644
--- a/hw/s390x/3270-ccw.c
+++ b/hw/s390x/3270-ccw.c
@@ -150,15 +150,10 @@ out_err:
g_free(sch);
}
-static Property emulated_ccw_3270_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
+static void emulated_ccw_3270_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- device_class_set_props(dc, emulated_ccw_3270_properties);
dc->realize = emulated_ccw_3270_realize;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
diff --git a/hw/s390x/Kconfig b/hw/s390x/Kconfig
index 3bbf4ae..02ea199 100644
--- a/hw/s390x/Kconfig
+++ b/hw/s390x/Kconfig
@@ -7,6 +7,7 @@ config S390_CCW_VIRTIO
imply VFIO_AP
imply VFIO_CCW
imply WDT_DIAG288
+ imply PCI_BRIDGE
imply PCIE_DEVICES
imply IOMMUFD
select PCI_EXPRESS
@@ -15,3 +16,4 @@ config S390_CCW_VIRTIO
select SCLPCONSOLE
select VIRTIO_CCW
select MSI_NONBROKEN
+ select VIRTIO_MEM_SUPPORTED
diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c
index ef8fa2b..edeb3db 100644
--- a/hw/s390x/ap-bridge.c
+++ b/hw/s390x/ap-bridge.c
@@ -22,7 +22,7 @@ static char *ap_bus_get_dev_path(DeviceState *dev)
return g_strdup_printf("/1");
}
-static void ap_bus_class_init(ObjectClass *oc, void *data)
+static void ap_bus_class_init(ObjectClass *oc, const void *data)
{
BusClass *k = BUS_CLASS(oc);
@@ -61,7 +61,7 @@ void s390_init_ap(void)
qbus_set_hotplug_handler(bus, OBJECT(dev));
}
-static void ap_bridge_class_init(ObjectClass *oc, void *data)
+static void ap_bridge_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -75,7 +75,7 @@ static const TypeInfo ap_bridge_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = 0,
.class_init = ap_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/s390x/ap-device.c b/hw/s390x/ap-device.c
index 237d1f1..7331044 100644
--- a/hw/s390x/ap-device.c
+++ b/hw/s390x/ap-device.c
@@ -12,7 +12,7 @@
#include "qapi/error.h"
#include "hw/s390x/ap-device.h"
-static void ap_class_init(ObjectClass *klass, void *data)
+static void ap_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/s390x/ap-stub.c b/hw/s390x/ap-stub.c
new file mode 100644
index 0000000..001fe5f
--- /dev/null
+++ b/hw/s390x/ap-stub.c
@@ -0,0 +1,21 @@
+/*
+ * VFIO based AP matrix device assignment
+ *
+ * Copyright 2025 IBM Corp.
+ * Author(s): Rorie Reyes <rreyes@linux.ibm.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/s390x/ap-bridge.h"
+
+int ap_chsc_sei_nt0_get_event(void *res)
+{
+ return EVENT_INFORMATION_NOT_STORED;
+}
+
+bool ap_chsc_sei_nt0_have_event(void)
+{
+ return false;
+}
diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c
index a7d682e..8be1813 100644
--- a/hw/s390x/ccw-device.c
+++ b/hw/s390x/ccw-device.c
@@ -13,6 +13,10 @@
#include "ccw-device.h"
#include "hw/qdev-properties.h"
#include "qemu/module.h"
+#include "ipl.h"
+#include "qapi/visitor.h"
+#include "qemu/ctype.h"
+#include "qapi/error.h"
static void ccw_device_refill_ids(CcwDevice *dev)
{
@@ -37,29 +41,69 @@ static bool ccw_device_realize(CcwDevice *dev, Error **errp)
return true;
}
-static Property ccw_device_properties[] = {
+static void ccw_device_get_loadparm(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CcwDevice *dev = CCW_DEVICE(obj);
+ char *str = g_strndup((char *) dev->loadparm, sizeof(dev->loadparm));
+
+ visit_type_str(v, name, &str, errp);
+ g_free(str);
+}
+
+static void ccw_device_set_loadparm(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CcwDevice *dev = CCW_DEVICE(obj);
+ g_autofree char *val = NULL;
+ int index;
+
+ index = object_property_get_int(obj, "bootindex", NULL);
+
+ if (index < 0) {
+ error_setg(errp, "LOADPARM is only valid for boot devices!");
+ }
+
+ if (!visit_type_str(v, name, &val, errp)) {
+ return;
+ }
+
+ s390_ipl_fmt_loadparm(dev->loadparm, val, errp);
+}
+
+const PropertyInfo ccw_loadparm = {
+ .type = "str",
+ .description = "Up to 8 chars in set of [A-Za-z0-9. ] to select"
+ " a guest kernel",
+ .get = ccw_device_get_loadparm,
+ .set = ccw_device_set_loadparm,
+};
+
+static const Property ccw_device_properties[] = {
DEFINE_PROP_CSS_DEV_ID("devno", CcwDevice, devno),
DEFINE_PROP_CSS_DEV_ID_RO("dev_id", CcwDevice, dev_id),
DEFINE_PROP_CSS_DEV_ID_RO("subch_id", CcwDevice, subch_id),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ccw_device_reset(DeviceState *d)
+static void ccw_device_reset_hold(Object *obj, ResetType type)
{
- CcwDevice *ccw_dev = CCW_DEVICE(d);
+ CcwDevice *ccw_dev = CCW_DEVICE(obj);
css_reset_sch(ccw_dev->sch);
}
-static void ccw_device_class_init(ObjectClass *klass, void *data)
+static void ccw_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
CCWDeviceClass *k = CCW_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
k->realize = ccw_device_realize;
k->refill_ids = ccw_device_refill_ids;
device_class_set_props(dc, ccw_device_properties);
- dc->reset = ccw_device_reset;
+ rc->phases.hold = ccw_device_reset_hold;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
}
diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h
index 5feeb0e..4439feb 100644
--- a/hw/s390x/ccw-device.h
+++ b/hw/s390x/ccw-device.h
@@ -26,6 +26,8 @@ struct CcwDevice {
CssDevId dev_id;
/* The actual busid of the virtual subchannel. */
CssDevId subch_id;
+ /* If set, use this loadparm value when device is boot target */
+ uint8_t loadparm[8];
};
typedef struct CcwDevice CcwDevice;
@@ -49,4 +51,9 @@ static inline CcwDevice *to_ccw_dev_fast(DeviceState *d)
OBJECT_DECLARE_TYPE(CcwDevice, CCWDeviceClass, CCW_DEVICE)
+extern const PropertyInfo ccw_loadparm;
+
+#define DEFINE_PROP_CCW_LOADPARM(_n, _s, _f) \
+ DEFINE_PROP(_n, _s, _f, ccw_loadparm, typeof(uint8_t[8]))
+
#endif
diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c
index f16bdf6..b513f89 100644
--- a/hw/s390x/cpu-topology.c
+++ b/hw/s390x/cpu-topology.c
@@ -23,8 +23,8 @@
#include "target/s390x/cpu.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/cpu-topology.h"
-#include "qapi/qapi-commands-machine-target.h"
-#include "qapi/qapi-events-machine-target.h"
+#include "qapi/qapi-commands-machine-s390x.h"
+#include "qapi/qapi-events-machine-s390x.h"
/*
* s390_topology is used to keep the topology information.
@@ -105,7 +105,7 @@ static void s390_topology_init(MachineState *ms)
*/
void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra)
{
- CpuS390Polarization polarization;
+ S390CpuPolarization polarization;
CPUS390XState *env = &cpu->env;
uint64_t reg = env->regs[r1];
int fc = reg & S390_TOPO_FC_MASK;
@@ -357,7 +357,7 @@ static void s390_change_topology(uint16_t core_id,
bool has_book_id, uint16_t book_id,
bool has_drawer_id, uint16_t drawer_id,
bool has_entitlement,
- CpuS390Entitlement entitlement,
+ S390CpuEntitlement entitlement,
bool has_dedicated, bool dedicated,
Error **errp)
{
@@ -446,7 +446,7 @@ void qmp_set_cpu_topology(uint16_t core,
bool has_socket, uint16_t socket,
bool has_book, uint16_t book,
bool has_drawer, uint16_t drawer,
- bool has_entitlement, CpuS390Entitlement entitlement,
+ bool has_entitlement, S390CpuEntitlement entitlement,
bool has_dedicated, bool dedicated,
Error **errp)
{
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 8657ff7..0f87b8c 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -66,19 +66,11 @@ static char *virtual_css_bus_get_dev_path(DeviceState *dev)
{
CcwDevice *ccw_dev = CCW_DEVICE(dev);
SubchDev *sch = ccw_dev->sch;
- VirtualCssBridge *bridge =
- VIRTUAL_CSS_BRIDGE(qdev_get_parent_bus(dev)->parent);
- /*
- * We can't provide a dev path for backward compatibility on
- * older machines, as it is visible in the migration stream.
- */
- return bridge->css_dev_path ?
- g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno) :
- NULL;
+ return g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno);
}
-static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
+static void virtual_css_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -120,25 +112,18 @@ VirtualCssBus *virtual_css_bus_init(void)
/***************** Virtual-css Bus Bridge Device ********************/
-static Property virtual_css_bridge_properties[] = {
- DEFINE_PROP_BOOL("css_dev_path", VirtualCssBridge, css_dev_path,
- true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static bool prop_get_true(Object *obj, Error **errp)
{
return true;
}
-static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
+static void virtual_css_bridge_class_init(ObjectClass *klass, const void *data)
{
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
hc->unplug = ccw_device_unplug;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- device_class_set_props(dc, virtual_css_bridge_properties);
object_class_property_add_bool(klass, "cssid-unrestricted",
prop_get_true, NULL);
object_class_property_set_description(klass, "cssid-unrestricted",
@@ -151,7 +136,7 @@ static const TypeInfo virtual_css_bridge_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(VirtualCssBridge),
.class_init = virtual_css_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index b2d5327..53444f6 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -14,7 +14,7 @@
#include "qapi/visitor.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/s390x/ioinst.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/css.h"
@@ -23,8 +23,6 @@
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/s390-ccw.h"
-bool css_migration_enabled = true;
-
typedef struct CrwContainer {
CRW crw;
QTAILQ_ENTRY(CrwContainer) sibling;
@@ -180,16 +178,10 @@ static const VMStateDescription vmstate_orb = {
}
};
-static bool vmstate_schdev_orb_needed(void *opaque)
-{
- return css_migration_enabled;
-}
-
static const VMStateDescription vmstate_schdev_orb = {
.name = "s390_subch_dev/orb",
.version_id = 1,
.minimum_version_id = 1,
- .needed = vmstate_schdev_orb_needed,
.fields = (const VMStateField[]) {
VMSTATE_STRUCT(orb, SubchDev, 1, vmstate_orb, ORB),
VMSTATE_END_OF_LIST()
@@ -390,33 +382,12 @@ static int subch_dev_post_load(void *opaque, int version_id)
css_subch_assign(s->cssid, s->ssid, s->schid, s->devno, s);
}
- if (css_migration_enabled) {
- /* No compat voodoo to do ;) */
- return 0;
- }
- /*
- * Hack alert. If we don't migrate the channel subsystem status
- * we still need to find out if the guest enabled mss/mcss-e.
- * If the subchannel is enabled, it certainly was able to access it,
- * so adjust the max_ssid/max_cssid values for relevant ssid/cssid
- * values. This is not watertight, but better than nothing.
- */
- if (s->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA) {
- if (s->ssid) {
- channel_subsys.max_ssid = MAX_SSID;
- }
- if (s->cssid != channel_subsys.default_cssid) {
- channel_subsys.max_cssid = MAX_CSSID;
- }
- }
return 0;
}
void css_register_vmstate(void)
{
- if (css_migration_enabled) {
- vmstate_register(NULL, 0, &vmstate_css, &channel_subsys);
- }
+ vmstate_register(NULL, 0, &vmstate_css, &channel_subsys);
}
IndAddr *get_indicator(hwaddr ind_addr, int len)
@@ -2463,7 +2434,7 @@ void css_reset(void)
static void get_css_devid(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
CssDevId *dev_id = object_field_prop_ptr(obj, prop);
char buffer[] = "xx.x.xxxx";
char *p = buffer;
@@ -2492,7 +2463,7 @@ static void get_css_devid(Object *obj, Visitor *v, const char *name,
static void set_css_devid(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
CssDevId *dev_id = object_field_prop_ptr(obj, prop);
char *str;
int num, n1, n2;
@@ -2523,7 +2494,7 @@ out:
}
const PropertyInfo css_devid_propinfo = {
- .name = "str",
+ .type = "str",
.description = "Identifier of an I/O device in the channel "
"subsystem, example: fe.1.23ab",
.get = get_css_devid,
@@ -2531,7 +2502,7 @@ const PropertyInfo css_devid_propinfo = {
};
const PropertyInfo css_devid_ro_propinfo = {
- .name = "str",
+ .type = "str",
.description = "Read-only identifier of an I/O device in the channel "
"subsystem, example: fe.1.23ab",
.get = get_css_devid,
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 06c1da0..fee286e 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -4,6 +4,7 @@
* handles SCLP event types
* - Signal Quiesce - system power down
* - ASCII Console Data - VT220 read and write
+ * - Control-Program Identification - Send OS data from guest to host
*
* Copyright IBM, Corp. 2012
*
@@ -40,18 +41,12 @@ struct SCLPEventFacility {
SysBusDevice parent_obj;
SCLPEventsBus sbus;
SCLPEvent quiesce, cpu_hotplug;
+ SCLPEventCPI cpi;
/* guest's receive mask */
union {
uint32_t receive_mask_pieces[2];
sccb_mask_t receive_mask;
};
- /*
- * when false, we keep the same broken, backwards compatible behaviour as
- * before, allowing only masks of size exactly 4; when true, we implement
- * the architecture correctly, allowing all valid mask sizes. Needed for
- * migration toward older versions.
- */
- bool allow_all_mask_sizes;
/* length of the receive mask */
uint16_t mask_length;
};
@@ -294,8 +289,7 @@ static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
uint16_t mask_length = be16_to_cpu(we_mask->mask_length);
sccb_mask_t tmp_mask;
- if (!mask_length || (mask_length > SCLP_EVENT_MASK_LEN_MAX) ||
- ((mask_length != 4) && !ef->allow_all_mask_sizes)) {
+ if (!mask_length || mask_length > SCLP_EVENT_MASK_LEN_MAX) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
return;
}
@@ -355,13 +349,6 @@ static bool vmstate_event_facility_mask64_needed(void *opaque)
return (ef->receive_mask & 0xFFFFFFFF) != 0;
}
-static bool vmstate_event_facility_mask_length_needed(void *opaque)
-{
- SCLPEventFacility *ef = opaque;
-
- return ef->allow_all_mask_sizes;
-}
-
static const VMStateDescription vmstate_event_facility_mask64 = {
.name = "vmstate-event-facility/mask64",
.version_id = 0,
@@ -377,7 +364,6 @@ static const VMStateDescription vmstate_event_facility_mask_length = {
.name = "vmstate-event-facility/mask_length",
.version_id = 0,
.minimum_version_id = 0,
- .needed = vmstate_event_facility_mask_length_needed,
.fields = (const VMStateField[]) {
VMSTATE_UINT16(mask_length, SCLPEventFacility),
VMSTATE_END_OF_LIST()
@@ -399,31 +385,12 @@ static const VMStateDescription vmstate_event_facility = {
}
};
-static void sclp_event_set_allow_all_mask_sizes(Object *obj, bool value,
- Error **errp)
-{
- SCLPEventFacility *ef = (SCLPEventFacility *)obj;
-
- ef->allow_all_mask_sizes = value;
-}
-
-static bool sclp_event_get_allow_all_mask_sizes(Object *obj, Error **errp)
-{
- SCLPEventFacility *ef = (SCLPEventFacility *)obj;
-
- return ef->allow_all_mask_sizes;
-}
-
static void init_event_facility(Object *obj)
{
SCLPEventFacility *event_facility = EVENT_FACILITY(obj);
DeviceState *sdev = DEVICE(obj);
event_facility->mask_length = 4;
- event_facility->allow_all_mask_sizes = true;
- object_property_add_bool(obj, "allow_all_mask_sizes",
- sclp_event_get_allow_all_mask_sizes,
- sclp_event_set_allow_all_mask_sizes);
/* Spawn a new bus for SCLP events */
qbus_init(&event_facility->sbus, sizeof(event_facility->sbus),
@@ -460,14 +427,14 @@ static void reset_event_facility(DeviceState *dev)
sdev->receive_mask = 0;
}
-static void init_event_facility_class(ObjectClass *klass, void *data)
+static void init_event_facility_class(ObjectClass *klass, const void *data)
{
SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(sbdc);
SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
dc->realize = realize_event_facility;
- dc->reset = reset_event_facility;
+ device_class_set_legacy_reset(dc, reset_event_facility);
dc->vmsd = &vmstate_event_facility;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
k->command_handler = command_handler;
@@ -497,7 +464,7 @@ static void event_realize(DeviceState *qdev, Error **errp)
}
}
-static void event_class_init(ObjectClass *klass, void *data)
+static void event_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index e934bf8..2f08239 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -15,9 +15,9 @@
#include "qemu/osdep.h"
#include "qemu/datadir.h"
#include "qapi/error.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/tcg.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/tcg.h"
#include "elf.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
@@ -26,7 +26,6 @@
#include "hw/s390x/vfio-ccw.h"
#include "hw/s390x/css.h"
#include "hw/s390x/ebcdic.h"
-#include "target/s390x/kvm/pv.h"
#include "hw/scsi/scsi.h"
#include "hw/virtio/virtio-net.h"
#include "ipl.h"
@@ -34,6 +33,7 @@
#include "qemu/config-file.h"
#include "qemu/cutils.h"
#include "qemu/option.h"
+#include "qemu/ctype.h"
#include "standard-headers/linux/virtio_ids.h"
#define KERN_IMAGE_START 0x010000UL
@@ -45,20 +45,20 @@
#define INITRD_PARM_START 0x010408UL
#define PARMFILE_START 0x001000UL
#define ZIPL_IMAGE_START 0x009000UL
+#define BIOS_MAX_SIZE 0x300000UL
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
-static bool iplb_extended_needed(void *opaque)
+/* Place the IPLB chain immediately before the BIOS in memory */
+static uint64_t find_iplb_chain_addr(uint64_t bios_addr, uint16_t count)
{
- S390IPLState *ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL));
-
- return ipl->iplbext_migration;
+ return (bios_addr & TARGET_PAGE_MASK)
+ - (count * sizeof(IplParameterBlock));
}
static const VMStateDescription vmstate_iplb_extended = {
.name = "ipl/iplb_extended",
.version_id = 0,
.minimum_version_id = 0,
- .needed = iplb_extended_needed,
.fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(reserved_ext, IplParameterBlock, 4096 - 200),
VMSTATE_END_OF_LIST()
@@ -144,7 +144,14 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
* even if an external kernel has been defined.
*/
if (!ipl->kernel || ipl->enforce_bios) {
- uint64_t fwbase = (MIN(ms->ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
+ uint64_t fwbase;
+
+ if (ms->ram_size < BIOS_MAX_SIZE) {
+ error_setg(errp, "not enough RAM to load the BIOS file");
+ return;
+ }
+
+ fwbase = (MIN(ms->ram_size, 0x80000000U) - BIOS_MAX_SIZE) & ~0xffffUL;
bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->firmware);
if (bios_filename == NULL) {
@@ -154,8 +161,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
bios_size = load_elf(bios_filename, NULL,
bios_translate_addr, &fwbase,
- &ipl->bios_start_addr, NULL, NULL, NULL, 1,
- EM_S390, 0, 0);
+ &ipl->bios_start_addr, NULL, NULL, NULL,
+ ELFDATA2MSB, EM_S390, 0, 0);
if (bios_size > 0) {
/* Adjust ELF start address to final location */
ipl->bios_start_addr += fwbase;
@@ -179,7 +186,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
if (ipl->kernel) {
kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL,
&pentry, NULL,
- NULL, NULL, 1, EM_S390, 0, 0);
+ NULL, NULL, ELFDATA2MSB, EM_S390, 0, 0);
if (kernel_size < 0) {
kernel_size = load_image_targphys(ipl->kernel, 0, ms->ram_size);
if (kernel_size < 0) {
@@ -252,8 +259,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
*/
romptr = rom_ptr(INITRD_PARM_START, 16);
if (romptr) {
- stq_p(romptr, initrd_offset);
- stq_p(romptr + 1, initrd_size);
+ stq_be_p(romptr, initrd_offset);
+ stq_be_p(romptr + 1, initrd_size);
}
}
}
@@ -275,16 +282,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
qemu_register_reset(resettable_cold_reset_fn, dev);
}
-static Property s390_ipl_properties[] = {
+static const Property s390_ipl_properties[] = {
DEFINE_PROP_STRING("kernel", S390IPLState, kernel),
DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
- DEFINE_PROP_STRING("netboot_fw", S390IPLState, netboot_fw),
DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
- DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration,
- true),
- DEFINE_PROP_END_OF_LIST(),
};
static void s390_ipl_set_boot_menu(S390IPLState *ipl)
@@ -390,174 +393,162 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
return ccw_dev;
}
-static bool s390_gen_initial_iplb(S390IPLState *ipl)
+static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain)
+{
+ S390IPLState *ipl = get_ipl_device();
+ uint16_t count = be16_to_cpu(ipl->qipl.chain_len);
+ uint64_t len = sizeof(IplParameterBlock) * count;
+ uint64_t chain_addr = find_iplb_chain_addr(ipl->bios_start_addr, count);
+
+ cpu_physical_memory_write(chain_addr, iplb_chain, len);
+ return chain_addr;
+}
+
+void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp)
+{
+ /* Initialize the loadparm with spaces */
+ memset(loadparm, ' ', LOADPARM_LEN);
+ qdev_prop_sanitize_s390x_loadparm(loadparm, str, errp);
+}
+
+void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp)
+{
+ int i;
+
+ /* Initialize the loadparm with EBCDIC spaces (0x40) */
+ memset(ebcdic_lp, '@', LOADPARM_LEN);
+ for (i = 0; i < LOADPARM_LEN && ascii_lp[i]; i++) {
+ ebcdic_lp[i] = ascii2ebcdic[(uint8_t) ascii_lp[i]];
+ }
+}
+
+static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
{
- DeviceState *dev_st;
CcwDevice *ccw_dev = NULL;
SCSIDevice *sd;
int devtype;
-
- dev_st = get_boot_device(0);
- if (dev_st) {
- ccw_dev = s390_get_ccw_device(dev_st, &devtype);
- }
+ uint8_t *lp;
+ g_autofree void *scsi_lp = NULL;
/*
* Currently allow IPL only from CCW devices.
*/
+ ccw_dev = s390_get_ccw_device(dev_st, &devtype);
if (ccw_dev) {
+ lp = ccw_dev->loadparm;
+
switch (devtype) {
case CCW_DEVTYPE_SCSI:
sd = SCSI_DEVICE(dev_st);
- ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
- ipl->iplb.blk0_len =
+ scsi_lp = object_property_get_str(OBJECT(sd), "loadparm", NULL);
+ if (scsi_lp && strlen(scsi_lp) > 0) {
+ lp = scsi_lp;
+ }
+ iplb->len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
+ iplb->blk0_len =
cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
- ipl->iplb.pbt = S390_IPL_TYPE_QEMU_SCSI;
- ipl->iplb.scsi.lun = cpu_to_be32(sd->lun);
- ipl->iplb.scsi.target = cpu_to_be16(sd->id);
- ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
- ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
- ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
+ iplb->pbt = S390_IPL_TYPE_QEMU_SCSI;
+ iplb->scsi.lun = cpu_to_be32(sd->lun);
+ iplb->scsi.target = cpu_to_be16(sd->id);
+ iplb->scsi.channel = cpu_to_be16(sd->channel);
+ iplb->scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
+ iplb->scsi.ssid = ccw_dev->sch->ssid & 3;
break;
case CCW_DEVTYPE_VFIO:
- ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
- ipl->iplb.pbt = S390_IPL_TYPE_CCW;
- ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
- ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+ iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+ iplb->pbt = S390_IPL_TYPE_CCW;
+ iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+ iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
break;
case CCW_DEVTYPE_VIRTIO_NET:
- ipl->netboot = true;
- /* Fall through to CCW_DEVTYPE_VIRTIO case */
case CCW_DEVTYPE_VIRTIO:
- ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
- ipl->iplb.blk0_len =
+ iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+ iplb->blk0_len =
cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
- ipl->iplb.pbt = S390_IPL_TYPE_CCW;
- ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
- ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+ iplb->pbt = S390_IPL_TYPE_CCW;
+ iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+ iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
break;
}
- if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
- ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+ /* If the device loadparm is empty use the global machine loadparm */
+ if (memcmp(lp, NO_LOADPARM, 8) == 0) {
+ lp = S390_CCW_MACHINE(qdev_get_machine())->loadparm;
}
+ s390_ipl_convert_loadparm((char *)lp, iplb->loadparm);
+ iplb->flags |= DIAG308_FLAGS_LP_VALID;
+
return true;
}
return false;
}
-int s390_ipl_set_loadparm(uint8_t *loadparm)
+void s390_rebuild_iplb(uint16_t dev_index, IplParameterBlock *iplb)
{
- MachineState *machine = MACHINE(qdev_get_machine());
- char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
-
- if (lp) {
- int i;
-
- /* lp is an uppercase string without leading/embedded spaces */
- for (i = 0; i < 8 && lp[i]; i++) {
- loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
- }
-
- if (i < 8) {
- memset(loadparm + i, 0x40, 8 - i); /* fill with EBCDIC spaces */
- }
-
- g_free(lp);
- return 0;
- }
+ S390IPLState *ipl = get_ipl_device();
+ uint16_t index;
+ index = ipl->rebuilt_iplb ? ipl->iplb_index : dev_index;
- return -1;
+ ipl->rebuilt_iplb = s390_build_iplb(get_boot_device(index), iplb);
+ ipl->iplb_index = index;
}
-static int load_netboot_image(Error **errp)
+static bool s390_init_all_iplbs(S390IPLState *ipl)
{
- MachineState *ms = MACHINE(qdev_get_machine());
- S390IPLState *ipl = get_ipl_device();
- char *netboot_filename;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *mr = NULL;
- void *ram_ptr = NULL;
- int img_size = -1;
-
- mr = memory_region_find(sysmem, 0, 1).mr;
- if (!mr) {
- error_setg(errp, "Failed to find memory region at address 0");
- return -1;
- }
+ int iplb_num = 0;
+ IplParameterBlock iplb_chain[7];
+ DeviceState *dev_st = get_boot_device(0);
+ Object *machine = qdev_get_machine();
- ram_ptr = memory_region_get_ram_ptr(mr);
- if (!ram_ptr) {
- error_setg(errp, "No RAM found");
- goto unref_mr;
+ /*
+ * Parse the boot devices. Generate an IPLB for only the first boot device
+ * which will later be set with DIAG308.
+ */
+ if (!dev_st) {
+ ipl->qipl.chain_len = 0;
+ return false;
}
- netboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->netboot_fw);
- if (netboot_filename == NULL) {
- error_setg(errp, "Could not find network bootloader '%s'",
- ipl->netboot_fw);
- goto unref_mr;
+ /* If no machine loadparm was defined fill it with spaces */
+ if (memcmp(S390_CCW_MACHINE(machine)->loadparm, NO_LOADPARM, 8) == 0) {
+ object_property_set_str(machine, "loadparm", " ", NULL);
}
- img_size = load_elf_ram(netboot_filename, NULL, NULL, NULL,
- &ipl->start_addr,
- NULL, NULL, NULL, 1, EM_S390, 0, 0, NULL,
- false);
-
- if (img_size < 0) {
- img_size = load_image_size(netboot_filename, ram_ptr, ms->ram_size);
- ipl->start_addr = KERN_IMAGE_START;
- }
+ iplb_num = 1;
+ s390_build_iplb(dev_st, &ipl->iplb);
- if (img_size < 0) {
- error_setg(errp, "Failed to load network bootloader");
+ /* Index any fallback boot devices */
+ while (get_boot_device(iplb_num)) {
+ iplb_num++;
}
- g_free(netboot_filename);
-
-unref_mr:
- memory_region_unref(mr);
- return img_size;
-}
-
-static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
- int virtio_id)
-{
- uint8_t cssid;
- uint8_t ssid;
- uint16_t devno;
- uint16_t schid;
- SubchDev *sch = NULL;
+ if (iplb_num > MAX_BOOT_DEVS) {
+ warn_report("Excess boot devices defined! %d boot devices found, "
+ "but only the first %d will be considered.",
+ iplb_num, MAX_BOOT_DEVS);
- if (iplb->pbt != S390_IPL_TYPE_CCW) {
- return false;
+ iplb_num = MAX_BOOT_DEVS;
}
- devno = be16_to_cpu(iplb->ccw.devno);
- ssid = iplb->ccw.ssid & 3;
-
- for (schid = 0; schid < MAX_SCHID; schid++) {
- for (cssid = 0; cssid < MAX_CSSID; cssid++) {
- sch = css_find_subch(1, cssid, ssid, schid);
+ ipl->qipl.chain_len = cpu_to_be16(iplb_num - 1);
- if (sch && sch->devno == devno) {
- return sch->id.cu_model == virtio_id;
- }
+ /*
+ * Build fallback IPLBs for any boot devices above index 0, up to a
+ * maximum amount as defined in ipl.h
+ */
+ if (iplb_num > 1) {
+ /* Start at 1 because the IPLB for boot index 0 is not chained */
+ for (int i = 1; i < iplb_num; i++) {
+ dev_st = get_boot_device(i);
+ s390_build_iplb(dev_st, &iplb_chain[i - 1]);
}
- }
- return false;
-}
-static bool is_virtio_net_device(IplParameterBlock *iplb)
-{
- return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_NET);
-}
+ ipl->qipl.next_iplb = cpu_to_be64(s390_ipl_map_iplb_chain(iplb_chain));
+ }
-static bool is_virtio_scsi_device(IplParameterBlock *iplb)
-{
- return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
+ return iplb_num;
}
static void update_machine_ipl_properties(IplParameterBlock *iplb)
@@ -577,7 +568,7 @@ static void update_machine_ipl_properties(IplParameterBlock *iplb)
ascii_loadparm[i] = 0;
object_property_set_str(machine, "loadparm", ascii_loadparm, &err);
} else {
- object_property_set_str(machine, "loadparm", "", &err);
+ object_property_set_str(machine, "loadparm", " ", &err);
}
if (err) {
warn_report_err(err);
@@ -599,7 +590,7 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
ipl->iplb = *iplb;
ipl->iplb_valid = true;
}
- ipl->netboot = is_virtio_net_device(iplb);
+
update_machine_ipl_properties(iplb);
}
@@ -626,32 +617,14 @@ IplParameterBlock *s390_ipl_get_iplb(void)
void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
{
S390IPLState *ipl = get_ipl_device();
-
if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) {
/* use CPU 0 for full resets */
ipl->reset_cpu_index = 0;
} else {
ipl->reset_cpu_index = cs->cpu_index;
}
- ipl->reset_type = reset_type;
- if (reset_type == S390_RESET_REIPL &&
- ipl->iplb_valid &&
- !ipl->netboot &&
- ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
- is_virtio_scsi_device(&ipl->iplb)) {
- CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0), NULL);
-
- if (ccw_dev &&
- cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
- (ccw_dev->sch->ssid & 3) == ipl->iplb.ccw.ssid) {
- /*
- * this is the original boot device's SCSI
- * so restore IPL parameter info from it
- */
- ipl->iplb_valid = s390_gen_initial_iplb(ipl);
- }
- }
+ ipl->reset_type = reset_type;
if (reset_type == S390_RESET_MODIFIED_CLEAR ||
reset_type == S390_RESET_LOAD_NORMAL ||
reset_type == S390_RESET_PV) {
@@ -702,7 +675,7 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu)
cpu_physical_memory_unmap(addr, len, 1, len);
}
-int s390_ipl_prepare_pv_header(Error **errp)
+int s390_ipl_prepare_pv_header(struct S390PVResponse *pv_resp, Error **errp)
{
IplParameterBlock *ipib = s390_ipl_get_iplb_pv();
IPLBlockPV *ipib_pv = &ipib->pv;
@@ -711,12 +684,13 @@ int s390_ipl_prepare_pv_header(Error **errp)
cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr,
ipib_pv->pv_header_len);
- rc = s390_pv_set_sec_parms((uintptr_t)hdr, ipib_pv->pv_header_len, errp);
+ rc = s390_pv_set_sec_parms((uintptr_t)hdr, ipib_pv->pv_header_len,
+ pv_resp, errp);
g_free(hdr);
return rc;
}
-int s390_ipl_pv_unpack(void)
+int s390_ipl_pv_unpack(struct S390PVResponse *pv_resp)
{
IplParameterBlock *ipib = s390_ipl_get_iplb_pv();
IPLBlockPV *ipib_pv = &ipib->pv;
@@ -725,7 +699,8 @@ int s390_ipl_pv_unpack(void)
for (i = 0; i < ipib_pv->num_comp; i++) {
rc = s390_pv_unpack(ipib_pv->components[i].addr,
TARGET_PAGE_ALIGN(ipib_pv->components[i].size),
- ipib_pv->components[i].tweak_pref);
+ ipib_pv->components[i].tweak_pref,
+ pv_resp);
if (rc) {
break;
}
@@ -743,13 +718,11 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
if (!ipl->kernel || ipl->iplb_valid) {
cpu->env.psw.addr = ipl->bios_start_addr;
if (!ipl->iplb_valid) {
- ipl->iplb_valid = s390_gen_initial_iplb(ipl);
+ ipl->iplb_valid = s390_init_all_iplbs(ipl);
+ } else {
+ ipl->qipl.chain_len = 0;
}
}
- if (ipl->netboot) {
- load_netboot_image(&error_fatal);
- ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
- }
s390_ipl_set_boot_menu(ipl);
s390_ipl_prepare_qipl(cpu);
}
@@ -764,13 +737,13 @@ static void s390_ipl_reset(DeviceState *dev)
}
}
-static void s390_ipl_class_init(ObjectClass *klass, void *data)
+static void s390_ipl_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = s390_ipl_realize;
device_class_set_props(dc, s390_ipl_properties);
- dc->reset = s390_ipl_reset;
+ device_class_set_legacy_reset(dc, s390_ipl_reset);
dc->vmsd = &vmstate_ipl;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
/* Reason: Loads the ROMs and thus can only be used one time - internally */
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 57cd125..505cded 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -14,101 +14,24 @@
#define HW_S390_IPL_H
#include "cpu.h"
-#include "exec/address-spaces.h"
+#include "exec/target_page.h"
+#include "system/address-spaces.h"
+#include "system/memory.h"
#include "hw/qdev-core.h"
+#include "hw/s390x/ipl/qipl.h"
#include "qom/object.h"
-
-struct IPLBlockPVComp {
- uint64_t tweak_pref;
- uint64_t addr;
- uint64_t size;
-} QEMU_PACKED;
-typedef struct IPLBlockPVComp IPLBlockPVComp;
-
-struct IPLBlockPV {
- uint8_t reserved18[87]; /* 0x18 */
- uint8_t version; /* 0x6f */
- uint32_t reserved70; /* 0x70 */
- uint32_t num_comp; /* 0x74 */
- uint64_t pv_header_addr; /* 0x78 */
- uint64_t pv_header_len; /* 0x80 */
- struct IPLBlockPVComp components[0];
-} QEMU_PACKED;
-typedef struct IPLBlockPV IPLBlockPV;
-
-struct IplBlockCcw {
- uint8_t reserved0[85];
- uint8_t ssid;
- uint16_t devno;
- uint8_t vm_flags;
- uint8_t reserved3[3];
- uint32_t vm_parm_len;
- uint8_t nss_name[8];
- uint8_t vm_parm[64];
- uint8_t reserved4[8];
-} QEMU_PACKED;
-typedef struct IplBlockCcw IplBlockCcw;
-
-struct IplBlockFcp {
- uint8_t reserved1[305 - 1];
- uint8_t opt;
- uint8_t reserved2[3];
- uint16_t reserved3;
- uint16_t devno;
- uint8_t reserved4[4];
- uint64_t wwpn;
- uint64_t lun;
- uint32_t bootprog;
- uint8_t reserved5[12];
- uint64_t br_lba;
- uint32_t scp_data_len;
- uint8_t reserved6[260];
- uint8_t scp_data[0];
-} QEMU_PACKED;
-typedef struct IplBlockFcp IplBlockFcp;
-
-struct IplBlockQemuScsi {
- uint32_t lun;
- uint16_t target;
- uint16_t channel;
- uint8_t reserved0[77];
- uint8_t ssid;
- uint16_t devno;
-} QEMU_PACKED;
-typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+#include "target/s390x/kvm/pv.h"
#define DIAG308_FLAGS_LP_VALID 0x80
+#define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
-union IplParameterBlock {
- struct {
- uint32_t len;
- uint8_t reserved0[3];
- uint8_t version;
- uint32_t blk0_len;
- uint8_t pbt;
- uint8_t flags;
- uint16_t reserved01;
- uint8_t loadparm[8];
- union {
- IplBlockCcw ccw;
- IplBlockFcp fcp;
- IPLBlockPV pv;
- IplBlockQemuScsi scsi;
- };
- } QEMU_PACKED;
- struct {
- uint8_t reserved1[110];
- uint16_t devno;
- uint8_t reserved2[88];
- uint8_t reserved_ext[4096 - 200];
- } QEMU_PACKED;
-} QEMU_PACKED;
-typedef union IplParameterBlock IplParameterBlock;
-
-int s390_ipl_set_loadparm(uint8_t *loadparm);
+void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
+void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
+void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb);
void s390_ipl_update_diag308(IplParameterBlock *iplb);
-int s390_ipl_prepare_pv_header(Error **errp);
-int s390_ipl_pv_unpack(void);
+int s390_ipl_prepare_pv_header(struct S390PVResponse *pv_resp,
+ Error **errp);
+int s390_ipl_pv_unpack(struct S390PVResponse *pv_resp);
void s390_ipl_prepare_cpu(S390CPU *cpu);
IplParameterBlock *s390_ipl_get_iplb(void);
IplParameterBlock *s390_ipl_get_iplb_pv(void);
@@ -131,27 +54,6 @@ void s390_ipl_clear_reset_request(void);
#define QIPL_FLAG_BM_OPTS_CMD 0x80
#define QIPL_FLAG_BM_OPTS_ZIPL 0x40
-/*
- * The QEMU IPL Parameters will be stored at absolute address
- * 204 (0xcc) which means it is 32-bit word aligned but not
- * double-word aligned.
- * Placement of data fields in this area must account for
- * their alignment needs. E.g., netboot_start_address must
- * have an offset of 4 + n * 8 bytes within the struct in order
- * to keep it double-word aligned.
- * The total size of the struct must never exceed 28 bytes.
- * This definition must be kept in sync with the definition
- * in pc-bios/s390-ccw/iplb.h.
- */
-struct QemuIplParameters {
- uint8_t qipl_flags;
- uint8_t reserved1[3];
- uint64_t netboot_start_addr;
- uint32_t boot_menu_timeout;
- uint8_t reserved2[12];
-} QEMU_PACKED;
-typedef struct QemuIplParameters QemuIplParameters;
-
#define TYPE_S390_IPL "s390-ipl"
OBJECT_DECLARE_SIMPLE_TYPE(S390IPLState, S390_IPL)
@@ -168,7 +70,8 @@ struct S390IPLState {
bool enforce_bios;
bool iplb_valid;
bool iplb_valid_pv;
- bool netboot;
+ bool rebuilt_iplb;
+ uint16_t iplb_index;
/* reset related properties don't have to be migrated or reset */
enum s390_reset reset_type;
int reset_cpu_index;
@@ -178,11 +81,9 @@ struct S390IPLState {
char *initrd;
char *cmdline;
char *firmware;
- char *netboot_fw;
uint8_t cssid;
uint8_t ssid;
uint16_t devno;
- bool iplbext_migration;
};
QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
@@ -276,11 +177,14 @@ static inline bool iplb_valid_pv(IplParameterBlock *iplb)
static inline bool iplb_valid(IplParameterBlock *iplb)
{
+ uint32_t len = be32_to_cpu(iplb->len);
+
switch (iplb->pbt) {
case S390_IPL_TYPE_FCP:
- return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN;
+ return len >= S390_IPLB_MIN_FCP_LEN;
case S390_IPL_TYPE_CCW:
- return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN;
+ return len >= S390_IPLB_MIN_CCW_LEN;
+ case S390_IPL_TYPE_QEMU_SCSI:
default:
return false;
}
diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build
index 482fd13..1bc8583 100644
--- a/hw/s390x/meson.build
+++ b/hw/s390x/meson.build
@@ -12,8 +12,8 @@ s390x_ss.add(files(
's390-pci-inst.c',
's390-skeys.c',
's390-stattrib.c',
- 's390-virtio-hcall.c',
'sclp.c',
+ 'sclpcpi.c',
'sclpcpu.c',
'sclpquiesce.c',
'tod.c',
@@ -28,9 +28,13 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
'tod-tcg.c',
))
-s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files('s390-virtio-ccw.c'))
+s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files(
+ 's390-virtio-ccw.c',
+ 's390-hypercall.c',
+))
s390x_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('3270-ccw.c'))
s390x_ss.add(when: 'CONFIG_VFIO', if_true: files('s390-pci-vfio.c'))
+s390x_ss.add(when: 'CONFIG_VFIO_AP', if_false: files('ap-stub.c'))
virtio_ss = ss.source_set()
virtio_ss.add(files('virtio-ccw.c'))
@@ -48,8 +52,12 @@ endif
virtio_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-ccw.c'))
virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c'))
virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c'))
+virtio_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-ccw-md.c'))
+virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-ccw-mem.c'))
s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss)
+s390x_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-ccw-md-stubs.c'))
+
hw_arch += {'s390x': s390x_ss}
hw_s390x_modules = {}
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 3c09750..10c81a4 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -18,7 +18,7 @@
#include "hw/s390x/css.h"
#include "hw/s390x/css-bridge.h"
#include "hw/s390x/s390-ccw.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
IOInstEnding s390_ccw_cmd_request(SubchDev *sch)
{
@@ -175,7 +175,7 @@ static void s390_ccw_instance_init(Object *obj)
"/disk@0,0", DEVICE(obj));
}
-static void s390_ccw_class_init(ObjectClass *klass, void *data)
+static void s390_ccw_class_init(ObjectClass *klass, const void *data)
{
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/s390-hypercall.c b/hw/s390x/s390-hypercall.c
new file mode 100644
index 0000000..ac1b08b
--- /dev/null
+++ b/hw/s390x/s390-hypercall.c
@@ -0,0 +1,85 @@
+/*
+ * Support for QEMU/KVM hypercalls on s390
+ *
+ * Copyright 2012 IBM Corp.
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/s390-hypercall.h"
+#include "hw/s390x/ioinst.h"
+#include "hw/s390x/css.h"
+#include "virtio-ccw.h"
+
+static int handle_virtio_notify(uint64_t mem)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+
+ if (mem < ms->ram_size) {
+ /* Early printk */
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data)
+{
+ SubchDev *sch;
+ VirtIODevice *vdev;
+ int cssid, ssid, schid, m;
+ uint16_t vq_idx = data;
+
+ if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
+ return -EINVAL;
+ }
+ sch = css_find_subch(m, cssid, ssid, schid);
+ if (!sch || !css_subch_visible(sch)) {
+ return -EINVAL;
+ }
+
+ vdev = virtio_ccw_get_vdev(sch);
+ if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {
+ return -EINVAL;
+ }
+
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
+ virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx),
+ (data >> 16) & 0xFFFF);
+ }
+
+ virtio_queue_notify(vdev, vq_idx);
+ return 0;
+}
+
+static uint64_t handle_storage_limit(void)
+{
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
+
+ return s390_get_memory_limit(s390ms) - 1;
+}
+
+void handle_diag_500(S390CPU *cpu, uintptr_t ra)
+{
+ CPUS390XState *env = &cpu->env;
+ const uint64_t subcode = env->regs[1];
+
+ switch (subcode) {
+ case DIAG500_VIRTIO_NOTIFY:
+ env->regs[2] = handle_virtio_notify(env->regs[2]);
+ break;
+ case DIAG500_VIRTIO_CCW_NOTIFY:
+ env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]);
+ break;
+ case DIAG500_STORAGE_LIMIT:
+ env->regs[2] = handle_storage_limit();
+ break;
+ default:
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+}
diff --git a/hw/s390x/s390-hypercall.h b/hw/s390x/s390-hypercall.h
new file mode 100644
index 0000000..4f07209
--- /dev/null
+++ b/hw/s390x/s390-hypercall.h
@@ -0,0 +1,25 @@
+/*
+ * Support for QEMU/KVM hypercalls on s390x
+ *
+ * Copyright IBM Corp. 2012, 2017
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef HW_S390_HYPERCALL_H
+#define HW_S390_HYPERCALL_H
+
+#include "cpu.h"
+
+#define DIAG500_VIRTIO_NOTIFY 0 /* legacy, implemented as a NOP */
+#define DIAG500_VIRTIO_RESET 1 /* legacy */
+#define DIAG500_VIRTIO_SET_STATUS 2 /* legacy */
+#define DIAG500_VIRTIO_CCW_NOTIFY 3 /* KVM_S390_VIRTIO_CCW_NOTIFY */
+#define DIAG500_STORAGE_LIMIT 4
+
+void handle_diag_500(S390CPU *cpu, uintptr_t ra);
+
+#endif /* HW_S390_HYPERCALL_H */
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 3e57d5f..e6aa445 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -14,18 +14,21 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
+#include "exec/target_page.h"
#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/s390-pci-inst.h"
#include "hw/s390x/s390-pci-kvm.h"
#include "hw/s390x/s390-pci-vfio.h"
+#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/boards.h"
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/msi.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "trace.h"
@@ -595,7 +598,6 @@ static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu,
* zpci device" construct. But when we support migration of vfio-pci
* devices in future, we need to revisit this.
*/
- return;
}
static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus,
@@ -724,12 +726,42 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
g_free(name);
}
+void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(ms);
+
+ /*
+ * For direct-mapping we must map the entire guest address space. Rather
+ * than using an iommu, create a memory region alias that maps GPA X to
+ * IOVA X + SDMA. VFIO will handle pinning via its memory listener.
+ */
+ g_autofree char *name = g_strdup_printf("iommu-dm-s390-%04x",
+ iommu->pbdev->uid);
+
+ iommu->dm_mr = g_malloc0(sizeof(*iommu->dm_mr));
+ memory_region_init_alias(iommu->dm_mr, OBJECT(&iommu->mr), name,
+ get_system_memory(), 0,
+ s390_get_memory_limit(s390ms));
+ iommu->enabled = true;
+ memory_region_add_subregion(&iommu->mr, iommu->pbdev->zpci_fn.sdma,
+ iommu->dm_mr);
+}
+
void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
{
iommu->enabled = false;
g_hash_table_remove_all(iommu->iotlb);
- memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&iommu->iommu_mr));
- object_unparent(OBJECT(&iommu->iommu_mr));
+ if (iommu->dm_mr) {
+ memory_region_del_subregion(&iommu->mr, iommu->dm_mr);
+ object_unparent(OBJECT(iommu->dm_mr));
+ g_free(iommu->dm_mr);
+ iommu->dm_mr = NULL;
+ } else {
+ memory_region_del_subregion(&iommu->mr,
+ MEMORY_REGION(&iommu->iommu_mr));
+ object_unparent(OBJECT(&iommu->iommu_mr));
+ }
}
static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn)
@@ -971,14 +1003,7 @@ static void s390_pcihost_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
"this device");
}
- if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
- PCIDevice *pdev = PCI_DEVICE(dev);
-
- if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
- error_setg(errp, "multifunction not supported in s390");
- return;
- }
- } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
+ if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev);
if (!s390_pci_alloc_idx(s, pbdev)) {
@@ -1069,6 +1094,18 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
pdev = PCI_DEVICE(dev);
+ /*
+ * Multifunction is not supported due to the lack of CLP. However,
+ * do not check for multifunction capability for SR-IOV devices because
+ * SR-IOV devices automatically add the multifunction capability whether
+ * the user intends to use the functions other than the PF.
+ */
+ if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION &&
+ !pdev->exp.sriov_cap) {
+ error_setg(errp, "multifunction not supported in s390");
+ return;
+ }
+
if (!dev->id) {
/* In the case the PCI device does not define an id */
/* we generate one based on the PCI address */
@@ -1080,6 +1117,16 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
pbdev = s390_pci_find_dev_by_target(s, dev->id);
if (!pbdev) {
+ /*
+ * VFs are automatically created by PF, and creating zpci for them
+ * will result in unexpected usage of fids. Currently QEMU does not
+ * support multifunction for s390x so we don't need zpci for VFs
+ * anyway.
+ */
+ if (pci_is_vf(pdev)) {
+ return;
+ }
+
pbdev = s390_pci_device_new(s, dev->id, errp);
if (!pbdev) {
return;
@@ -1130,6 +1177,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
/* Always intercept emulated devices */
pbdev->interp = false;
pbdev->forwarding_assist = false;
+ pbdev->rtr_avail = false;
}
if (s390_pci_msix_init(pbdev) && !pbdev->interp) {
@@ -1167,7 +1215,10 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
int32_t devfn;
pbdev = s390_pci_find_dev_by_pci(s, PCI_DEVICE(dev));
- g_assert(pbdev);
+ if (!pbdev) {
+ g_assert(pci_is_vf(pci_dev));
+ return;
+ }
s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
pbdev->fh, pbdev->fid);
@@ -1206,7 +1257,11 @@ static void s390_pcihost_unplug_request(HotplugHandler *hotplug_dev,
* we've checked the PCI device already (to prevent endless recursion).
*/
pbdev = s390_pci_find_dev_by_pci(s, PCI_DEVICE(dev));
- g_assert(pbdev);
+ if (!pbdev) {
+ g_assert(pci_is_vf(PCI_DEVICE(dev)));
+ return;
+ }
+
pbdev->pci_unplug_request_processed = true;
qdev_unplug(DEVICE(pbdev), errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
@@ -1318,12 +1373,12 @@ static void s390_pcihost_reset(DeviceState *dev)
pci_for_each_device_under_bus(bus, s390_pci_enumerate_bridge, s);
}
-static void s390_pcihost_class_init(ObjectClass *klass, void *data)
+static void s390_pcihost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
- dc->reset = s390_pcihost_reset;
+ device_class_set_legacy_reset(dc, s390_pcihost_reset);
dc->realize = s390_pcihost_realize;
dc->unrealize = s390_pcihost_unrealize;
hc->pre_plug = s390_pcihost_pre_plug;
@@ -1338,7 +1393,7 @@ static const TypeInfo s390_pcihost_info = {
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(S390pciState),
.class_init = s390_pcihost_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
@@ -1453,7 +1508,7 @@ static void s390_pci_device_reset(DeviceState *dev)
static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint32(v, name, ptr, errp);
@@ -1463,7 +1518,7 @@ static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
S390PCIBusDevice *zpci = S390_PCI_DEVICE(obj);
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
if (!visit_type_uint32(v, name, ptr, errp)) {
@@ -1473,7 +1528,8 @@ static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name,
}
static const PropertyInfo s390_pci_fid_propinfo = {
- .name = "zpci_fid",
+ .type = "uint32",
+ .description = "zpci_fid",
.get = s390_pci_get_fid,
.set = s390_pci_set_fid,
};
@@ -1481,14 +1537,15 @@ static const PropertyInfo s390_pci_fid_propinfo = {
#define DEFINE_PROP_S390_PCI_FID(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, s390_pci_fid_propinfo, uint32_t)
-static Property s390_pci_device_properties[] = {
+static const Property s390_pci_device_properties[] = {
DEFINE_PROP_UINT16("uid", S390PCIBusDevice, uid, UID_UNDEFINED),
DEFINE_PROP_S390_PCI_FID("fid", S390PCIBusDevice, fid),
DEFINE_PROP_STRING("target", S390PCIBusDevice, target),
DEFINE_PROP_BOOL("interpret", S390PCIBusDevice, interp, true),
DEFINE_PROP_BOOL("forwarding-assist", S390PCIBusDevice, forwarding_assist,
true),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("relaxed-translation", S390PCIBusDevice, rtr_avail,
+ true),
};
static const VMStateDescription s390_pci_device_vmstate = {
@@ -1500,13 +1557,13 @@ static const VMStateDescription s390_pci_device_vmstate = {
.unmigratable = 1,
};
-static void s390_pci_device_class_init(ObjectClass *klass, void *data)
+static void s390_pci_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "zpci device";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = s390_pci_device_reset;
+ device_class_set_legacy_reset(dc, s390_pci_device_reset);
dc->bus_type = TYPE_S390_PCI_BUS;
dc->realize = s390_pci_device_realize;
device_class_set_props(dc, s390_pci_device_properties);
@@ -1526,7 +1583,8 @@ static const TypeInfo s390_pci_iommu_info = {
.instance_size = sizeof(S390PCIIOMMU),
};
-static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+static void s390_iommu_memory_region_class_init(ObjectClass *klass,
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 3014954..b5dddb2 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -13,9 +13,11 @@
#include "qemu/osdep.h"
#include "exec/memop.h"
-#include "exec/memory.h"
+#include "exec/target_page.h"
+#include "system/memory.h"
#include "qemu/error-report.h"
-#include "sysemu/hw_accel.h"
+#include "system/hw_accel.h"
+#include "hw/boards.h"
#include "hw/pci/pci_device.h"
#include "hw/s390x/s390-pci-inst.h"
#include "hw/s390x/s390-pci-bus.h"
@@ -55,26 +57,26 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
uint64_t resume_token;
rc = 0;
- if (lduw_p(&rrb->request.hdr.len) != 32) {
+ if (lduw_be_p(&rrb->request.hdr.len) != 32) {
res_code = CLP_RC_LEN;
rc = -EINVAL;
goto out;
}
- if ((ldl_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) {
+ if ((ldl_be_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) {
res_code = CLP_RC_FMT;
rc = -EINVAL;
goto out;
}
- if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 ||
- ldq_p(&rrb->request.reserved1) != 0) {
+ if ((ldl_be_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 ||
+ ldq_be_p(&rrb->request.reserved1) != 0) {
res_code = CLP_RC_RESNOT0;
rc = -EINVAL;
goto out;
}
- resume_token = ldq_p(&rrb->request.resume_token);
+ resume_token = ldq_be_p(&rrb->request.resume_token);
if (resume_token) {
pbdev = s390_pci_find_dev_by_idx(s, resume_token);
@@ -87,13 +89,13 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
pbdev = s390_pci_find_next_avail_dev(s, NULL);
}
- if (lduw_p(&rrb->response.hdr.len) < 48) {
+ if (lduw_be_p(&rrb->response.hdr.len) < 48) {
res_code = CLP_RC_8K;
rc = -EINVAL;
goto out;
}
- initial_l2 = lduw_p(&rrb->response.hdr.len);
+ initial_l2 = lduw_be_p(&rrb->response.hdr.len);
if ((initial_l2 - LIST_PCI_HDR_LEN) % sizeof(ClpFhListEntry)
!= 0) {
res_code = CLP_RC_LEN;
@@ -102,33 +104,33 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
goto out;
}
- stl_p(&rrb->response.fmt, 0);
- stq_p(&rrb->response.reserved1, 0);
- stl_p(&rrb->response.mdd, FH_MASK_SHM);
- stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS);
+ stl_be_p(&rrb->response.fmt, 0);
+ stq_be_p(&rrb->response.reserved1, 0);
+ stl_be_p(&rrb->response.mdd, FH_MASK_SHM);
+ stw_be_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS);
rrb->response.flags = UID_CHECKING_ENABLED;
rrb->response.entry_size = sizeof(ClpFhListEntry);
i = 0;
g_l2 = LIST_PCI_HDR_LEN;
while (g_l2 < initial_l2 && pbdev) {
- stw_p(&rrb->response.fh_list[i].device_id,
+ stw_be_p(&rrb->response.fh_list[i].device_id,
pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
- stw_p(&rrb->response.fh_list[i].vendor_id,
+ stw_be_p(&rrb->response.fh_list[i].vendor_id,
pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
/* Ignore RESERVED devices. */
- stl_p(&rrb->response.fh_list[i].config,
+ stl_be_p(&rrb->response.fh_list[i].config,
pbdev->state == ZPCI_FS_STANDBY ? 0 : 1 << 31);
- stl_p(&rrb->response.fh_list[i].fid, pbdev->fid);
- stl_p(&rrb->response.fh_list[i].fh, pbdev->fh);
+ stl_be_p(&rrb->response.fh_list[i].fid, pbdev->fid);
+ stl_be_p(&rrb->response.fh_list[i].fh, pbdev->fh);
g_l2 += sizeof(ClpFhListEntry);
/* Add endian check for DPRINTF? */
trace_s390_pci_list_entry(g_l2,
- lduw_p(&rrb->response.fh_list[i].vendor_id),
- lduw_p(&rrb->response.fh_list[i].device_id),
- ldl_p(&rrb->response.fh_list[i].fid),
- ldl_p(&rrb->response.fh_list[i].fh));
+ lduw_be_p(&rrb->response.fh_list[i].vendor_id),
+ lduw_be_p(&rrb->response.fh_list[i].device_id),
+ ldl_be_p(&rrb->response.fh_list[i].fid),
+ ldl_be_p(&rrb->response.fh_list[i].fh));
pbdev = s390_pci_find_next_avail_dev(s, pbdev);
i++;
}
@@ -138,13 +140,13 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
} else {
resume_token = pbdev->fh & FH_MASK_INDEX;
}
- stq_p(&rrb->response.resume_token, resume_token);
- stw_p(&rrb->response.hdr.len, g_l2);
- stw_p(&rrb->response.hdr.rsp, CLP_RC_OK);
+ stq_be_p(&rrb->response.resume_token, resume_token);
+ stw_be_p(&rrb->response.hdr.len, g_l2);
+ stw_be_p(&rrb->response.hdr.rsp, CLP_RC_OK);
out:
if (rc) {
trace_s390_pci_list(rc);
- stw_p(&rrb->response.hdr.rsp, res_code);
+ stw_be_p(&rrb->response.hdr.rsp, res_code);
}
return rc;
}
@@ -172,7 +174,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
return 0;
}
reqh = (ClpReqHdr *)buffer;
- req_len = lduw_p(&reqh->len);
+ req_len = lduw_be_p(&reqh->len);
if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return 0;
@@ -184,7 +186,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
return 0;
}
resh = (ClpRspHdr *)(buffer + req_len);
- res_len = lduw_p(&resh->len);
+ res_len = lduw_be_p(&resh->len);
if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return 0;
@@ -201,11 +203,11 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
}
if (req_len != 32) {
- stw_p(&resh->rsp, CLP_RC_LEN);
+ stw_be_p(&resh->rsp, CLP_RC_LEN);
goto out;
}
- switch (lduw_p(&reqh->cmd)) {
+ switch (lduw_be_p(&reqh->cmd)) {
case CLP_LIST_PCI: {
ClpReqRspListPci *rrb = (ClpReqRspListPci *)buffer;
list_pci(rrb, &cc);
@@ -215,9 +217,9 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh;
ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh;
- pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqsetpci->fh));
+ pbdev = s390_pci_find_dev_by_fh(s, ldl_be_p(&reqsetpci->fh));
if (!pbdev) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out;
}
@@ -225,17 +227,17 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
case CLP_SET_ENABLE_PCI_FN:
switch (reqsetpci->ndas) {
case 0:
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS);
goto out;
case 1:
break;
default:
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES);
goto out;
}
if (pbdev->fh & FH_MASK_ENABLE) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
goto out;
}
@@ -249,29 +251,29 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
/* Take this opportunity to make sure we are sync'd with host */
if (!s390_pci_get_host_fh(pbdev, &pbdev->fh) ||
!(pbdev->fh & FH_MASK_ENABLE)) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out;
}
}
pbdev->fh |= FH_MASK_ENABLE;
pbdev->state = ZPCI_FS_ENABLED;
- stl_p(&ressetpci->fh, pbdev->fh);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
+ stl_be_p(&ressetpci->fh, pbdev->fh);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
case CLP_SET_DISABLE_PCI_FN:
if (!(pbdev->fh & FH_MASK_ENABLE)) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
goto out;
}
device_cold_reset(DEVICE(pbdev));
pbdev->fh &= ~FH_MASK_ENABLE;
pbdev->state = ZPCI_FS_DISABLED;
- stl_p(&ressetpci->fh, pbdev->fh);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
+ stl_be_p(&ressetpci->fh, pbdev->fh);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
default:
trace_s390_pci_unknown("set-pci", reqsetpci->oc);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
break;
}
break;
@@ -280,23 +282,23 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh;
ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh;
- pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqquery->fh));
+ pbdev = s390_pci_find_dev_by_fh(s, ldl_be_p(&reqquery->fh));
if (!pbdev) {
- trace_s390_pci_nodev("query", ldl_p(&reqquery->fh));
- stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
+ trace_s390_pci_nodev("query", ldl_be_p(&reqquery->fh));
+ stw_be_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out;
}
- stq_p(&resquery->sdma, pbdev->zpci_fn.sdma);
- stq_p(&resquery->edma, pbdev->zpci_fn.edma);
- stw_p(&resquery->pchid, pbdev->zpci_fn.pchid);
- stw_p(&resquery->vfn, pbdev->zpci_fn.vfn);
+ stq_be_p(&resquery->sdma, pbdev->zpci_fn.sdma);
+ stq_be_p(&resquery->edma, pbdev->zpci_fn.edma);
+ stw_be_p(&resquery->pchid, pbdev->zpci_fn.pchid);
+ stw_be_p(&resquery->vfn, pbdev->zpci_fn.vfn);
resquery->flags = pbdev->zpci_fn.flags;
resquery->pfgid = pbdev->zpci_fn.pfgid;
resquery->pft = pbdev->zpci_fn.pft;
resquery->fmbl = pbdev->zpci_fn.fmbl;
- stl_p(&resquery->fid, pbdev->zpci_fn.fid);
- stl_p(&resquery->uid, pbdev->zpci_fn.uid);
+ stl_be_p(&resquery->fid, pbdev->zpci_fn.fid);
+ stl_be_p(&resquery->uid, pbdev->zpci_fn.uid);
memcpy(resquery->pfip, pbdev->zpci_fn.pfip, CLP_PFIP_NR_SEGMENTS);
memcpy(resquery->util_str, pbdev->zpci_fn.util_str, CLP_UTIL_STR_LEN);
@@ -304,16 +306,16 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
uint32_t data = pci_get_long(pbdev->pdev->config +
PCI_BASE_ADDRESS_0 + (i * 4));
- stl_p(&resquery->bar[i], data);
+ stl_be_p(&resquery->bar[i], data);
resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ?
ctz64(pbdev->pdev->io_regions[i].size) : 0;
trace_s390_pci_bar(i,
- ldl_p(&resquery->bar[i]),
+ ldl_be_p(&resquery->bar[i]),
pbdev->pdev->io_regions[i].size,
resquery->bar_size[i]);
}
- stw_p(&resquery->hdr.rsp, CLP_RC_OK);
+ stw_be_p(&resquery->hdr.rsp, CLP_RC_OK);
break;
}
case CLP_QUERY_PCI_FNGRP: {
@@ -326,23 +328,23 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
if (!group) {
/* We do not allow access to unknown groups */
/* The group must have been obtained with a vfio device */
- stw_p(&resgrp->hdr.rsp, CLP_RC_QUERYPCIFG_PFGID);
+ stw_be_p(&resgrp->hdr.rsp, CLP_RC_QUERYPCIFG_PFGID);
goto out;
}
resgrp->fr = group->zpci_group.fr;
- stq_p(&resgrp->dasm, group->zpci_group.dasm);
- stq_p(&resgrp->msia, group->zpci_group.msia);
- stw_p(&resgrp->mui, group->zpci_group.mui);
- stw_p(&resgrp->i, group->zpci_group.i);
- stw_p(&resgrp->maxstbl, group->zpci_group.maxstbl);
+ stq_be_p(&resgrp->dasm, group->zpci_group.dasm);
+ stq_be_p(&resgrp->msia, group->zpci_group.msia);
+ stw_be_p(&resgrp->mui, group->zpci_group.mui);
+ stw_be_p(&resgrp->i, group->zpci_group.i);
+ stw_be_p(&resgrp->maxstbl, group->zpci_group.maxstbl);
resgrp->version = group->zpci_group.version;
resgrp->dtsm = group->zpci_group.dtsm;
- stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
+ stw_be_p(&resgrp->hdr.rsp, CLP_RC_OK);
break;
}
default:
- trace_s390_pci_unknown("clp", lduw_p(&reqh->cmd));
- stw_p(&resh->rsp, CLP_RC_CMD);
+ trace_s390_pci_unknown("clp", lduw_be_p(&reqh->cmd));
+ stw_be_p(&resh->rsp, CLP_RC_CMD);
break;
}
@@ -914,7 +916,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
for (i = 0; i < len / 8; i++) {
result = memory_region_dispatch_write(mr, offset + i * 8,
- ldq_p(buffer + i * 8),
+ ldq_be_p(buffer + i * 8),
MO_64, MEMTXATTRS_UNSPECIFIED);
if (result != MEMTX_OK) {
s390_program_interrupt(env, PGM_OPERAND, ra);
@@ -935,13 +937,13 @@ specification_error:
static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
{
int ret, len;
- uint8_t isc = FIB_DATA_ISC(ldl_p(&fib.data));
+ uint8_t isc = FIB_DATA_ISC(ldl_be_p(&fib.data));
pbdev->routes.adapter.adapter_id = css_get_adapter_id(
CSS_IO_ADAPTER_PCI, isc);
- pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t));
- len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
- pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
+ pbdev->summary_ind = get_indicator(ldq_be_p(&fib.aisb), sizeof(uint64_t));
+ len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_be_p(&fib.data))) * sizeof(unsigned long);
+ pbdev->indicator = get_indicator(ldq_be_p(&fib.aibv), len);
ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
if (ret) {
@@ -953,13 +955,13 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
goto out;
}
- pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
- pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
- pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv);
- pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data));
+ pbdev->routes.adapter.summary_addr = ldq_be_p(&fib.aisb);
+ pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_be_p(&fib.data));
+ pbdev->routes.adapter.ind_addr = ldq_be_p(&fib.aibv);
+ pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_be_p(&fib.data));
pbdev->isc = isc;
- pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data));
- pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data));
+ pbdev->noi = FIB_DATA_NOI(ldl_be_p(&fib.data));
+ pbdev->sum = FIB_DATA_SUM(ldl_be_p(&fib.data));
trace_s390_pci_irqs("register", pbdev->routes.adapter.adapter_id);
return 0;
@@ -994,9 +996,9 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib,
uintptr_t ra)
{
S390PCIIOMMU *iommu = pbdev->iommu;
- uint64_t pba = ldq_p(&fib.pba);
- uint64_t pal = ldq_p(&fib.pal);
- uint64_t g_iota = ldq_p(&fib.iota);
+ uint64_t pba = ldq_be_p(&fib.pba);
+ uint64_t pal = ldq_be_p(&fib.pal);
+ uint64_t g_iota = ldq_be_p(&fib.iota);
uint8_t dt = (g_iota >> 2) & 0x7;
uint8_t t = (g_iota >> 11) & 0x1;
@@ -1008,17 +1010,25 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib,
}
/* currently we only support designation type 1 with translation */
- if (!(dt == ZPCI_IOTA_RTTO && t)) {
+ if (t && dt != ZPCI_IOTA_RTTO) {
error_report("unsupported ioat dt %d t %d", dt, t);
s390_program_interrupt(env, PGM_OPERAND, ra);
return -EINVAL;
+ } else if (!t && !pbdev->rtr_avail) {
+ error_report("relaxed translation not allowed");
+ s390_program_interrupt(env, PGM_OPERAND, ra);
+ return -EINVAL;
}
iommu->pba = pba;
iommu->pal = pal;
iommu->g_iota = g_iota;
- s390_pci_iommu_enable(iommu);
+ if (t) {
+ s390_pci_iommu_enable(iommu);
+ } else {
+ s390_pci_iommu_direct_map_enable(iommu);
+ }
return 0;
}
@@ -1289,7 +1299,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
}
break;
case ZPCI_MOD_FC_SET_MEASURE: {
- uint64_t fmb_addr = ldq_p(&fib.fmb_addr);
+ uint64_t fmb_addr = ldq_be_p(&fib.fmb_addr);
if (fmb_addr & FMBK_MASK) {
cc = ZPCI_PCI_LS_ERR;
@@ -1399,17 +1409,17 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
return 0;
}
- stq_p(&fib.pba, pbdev->iommu->pba);
- stq_p(&fib.pal, pbdev->iommu->pal);
- stq_p(&fib.iota, pbdev->iommu->g_iota);
- stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
- stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
- stq_p(&fib.fmb_addr, pbdev->fmb_addr);
+ stq_be_p(&fib.pba, pbdev->iommu->pba);
+ stq_be_p(&fib.pal, pbdev->iommu->pal);
+ stq_be_p(&fib.iota, pbdev->iommu->g_iota);
+ stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
+ stq_be_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
+ stq_be_p(&fib.fmb_addr, pbdev->fmb_addr);
data = ((uint32_t)pbdev->isc << 28) | ((uint32_t)pbdev->noi << 16) |
((uint32_t)pbdev->routes.adapter.ind_offset << 8) |
((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
- stl_p(&fib.data, data);
+ stl_be_p(&fib.data, data);
out:
if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c
index 7dbbc76..aaf9131 100644
--- a/hw/s390x/s390-pci-vfio.c
+++ b/hw/s390x/s390-pci-vfio.c
@@ -20,7 +20,8 @@
#include "hw/s390x/s390-pci-clp.h"
#include "hw/s390x/s390-pci-vfio.h"
#include "hw/vfio/pci.h"
-#include "hw/vfio/vfio-common.h"
+#include "hw/vfio/vfio-container.h"
+#include "hw/vfio/vfio-helpers.h"
/*
* Get the current DMA available count from vfio. Returns true if vfio is
@@ -132,12 +133,27 @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev,
pbdev->pft = cap->pft;
/*
+ * If the device is a passthrough ISM device, disallow relaxed
+ * translation.
+ */
+ if (pbdev->pft == ZPCI_PFT_ISM) {
+ pbdev->rtr_avail = false;
+ }
+
+ /*
* If appropriate, reduce the size of the supported DMA aperture reported
- * to the guest based upon the vfio DMA limit.
+ * to the guest based upon the vfio DMA limit. This is applicable for
+ * devices that are guaranteed to not use relaxed translation. If the
+ * device is capable of relaxed translation then we must advertise the
+ * full aperture. In this case, if translation is used then we will
+ * rely on the vfio DMA limit counting and use RPCIT CC1 / status 16
+ * to request that the guest free DMA mappings as necessary.
*/
- vfio_size = pbdev->iommu->max_dma_limit << TARGET_PAGE_BITS;
- if (vfio_size > 0 && vfio_size < cap->end_dma - cap->start_dma + 1) {
- pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1;
+ if (!pbdev->rtr_avail) {
+ vfio_size = pbdev->iommu->max_dma_limit << TARGET_PAGE_BITS;
+ if (vfio_size > 0 && vfio_size < cap->end_dma - cap->start_dma + 1) {
+ pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1;
+ }
}
}
@@ -223,8 +239,11 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev,
pbdev->pci_group = s390_group_create(pbdev->zpci_fn.pfgid, start_gid);
resgrp = &pbdev->pci_group->zpci_group;
+ if (pbdev->rtr_avail) {
+ resgrp->fr |= CLP_RSP_QPCIG_MASK_RTR;
+ }
if (cap->flags & VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH) {
- resgrp->fr = 1;
+ resgrp->fr |= CLP_RSP_QPCIG_MASK_REFRESH;
}
resgrp->dasm = cap->dasm;
resgrp->msia = cap->msi_addr;
@@ -349,6 +368,4 @@ void s390_pci_get_clp_info(S390PCIBusDevice *pbdev)
s390_pci_read_group(pbdev, info);
s390_pci_read_util(pbdev, info);
s390_pci_read_pfip(pbdev, info);
-
- return;
}
diff --git a/hw/s390x/s390-skeys-kvm.c b/hw/s390x/s390-skeys-kvm.c
index 3ff9d94..f3056d6 100644
--- a/hw/s390x/s390-skeys-kvm.c
+++ b/hw/s390x/s390-skeys-kvm.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "hw/s390x/storage-keys.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
@@ -52,7 +52,7 @@ static int kvm_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
return kvm_vm_ioctl(kvm_state, KVM_S390_SET_SKEYS, &args);
}
-static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data)
+static void kvm_s390_skeys_class_init(ObjectClass *oc, const void *data)
{
S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index bf22d68..8eeecfd 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -11,16 +11,17 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "hw/boards.h"
+#include "exec/target_page.h"
+#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/storage-keys.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc-target.h"
-#include "qapi/qmp/qdict.h"
+#include "qapi/qapi-commands-machine.h"
+#include "qobject/qdict.h"
#include "qemu/error-report.h"
-#include "sysemu/memory_mapping.h"
-#include "exec/address-spaces.h"
-#include "sysemu/kvm.h"
+#include "system/memory_mapping.h"
+#include "system/address-spaces.h"
+#include "system/kvm.h"
#include "migration/qemu-file-types.h"
#include "migration/register.h"
#include "trace.h"
@@ -142,7 +143,7 @@ void hmp_dump_skeys(Monitor *mon, const QDict *qdict)
}
}
-void qmp_dump_skeys(const char *filename, Error **errp)
+void s390_qmp_dump_skeys(const char *filename, Error **errp)
{
S390SKeysState *ss = s390_get_skeys_device();
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
@@ -251,9 +252,9 @@ static bool qemu_s390_enable_skeys(S390SKeysState *ss)
* g_once_init_enter() is good enough.
*/
if (g_once_init_enter(&initialized)) {
- MachineState *machine = MACHINE(qdev_get_machine());
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
- skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
+ skeys->key_count = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE;
skeys->keydata = g_malloc0(skeys->key_count);
g_once_init_leave(&initialized, 1);
}
@@ -302,7 +303,7 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
return 0;
}
-static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
+static void qemu_s390_skeys_class_init(ObjectClass *oc, const void *data)
{
S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -316,14 +317,6 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
dc->user_creatable = false;
}
-static const TypeInfo qemu_s390_skeys_info = {
- .name = TYPE_QEMU_S390_SKEYS,
- .parent = TYPE_S390_SKEYS,
- .instance_size = sizeof(QEMUS390SKeysState),
- .class_init = qemu_s390_skeys_class_init,
- .class_size = sizeof(S390SKeysClass),
-};
-
static void s390_storage_keys_save(QEMUFile *f, void *opaque)
{
S390SKeysState *ss = S390_SKEYS(opaque);
@@ -469,40 +462,39 @@ static void s390_skeys_realize(DeviceState *dev, Error **errp)
{
S390SKeysState *ss = S390_SKEYS(dev);
- if (ss->migration_enabled) {
- register_savevm_live(TYPE_S390_SKEYS, 0, 1,
- &savevm_s390_storage_keys, ss);
- }
+ register_savevm_live(TYPE_S390_SKEYS, 0, 1, &savevm_s390_storage_keys, ss);
}
-static Property s390_skeys_props[] = {
- DEFINE_PROP_BOOL("migration-enabled", S390SKeysState, migration_enabled, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void s390_skeys_class_init(ObjectClass *oc, void *data)
+static void s390_skeys_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->hotpluggable = false;
dc->realize = s390_skeys_realize;
- device_class_set_props(dc, s390_skeys_props);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
-static const TypeInfo s390_skeys_info = {
- .name = TYPE_S390_SKEYS,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(S390SKeysState),
- .class_init = s390_skeys_class_init,
- .class_size = sizeof(S390SKeysClass),
- .abstract = true,
+static const TypeInfo s390_skeys_types[] = {
+ {
+ .name = TYPE_DUMP_SKEYS_INTERFACE,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(DumpSKeysInterface),
+ },
+ {
+ .name = TYPE_S390_SKEYS,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(S390SKeysState),
+ .class_init = s390_skeys_class_init,
+ .class_size = sizeof(S390SKeysClass),
+ .abstract = true,
+ },
+ {
+ .name = TYPE_QEMU_S390_SKEYS,
+ .parent = TYPE_S390_SKEYS,
+ .instance_size = sizeof(QEMUS390SKeysState),
+ .class_init = qemu_s390_skeys_class_init,
+ .class_size = sizeof(S390SKeysClass),
+ },
};
-static void qemu_s390_skeys_register_types(void)
-{
- type_register_static(&s390_skeys_info);
- type_register_static(&qemu_s390_skeys_info);
-}
-
-type_init(qemu_s390_skeys_register_types)
+DEFINE_TYPES(s390_skeys_types)
diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c
index eeaa811..e1fee36 100644
--- a/hw/s390x/s390-stattrib-kvm.c
+++ b/hw/s390x/s390-stattrib-kvm.c
@@ -10,12 +10,13 @@
*/
#include "qemu/osdep.h"
-#include "hw/boards.h"
+#include "hw/s390x/s390-virtio-ccw.h"
#include "migration/qemu-file.h"
#include "hw/s390x/storage-attributes.h"
#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "exec/ram_addr.h"
+#include "system/kvm.h"
+#include "system/memory_mapping.h"
+#include "system/ram_addr.h"
#include "kvm/kvm_s390x.h"
#include "qapi/error.h"
@@ -84,8 +85,8 @@ static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa,
uint8_t *values)
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
- MachineState *machine = MACHINE(qdev_get_machine());
- unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
+ unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE;
if (start_gfn + count > max) {
error_report("Out of memory bounds when setting storage attributes");
@@ -103,39 +104,57 @@ static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa,
static void kvm_s390_stattrib_synchronize(S390StAttribState *sa)
{
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
- MachineState *machine = MACHINE(qdev_get_machine());
- unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
- /* We do not need to reach the maximum buffer size allowed */
- unsigned long cx, len = KVM_S390_SKEYS_MAX / 2;
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
+ unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE;
+ unsigned long start_gfn, end_gfn, pages;
+ GuestPhysBlockList guest_phys_blocks;
+ GuestPhysBlock *block;
int r;
struct kvm_s390_cmma_log clog = {
.flags = 0,
.mask = ~0ULL,
};
- if (sas->incoming_buffer) {
- for (cx = 0; cx + len <= max; cx += len) {
- clog.start_gfn = cx;
- clog.count = len;
- clog.values = (uint64_t)(sas->incoming_buffer + cx);
- r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
- if (r) {
- error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
- return;
- }
- }
- if (cx < max) {
- clog.start_gfn = cx;
- clog.count = max - cx;
- clog.values = (uint64_t)(sas->incoming_buffer + cx);
+ if (!sas->incoming_buffer) {
+ return;
+ }
+ guest_phys_blocks_init(&guest_phys_blocks);
+ guest_phys_blocks_append(&guest_phys_blocks);
+
+ QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
+ assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
+ assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
+
+ start_gfn = block->target_start / TARGET_PAGE_SIZE;
+ end_gfn = block->target_end / TARGET_PAGE_SIZE;
+
+ while (start_gfn < end_gfn) {
+ /* Don't exceed the maximum buffer size. */
+ pages = MIN(end_gfn - start_gfn, KVM_S390_SKEYS_MAX / 2);
+
+ /*
+ * If we ever get guest physical memory beyond the configured
+ * memory limit, something went very wrong.
+ */
+ assert(start_gfn + pages <= max);
+
+ clog.start_gfn = start_gfn;
+ clog.count = pages;
+ clog.values = (uint64_t)(sas->incoming_buffer + start_gfn);
r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
if (r) {
error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
+ goto out;
}
+
+ start_gfn += pages;
}
- g_free(sas->incoming_buffer);
- sas->incoming_buffer = NULL;
}
+
+out:
+ guest_phys_blocks_free(&guest_phys_blocks);
+ g_free(sas->incoming_buffer);
+ sas->incoming_buffer = NULL;
}
static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val,
@@ -166,10 +185,10 @@ static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa)
static int kvm_s390_stattrib_get_active(S390StAttribState *sa)
{
- return kvm_s390_cmma_active() && sa->migration_enabled;
+ return kvm_s390_cmma_active();
}
-static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data)
+static void kvm_s390_stattrib_class_init(ObjectClass *oc, const void *data)
{
S390StAttribClass *sac = S390_STATTRIB_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index c4259b5..f74cf32 100644
--- a/hw/s390x/s390-stattrib.c
+++ b/hw/s390x/s390-stattrib.c
@@ -16,9 +16,9 @@
#include "hw/qdev-properties.h"
#include "hw/s390x/storage-attributes.h"
#include "qemu/error-report.h"
-#include "exec/ram_addr.h"
+#include "system/ram_addr.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "cpu.h"
/* 512KiB cover 2GB of guest memory */
@@ -304,10 +304,10 @@ static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value,
static int qemu_s390_get_active(S390StAttribState *sa)
{
- return sa->migration_enabled;
+ return true;
}
-static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data)
+static void qemu_s390_stattrib_class_init(ObjectClass *oc, const void *data)
{
S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -360,19 +360,13 @@ static void s390_stattrib_realize(DeviceState *dev, Error **errp)
&savevm_s390_stattrib_handlers, dev);
}
-static Property s390_stattrib_props[] = {
- DEFINE_PROP_BOOL("migration-enabled", S390StAttribState, migration_enabled, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void s390_stattrib_class_init(ObjectClass *oc, void *data)
+static void s390_stattrib_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->realize = s390_stattrib_realize;
- device_class_set_props(dc, s390_stattrib_props);
}
static void s390_stattrib_instance_init(Object *obj)
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index c483ff8..a79bd13 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -13,14 +13,11 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "exec/ram_addr.h"
-#include "exec/confidential-guest-support.h"
+#include "system/ram_addr.h"
+#include "system/confidential-guest-support.h"
#include "hw/boards.h"
-#include "hw/s390x/s390-virtio-hcall.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/s390_flic.h"
-#include "hw/s390x/ioinst.h"
-#include "hw/s390x/css.h"
#include "virtio-ccw.h"
#include "qemu/config-file.h"
#include "qemu/ctype.h"
@@ -29,7 +26,7 @@
#include "qemu/qemu-print.h"
#include "qemu/units.h"
#include "hw/s390x/s390-pci-bus.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/s390x/storage-keys.h"
#include "hw/s390x/storage-attributes.h"
#include "hw/s390x/event-facility.h"
@@ -38,16 +35,21 @@
#include "hw/s390x/css-bridge.h"
#include "hw/s390x/ap-bridge.h"
#include "migration/register.h"
-#include "cpu_models.h"
+#include "target/s390x/cpu_models.h"
#include "hw/nmi.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/tod.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/cpus.h"
+#include "system/system.h"
+#include "system/cpus.h"
+#include "system/hostmem.h"
#include "target/s390x/kvm/pv.h"
#include "migration/blocker.h"
#include "qapi/visitor.h"
#include "hw/s390x/cpu-topology.h"
+#include "kvm/kvm_s390x.h"
+#include "hw/virtio/virtio-md-pci.h"
+#include "hw/s390x/virtio-ccw-md.h"
+#include "system/replay.h"
#include CONFIG_DEVICES
static Error *pv_mig_blocker;
@@ -124,70 +126,86 @@ static void subsystem_reset(void)
}
}
-static int virtio_ccw_hcall_notify(const uint64_t *args)
+static void s390_set_memory_limit(S390CcwMachineState *s390ms,
+ uint64_t new_limit)
{
- uint64_t subch_id = args[0];
- uint64_t data = args[1];
- SubchDev *sch;
- VirtIODevice *vdev;
- int cssid, ssid, schid, m;
- uint16_t vq_idx = data;
+ uint64_t hw_limit = 0;
+ int ret = 0;
- if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
- return -EINVAL;
+ assert(!s390ms->memory_limit && new_limit);
+ if (kvm_enabled()) {
+ ret = kvm_s390_set_mem_limit(new_limit, &hw_limit);
}
- sch = css_find_subch(m, cssid, ssid, schid);
- if (!sch || !css_subch_visible(sch)) {
- return -EINVAL;
- }
-
- vdev = virtio_ccw_get_vdev(sch);
- if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {
- return -EINVAL;
+ if (ret == -E2BIG) {
+ error_report("host supports a maximum of %" PRIu64 " GB",
+ hw_limit / GiB);
+ exit(EXIT_FAILURE);
+ } else if (ret) {
+ error_report("setting the guest size failed");
+ exit(EXIT_FAILURE);
}
+ s390ms->memory_limit = new_limit;
+}
- if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
- virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx),
- (data >> 16) & 0xFFFF);
+static void s390_set_max_pagesize(S390CcwMachineState *s390ms,
+ uint64_t pagesize)
+{
+ assert(!s390ms->max_pagesize && pagesize);
+ if (kvm_enabled()) {
+ kvm_s390_set_max_pagesize(pagesize, &error_fatal);
}
-
- virtio_queue_notify(vdev, vq_idx);
- return 0;
+ s390ms->max_pagesize = pagesize;
}
-static int virtio_ccw_hcall_early_printk(const uint64_t *args)
+static void s390_memory_init(MachineState *machine)
{
- uint64_t mem = args[0];
- MachineState *ms = MACHINE(qdev_get_machine());
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(machine);
+ MemoryRegion *sysmem = get_system_memory();
+ MemoryRegion *ram = machine->ram;
+ uint64_t ram_size = memory_region_size(ram);
+ uint64_t devmem_base, devmem_size;
- if (mem < ms->ram_size) {
- /* Early printk */
- return 0;
+ if (!QEMU_IS_ALIGNED(ram_size, 1 * MiB)) {
+ /*
+ * SCLP cannot possibly expose smaller granularity right now and KVM
+ * cannot handle smaller granularity. As we don't support NUMA, the
+ * region size directly corresponds to machine->ram_size, and the region
+ * is a single RAM memory region.
+ */
+ error_report("ram size must be multiples of 1 MiB");
+ exit(EXIT_FAILURE);
}
- return -EINVAL;
-}
-static void virtio_ccw_register_hcalls(void)
-{
- s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY,
- virtio_ccw_hcall_notify);
- /* Tolerate early printk. */
- s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
- virtio_ccw_hcall_early_printk);
-}
+ devmem_size = 0;
+ devmem_base = ram_size;
+#ifdef CONFIG_MEM_DEVICE
+ if (machine->ram_size < machine->maxram_size) {
-static void s390_memory_init(MemoryRegion *ram)
-{
- MemoryRegion *sysmem = get_system_memory();
+ /*
+ * Make sure memory devices have a sane default alignment, even
+ * when weird initial memory sizes are specified.
+ */
+ devmem_base = QEMU_ALIGN_UP(devmem_base, 1 * GiB);
+ devmem_size = machine->maxram_size - machine->ram_size;
+ }
+#endif
+ s390_set_memory_limit(s390ms, devmem_base + devmem_size);
- /* allocate RAM for core */
+ /* Map the initial memory. Must happen after setting the memory limit. */
memory_region_add_subregion(sysmem, 0, ram);
+ /* Initialize address space for memory devices. */
+#ifdef CONFIG_MEM_DEVICE
+ if (devmem_size) {
+ machine_memory_devices_init(machine, devmem_base, devmem_size);
+ }
+#endif /* CONFIG_MEM_DEVICE */
+
/*
* Configure the maximum page size. As no memory devices were created
* yet, this is the page size of initial memory only.
*/
- s390_set_max_pagesize(qemu_maxrampagesize(), &error_fatal);
+ s390_set_max_pagesize(s390ms, qemu_maxrampagesize());
/* Initialize storage key device */
s390_skeys_init();
/* Initialize storage attributes device */
@@ -197,11 +215,10 @@ static void s390_memory_init(MemoryRegion *ram)
static void s390_init_ipl_dev(const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename, const char *firmware,
- const char *netboot_fw, bool enforce_bios)
+ bool enforce_bios)
{
Object *new = object_new(TYPE_S390_IPL);
DeviceState *dev = DEVICE(new);
- char *netboot_fw_prop;
if (kernel_filename) {
qdev_prop_set_string(dev, "kernel", kernel_filename);
@@ -212,11 +229,6 @@ static void s390_init_ipl_dev(const char *kernel_filename,
qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
qdev_prop_set_string(dev, "firmware", firmware);
qdev_prop_set_bit(dev, "enforce_bios", enforce_bios);
- netboot_fw_prop = object_property_get_str(new, "netboot_fw", &error_abort);
- if (!strlen(netboot_fw_prop)) {
- qdev_prop_set_string(dev, "netboot_fw", netboot_fw);
- }
- g_free(netboot_fw_prop);
object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
new);
object_unref(new);
@@ -248,9 +260,21 @@ static void s390_create_sclpconsole(SCLPDevice *sclp,
qdev_realize_and_unref(dev, ev_fac_bus, &error_fatal);
}
+static void s390_create_sclpcpi(SCLPDevice *sclp)
+{
+ SCLPEventFacility *ef = sclp->event_facility;
+ BusState *ev_fac_bus = sclp_get_event_facility_bus(ef);
+ DeviceState *dev;
+
+ dev = qdev_new(TYPE_SCLP_EVENT_CPI);
+ object_property_add_child(OBJECT(ef), "sclpcpi", OBJECT(dev));
+ qdev_realize_and_unref(dev, ev_fac_bus, &error_fatal);
+}
+
static void ccw_init(MachineState *machine)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
+ S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
int ret;
VirtualCssBus *css_bus;
@@ -261,7 +285,7 @@ static void ccw_init(MachineState *machine)
qdev_realize_and_unref(DEVICE(ms->sclp), NULL, &error_fatal);
/* init memory + setup max page size. Required for the CPU model */
- s390_memory_init(machine->ram);
+ s390_memory_init(machine);
/* init CPUs (incl. CPU model) early so s390_has_feature() works */
s390_init_cpus(machine);
@@ -284,16 +308,13 @@ static void ccw_init(MachineState *machine)
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
machine->initrd_filename,
machine->firmware ?: "s390-ccw.img",
- "s390-netboot.img", true);
+ true);
dev = qdev_new(TYPE_S390_PCI_HOST_BRIDGE);
object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
OBJECT(dev));
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- /* register hypercalls */
- virtio_ccw_register_hcalls();
-
s390_enable_css_support(s390_cpu_addr2state(0));
ret = css_create_css_image(VIRTUAL_CSSID, true);
@@ -314,6 +335,12 @@ static void ccw_init(MachineState *machine)
/* init the TOD clock */
s390_init_tod();
+
+ /* init SCLP event Control-Program Identification */
+ if (s390mc->use_cpi) {
+ s390_create_sclpcpi(ms->sclp);
+ }
+
}
static void s390_cpu_plug(HotplugHandler *hotplug_dev,
@@ -356,7 +383,8 @@ static void s390_machine_unprotect(S390CcwMachineState *ms)
ram_block_discard_disable(false);
}
-static int s390_machine_protect(S390CcwMachineState *ms)
+static int s390_machine_protect(S390CcwMachineState *ms,
+ struct S390PVResponse *pv_resp)
{
Error *local_err = NULL;
int rc;
@@ -399,19 +427,19 @@ static int s390_machine_protect(S390CcwMachineState *ms)
}
/* Set SE header and unpack */
- rc = s390_ipl_prepare_pv_header(&local_err);
+ rc = s390_ipl_prepare_pv_header(pv_resp, &local_err);
if (rc) {
goto out_err;
}
/* Decrypt image */
- rc = s390_ipl_pv_unpack();
+ rc = s390_ipl_pv_unpack(pv_resp);
if (rc) {
goto out_err;
}
/* Verify integrity */
- rc = s390_pv_verify();
+ rc = s390_pv_verify(pv_resp);
if (rc) {
goto out_err;
}
@@ -440,13 +468,26 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms)
s390_pv_prep_reset();
}
-static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
+static void s390_machine_reset(MachineState *machine, ResetType type)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
+ struct S390PVResponse pv_resp;
enum s390_reset reset_type;
CPUState *cs, *t;
S390CPU *cpu;
+ /*
+ * Temporarily drop the record/replay mutex to let rr_cpu_thread_fn()
+ * process the run_on_cpu() requests below. This is safe, because at this
+ * point one of the following is true:
+ * - All CPU threads are not running, either because the machine is being
+ * initialized, or because the guest requested a reset using diag 308.
+ * There is no risk to desync the record/replay state.
+ * - A snapshot is about to be loaded. The record/replay state consistency
+ * is not important.
+ */
+ replay_mutex_unlock();
+
/* get the reset parameters, reset them once done */
s390_ipl_get_reset_request(&cs, &reset_type);
@@ -472,7 +513,7 @@ static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
* Device reset includes CPU clear resets so this has to be
* done AFTER the unprotect call above.
*/
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
s390_crypto_reset();
/* configure and start the ipl CPU only */
@@ -519,14 +560,14 @@ static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
}
run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
- if (s390_machine_protect(ms)) {
- s390_pv_inject_reset_error(cs);
+ if (s390_machine_protect(ms, &pv_resp)) {
+ s390_pv_inject_reset_error(cs, pv_resp);
/*
* Continue after the diag308 so the guest knows something
* went wrong.
*/
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
- return;
+ goto out_lock;
}
run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
@@ -539,13 +580,54 @@ static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
run_on_cpu(t, s390_do_cpu_set_diag318, RUN_ON_CPU_HOST_ULONG(0));
}
s390_ipl_clear_reset_request();
+
+out_lock:
+ /*
+ * Re-take the record/replay mutex, temporarily dropping the BQL in order
+ * to satisfy the ordering requirements.
+ */
+ bql_unlock();
+ replay_mutex_lock();
+ bql_lock();
+}
+
+static void s390_machine_device_pre_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
+ virtio_ccw_md_pre_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
+ virtio_md_pci_pre_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
+ }
}
static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(hotplug_dev);
+
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
s390_cpu_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
+ /*
+ * At this point, the device is realized and set all memdevs mapped, so
+ * qemu_maxrampagesize() will pick up the page sizes of these memdevs
+ * as well. Before we plug the device and expose any RAM memory regions
+ * to the system, make sure we don't exceed the previously set max page
+ * size. While only relevant for KVM, there is not really any use case
+ * for this with TCG, so we'll unconditionally reject it.
+ */
+ if (qemu_maxrampagesize() != s390ms->max_pagesize) {
+ error_setg(errp, "Memory device uses a bigger page size than"
+ " initial memory");
+ return;
+ }
+ if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
+ virtio_ccw_md_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
+ } else {
+ virtio_md_pci_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
+ }
}
}
@@ -554,10 +636,25 @@ static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev,
{
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
error_setg(errp, "CPU hot unplug not supported on this machine");
- return;
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
+ virtio_ccw_md_unplug_request(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev),
+ errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
+ virtio_md_pci_unplug_request(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev),
+ errp);
}
}
+static void s390_machine_device_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
+ virtio_ccw_md_unplug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
+ virtio_md_pci_unplug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
+ }
+ }
+
static CpuInstanceProperties s390_cpu_index_to_props(MachineState *ms,
unsigned cpu_index)
{
@@ -604,7 +701,9 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms)
static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
DeviceState *dev)
{
- if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
return HOTPLUG_HANDLER(machine);
}
return NULL;
@@ -667,50 +766,6 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value,
ms->dea_key_wrap = value;
}
-static S390CcwMachineClass *current_mc;
-
-/*
- * Get the class of the s390-ccw-virtio machine that is currently in use.
- * Note: libvirt is using the "none" machine to probe for the features of the
- * host CPU, so in case this is called with the "none" machine, the function
- * returns the TYPE_S390_CCW_MACHINE base class. In this base class, all the
- * various "*_allowed" variables are enabled, so that the *_allowed() wrappers
- * below return the correct default value for the "none" machine.
- *
- * Attention! Do *not* add additional new wrappers for CPU features (e.g. like
- * the ri_allowed() wrapper) via this mechanism anymore. CPU features should
- * be handled via the CPU models, i.e. checking with cpu_model_allowed() during
- * CPU initialization and s390_has_feat() later should be sufficient.
- */
-static S390CcwMachineClass *get_machine_class(void)
-{
- if (unlikely(!current_mc)) {
- /*
- * No s390 ccw machine was instantiated, we are likely to
- * be called for the 'none' machine. The properties will
- * have their after-initialization values.
- */
- current_mc = S390_CCW_MACHINE_CLASS(
- object_class_by_name(TYPE_S390_CCW_MACHINE));
- }
- return current_mc;
-}
-
-bool ri_allowed(void)
-{
- return get_machine_class()->ri_allowed;
-}
-
-bool cpu_model_allowed(void)
-{
- return get_machine_class()->cpu_model_allowed;
-}
-
-bool hpage_1m_allowed(void)
-{
- return get_machine_class()->hpage_1m_allowed;
-}
-
static void machine_get_loadparm(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
@@ -728,48 +783,30 @@ static void machine_set_loadparm(Object *obj, Visitor *v,
{
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
char *val;
- int i;
if (!visit_type_str(v, name, &val, errp)) {
return;
}
- for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
- uint8_t c = qemu_toupper(val[i]); /* mimic HMC */
-
- if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
- (c == ' ')) {
- ms->loadparm[i] = c;
- } else {
- error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
- c, c);
- return;
- }
- }
-
- for (; i < sizeof(ms->loadparm); i++) {
- ms->loadparm[i] = ' '; /* pad right with spaces */
- }
+ s390_ipl_fmt_loadparm(ms->loadparm, val, errp);
+ g_free(val);
}
-static void ccw_machine_class_init(ObjectClass *oc, void *data)
+static void ccw_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
+ DumpSKeysInterface *dsi = DUMP_SKEYS_INTERFACE_CLASS(oc);
- s390mc->ri_allowed = true;
- s390mc->cpu_model_allowed = true;
- s390mc->hpage_1m_allowed = true;
s390mc->max_threads = 1;
- mc->init = ccw_init;
+ s390mc->use_cpi = true;
mc->reset = s390_machine_reset;
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->no_floppy = 1;
mc->no_parallel = 1;
- mc->no_sdcard = 1;
mc->max_cpus = S390_MAX_CPUS;
mc->has_hotpluggable_cpus = true;
mc->smp_props.books_supported = true;
@@ -780,11 +817,14 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids;
/* it is overridden with 'host' cpu *in kvm_arch_init* */
mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu");
+ hc->pre_plug = s390_machine_device_pre_plug;
hc->plug = s390_machine_device_plug;
hc->unplug_request = s390_machine_device_unplug_request;
+ hc->unplug = s390_machine_device_unplug;
nc->nmi_monitor_handler = s390_nmi;
mc->default_ram_id = "s390.ram";
mc->default_nic = "virtio-net-ccw";
+ dsi->qmp_dump_skeys = s390_qmp_dump_skeys;
object_class_property_add_bool(oc, "aes-key-wrap",
machine_get_aes_key_wrap,
@@ -823,39 +863,39 @@ static const TypeInfo ccw_machine_info = {
.instance_init = s390_machine_initfn,
.class_size = sizeof(S390CcwMachineClass),
.class_init = ccw_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NMI },
{ TYPE_HOTPLUG_HANDLER},
+ { TYPE_DUMP_SKEYS_INTERFACE},
{ }
},
};
#define DEFINE_CCW_MACHINE_IMPL(latest, ...) \
+ static void MACHINE_VER_SYM(mach_init, ccw, __VA_ARGS__)(MachineState *mach) \
+ { \
+ MACHINE_VER_SYM(instance_options, ccw, __VA_ARGS__)(mach); \
+ ccw_init(mach); \
+ } \
static void MACHINE_VER_SYM(class_init, ccw, __VA_ARGS__)( \
ObjectClass *oc, \
- void *data) \
+ const void *data) \
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
MACHINE_VER_SYM(class_options, ccw, __VA_ARGS__)(mc); \
mc->desc = "Virtual s390x machine (version " MACHINE_VER_STR(__VA_ARGS__) ")"; \
+ mc->init = MACHINE_VER_SYM(mach_init, ccw, __VA_ARGS__); \
MACHINE_VER_DEPRECATION(__VA_ARGS__); \
if (latest) { \
mc->alias = "s390-ccw-virtio"; \
mc->is_default = true; \
} \
} \
- static void MACHINE_VER_SYM(instance_init, ccw, __VA_ARGS__)(Object *obj) \
- { \
- MachineState *machine = MACHINE(obj); \
- current_mc = S390_CCW_MACHINE_CLASS(MACHINE_GET_CLASS(machine)); \
- MACHINE_VER_SYM(instance_options, ccw, __VA_ARGS__)(machine); \
- } \
static const TypeInfo MACHINE_VER_SYM(info, ccw, __VA_ARGS__) = \
{ \
.name = MACHINE_VER_TYPE_NAME("s390-ccw-virtio", __VA_ARGS__), \
.parent = TYPE_S390_CCW_MACHINE, \
.class_init = MACHINE_VER_SYM(class_init, ccw, __VA_ARGS__), \
- .instance_init = MACHINE_VER_SYM(instance_init, ccw, __VA_ARGS__), \
}; \
static void MACHINE_VER_SYM(register, ccw, __VA_ARGS__)(void) \
{ \
@@ -871,14 +911,58 @@ static const TypeInfo ccw_machine_info = {
DEFINE_CCW_MACHINE_IMPL(false, major, minor)
+static void ccw_machine_10_1_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_10_1_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE_AS_LATEST(10, 1);
+
+static void ccw_machine_10_0_instance_options(MachineState *machine)
+{
+ ccw_machine_10_1_instance_options(machine);
+}
+
+static void ccw_machine_10_0_class_options(MachineClass *mc)
+{
+ S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
+ s390mc->use_cpi = false;
+
+ ccw_machine_10_1_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len);
+}
+DEFINE_CCW_MACHINE(10, 0);
+
+static void ccw_machine_9_2_instance_options(MachineState *machine)
+{
+ ccw_machine_10_0_instance_options(machine);
+}
+
+static void ccw_machine_9_2_class_options(MachineClass *mc)
+{
+ static GlobalProperty compat[] = {
+ { TYPE_S390_PCI_DEVICE, "relaxed-translation", "off", },
+ };
+
+ ccw_machine_10_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_2, hw_compat_9_2_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
+}
+DEFINE_CCW_MACHINE(9, 2);
+
static void ccw_machine_9_1_instance_options(MachineState *machine)
{
+ ccw_machine_9_2_instance_options(machine);
}
static void ccw_machine_9_1_class_options(MachineClass *mc)
{
+ ccw_machine_9_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
}
-DEFINE_CCW_MACHINE_AS_LATEST(9, 1);
+DEFINE_CCW_MACHINE(9, 1);
static void ccw_machine_9_0_instance_options(MachineState *machine)
{
@@ -1083,229 +1167,6 @@ static void ccw_machine_4_2_class_options(MachineClass *mc)
}
DEFINE_CCW_MACHINE(4, 2);
-static void ccw_machine_4_1_instance_options(MachineState *machine)
-{
- static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V4_1 };
- ccw_machine_4_2_instance_options(machine);
- s390_set_qemu_cpu_model(0x2964, 13, 2, qemu_cpu_feat);
-}
-
-static void ccw_machine_4_1_class_options(MachineClass *mc)
-{
- ccw_machine_4_2_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
-}
-DEFINE_CCW_MACHINE(4, 1);
-
-static void ccw_machine_4_0_instance_options(MachineState *machine)
-{
- static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V4_0 };
- ccw_machine_4_1_instance_options(machine);
- s390_set_qemu_cpu_model(0x2827, 12, 2, qemu_cpu_feat);
-}
-
-static void ccw_machine_4_0_class_options(MachineClass *mc)
-{
- ccw_machine_4_1_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
-}
-DEFINE_CCW_MACHINE(4, 0);
-
-static void ccw_machine_3_1_instance_options(MachineState *machine)
-{
- static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V3_1 };
- ccw_machine_4_0_instance_options(machine);
- s390_cpudef_featoff_greater(14, 1, S390_FEAT_MULTIPLE_EPOCH);
- s390_cpudef_group_featoff_greater(14, 1, S390_FEAT_GROUP_MULTIPLE_EPOCH_PTFF);
- s390_set_qemu_cpu_model(0x2827, 12, 2, qemu_cpu_feat);
-}
-
-static void ccw_machine_3_1_class_options(MachineClass *mc)
-{
- ccw_machine_4_0_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
-}
-DEFINE_CCW_MACHINE(3, 1);
-
-static void ccw_machine_3_0_instance_options(MachineState *machine)
-{
- ccw_machine_3_1_instance_options(machine);
-}
-
-static void ccw_machine_3_0_class_options(MachineClass *mc)
-{
- S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
-
- s390mc->hpage_1m_allowed = false;
- ccw_machine_3_1_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
-}
-DEFINE_CCW_MACHINE(3, 0);
-
-static void ccw_machine_2_12_instance_options(MachineState *machine)
-{
- ccw_machine_3_0_instance_options(machine);
- s390_cpudef_featoff_greater(11, 1, S390_FEAT_PPA15);
- s390_cpudef_featoff_greater(11, 1, S390_FEAT_BPB);
-}
-
-static void ccw_machine_2_12_class_options(MachineClass *mc)
-{
- ccw_machine_3_0_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
-}
-DEFINE_CCW_MACHINE(2, 12);
-
-#ifdef CONFIG_S390X_LEGACY_CPUS
-
-static void ccw_machine_2_11_instance_options(MachineState *machine)
-{
- static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V2_11 };
- ccw_machine_2_12_instance_options(machine);
-
- /* before 2.12 we emulated the very first z900 */
- s390_set_qemu_cpu_model(0x2064, 7, 1, qemu_cpu_feat);
-}
-
-static void ccw_machine_2_11_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { TYPE_SCLP_EVENT_FACILITY, "allow_all_mask_sizes", "off", },
- };
-
- ccw_machine_2_12_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-}
-DEFINE_CCW_MACHINE(2, 11);
-
-static void ccw_machine_2_10_instance_options(MachineState *machine)
-{
- ccw_machine_2_11_instance_options(machine);
-}
-
-static void ccw_machine_2_10_class_options(MachineClass *mc)
-{
- ccw_machine_2_11_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
-}
-DEFINE_CCW_MACHINE(2, 10);
-
-static void ccw_machine_2_9_instance_options(MachineState *machine)
-{
- ccw_machine_2_10_instance_options(machine);
- s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP);
- s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2);
- s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI);
- s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION);
- s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION);
-}
-
-static void ccw_machine_2_9_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { TYPE_S390_STATTRIB, "migration-enabled", "off", },
- { TYPE_S390_FLIC_COMMON, "migration-enabled", "off", },
- };
-
- ccw_machine_2_10_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
- css_migration_enabled = false;
-}
-DEFINE_CCW_MACHINE(2, 9);
-
-static void ccw_machine_2_8_instance_options(MachineState *machine)
-{
- ccw_machine_2_9_instance_options(machine);
-}
-
-static void ccw_machine_2_8_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { TYPE_S390_FLIC_COMMON, "adapter_routes_max_batch", "64", },
- };
-
- ccw_machine_2_9_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-}
-DEFINE_CCW_MACHINE(2, 8);
-
-static void ccw_machine_2_7_instance_options(MachineState *machine)
-{
- ccw_machine_2_8_instance_options(machine);
-}
-
-static void ccw_machine_2_7_class_options(MachineClass *mc)
-{
- S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
-
- s390mc->cpu_model_allowed = false;
- ccw_machine_2_8_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
-}
-DEFINE_CCW_MACHINE(2, 7);
-
-static void ccw_machine_2_6_instance_options(MachineState *machine)
-{
- ccw_machine_2_7_instance_options(machine);
-}
-
-static void ccw_machine_2_6_class_options(MachineClass *mc)
-{
- S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
- static GlobalProperty compat[] = {
- { TYPE_S390_IPL, "iplbext_migration", "off", },
- { TYPE_VIRTUAL_CSS_BRIDGE, "css_dev_path", "off", },
- };
-
- s390mc->ri_allowed = false;
- ccw_machine_2_7_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-}
-DEFINE_CCW_MACHINE(2, 6);
-
-static void ccw_machine_2_5_instance_options(MachineState *machine)
-{
- ccw_machine_2_6_instance_options(machine);
-}
-
-static void ccw_machine_2_5_class_options(MachineClass *mc)
-{
- ccw_machine_2_6_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
-}
-DEFINE_CCW_MACHINE(2, 5);
-
-static void ccw_machine_2_4_instance_options(MachineState *machine)
-{
- ccw_machine_2_5_instance_options(machine);
-}
-
-static void ccw_machine_2_4_class_options(MachineClass *mc)
-{
- static GlobalProperty compat[] = {
- { TYPE_S390_SKEYS, "migration-enabled", "off", },
- { "virtio-blk-ccw", "max_revision", "0", },
- { "virtio-balloon-ccw", "max_revision", "0", },
- { "virtio-serial-ccw", "max_revision", "0", },
- { "virtio-9p-ccw", "max_revision", "0", },
- { "virtio-rng-ccw", "max_revision", "0", },
- { "virtio-net-ccw", "max_revision", "0", },
- { "virtio-scsi-ccw", "max_revision", "0", },
- { "vhost-scsi-ccw", "max_revision", "0", },
- };
-
- ccw_machine_2_5_class_options(mc);
- compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
- compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
-}
-DEFINE_CCW_MACHINE(2, 4);
-
-#endif
-
static void ccw_machine_register_types(void)
{
type_register_static(&ccw_machine_info);
diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c
deleted file mode 100644
index ec7cf8b..0000000
--- a/hw/s390x/s390-virtio-hcall.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Support for virtio hypercalls on s390
- *
- * Copyright 2012 IBM Corp.
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "hw/s390x/s390-virtio-hcall.h"
-
-#define MAX_DIAG_SUBCODES 255
-
-static s390_virtio_fn s390_diag500_table[MAX_DIAG_SUBCODES];
-
-void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
-{
- assert(code < MAX_DIAG_SUBCODES);
- assert(!s390_diag500_table[code]);
-
- s390_diag500_table[code] = fn;
-}
-
-int s390_virtio_hypercall(CPUS390XState *env)
-{
- s390_virtio_fn fn;
-
- if (env->regs[1] < MAX_DIAG_SUBCODES) {
- fn = s390_diag500_table[env->regs[1]];
- if (fn) {
- env->regs[2] = fn(&env->regs[2]);
- return 0;
- }
- }
-
- return -EINVAL;
-}
diff --git a/hw/s390x/s390-virtio-hcall.h b/hw/s390x/s390-virtio-hcall.h
deleted file mode 100644
index 3ae6d6a..0000000
--- a/hw/s390x/s390-virtio-hcall.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Support for virtio hypercalls on s390x
- *
- * Copyright IBM Corp. 2012, 2017
- * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-
-#ifndef HW_S390_VIRTIO_HCALL_H
-#define HW_S390_VIRTIO_HCALL_H
-
-#include "standard-headers/asm-s390/virtio-ccw.h"
-#include "cpu.h"
-
-/* The only thing that we need from the old kvm_virtio.h file */
-#define KVM_S390_VIRTIO_NOTIFY 0
-
-typedef int (*s390_virtio_fn)(const uint64_t *args);
-void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
-int s390_virtio_hypercall(CPUS390XState *env);
-
-#endif /* HW_S390_VIRTIO_HCALL_H */
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index e725dcd..9718564 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -110,7 +110,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
MachineState *machine = MACHINE(qdev_get_machine());
int cpu_count;
int rnsize, rnmax;
- IplParameterBlock *ipib = s390_ipl_get_iplb();
int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len);
int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ?
offsetof(ReadInfo, entries) :
@@ -162,7 +161,11 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->rnsize2 = cpu_to_be32(rnsize);
}
- /* we don't support standby memory, maxram_size is never exposed */
+ /*
+ * We don't support standby memory. maxram_size is used for sizing the
+ * memory device region, which is not exposed through SCLP but through
+ * diag500.
+ */
rnmax = machine->ram_size >> sclp->increment_size;
if (rnmax < 0x10000) {
read_info->rnmax = cpu_to_be16(rnmax);
@@ -171,12 +174,8 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->rnmax2 = cpu_to_be64(rnmax);
}
- if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
- memcpy(&read_info->loadparm, &ipib->loadparm,
- sizeof(read_info->loadparm));
- } else {
- s390_ipl_set_loadparm(read_info->loadparm);
- }
+ s390_ipl_convert_loadparm((char *)S390_CCW_MACHINE(machine)->loadparm,
+ read_info->loadparm);
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
@@ -381,10 +380,7 @@ void sclp_service_interrupt(uint32_t sccb)
/* qemu object creation and initialization functions */
static void sclp_realize(DeviceState *dev, Error **errp)
{
- MachineState *machine = MACHINE(qdev_get_machine());
SCLPDevice *sclp = SCLP(dev);
- uint64_t hw_limit;
- int ret;
/*
* qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long
@@ -394,14 +390,6 @@ static void sclp_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), errp)) {
return;
}
-
- ret = s390_set_memory_limit(machine->maxram_size, &hw_limit);
- if (ret == -E2BIG) {
- error_setg(errp, "host supports a maximum of %" PRIu64 " GB",
- hw_limit / GiB);
- } else if (ret) {
- error_setg(errp, "setting the guest size failed");
- }
}
static void sclp_memory_init(SCLPDevice *sclp)
@@ -436,7 +424,7 @@ static void sclp_init(Object *obj)
sclp_memory_init(sclp);
}
-static void sclp_class_init(ObjectClass *oc, void *data)
+static void sclp_class_init(ObjectClass *oc, const void *data)
{
SCLPDeviceClass *sc = SCLP_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/s390x/sclpcpi.c b/hw/s390x/sclpcpi.c
new file mode 100644
index 0000000..7aa039d
--- /dev/null
+++ b/hw/s390x/sclpcpi.c
@@ -0,0 +1,212 @@
+ /*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * SCLP event type 11 - Control-Program Identification (CPI):
+ * CPI is used to send program identifiers from the guest to the
+ * Service-Call Logical Processor (SCLP). It is not sent by the SCLP.
+ *
+ * Control-program identifiers provide data about the guest operating
+ * system. The control-program identifiers are: system type, system name,
+ * system level and sysplex name.
+ *
+ * In Linux, all the control-program identifiers are user configurable. The
+ * system type, system name, and sysplex name use EBCDIC characters from
+ * this set: capital A-Z, 0-9, $, @, #, and blank. In Linux, the system
+ * type, system name and sysplex name are arbitrary free-form texts.
+ *
+ * In Linux, the 8-byte hexadecimal system-level has the format
+ * 0x<a><b><cc><dd><eeee><ff><gg><hh>, where:
+ * <a>: is a 4-bit digit, its most significant bit indicates hypervisor use
+ * <b>: is one digit that represents Linux distributions as follows
+ * 0: generic Linux
+ * 1: Red Hat Enterprise Linux
+ * 2: SUSE Linux Enterprise Server
+ * 3: Canonical Ubuntu
+ * 4: Fedora
+ * 5: openSUSE Leap
+ * 6: Debian GNU/Linux
+ * 7: Red Hat Enterprise Linux CoreOS
+ * <cc>: are two digits for a distribution-specific encoding of the major
+ * version of the distribution
+ * <dd>: are two digits for a distribution-specific encoding of the minor
+ * version of the distribution
+ * <eeee>: are four digits for the patch level of the distribution
+ * <ff>: are two digits for the major version of the kernel
+ * <gg>: are two digits for the minor version of the kernel
+ * <hh>: are two digits for the stable version of the kernel
+ * (e.g. 74872343805430528, when converted to hex is 0x010a000000060b00). On
+ * machines prior to z16, some of the values are not available to display.
+ *
+ * Sysplex refers to a cluster of logical partitions that communicates and
+ * co-operates with each other.
+ *
+ * The CPI feature is supported since 10.1.
+ *
+ * Copyright IBM, Corp. 2024
+ *
+ * Authors:
+ * Shalini Chellathurai Saroja <shalini@linux.ibm.com>
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "hw/s390x/event-facility.h"
+#include "hw/s390x/ebcdic.h"
+#include "qapi/qapi-visit-machine.h"
+#include "migration/vmstate.h"
+
+typedef struct Data {
+ uint8_t id_format;
+ uint8_t reserved0;
+ uint8_t system_type[8];
+ uint64_t reserved1;
+ uint8_t system_name[8];
+ uint64_t reserved2;
+ uint64_t system_level;
+ uint64_t reserved3;
+ uint8_t sysplex_name[8];
+ uint8_t reserved4[16];
+} QEMU_PACKED Data;
+
+typedef struct ControlProgramIdMsg {
+ EventBufferHeader ebh;
+ Data data;
+} QEMU_PACKED ControlProgramIdMsg;
+
+static bool can_handle_event(uint8_t type)
+{
+ return type == SCLP_EVENT_CTRL_PGM_ID;
+}
+
+static sccb_mask_t send_mask(void)
+{
+ return 0;
+}
+
+/* Enable SCLP to accept buffers of event type CPI from the control-program. */
+static sccb_mask_t receive_mask(void)
+{
+ return SCLP_EVENT_MASK_CTRL_PGM_ID;
+}
+
+static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
+{
+ ControlProgramIdMsg *cpim = container_of(evt_buf_hdr, ControlProgramIdMsg,
+ ebh);
+ SCLPEventCPI *e = SCLP_EVENT_CPI(event);
+
+ ascii_put(e->system_type, (char *)cpim->data.system_type,
+ sizeof(cpim->data.system_type));
+ ascii_put(e->system_name, (char *)cpim->data.system_name,
+ sizeof(cpim->data.system_name));
+ ascii_put(e->sysplex_name, (char *)cpim->data.sysplex_name,
+ sizeof(cpim->data.sysplex_name));
+ e->system_level = ldq_be_p(&cpim->data.system_level);
+ e->timestamp = qemu_clock_get_ns(QEMU_CLOCK_HOST);
+
+ cpim->ebh.flags = SCLP_EVENT_BUFFER_ACCEPTED;
+ return SCLP_RC_NORMAL_COMPLETION;
+}
+
+static char *get_system_type(Object *obj, Error **errp)
+{
+ SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
+
+ return g_strndup((char *) e->system_type, sizeof(e->system_type));
+}
+
+static char *get_system_name(Object *obj, Error **errp)
+{
+ SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
+
+ return g_strndup((char *) e->system_name, sizeof(e->system_name));
+}
+
+static char *get_sysplex_name(Object *obj, Error **errp)
+{
+ SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
+
+ return g_strndup((char *) e->sysplex_name, sizeof(e->sysplex_name));
+}
+
+static void get_system_level(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
+
+ visit_type_uint64(v, name, &e->system_level, errp);
+}
+
+static void get_timestamp(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
+
+ visit_type_uint64(v, name, &e->timestamp, errp);
+}
+
+static const VMStateDescription vmstate_sclpcpi = {
+ .name = "s390_control_program_id",
+ .version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(system_type, SCLPEventCPI, 8),
+ VMSTATE_UINT8_ARRAY(system_name, SCLPEventCPI, 8),
+ VMSTATE_UINT64(system_level, SCLPEventCPI),
+ VMSTATE_UINT8_ARRAY(sysplex_name, SCLPEventCPI, 8),
+ VMSTATE_UINT64(timestamp, SCLPEventCPI),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void cpi_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
+
+ dc->user_creatable = false;
+ dc->vmsd = &vmstate_sclpcpi;
+
+ k->can_handle_event = can_handle_event;
+ k->get_send_mask = send_mask;
+ k->get_receive_mask = receive_mask;
+ k->write_event_data = write_event_data;
+
+ object_class_property_add_str(klass, "system_type", get_system_type, NULL);
+ object_class_property_set_description(klass, "system_type",
+ "operating system e.g. \"LINUX \"");
+
+ object_class_property_add_str(klass, "system_name", get_system_name, NULL);
+ object_class_property_set_description(klass, "system_name",
+ "user configurable name of the VM e.g. \"TESTVM \"");
+
+ object_class_property_add_str(klass, "sysplex_name", get_sysplex_name,
+ NULL);
+ object_class_property_set_description(klass, "sysplex_name",
+ "name of the cluster which the VM belongs to, if any"
+ " e.g. \"PLEX \"");
+
+ object_class_property_add(klass, "system_level", "uint64", get_system_level,
+ NULL, NULL, NULL);
+ object_class_property_set_description(klass, "system_level",
+ "distribution and kernel version in Linux e.g. 74872343805430528");
+
+ object_class_property_add(klass, "timestamp", "uint64", get_timestamp,
+ NULL, NULL, NULL);
+ object_class_property_set_description(klass, "timestamp",
+ "latest update of CPI data in nanoseconds since the UNIX EPOCH");
+}
+
+static const TypeInfo sclp_cpi_info = {
+ .name = TYPE_SCLP_EVENT_CPI,
+ .parent = TYPE_SCLP_EVENT,
+ .instance_size = sizeof(SCLPEventCPI),
+ .class_init = cpi_class_init,
+};
+
+static void sclp_cpi_register_types(void)
+{
+ type_register_static(&sclp_cpi_info);
+}
+
+type_init(sclp_cpi_register_types)
diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c
index fa79891..4b6ebfe 100644
--- a/hw/s390x/sclpcpu.c
+++ b/hw/s390x/sclpcpu.c
@@ -17,7 +17,7 @@
#include "hw/s390x/sclp.h"
#include "qemu/module.h"
#include "hw/s390x/event-facility.h"
-#include "sysemu/cpus.h"
+#include "system/cpus.h"
typedef struct ConfigMgtData {
EventBufferHeader ebh;
@@ -73,7 +73,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
return 1;
}
-static void sclp_cpu_class_init(ObjectClass *oc, void *data)
+static void sclp_cpu_class_init(ObjectClass *oc, const void *data)
{
SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
index 14936aa..da4c8f3 100644
--- a/hw/s390x/sclpquiesce.c
+++ b/hw/s390x/sclpquiesce.c
@@ -16,7 +16,7 @@
#include "hw/s390x/sclp.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/s390x/event-facility.h"
typedef struct SignalQuiesce {
@@ -112,12 +112,12 @@ static void quiesce_reset(DeviceState *dev)
event->event_pending = false;
}
-static void quiesce_class_init(ObjectClass *klass, void *data)
+static void quiesce_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
- dc->reset = quiesce_reset;
+ device_class_set_legacy_reset(dc, quiesce_reset);
dc->vmsd = &vmstate_sclpquiesce;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
/*
diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c
index 9588b90..c9b8896 100644
--- a/hw/s390x/tod-kvm.c
+++ b/hw/s390x/tod-kvm.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "hw/s390x/tod.h"
#include "target/s390x/kvm/pv.h"
#include "kvm/kvm_s390x.h"
@@ -133,7 +133,7 @@ static void kvm_s390_tod_realize(DeviceState *dev, Error **errp)
qemu_add_vm_change_state_handler(kvm_s390_tod_vm_state_change, td);
}
-static void kvm_s390_tod_class_init(ObjectClass *oc, void *data)
+static void kvm_s390_tod_class_init(ObjectClass *oc, const void *data)
{
S390TODClass *tdc = S390_TOD_CLASS(oc);
diff --git a/hw/s390x/tod-tcg.c b/hw/s390x/tod-tcg.c
index 2d540db..0cc9662 100644
--- a/hw/s390x/tod-tcg.c
+++ b/hw/s390x/tod-tcg.c
@@ -16,7 +16,7 @@
#include "qemu/module.h"
#include "cpu.h"
#include "tcg/tcg_s390x.h"
-#include "sysemu/rtc.h"
+#include "system/rtc.h"
static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
Error **errp)
@@ -52,7 +52,7 @@ static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod,
}
}
-static void qemu_s390_tod_class_init(ObjectClass *oc, void *data)
+static void qemu_s390_tod_class_init(ObjectClass *oc, const void *data)
{
S390TODClass *tdc = S390_TOD_CLASS(oc);
diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c
index c81b1c0..3f913cc 100644
--- a/hw/s390x/tod.c
+++ b/hw/s390x/tod.c
@@ -13,9 +13,9 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "sysemu/kvm.h"
-#include "sysemu/tcg.h"
-#include "sysemu/qtest.h"
+#include "system/kvm.h"
+#include "system/tcg.h"
+#include "system/qtest.h"
#include "migration/qemu-file-types.h"
#include "migration/register.h"
@@ -111,7 +111,7 @@ static void s390_tod_realize(DeviceState *dev, Error **errp)
register_savevm_live("todclock", 0, 1, &savevm_tod, td);
}
-static void s390_tod_class_init(ObjectClass *oc, void *data)
+static void s390_tod_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/s390x/vhost-scsi-ccw.c b/hw/s390x/vhost-scsi-ccw.c
index 40dc14b..8341b23 100644
--- a/hw/s390x/vhost-scsi-ccw.c
+++ b/hw/s390x/vhost-scsi-ccw.c
@@ -41,13 +41,12 @@ static void vhost_ccw_scsi_instance_init(Object *obj)
TYPE_VHOST_SCSI);
}
-static Property vhost_ccw_scsi_properties[] = {
+static const Property vhost_ccw_scsi_properties[] = {
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
+static void vhost_ccw_scsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/vhost-user-fs-ccw.c b/hw/s390x/vhost-user-fs-ccw.c
index 6c6f269..cc1b822 100644
--- a/hw/s390x/vhost-user-fs-ccw.c
+++ b/hw/s390x/vhost-user-fs-ccw.c
@@ -23,12 +23,11 @@ typedef struct VHostUserFSCcw {
OBJECT_CHECK(VHostUserFSCcw, (obj), TYPE_VHOST_USER_FS_CCW)
-static Property vhost_user_fs_ccw_properties[] = {
+static const Property vhost_user_fs_ccw_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_fs_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp)
@@ -49,7 +48,7 @@ static void vhost_user_fs_ccw_instance_init(Object *obj)
TYPE_VHOST_USER_FS);
}
-static void vhost_user_fs_ccw_class_init(ObjectClass *klass, void *data)
+static void vhost_user_fs_ccw_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/vhost-vsock-ccw.c b/hw/s390x/vhost-vsock-ccw.c
index 07845a9..552e9e8 100644
--- a/hw/s390x/vhost-vsock-ccw.c
+++ b/hw/s390x/vhost-vsock-ccw.c
@@ -22,10 +22,9 @@ struct VHostVSockCCWState {
VHostVSock vdev;
};
-static Property vhost_vsock_ccw_properties[] = {
+static const Property vhost_vsock_ccw_properties[] = {
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_vsock_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp)
@@ -36,7 +35,7 @@ static void vhost_vsock_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp)
qdev_realize(vdev, BUS(&ccw_dev->bus), errp);
}
-static void vhost_vsock_ccw_class_init(ObjectClass *klass, void *data)
+static void vhost_vsock_ccw_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-9p.c b/hw/s390x/virtio-ccw-9p.c
index 6f931f5..72bf6ec 100644
--- a/hw/s390x/virtio-ccw-9p.c
+++ b/hw/s390x/virtio-ccw-9p.c
@@ -41,15 +41,14 @@ static void virtio_ccw_9p_instance_init(Object *obj)
TYPE_VIRTIO_9P);
}
-static Property virtio_ccw_9p_properties[] = {
+static const Property virtio_ccw_9p_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_9p_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-balloon.c b/hw/s390x/virtio-ccw-balloon.c
index 44287b9..399b40f 100644
--- a/hw/s390x/virtio-ccw-balloon.c
+++ b/hw/s390x/virtio-ccw-balloon.c
@@ -46,15 +46,14 @@ static void virtio_ccw_balloon_instance_init(Object *obj)
"guest-stats-polling-interval");
}
-static Property virtio_ccw_balloon_properties[] = {
+static const Property virtio_ccw_balloon_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_balloon_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-blk.c b/hw/s390x/virtio-ccw-blk.c
index 8e0e58b..7d8c4a75 100644
--- a/hw/s390x/virtio-ccw-blk.c
+++ b/hw/s390x/virtio-ccw-blk.c
@@ -43,15 +43,15 @@ static void virtio_ccw_blk_instance_init(Object *obj)
"bootindex");
}
-static Property virtio_ccw_blk_properties[] = {
+static const Property virtio_ccw_blk_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm),
};
-static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_blk_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c
index 0fa2f89..75e7146 100644
--- a/hw/s390x/virtio-ccw-crypto.c
+++ b/hw/s390x/virtio-ccw-crypto.c
@@ -44,15 +44,14 @@ static void virtio_ccw_crypto_instance_init(Object *obj)
TYPE_VIRTIO_CRYPTO);
}
-static Property virtio_ccw_crypto_properties[] = {
+static const Property virtio_ccw_crypto_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_crypto_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_crypto_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-gpu.c b/hw/s390x/virtio-ccw-gpu.c
index 0642c52..edb6a47 100644
--- a/hw/s390x/virtio-ccw-gpu.c
+++ b/hw/s390x/virtio-ccw-gpu.c
@@ -42,15 +42,14 @@ static void virtio_ccw_gpu_instance_init(Object *obj)
TYPE_VIRTIO_GPU);
}
-static Property virtio_ccw_gpu_properties[] = {
+static const Property virtio_ccw_gpu_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_gpu_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_gpu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-input.c b/hw/s390x/virtio-ccw-input.c
index 61a07ba..2250d8c 100644
--- a/hw/s390x/virtio-ccw-input.c
+++ b/hw/s390x/virtio-ccw-input.c
@@ -43,15 +43,14 @@ static void virtio_ccw_input_realize(VirtioCcwDevice *ccw_dev, Error **errp)
qdev_realize(vdev, BUS(&ccw_dev->bus), errp);
}
-static Property virtio_ccw_input_properties[] = {
+static const Property virtio_ccw_input_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_input_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_input_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-md-stubs.c b/hw/s390x/virtio-ccw-md-stubs.c
new file mode 100644
index 0000000..e937865
--- /dev/null
+++ b/hw/s390x/virtio-ccw-md-stubs.c
@@ -0,0 +1,24 @@
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/s390x/virtio-ccw-md.h"
+
+void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
+{
+ error_setg(errp, "virtio based memory devices not supported");
+}
+
+void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
+{
+ error_setg(errp, "virtio based memory devices not supported");
+}
+
+void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
+ Error **errp)
+{
+ error_setg(errp, "virtio based memory devices not supported");
+}
+
+void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
+{
+ error_setg(errp, "virtio based memory devices not supported");
+}
diff --git a/hw/s390x/virtio-ccw-md.c b/hw/s390x/virtio-ccw-md.c
new file mode 100644
index 0000000..0370f58
--- /dev/null
+++ b/hw/s390x/virtio-ccw-md.c
@@ -0,0 +1,153 @@
+/*
+ * Virtio CCW support for abstract virtio based memory device
+ *
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Authors:
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/s390x/virtio-ccw-md.h"
+#include "hw/mem/memory-device.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+
+void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
+{
+ DeviceState *dev = DEVICE(vmd);
+ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+ MemoryDeviceState *md = MEMORY_DEVICE(vmd);
+ Error *local_err = NULL;
+
+ if (!bus_handler && dev->hotplugged) {
+ /*
+ * Without a bus hotplug handler, we cannot control the plug/unplug
+ * order. We should never reach this point when hotplugging, but
+ * better add a safety net.
+ */
+ error_setg(errp, "hotplug of virtio based memory devices not supported"
+ " on this bus.");
+ return;
+ }
+
+ /*
+ * First, see if we can plug this memory device at all. If that
+ * succeeds, branch of to the actual hotplug handler.
+ */
+ memory_device_pre_plug(md, ms, &local_err);
+ if (!local_err && bus_handler) {
+ hotplug_handler_pre_plug(bus_handler, dev, &local_err);
+ }
+ error_propagate(errp, local_err);
+}
+
+void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
+{
+ DeviceState *dev = DEVICE(vmd);
+ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+ MemoryDeviceState *md = MEMORY_DEVICE(vmd);
+ Error *local_err = NULL;
+
+ /*
+ * Plug the memory device first and then branch off to the actual
+ * hotplug handler. If that one fails, we can easily undo the memory
+ * device bits.
+ */
+ memory_device_plug(md, ms);
+ if (bus_handler) {
+ hotplug_handler_plug(bus_handler, dev, &local_err);
+ if (local_err) {
+ memory_device_unplug(md, ms);
+ }
+ }
+ error_propagate(errp, local_err);
+}
+
+void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
+ Error **errp)
+{
+ VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd);
+ DeviceState *dev = DEVICE(vmd);
+ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+ HotplugHandlerClass *hdc;
+ Error *local_err = NULL;
+
+ if (!vmdc->unplug_request_check) {
+ error_setg(errp,
+ "this virtio based memory devices cannot be unplugged");
+ return;
+ }
+
+ if (!bus_handler) {
+ error_setg(errp, "hotunplug of virtio based memory devices not"
+ "supported on this bus");
+ return;
+ }
+
+ vmdc->unplug_request_check(vmd, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /*
+ * Forward the async request or turn it into a sync request (handling it
+ * like qdev_unplug()).
+ */
+ hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler);
+ if (hdc->unplug_request) {
+ hotplug_handler_unplug_request(bus_handler, dev, &local_err);
+ } else {
+ virtio_ccw_md_unplug(vmd, ms, &local_err);
+ if (!local_err) {
+ object_unparent(OBJECT(dev));
+ }
+ }
+}
+
+void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
+{
+ DeviceState *dev = DEVICE(vmd);
+ HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+ MemoryDeviceState *md = MEMORY_DEVICE(vmd);
+ Error *local_err = NULL;
+
+ /* Unplug the memory device while it is still realized. */
+ memory_device_unplug(md, ms);
+
+ if (bus_handler) {
+ hotplug_handler_unplug(bus_handler, dev, &local_err);
+ if (local_err) {
+ /* Not expected to fail ... but still try to recover. */
+ memory_device_plug(md, ms);
+ error_propagate(errp, local_err);
+ return;
+ }
+ } else {
+ /* Very unexpected, but let's just try to do the right thing. */
+ warn_report("Unexpected unplug of virtio based memory device");
+ qdev_unrealize(dev);
+ }
+}
+
+static const TypeInfo virtio_ccw_md_info = {
+ .name = TYPE_VIRTIO_MD_CCW,
+ .parent = TYPE_VIRTIO_CCW_DEVICE,
+ .instance_size = sizeof(VirtIOMDCcw),
+ .class_size = sizeof(VirtIOMDCcwClass),
+ .abstract = true,
+ .interfaces = (const InterfaceInfo[]) {
+ { TYPE_MEMORY_DEVICE },
+ { }
+ },
+};
+
+static void virtio_ccw_md_register(void)
+{
+ type_register_static(&virtio_ccw_md_info);
+}
+type_init(virtio_ccw_md_register)
diff --git a/hw/s390x/virtio-ccw-md.h b/hw/s390x/virtio-ccw-md.h
new file mode 100644
index 0000000..39ba864
--- /dev/null
+++ b/hw/s390x/virtio-ccw-md.h
@@ -0,0 +1,44 @@
+/*
+ * Virtio CCW support for abstract virtio based memory device
+ *
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Authors:
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_S390X_VIRTIO_CCW_MD_H
+#define HW_S390X_VIRTIO_CCW_MD_H
+
+#include "virtio-ccw.h"
+#include "qom/object.h"
+
+/*
+ * virtio-md-ccw: This extends VirtioCcwDevice.
+ */
+#define TYPE_VIRTIO_MD_CCW "virtio-md-ccw"
+
+OBJECT_DECLARE_TYPE(VirtIOMDCcw, VirtIOMDCcwClass, VIRTIO_MD_CCW)
+
+struct VirtIOMDCcwClass {
+ /* private */
+ VirtIOCCWDeviceClass parent;
+
+ /* public */
+ void (*unplug_request_check)(VirtIOMDCcw *vmd, Error **errp);
+};
+
+struct VirtIOMDCcw {
+ VirtioCcwDevice parent_obj;
+};
+
+void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
+void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
+void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
+ Error **errp);
+void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
+
+#endif /* HW_S390X_VIRTIO_CCW_MD_H */
diff --git a/hw/s390x/virtio-ccw-mem.c b/hw/s390x/virtio-ccw-mem.c
new file mode 100644
index 0000000..daa485d
--- /dev/null
+++ b/hw/s390x/virtio-ccw-mem.c
@@ -0,0 +1,225 @@
+/*
+ * virtio-mem CCW implementation
+ *
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Authors:
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "virtio-ccw-mem.h"
+#include "hw/mem/memory-device.h"
+#include "qapi/qapi-events-machine.h"
+#include "qapi/qapi-events-misc.h"
+
+static void virtio_ccw_mem_realize(VirtioCcwDevice *ccw_dev, Error **errp)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(ccw_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_realize(vdev, BUS(&ccw_dev->bus), errp);
+}
+
+static void virtio_ccw_mem_set_addr(MemoryDeviceState *md, uint64_t addr,
+ Error **errp)
+{
+ object_property_set_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP, addr, errp);
+}
+
+static uint64_t virtio_ccw_mem_get_addr(const MemoryDeviceState *md)
+{
+ return object_property_get_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP,
+ &error_abort);
+}
+
+static MemoryRegion *virtio_ccw_mem_get_memory_region(MemoryDeviceState *md,
+ Error **errp)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
+ VirtIOMEM *vmem = &dev->vdev;
+ VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem);
+
+ return vmc->get_memory_region(vmem, errp);
+}
+
+static void virtio_ccw_mem_decide_memslots(MemoryDeviceState *md,
+ unsigned int limit)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
+ VirtIOMEM *vmem = VIRTIO_MEM(&dev->vdev);
+ VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem);
+
+ vmc->decide_memslots(vmem, limit);
+}
+
+static unsigned int virtio_ccw_mem_get_memslots(MemoryDeviceState *md)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
+ VirtIOMEM *vmem = VIRTIO_MEM(&dev->vdev);
+ VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem);
+
+ return vmc->get_memslots(vmem);
+}
+
+static uint64_t virtio_ccw_mem_get_plugged_size(const MemoryDeviceState *md,
+ Error **errp)
+{
+ return object_property_get_uint(OBJECT(md), VIRTIO_MEM_SIZE_PROP,
+ errp);
+}
+
+static void virtio_ccw_mem_fill_device_info(const MemoryDeviceState *md,
+ MemoryDeviceInfo *info)
+{
+ VirtioMEMDeviceInfo *vi = g_new0(VirtioMEMDeviceInfo, 1);
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
+ VirtIOMEM *vmem = &dev->vdev;
+ VirtIOMEMClass *vpc = VIRTIO_MEM_GET_CLASS(vmem);
+ DeviceState *vdev = DEVICE(md);
+
+ if (vdev->id) {
+ vi->id = g_strdup(vdev->id);
+ }
+
+ /* let the real device handle everything else */
+ vpc->fill_device_info(vmem, vi);
+
+ info->u.virtio_mem.data = vi;
+ info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM;
+}
+
+static uint64_t virtio_ccw_mem_get_min_alignment(const MemoryDeviceState *md)
+{
+ return object_property_get_uint(OBJECT(md), VIRTIO_MEM_BLOCK_SIZE_PROP,
+ &error_abort);
+}
+
+static void virtio_ccw_mem_size_change_notify(Notifier *notifier, void *data)
+{
+ VirtIOMEMCcw *dev = container_of(notifier, VirtIOMEMCcw,
+ size_change_notifier);
+ DeviceState *vdev = DEVICE(dev);
+ char *qom_path = object_get_canonical_path(OBJECT(dev));
+ const uint64_t * const size_p = data;
+
+ qapi_event_send_memory_device_size_change(vdev->id, *size_p, qom_path);
+ g_free(qom_path);
+}
+
+static void virtio_ccw_mem_unplug_request_check(VirtIOMDCcw *vmd, Error **errp)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(vmd);
+ VirtIOMEM *vmem = &dev->vdev;
+ VirtIOMEMClass *vpc = VIRTIO_MEM_GET_CLASS(vmem);
+
+ vpc->unplug_request_check(vmem, errp);
+}
+
+static void virtio_ccw_mem_get_requested_size(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj);
+
+ object_property_get(OBJECT(&dev->vdev), name, v, errp);
+}
+
+static void virtio_ccw_mem_set_requested_size(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj);
+ DeviceState *vdev = DEVICE(obj);
+
+ /*
+ * If we passed virtio_ccw_mem_unplug_request_check(), making sure that
+ * the requested size is 0, don't allow modifying the requested size
+ * anymore, otherwise the VM might end up hotplugging memory before
+ * handling the unplug request.
+ */
+ if (vdev->pending_deleted_event) {
+ error_setg(errp, "'%s' cannot be changed if the device is in the"
+ " process of unplug", name);
+ return;
+ }
+
+ object_property_set(OBJECT(&dev->vdev), name, v, errp);
+}
+
+static const Property virtio_ccw_mem_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
+};
+
+static void virtio_ccw_mem_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
+ MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(klass);
+ VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_CLASS(klass);
+
+ k->realize = virtio_ccw_mem_realize;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ device_class_set_props(dc, virtio_ccw_mem_properties);
+
+ mdc->get_addr = virtio_ccw_mem_get_addr;
+ mdc->set_addr = virtio_ccw_mem_set_addr;
+ mdc->get_plugged_size = virtio_ccw_mem_get_plugged_size;
+ mdc->get_memory_region = virtio_ccw_mem_get_memory_region;
+ mdc->decide_memslots = virtio_ccw_mem_decide_memslots;
+ mdc->get_memslots = virtio_ccw_mem_get_memslots;
+ mdc->fill_device_info = virtio_ccw_mem_fill_device_info;
+ mdc->get_min_alignment = virtio_ccw_mem_get_min_alignment;
+
+ vmdc->unplug_request_check = virtio_ccw_mem_unplug_request_check;
+}
+
+static void virtio_ccw_mem_instance_init(Object *obj)
+{
+ VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj);
+ VirtIOMEMClass *vmc;
+ VirtIOMEM *vmem;
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_MEM);
+
+ dev->size_change_notifier.notify = virtio_ccw_mem_size_change_notify;
+ vmem = &dev->vdev;
+ vmc = VIRTIO_MEM_GET_CLASS(vmem);
+ /*
+ * We never remove the notifier again, as we expect both devices to
+ * disappear at the same time.
+ */
+ vmc->add_size_change_notifier(vmem, &dev->size_change_notifier);
+
+ object_property_add_alias(obj, VIRTIO_MEM_BLOCK_SIZE_PROP,
+ OBJECT(&dev->vdev), VIRTIO_MEM_BLOCK_SIZE_PROP);
+ object_property_add_alias(obj, VIRTIO_MEM_SIZE_PROP, OBJECT(&dev->vdev),
+ VIRTIO_MEM_SIZE_PROP);
+ object_property_add(obj, VIRTIO_MEM_REQUESTED_SIZE_PROP, "size",
+ virtio_ccw_mem_get_requested_size,
+ virtio_ccw_mem_set_requested_size, NULL, NULL);
+}
+
+static const TypeInfo virtio_ccw_mem = {
+ .name = TYPE_VIRTIO_MEM_CCW,
+ .parent = TYPE_VIRTIO_MD_CCW,
+ .instance_size = sizeof(VirtIOMEMCcw),
+ .instance_init = virtio_ccw_mem_instance_init,
+ .class_init = virtio_ccw_mem_class_init,
+};
+
+static void virtio_ccw_mem_register_types(void)
+{
+ type_register_static(&virtio_ccw_mem);
+}
+type_init(virtio_ccw_mem_register_types)
diff --git a/hw/s390x/virtio-ccw-mem.h b/hw/s390x/virtio-ccw-mem.h
new file mode 100644
index 0000000..738ab2c
--- /dev/null
+++ b/hw/s390x/virtio-ccw-mem.h
@@ -0,0 +1,34 @@
+/*
+ * Virtio MEM CCW device
+ *
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Authors:
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_S390X_VIRTIO_CCW_MEM_H
+#define HW_S390X_VIRTIO_CCW_MEM_H
+
+#include "virtio-ccw-md.h"
+#include "hw/virtio/virtio-mem.h"
+#include "qom/object.h"
+
+typedef struct VirtIOMEMCcw VirtIOMEMCcw;
+
+/*
+ * virtio-mem-ccw: This extends VirtIOMDCcw
+ */
+#define TYPE_VIRTIO_MEM_CCW "virtio-mem-ccw"
+DECLARE_INSTANCE_CHECKER(VirtIOMEMCcw, VIRTIO_MEM_CCW, TYPE_VIRTIO_MEM_CCW)
+
+struct VirtIOMEMCcw {
+ VirtIOMDCcw parent_obj;
+ VirtIOMEM vdev;
+ Notifier size_change_notifier;
+};
+
+#endif /* HW_S390X_VIRTIO_CCW_MEM_H */
diff --git a/hw/s390x/virtio-ccw-net.c b/hw/s390x/virtio-ccw-net.c
index 484e617..a7d4afb 100644
--- a/hw/s390x/virtio-ccw-net.c
+++ b/hw/s390x/virtio-ccw-net.c
@@ -46,15 +46,15 @@ static void virtio_ccw_net_instance_init(Object *obj)
"bootindex");
}
-static Property virtio_ccw_net_properties[] = {
+static const Property virtio_ccw_net_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm),
};
-static void virtio_ccw_net_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_net_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c
index a3fffb5..3263287 100644
--- a/hw/s390x/virtio-ccw-rng.c
+++ b/hw/s390x/virtio-ccw-rng.c
@@ -43,15 +43,14 @@ static void virtio_ccw_rng_instance_init(Object *obj)
TYPE_VIRTIO_RNG);
}
-static Property virtio_ccw_rng_properties[] = {
+static const Property virtio_ccw_rng_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_rng_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-scsi.c b/hw/s390x/virtio-ccw-scsi.c
index d003f89..06b4c6c 100644
--- a/hw/s390x/virtio-ccw-scsi.c
+++ b/hw/s390x/virtio-ccw-scsi.c
@@ -53,15 +53,14 @@ static void virtio_ccw_scsi_instance_init(Object *obj)
TYPE_VIRTIO_SCSI);
}
-static Property virtio_ccw_scsi_properties[] = {
+static const Property virtio_ccw_scsi_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_scsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw-serial.c b/hw/s390x/virtio-ccw-serial.c
index 8f8d230..0dac590 100644
--- a/hw/s390x/virtio-ccw-serial.c
+++ b/hw/s390x/virtio-ccw-serial.c
@@ -53,15 +53,14 @@ static void virtio_ccw_serial_instance_init(Object *obj)
TYPE_VIRTIO_SERIAL);
}
-static Property virtio_ccw_serial_properties[] = {
+static const Property virtio_ccw_serial_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_serial_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index b467690..d2f85b3 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -12,8 +12,8 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "sysemu/kvm.h"
+#include "system/address-spaces.h"
+#include "system/kvm.h"
#include "net/net.h"
#include "hw/virtio/virtio.h"
#include "migration/qemu-file-types.h"
@@ -32,7 +32,7 @@
#include "trace.h"
#include "hw/s390x/css-bridge.h"
#include "hw/s390x/s390-virtio-ccw.h"
-#include "sysemu/replay.h"
+#include "system/replay.h"
#define NR_CLASSIC_INDICATOR_BITS 64
@@ -913,14 +913,15 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
}
}
-static void virtio_ccw_reset(DeviceState *d)
+static void virtio_ccw_reset_hold(Object *obj, ResetType type)
{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(obj);
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
virtio_ccw_reset_virtio(dev);
- if (vdc->parent_reset) {
- vdc->parent_reset(d);
+
+ if (vdc->parent_phases.hold) {
+ vdc->parent_phases.hold(obj, type);
}
}
@@ -1156,7 +1157,6 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
CcwDevice *ccw_dev = CCW_DEVICE(d);
SubchDev *sch = ccw_dev->sch;
int n = virtio_get_num_queues(vdev);
- S390FLICState *flic = s390_get_flic();
if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) {
dev->max_rev = 0;
@@ -1183,10 +1183,10 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
VIRTIO_QUEUE_MAX);
return;
}
- if (virtio_get_num_queues(vdev) > flic->adapter_routes_max_batch) {
+ if (virtio_get_num_queues(vdev) > ADAPTER_ROUTES_MAX_GSI) {
error_setg(errp, "The number of virtqueues %d "
"exceeds flic adapter route limit %d", n,
- flic->adapter_routes_max_batch);
+ ADAPTER_ROUTES_MAX_GSI);
return;
}
@@ -1228,16 +1228,18 @@ static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
virtio_ccw_stop_ioeventfd(_dev);
}
-static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
CCWDeviceClass *k = CCW_DEVICE_CLASS(dc);
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
k->unplug = virtio_ccw_busdev_unplug;
dc->realize = virtio_ccw_busdev_realize;
dc->unrealize = virtio_ccw_busdev_unrealize;
- device_class_set_parent_reset(dc, virtio_ccw_reset, &vdc->parent_reset);
+ resettable_class_set_parent_phases(rc, NULL, virtio_ccw_reset_hold, NULL,
+ &vdc->parent_phases);
}
static const TypeInfo virtio_ccw_device_info = {
@@ -1260,7 +1262,7 @@ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
qbus_init(bus, bus_size, TYPE_VIRTIO_CCW_BUS, qdev, virtio_bus_name);
}
-static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
+static void virtio_ccw_bus_class_init(ObjectClass *klass, const void *data)
{
VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
BusClass *bus_class = BUS_CLASS(klass);
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index fac186c..c7a830a 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -57,7 +57,7 @@ struct VirtIOCCWDeviceClass {
CCWDeviceClass parent_class;
void (*realize)(VirtioCcwDevice *dev, Error **errp);
void (*unrealize)(VirtioCcwDevice *dev);
- void (*parent_reset)(DeviceState *dev);
+ ResettablePhases parent_phases;
};
/* Performance improves when virtqueue kick processing is decoupled from the
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index 42d9d2e..12c86eb 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -427,7 +427,7 @@ static void esp_pci_init(Object *obj)
object_initialize_child(obj, "esp", &pci->esp, TYPE_ESP);
}
-static void esp_pci_class_init(ObjectClass *klass, void *data)
+static void esp_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -440,7 +440,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_STORAGE_SCSI;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
- dc->reset = esp_pci_hard_reset;
+ device_class_set_legacy_reset(dc, esp_pci_hard_reset);
dc->vmsd = &vmstate_esp_pci_scsi;
}
@@ -450,7 +450,7 @@ static const TypeInfo esp_pci_info = {
.instance_init = esp_pci_init,
.instance_size = sizeof(PCIESPState),
.class_init = esp_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -557,7 +557,7 @@ static void dc390_scsi_realize(PCIDevice *dev, Error **errp)
contents[EE_CHKSUM2] = chksum >> 8;
}
-static void dc390_class_init(ObjectClass *klass, void *data)
+static void dc390_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b7af825..f24991f 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -242,10 +242,7 @@ static uint32_t esp_get_stc(ESPState *s)
static uint8_t esp_pdma_read(ESPState *s)
{
- uint8_t val;
-
- val = esp_fifo_pop(s);
- return val;
+ return esp_fifo_pop(s);
}
static void esp_pdma_write(ESPState *s, uint8_t val)
@@ -1571,12 +1568,12 @@ static const VMStateDescription vmstate_sysbus_esp_scsi = {
}
};
-static void sysbus_esp_class_init(ObjectClass *klass, void *data)
+static void sysbus_esp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sysbus_esp_realize;
- dc->reset = sysbus_esp_hard_reset;
+ device_class_set_legacy_reset(dc, sysbus_esp_hard_reset);
dc->vmsd = &vmstate_sysbus_esp_scsi;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
@@ -1597,7 +1594,7 @@ static void esp_init(Object *obj)
fifo8_create(&s->cmdfifo, ESP_CMDFIFO_SZ);
}
-static void esp_class_init(ObjectClass *klass, void *data)
+static void esp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index f1935e5..9ea4aa0 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -19,7 +19,7 @@
#include "hw/pci/pci_device.h"
#include "hw/scsi/scsi.h"
#include "migration/vmstate.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
@@ -1112,7 +1112,7 @@ bad:
static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
{
int n;
- uint8_t buf[LSI_BUF_SIZE];
+ QEMU_UNINITIALIZED uint8_t buf[LSI_BUF_SIZE];
trace_lsi_memcpy(dest, src, count);
while (count) {
@@ -2372,10 +2372,10 @@ static void lsi_scsi_exit(PCIDevice *dev)
LSIState *s = LSI53C895A(dev);
address_space_destroy(&s->pci_io_as);
- timer_del(s->scripts_timer);
+ timer_free(s->scripts_timer);
}
-static void lsi_class_init(ObjectClass *klass, void *data)
+static void lsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -2386,7 +2386,7 @@ static void lsi_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_LSI_53C895A;
k->class_id = PCI_CLASS_STORAGE_SCSI;
k->subsystem_id = 0x1000;
- dc->reset = lsi_scsi_reset;
+ device_class_set_legacy_reset(dc, lsi_scsi_reset);
dc->vmsd = &vmstate_lsi_scsi;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
@@ -2396,13 +2396,13 @@ static const TypeInfo lsi_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(LSIState),
.class_init = lsi_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void lsi53c810_class_init(ObjectClass *klass, void *data)
+static void lsi53c810_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 2d0c607..844643d 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -21,9 +21,9 @@
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
-#include "sysemu/dma.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/rtc.h"
+#include "system/dma.h"
+#include "system/block-backend.h"
+#include "system/rtc.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "qemu/iov.h"
@@ -981,13 +981,11 @@ static int megasas_event_wait(MegasasState *s, MegasasCmd *cmd)
static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
{
- struct mfi_pd_list info;
- size_t dcmd_size = sizeof(info);
+ struct mfi_pd_list info = {};
BusChild *kid;
uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
dma_addr_t residual;
- memset(&info, 0, dcmd_size);
offset = 8;
dcmd_limit = offset + sizeof(struct mfi_pd_address);
if (cmd->iov_size < dcmd_limit) {
@@ -1429,11 +1427,10 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd)
{
- struct mfi_ctrl_props info;
+ struct mfi_ctrl_props info = {};
size_t dcmd_size = sizeof(info);
dma_addr_t residual;
- memset(&info, 0x0, dcmd_size);
if (cmd->iov_size < dcmd_size) {
trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
dcmd_size);
@@ -1781,7 +1778,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd)
uint8_t cdb[16];
int len;
struct SCSIDevice *sdev = NULL;
- int target_id, lun_id, cdb_len;
+ int target_id, lun_id;
lba_count = le32_to_cpu(cmd->frame->io.header.data_len);
lba_start_lo = le32_to_cpu(cmd->frame->io.lba_lo);
@@ -1790,7 +1787,6 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd)
target_id = cmd->frame->header.target_id;
lun_id = cmd->frame->header.lun_id;
- cdb_len = cmd->frame->header.cdb_len;
if (target_id < MFI_MAX_LD && lun_id == 0) {
sdev = scsi_device_find(&s->bus, 0, target_id, lun_id);
@@ -1805,15 +1801,6 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd)
return MFI_STAT_DEVICE_NOT_FOUND;
}
- if (cdb_len > 16) {
- trace_megasas_scsi_invalid_cdb_len(
- mfi_frame_desc(frame_cmd), 1, target_id, lun_id, cdb_len);
- megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
- cmd->frame->header.scsi_status = CHECK_CONDITION;
- s->event_count++;
- return MFI_STAT_SCSI_DONE_WITH_ERROR;
- }
-
cmd->iov_size = lba_count * sdev->blocksize;
if (megasas_map_sgl(s, cmd, &cmd->frame->io.sgl)) {
megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE));
@@ -1824,7 +1811,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd)
megasas_encode_lba(cdb, lba_start, lba_count, is_write);
cmd->req = scsi_req_new(sdev, cmd->index,
- lun_id, cdb, cdb_len, cmd);
+ lun_id, cdb, sizeof(cdb), cmd);
if (!cmd->req) {
trace_megasas_scsi_req_alloc_failed(
mfi_frame_desc(frame_cmd), target_id, lun_id);
@@ -2236,7 +2223,6 @@ static uint64_t megasas_queue_read(void *opaque, hwaddr addr,
static void megasas_queue_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
- return;
}
static const MemoryRegionOps megasas_queue_ops = {
@@ -2458,7 +2444,7 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev), &megasas_scsi_info);
}
-static Property megasas_properties_gen1[] = {
+static const Property megasas_properties_gen1[] = {
DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
MEGASAS_DEFAULT_SGE),
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
@@ -2469,10 +2455,9 @@ static Property megasas_properties_gen1[] = {
DEFINE_PROP_ON_OFF_AUTO("msix", MegasasState, msix, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
MEGASAS_FLAG_USE_JBOD, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static Property megasas_properties_gen2[] = {
+static const Property megasas_properties_gen2[] = {
DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
MEGASAS_DEFAULT_SGE),
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
@@ -2483,7 +2468,6 @@ static Property megasas_properties_gen2[] = {
DEFINE_PROP_ON_OFF_AUTO("msix", MegasasState, msix, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
MEGASAS_FLAG_USE_JBOD, false),
- DEFINE_PROP_END_OF_LIST(),
};
typedef struct MegasasInfo {
@@ -2497,8 +2481,9 @@ typedef struct MegasasInfo {
int mmio_bar;
int osts;
const VMStateDescription *vmsd;
- Property *props;
- InterfaceInfo *interfaces;
+ const Property *props;
+ size_t props_count;
+ const InterfaceInfo *interfaces;
} MegasasInfo;
static struct MegasasInfo megasas_devices[] = {
@@ -2514,7 +2499,8 @@ static struct MegasasInfo megasas_devices[] = {
.osts = MFI_1078_RM | 1,
.vmsd = &vmstate_megasas_gen1,
.props = megasas_properties_gen1,
- .interfaces = (InterfaceInfo[]) {
+ .props_count = ARRAY_SIZE(megasas_properties_gen1),
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -2530,14 +2516,15 @@ static struct MegasasInfo megasas_devices[] = {
.osts = MFI_GEN2_RM,
.vmsd = &vmstate_megasas_gen2,
.props = megasas_properties_gen2,
- .interfaces = (InterfaceInfo[]) {
+ .props_count = ARRAY_SIZE(megasas_properties_gen2),
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
}
};
-static void megasas_class_init(ObjectClass *oc, void *data)
+static void megasas_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
@@ -2556,8 +2543,8 @@ static void megasas_class_init(ObjectClass *oc, void *data)
e->osts = info->osts;
e->product_name = info->product_name;
e->product_version = info->product_version;
- device_class_set_props(dc, info->props);
- dc->reset = megasas_scsi_reset;
+ device_class_set_props_n(dc, info->props, info->props_count);
+ device_class_set_legacy_reset(dc, megasas_scsi_reset);
dc->vmsd = info->vmsd;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = info->desc;
@@ -2582,11 +2569,11 @@ static void megasas_register_types(void)
type_info.name = info->name;
type_info.parent = TYPE_MEGASAS_BASE;
- type_info.class_data = (void *)info;
+ type_info.class_data = info;
type_info.class_init = megasas_class_init;
type_info.interfaces = info->interfaces;
- type_register(&type_info);
+ type_register_static(&type_info);
}
}
diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c
index 0d5abb4..6cba92f 100644
--- a/hw/scsi/mptendian.c
+++ b/hw/scsi/mptendian.c
@@ -22,7 +22,7 @@
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/pci/msi.h"
#include "qemu/iov.h"
#include "hw/scsi/scsi.h"
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index c5d3138..1ebe0b8 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/pci/msi.h"
#include "qemu/iov.h"
#include "qemu/main-loop.h"
@@ -1410,14 +1410,13 @@ static const VMStateDescription vmstate_mptsas = {
}
};
-static Property mptsas_properties[] = {
+static const Property mptsas_properties[] = {
DEFINE_PROP_UINT64("sas_address", MPTSASState, sas_addr, 0),
/* TODO: test MSI support under Windows */
DEFINE_PROP_ON_OFF_AUTO("msi", MPTSASState, msi, ON_OFF_AUTO_AUTO),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mptsas1068_class_init(ObjectClass *oc, void *data)
+static void mptsas1068_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
@@ -1431,7 +1430,7 @@ static void mptsas1068_class_init(ObjectClass *oc, void *data)
pc->subsystem_id = 0x8000;
pc->class_id = PCI_CLASS_STORAGE_SCSI;
device_class_set_props(dc, mptsas_properties);
- dc->reset = mptsas_reset;
+ device_class_set_legacy_reset(dc, mptsas_reset);
dc->vmsd = &vmstate_mptsas;
dc->desc = "LSI SAS 1068";
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
@@ -1442,7 +1441,7 @@ static const TypeInfo mptsas_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MPTSASState),
.class_init = mptsas1068_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -1450,7 +1449,7 @@ static const TypeInfo mptsas_info = {
static void mptsas_register_types(void)
{
- type_register(&mptsas_info);
+ type_register_static(&mptsas_info);
}
type_init(mptsas_register_types)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 53eff5d..9b12ee7 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -9,12 +9,12 @@
#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "scsi/constants.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
+#include "system/system.h"
+#include "system/runstate.h"
#include "trace.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/cutils.h"
static char *scsibus_get_dev_path(DeviceState *dev);
@@ -100,8 +100,15 @@ static void scsi_device_for_each_req_sync(SCSIDevice *s,
assert(!runstate_is_running());
assert(qemu_in_main_thread());
- QTAILQ_FOREACH_SAFE(req, &s->requests, next, next_req) {
- fn(req, opaque);
+ /*
+ * Locking is not necessary because the guest is stopped and no other
+ * threads can be accessing the requests list, but take the lock for
+ * consistency.
+ */
+ WITH_QEMU_LOCK_GUARD(&s->requests_lock) {
+ QTAILQ_FOREACH_SAFE(req, &s->requests, next, next_req) {
+ fn(req, opaque);
+ }
}
}
@@ -115,21 +122,29 @@ static void scsi_device_for_each_req_async_bh(void *opaque)
{
g_autofree SCSIDeviceForEachReqAsyncData *data = opaque;
SCSIDevice *s = data->s;
- AioContext *ctx;
- SCSIRequest *req;
- SCSIRequest *next;
+ g_autoptr(GList) reqs = NULL;
/*
- * The BB cannot have changed contexts between this BH being scheduled and
- * now: BBs' AioContexts, when they have a node attached, can only be
- * changed via bdrv_try_change_aio_context(), in a drained section. While
- * we have the in-flight counter incremented, that drain must block.
+ * Build a list of requests in this AioContext so fn() can be invoked later
+ * outside requests_lock.
*/
- ctx = blk_get_aio_context(s->conf.blk);
- assert(ctx == qemu_get_current_aio_context());
+ WITH_QEMU_LOCK_GUARD(&s->requests_lock) {
+ AioContext *ctx = qemu_get_current_aio_context();
+ SCSIRequest *req;
+ SCSIRequest *next;
+
+ QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
+ if (req->ctx == ctx) {
+ scsi_req_ref(req); /* dropped after calling fn() */
+ reqs = g_list_prepend(reqs, req);
+ }
+ }
+ }
- QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
- data->fn(req, data->fn_opaque);
+ /* Call fn() on each request */
+ for (GList *elem = g_list_first(reqs); elem; elem = g_list_next(elem)) {
+ data->fn(elem->data, data->fn_opaque);
+ scsi_req_unref(elem->data);
}
/* Drop the reference taken by scsi_device_for_each_req_async() */
@@ -139,9 +154,35 @@ static void scsi_device_for_each_req_async_bh(void *opaque)
blk_dec_in_flight(s->conf.blk);
}
+static void scsi_device_for_each_req_async_do_ctx(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ AioContext *ctx = key;
+ SCSIDeviceForEachReqAsyncData *params = user_data;
+ SCSIDeviceForEachReqAsyncData *data;
+
+ data = g_new(SCSIDeviceForEachReqAsyncData, 1);
+ data->s = params->s;
+ data->fn = params->fn;
+ data->fn_opaque = params->fn_opaque;
+
+ /*
+ * Hold a reference to the SCSIDevice until
+ * scsi_device_for_each_req_async_bh() finishes.
+ */
+ object_ref(OBJECT(data->s));
+
+ /* Paired with scsi_device_for_each_req_async_bh() */
+ blk_inc_in_flight(data->s->conf.blk);
+
+ aio_bh_schedule_oneshot(ctx, scsi_device_for_each_req_async_bh, data);
+}
+
/*
* Schedule @fn() to be invoked for each enqueued request in device @s. @fn()
- * runs in the AioContext that is executing the request.
+ * must be thread-safe because it runs concurrently in each AioContext that is
+ * executing a request.
+ *
* Keeps the BlockBackend's in-flight counter incremented until everything is
* done, so draining it will settle all scheduled @fn() calls.
*/
@@ -151,24 +192,26 @@ static void scsi_device_for_each_req_async(SCSIDevice *s,
{
assert(qemu_in_main_thread());
- SCSIDeviceForEachReqAsyncData *data =
- g_new(SCSIDeviceForEachReqAsyncData, 1);
-
- data->s = s;
- data->fn = fn;
- data->fn_opaque = opaque;
-
- /*
- * Hold a reference to the SCSIDevice until
- * scsi_device_for_each_req_async_bh() finishes.
- */
- object_ref(OBJECT(s));
+ /* The set of AioContexts where the requests are being processed */
+ g_autoptr(GHashTable) aio_contexts = g_hash_table_new(NULL, NULL);
+ WITH_QEMU_LOCK_GUARD(&s->requests_lock) {
+ SCSIRequest *req;
+ QTAILQ_FOREACH(req, &s->requests, next) {
+ g_hash_table_add(aio_contexts, req->ctx);
+ }
+ }
- /* Paired with blk_dec_in_flight() in scsi_device_for_each_req_async_bh() */
- blk_inc_in_flight(s->conf.blk);
- aio_bh_schedule_oneshot(blk_get_aio_context(s->conf.blk),
- scsi_device_for_each_req_async_bh,
- data);
+ /* Schedule a BH for each AioContext */
+ SCSIDeviceForEachReqAsyncData params = {
+ .s = s,
+ .fn = fn,
+ .fn_opaque = opaque,
+ };
+ g_hash_table_foreach(
+ aio_contexts,
+ scsi_device_for_each_req_async_do_ctx,
+ &params
+ );
}
static void scsi_device_realize(SCSIDevice *s, Error **errp)
@@ -349,6 +392,7 @@ static void scsi_qdev_realize(DeviceState *qdev, Error **errp)
dev->lun = lun;
}
+ qemu_mutex_init(&dev->requests_lock);
QTAILQ_INIT(&dev->requests);
scsi_device_realize(dev, &local_err);
if (local_err) {
@@ -356,7 +400,7 @@ static void scsi_qdev_realize(DeviceState *qdev, Error **errp)
return;
}
dev->vmsentry = qdev_add_vm_change_state_handler(DEVICE(dev),
- scsi_dma_restart_cb, dev);
+ scsi_dma_restart_cb, NULL, dev);
}
static void scsi_qdev_unrealize(DeviceState *qdev)
@@ -369,6 +413,8 @@ static void scsi_qdev_unrealize(DeviceState *qdev)
scsi_device_purge_requests(dev, SENSE_CODE(NO_SENSE));
+ qemu_mutex_destroy(&dev->requests_lock);
+
scsi_device_unrealize(dev);
blockdev_mark_auto_del(dev->conf.blk);
@@ -868,6 +914,7 @@ invalid_opcode:
}
}
+ req->ctx = qemu_get_current_aio_context();
req->cmd = cmd;
req->residual = req->cmd.xfer;
@@ -964,7 +1011,10 @@ static void scsi_req_enqueue_internal(SCSIRequest *req)
req->sg = NULL;
}
req->enqueued = true;
- QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
+
+ WITH_QEMU_LOCK_GUARD(&req->dev->requests_lock) {
+ QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
+ }
}
int32_t scsi_req_enqueue(SCSIRequest *req)
@@ -984,7 +1034,9 @@ static void scsi_req_dequeue(SCSIRequest *req)
trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
req->retry = false;
if (req->enqueued) {
- QTAILQ_REMOVE(&req->dev->requests, req, next);
+ WITH_QEMU_LOCK_GUARD(&req->dev->requests_lock) {
+ QTAILQ_REMOVE(&req->dev->requests, req, next);
+ }
req->enqueued = false;
scsi_req_unref(req);
}
@@ -1943,14 +1995,13 @@ const VMStateDescription vmstate_scsi_device = {
}
};
-static Property scsi_props[] = {
+static const Property scsi_props[] = {
DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void scsi_device_class_init(ObjectClass *klass, void *data)
+static void scsi_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
@@ -1962,8 +2013,7 @@ static void scsi_device_class_init(ObjectClass *klass, void *data)
static void scsi_dev_instance_init(Object *obj)
{
- DeviceState *dev = DEVICE(obj);
- SCSIDevice *s = SCSI_DEVICE(dev);
+ SCSIDevice *s = SCSI_DEVICE(obj);
device_add_bootindex_property(obj, &s->conf.bootindex,
"bootindex", NULL,
@@ -1980,7 +2030,7 @@ static const TypeInfo scsi_device_type_info = {
.instance_init = scsi_dev_instance_init,
};
-static void scsi_bus_class_init(ObjectClass *klass, void *data)
+static void scsi_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
@@ -1996,7 +2046,7 @@ static const TypeInfo scsi_bus_info = {
.parent = TYPE_BUS,
.instance_size = sizeof(SCSIBus),
.class_init = scsi_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 4d94b2b..b4782c6 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -32,13 +32,14 @@
#include "migration/vmstate.h"
#include "hw/scsi/emulation.h"
#include "scsi/constants.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
+#include "system/arch_init.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
#include "hw/block/block.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
+#include "system/dma.h"
+#include "system/system.h"
#include "qemu/cutils.h"
#include "trace.h"
#include "qom/object.h"
@@ -67,14 +68,13 @@ struct SCSIDiskClass {
SCSIDeviceClass parent_class;
/*
* Callbacks receive ret == 0 for success. Errors are represented either as
- * negative errno values, or as positive SAM status codes.
- *
- * Beware: For errors returned in host_status, the function may directly
- * complete the request and never call the callback.
+ * negative errno values, or as positive SAM status codes. For host_status
+ * errors, the function passes ret == -ENODEV and sets the host_status field
+ * of the SCSIRequest.
*/
DMAIOFunc *dma_readv;
DMAIOFunc *dma_writev;
- bool (*need_fua_emulation)(SCSICommand *cmd);
+ bool (*need_fua)(SCSICommand *cmd);
void (*update_sense)(SCSIRequest *r);
};
@@ -85,7 +85,7 @@ typedef struct SCSIDiskReq {
uint32_t sector_count;
uint32_t buflen;
bool started;
- bool need_fua_emulation;
+ bool need_fua;
struct iovec iov;
QEMUIOVector qiov;
BlockAcctCookie acct;
@@ -105,12 +105,12 @@ struct SCSIDiskState {
uint64_t max_unmap_size;
uint64_t max_io_size;
uint32_t quirks;
- QEMUBH *bh;
char *version;
char *serial;
char *vendor;
char *product;
char *device_id;
+ char *loadparm; /* only for s390x */
bool tray_open;
bool tray_locked;
/*
@@ -224,11 +224,26 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
SCSISense sense = SENSE_CODE(NO_SENSE);
+ int16_t host_status;
int error;
bool req_has_sense = false;
BlockErrorAction action;
int status;
+ /*
+ * host_status should only be set for SG_IO requests that came back with a
+ * host_status error in scsi_block_sgio_complete(). This error path passes
+ * -ENODEV as the return value.
+ *
+ * Reset host_status in the request because we may still want to complete
+ * the request successfully with the 'stop' or 'ignore' error policy.
+ */
+ host_status = r->req.host_status;
+ if (host_status != -1) {
+ assert(ret == -ENODEV);
+ r->req.host_status = -1;
+ }
+
if (ret < 0) {
status = scsi_sense_from_errno(-ret, &sense);
error = -ret;
@@ -288,6 +303,10 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
if (acct_failed) {
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
}
+ if (host_status != -1) {
+ scsi_req_complete_failed(&r->req, host_status);
+ return true;
+ }
if (req_has_sense) {
sdc->update_sense(&r->req);
} else if (status == CHECK_CONDITION) {
@@ -327,9 +346,8 @@ static void scsi_aio_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- /* The request must only run in the BlockBackend's AioContext */
- assert(blk_get_aio_context(s->qdev.conf.blk) ==
- qemu_get_current_aio_context());
+ /* The request must run in its AioContext */
+ assert(r->req.ctx == qemu_get_current_aio_context());
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
@@ -371,24 +389,6 @@ static bool scsi_is_cmd_fua(SCSICommand *cmd)
}
}
-static void scsi_write_do_fua(SCSIDiskReq *r)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- assert(r->req.aiocb == NULL);
- assert(!r->req.io_canceled);
-
- if (r->need_fua_emulation) {
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
- BLOCK_ACCT_FLUSH);
- r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
- return;
- }
-
- scsi_req_complete(&r->req, GOOD);
- scsi_req_unref(&r->req);
-}
-
static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
{
assert(r->req.aiocb == NULL);
@@ -398,18 +398,12 @@ static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
r->sector += r->sector_count;
r->sector_count = 0;
- if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
- scsi_write_do_fua(r);
- return;
- } else {
- scsi_req_complete(&r->req, GOOD);
- }
+ scsi_req_complete(&r->req, GOOD);
done:
scsi_req_unref(&r->req);
}
-/* May not be called in all error cases, don't rely on cleanup here */
static void scsi_dma_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -429,12 +423,10 @@ static void scsi_dma_complete(void *opaque, int ret)
static void scsi_read_complete_noio(SCSIDiskReq *r, int ret)
{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- /* The request must only run in the BlockBackend's AioContext */
- assert(blk_get_aio_context(s->qdev.conf.blk) ==
- qemu_get_current_aio_context());
+ /* The request must run in its AioContext */
+ assert(r->req.ctx == qemu_get_current_aio_context());
assert(r->req.aiocb == NULL);
if (scsi_disk_req_check_error(r, ret, ret > 0)) {
@@ -450,7 +442,6 @@ done:
scsi_req_unref(&r->req);
}
-/* May not be called in all error cases, don't rely on cleanup here */
static void scsi_read_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -486,8 +477,7 @@ static void scsi_do_read(SCSIDiskReq *r, int ret)
if (r->req.sg) {
dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ);
r->req.residual -= r->req.sg->size;
- r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk),
- r->req.sg, r->sector << BDRV_SECTOR_BITS,
+ r->req.aiocb = dma_blk_io(r->req.sg, r->sector << BDRV_SECTOR_BITS,
BDRV_SECTOR_SIZE,
sdc->dma_readv, r, scsi_dma_complete, r,
DMA_DIRECTION_FROM_DEVICE);
@@ -551,7 +541,7 @@ static void scsi_read_data(SCSIRequest *req)
first = !r->started;
r->started = true;
- if (first && r->need_fua_emulation) {
+ if (first && r->need_fua) {
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
BLOCK_ACCT_FLUSH);
r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r);
@@ -562,12 +552,10 @@ static void scsi_read_data(SCSIRequest *req)
static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- /* The request must only run in the BlockBackend's AioContext */
- assert(blk_get_aio_context(s->qdev.conf.blk) ==
- qemu_get_current_aio_context());
+ /* The request must run in its AioContext */
+ assert(r->req.ctx == qemu_get_current_aio_context());
assert (r->req.aiocb == NULL);
if (scsi_disk_req_check_error(r, ret, ret > 0)) {
@@ -578,8 +566,7 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
r->sector += n;
r->sector_count -= n;
if (r->sector_count == 0) {
- scsi_write_do_fua(r);
- return;
+ scsi_req_complete(&r->req, GOOD);
} else {
scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
trace_scsi_disk_write_complete_noio(r->req.tag, r->qiov.size);
@@ -590,7 +577,6 @@ done:
scsi_req_unref(&r->req);
}
-/* May not be called in all error cases, don't rely on cleanup here */
static void scsi_write_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -613,6 +599,7 @@ static void scsi_write_data(SCSIRequest *req)
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
+ BlockCompletionFunc *cb;
/* No data transfer may already be in progress */
assert(r->req.aiocb == NULL);
@@ -638,19 +625,17 @@ static void scsi_write_data(SCSIRequest *req)
if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
r->req.cmd.buf[0] == VERIFY_16) {
- if (r->req.sg) {
- scsi_dma_complete_noio(r, 0);
- } else {
- scsi_write_complete_noio(r, 0);
- }
+ block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
+ BLOCK_ACCT_FLUSH);
+ cb = r->req.sg ? scsi_dma_complete : scsi_write_complete;
+ r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, cb, r);
return;
}
if (r->req.sg) {
dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_WRITE);
r->req.residual -= r->req.sg->size;
- r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk),
- r->req.sg, r->sector << BDRV_SECTOR_BITS,
+ r->req.aiocb = dma_blk_io(r->req.sg, r->sector << BDRV_SECTOR_BITS,
BDRV_SECTOR_SIZE,
sdc->dma_writev, r, scsi_dma_complete, r,
DMA_DIRECTION_TO_DEVICE);
@@ -2382,7 +2367,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
return 0;
}
- r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd);
+ r->need_fua = sdc->need_fua(&r->req.cmd);
if (r->sector_count == 0) {
scsi_req_complete(&r->req, GOOD);
}
@@ -2852,14 +2837,10 @@ static void scsi_block_sgio_complete(void *opaque, int ret)
sg_io_hdr_t *io_hdr = &req->io_header;
if (ret == 0) {
- /* FIXME This skips calling req->cb() and any cleanup in it */
if (io_hdr->host_status != SCSI_HOST_OK) {
- scsi_req_complete_failed(&r->req, io_hdr->host_status);
- scsi_req_unref(&r->req);
- return;
- }
-
- if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
+ r->req.host_status = io_hdr->host_status;
+ ret = -ENODEV;
+ } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
ret = BUSY;
} else {
ret = io_hdr->status;
@@ -3132,19 +3113,57 @@ BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov,
{
SCSIDiskReq *r = opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
+ int flags = r->need_fua ? BDRV_REQ_FUA : 0;
+ return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, flags, cb, cb_opaque);
}
-static void scsi_disk_base_class_initfn(ObjectClass *klass, void *data)
+static char *scsi_property_get_loadparm(Object *obj, Error **errp)
+{
+ return g_strdup(SCSI_DISK_BASE(obj)->loadparm);
+}
+
+static void scsi_property_set_loadparm(Object *obj, const char *value,
+ Error **errp)
+{
+ void *lp_str;
+
+ if (object_property_get_int(obj, "bootindex", NULL) < 0) {
+ error_setg(errp, "'loadparm' is only valid for boot devices");
+ return;
+ }
+
+ lp_str = g_malloc0(strlen(value) + 1);
+ if (!qdev_prop_sanitize_s390x_loadparm(lp_str, value, errp)) {
+ g_free(lp_str);
+ return;
+ }
+ SCSI_DISK_BASE(obj)->loadparm = lp_str;
+}
+
+static void scsi_property_add_specifics(DeviceClass *dc)
+{
+ ObjectClass *oc = OBJECT_CLASS(dc);
+
+ /* The loadparm property is only supported on s390x */
+ if (qemu_arch_available(QEMU_ARCH_S390X)) {
+ object_class_property_add_str(oc, "loadparm",
+ scsi_property_get_loadparm,
+ scsi_property_set_loadparm);
+ object_class_property_set_description(oc, "loadparm",
+ "load parameter (s390x only)");
+ }
+}
+
+static void scsi_disk_base_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass);
dc->fw_name = "disk";
- dc->reset = scsi_disk_reset;
+ device_class_set_legacy_reset(dc, scsi_disk_reset);
sdc->dma_readv = scsi_dma_readv;
sdc->dma_writev = scsi_dma_writev;
- sdc->need_fua_emulation = scsi_is_cmd_fua;
+ sdc->need_fua = scsi_is_cmd_fua;
}
static const TypeInfo scsi_disk_base_info = {
@@ -3168,12 +3187,12 @@ static const TypeInfo scsi_disk_base_info = {
DEFINE_PROP_BOOL("migrate-emulated-scsi-request", SCSIDiskState, migrate_emulated_scsi_request, true)
-static Property scsi_hd_properties[] = {
+static const Property scsi_hd_properties[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_BIT("removable", SCSIDiskState, features,
SCSI_DISK_F_REMOVABLE, false),
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
- SCSI_DISK_F_DPOFUA, false),
+ SCSI_DISK_F_DPOFUA, true),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0),
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0),
DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
@@ -3188,7 +3207,6 @@ static Property scsi_hd_properties[] = {
quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE,
0),
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_scsi_disk_state = {
@@ -3206,7 +3224,7 @@ static const VMStateDescription vmstate_scsi_disk_state = {
}
};
-static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
+static void scsi_hd_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
@@ -3218,6 +3236,8 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
dc->desc = "virtual SCSI disk";
device_class_set_props(dc, scsi_hd_properties);
dc->vmsd = &vmstate_scsi_disk_state;
+
+ scsi_property_add_specifics(dc);
}
static const TypeInfo scsi_hd_info = {
@@ -3226,7 +3246,7 @@ static const TypeInfo scsi_hd_info = {
.class_init = scsi_hd_class_initfn,
};
-static Property scsi_cd_properties[] = {
+static const Property scsi_cd_properties[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0),
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0),
@@ -3244,10 +3264,9 @@ static Property scsi_cd_properties[] = {
0),
DEFINE_PROP_BIT("quirk_mode_page_truncated", SCSIDiskState, quirks,
SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
+static void scsi_cd_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
@@ -3258,6 +3277,8 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
dc->desc = "virtual SCSI CD-ROM";
device_class_set_props(dc, scsi_cd_properties);
dc->vmsd = &vmstate_scsi_disk_state;
+
+ scsi_property_add_specifics(dc);
}
static const TypeInfo scsi_cd_info = {
@@ -3267,7 +3288,7 @@ static const TypeInfo scsi_cd_info = {
};
#ifdef __linux__
-static Property scsi_block_properties[] = {
+static const Property scsi_block_properties[] = {
DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf),
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk),
DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false),
@@ -3280,10 +3301,9 @@ static Property scsi_block_properties[] = {
-1),
DEFINE_PROP_UINT32("io_timeout", SCSIDiskState, qdev.io_timeout,
DEFAULT_IO_TIMEOUT),
- DEFINE_PROP_END_OF_LIST(),
};
-static void scsi_block_class_initfn(ObjectClass *klass, void *data)
+static void scsi_block_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
@@ -3295,7 +3315,7 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data)
sdc->dma_readv = scsi_block_dma_readv;
sdc->dma_writev = scsi_block_dma_writev;
sdc->update_sense = scsi_block_update_sense;
- sdc->need_fua_emulation = scsi_block_no_fua;
+ sdc->need_fua = scsi_block_no_fua;
dc->desc = "SCSI block device passthrough";
device_class_set_props(dc, scsi_block_properties);
dc->vmsd = &vmstate_scsi_disk_state;
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index ee945f8..9e380a2 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -21,7 +21,7 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/scsi/emulation.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "trace.h"
#ifdef __linux__
@@ -772,12 +772,11 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
}
-static Property scsi_generic_properties[] = {
+static const Property scsi_generic_properties[] = {
DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
DEFINE_PROP_UINT32("io_timeout", SCSIDevice, io_timeout,
DEFAULT_IO_TIMEOUT),
- DEFINE_PROP_END_OF_LIST(),
};
static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
@@ -787,7 +786,7 @@ static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
return scsi_bus_parse_cdb(dev, cmd, buf, buf_len, hba_private);
}
-static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
+static void scsi_generic_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
@@ -797,7 +796,7 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
sc->parse_cdb = scsi_generic_parse_cdb;
dc->fw_name = "disk";
dc->desc = "pass through generic scsi device (/dev/sg*)";
- dc->reset = scsi_generic_reset;
+ device_class_set_legacy_reset(dc, scsi_generic_reset);
device_class_set_props(dc, scsi_generic_properties);
dc->vmsd = &vmstate_scsi_device;
}
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index c75a6c8..20f70fb 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -1250,9 +1250,8 @@ static int spapr_vscsi_devnode(SpaprVioDevice *dev, void *fdt, int node_off)
return 0;
}
-static Property spapr_vscsi_properties[] = {
+static const Property spapr_vscsi_properties[] = {
DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_spapr_vscsi = {
@@ -1268,7 +1267,7 @@ static const VMStateDescription vmstate_spapr_vscsi = {
},
};
-static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
+static void spapr_vscsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c
index 4c86370..43525ba 100644
--- a/hw/scsi/vhost-scsi-common.c
+++ b/hw/scsi/vhost-scsi-common.c
@@ -101,24 +101,25 @@ err_host_notifiers:
return ret;
}
-void vhost_scsi_common_stop(VHostSCSICommon *vsc)
+int vhost_scsi_common_stop(VHostSCSICommon *vsc)
{
VirtIODevice *vdev = VIRTIO_DEVICE(vsc);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret = 0;
- vhost_dev_stop(&vsc->dev, vdev, true);
+ ret = vhost_dev_stop(&vsc->dev, vdev, true);
if (k->set_guest_notifiers) {
- ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
- if (ret < 0) {
- error_report("vhost guest notifier cleanup failed: %d", ret);
+ int r = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
+ if (r < 0) {
+ error_report("vhost guest notifier cleanup failed: %d", ret);
+ return r;
}
}
- assert(ret >= 0);
vhost_dev_disable_notifiers(&vsc->dev, vdev);
+ return ret;
}
uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features,
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 49cff2a..cdf405b 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -29,7 +29,7 @@
#include "hw/fw-path-provider.h"
#include "hw/qdev-properties.h"
#include "qemu/cutils.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
/* Features supported by host kernel. */
static const int kernel_feature_bits[] = {
@@ -114,7 +114,7 @@ static void vhost_scsi_stop(VHostSCSI *s)
vhost_scsi_common_stop(vsc);
}
-static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
+static int vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
{
VHostSCSI *s = VHOST_SCSI(vdev);
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
@@ -125,7 +125,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
}
if (vhost_dev_is_started(&vsc->dev) == start) {
- return;
+ return 0;
}
if (start) {
@@ -139,6 +139,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
} else {
vhost_scsi_stop(s);
}
+ return 0;
}
static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
@@ -172,7 +173,7 @@ static int vhost_scsi_set_workers(VHostSCSICommon *vsc, bool per_virtqueue)
struct vhost_dev *dev = &vsc->dev;
struct vhost_vring_worker vq_worker;
struct vhost_worker_state worker;
- int i, ret;
+ int i, ret = 0;
/* Use default worker */
if (!per_virtqueue || dev->nvqs == VHOST_SCSI_VQ_NUM_FIXED + 1) {
@@ -314,7 +315,6 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
if (vhostfd >= 0) {
close(vhostfd);
}
- return;
}
static void vhost_scsi_unrealize(DeviceState *dev)
@@ -343,7 +343,7 @@ static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev)
return &vsc->dev;
}
-static Property vhost_scsi_properties[] = {
+static const Property vhost_scsi_properties[] = {
DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd),
DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn),
DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
@@ -359,13 +359,15 @@ static Property vhost_scsi_properties[] = {
DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
VIRTIO_SCSI_F_T10_PI,
false),
+ DEFINE_PROP_BIT64("hotplug", VHostSCSICommon, host_features,
+ VIRTIO_SCSI_F_HOTPLUG,
+ false),
DEFINE_PROP_BOOL("migratable", VHostSCSICommon, migratable, false),
DEFINE_PROP_BOOL("worker_per_virtqueue", VirtIOSCSICommon,
conf.worker_per_virtqueue, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vhost_scsi_class_init(ObjectClass *klass, void *data)
+static void vhost_scsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -399,7 +401,7 @@ static const TypeInfo vhost_scsi_info = {
.instance_size = sizeof(VHostSCSI),
.class_init = vhost_scsi_class_init,
.instance_init = vhost_scsi_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
{ }
},
diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c
index 55e4be5..25f2d89 100644
--- a/hw/scsi/vhost-user-scsi.c
+++ b/hw/scsi/vhost-user-scsi.c
@@ -27,7 +27,7 @@
#include "hw/virtio/vhost-user-scsi.h"
#include "hw/virtio/virtio.h"
#include "chardev/char-fe.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
/* Features supported by the host application */
static const int user_feature_bits[] = {
@@ -52,19 +52,19 @@ static int vhost_user_scsi_start(VHostUserSCSI *s, Error **errp)
return ret;
}
-static void vhost_user_scsi_stop(VHostUserSCSI *s)
+static int vhost_user_scsi_stop(VHostUserSCSI *s)
{
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
if (!s->started_vu) {
- return;
+ return 0;
}
s->started_vu = false;
- vhost_scsi_common_stop(vsc);
+ return vhost_scsi_common_stop(vsc);
}
-static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
+static int vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserSCSI *s = (VHostUserSCSI *)vdev;
DeviceState *dev = DEVICE(vdev);
@@ -75,11 +75,11 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
int ret;
if (!s->connected) {
- return;
+ return -1;
}
if (vhost_dev_is_started(&vsc->dev) == should_start) {
- return;
+ return 0;
}
if (should_start) {
@@ -91,8 +91,12 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
qemu_chr_fe_disconnect(&vs->conf.chardev);
}
} else {
- vhost_user_scsi_stop(s);
+ ret = vhost_user_scsi_stop(s);
+ if (ret) {
+ return ret;
+ }
}
+ return 0;
}
static void vhost_user_scsi_handle_output(VirtIODevice *vdev, VirtQueue *vq)
@@ -341,7 +345,7 @@ static void vhost_user_scsi_unrealize(DeviceState *dev)
virtio_scsi_common_unrealize(dev);
}
-static Property vhost_user_scsi_properties[] = {
+static const Property vhost_user_scsi_properties[] = {
DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev),
DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues,
@@ -360,7 +364,6 @@ static Property vhost_user_scsi_properties[] = {
DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
VIRTIO_SCSI_F_T10_PI,
false),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_scsi_reset(VirtIODevice *vdev)
@@ -387,7 +390,7 @@ static const VMStateDescription vmstate_vhost_scsi = {
},
};
-static void vhost_user_scsi_class_init(ObjectClass *klass, void *data)
+static void vhost_user_scsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -423,7 +426,7 @@ static const TypeInfo vhost_user_scsi_info = {
.instance_size = sizeof(VHostUserSCSI),
.class_init = vhost_user_scsi_class_init,
.instance_init = vhost_user_scsi_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
{ }
},
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 2806a12..95f13fb 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -15,9 +15,10 @@
#include "qapi/error.h"
#include "hw/virtio/virtio-scsi.h"
#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "hw/scsi/scsi.h"
#include "scsi/constants.h"
+#include "hw/virtio/iothread-vq-mapping.h"
#include "hw/virtio/virtio-bus.h"
/* Context: BQL held */
@@ -28,7 +29,14 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- if (vs->conf.iothread) {
+ if (vs->conf.iothread && vs->conf.iothread_vq_mapping_list) {
+ error_setg(errp,
+ "iothread and iothread-vq-mapping properties cannot be set "
+ "at the same time");
+ return;
+ }
+
+ if (vs->conf.iothread || vs->conf.iothread_vq_mapping_list) {
if (!k->set_guest_notifiers || !k->ioeventfd_assign) {
error_setg(errp,
"device is incompatible with iothread "
@@ -39,15 +47,64 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
error_setg(errp, "ioeventfd is required for iothread");
return;
}
- s->ctx = iothread_get_aio_context(vs->conf.iothread);
- } else {
- if (!virtio_device_ioeventfd_enabled(vdev)) {
+ }
+
+ s->vq_aio_context = g_new(AioContext *, vs->conf.num_queues +
+ VIRTIO_SCSI_VQ_NUM_FIXED);
+
+ /*
+ * Handle the ctrl virtqueue in the main loop thread where device resets
+ * can be performed.
+ */
+ s->vq_aio_context[0] = qemu_get_aio_context();
+
+ /*
+ * Handle the event virtqueue in the main loop thread where its no_poll
+ * behavior won't stop IOThread polling.
+ */
+ s->vq_aio_context[1] = qemu_get_aio_context();
+
+ if (vs->conf.iothread_vq_mapping_list) {
+ if (!iothread_vq_mapping_apply(vs->conf.iothread_vq_mapping_list,
+ &s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED],
+ vs->conf.num_queues, errp)) {
+ g_free(s->vq_aio_context);
+ s->vq_aio_context = NULL;
return;
}
- s->ctx = qemu_get_aio_context();
+ } else if (vs->conf.iothread) {
+ AioContext *ctx = iothread_get_aio_context(vs->conf.iothread);
+ for (uint16_t i = 0; i < vs->conf.num_queues; i++) {
+ s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i] = ctx;
+ }
+
+ /* Released in virtio_scsi_dataplane_cleanup() */
+ object_ref(OBJECT(vs->conf.iothread));
+ } else {
+ AioContext *ctx = qemu_get_aio_context();
+ for (unsigned i = 0; i < vs->conf.num_queues; i++) {
+ s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i] = ctx;
+ }
}
}
+/* Context: BQL held */
+void virtio_scsi_dataplane_cleanup(VirtIOSCSI *s)
+{
+ VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
+
+ if (vs->conf.iothread_vq_mapping_list) {
+ iothread_vq_mapping_cleanup(vs->conf.iothread_vq_mapping_list);
+ }
+
+ if (vs->conf.iothread) {
+ object_unref(OBJECT(vs->conf.iothread));
+ }
+
+ g_free(s->vq_aio_context);
+ s->vq_aio_context = NULL;
+}
+
static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
@@ -66,31 +123,20 @@ static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
}
/* Context: BH in IOThread */
-static void virtio_scsi_dataplane_stop_bh(void *opaque)
+static void virtio_scsi_dataplane_stop_vq_bh(void *opaque)
{
- VirtIOSCSI *s = opaque;
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
+ AioContext *ctx = qemu_get_current_aio_context();
+ VirtQueue *vq = opaque;
EventNotifier *host_notifier;
- int i;
- virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx);
- host_notifier = virtio_queue_get_host_notifier(vs->ctrl_vq);
+ virtio_queue_aio_detach_host_notifier(vq, ctx);
+ host_notifier = virtio_queue_get_host_notifier(vq);
/*
* Test and clear notifier after disabling event, in case poll callback
* didn't have time to run.
*/
virtio_queue_host_notifier_read(host_notifier);
-
- virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx);
- host_notifier = virtio_queue_get_host_notifier(vs->event_vq);
- virtio_queue_host_notifier_read(host_notifier);
-
- for (i = 0; i < vs->conf.num_queues; i++) {
- virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx);
- host_notifier = virtio_queue_get_host_notifier(vs->cmd_vqs[i]);
- virtio_queue_host_notifier_read(host_notifier);
- }
}
/* Context: BQL held */
@@ -154,11 +200,14 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
smp_wmb(); /* paired with aio_notify_accept() */
if (s->bus.drain_count == 0) {
- virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
- virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
+ virtio_queue_aio_attach_host_notifier(vs->ctrl_vq,
+ s->vq_aio_context[0]);
+ virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq,
+ s->vq_aio_context[1]);
for (i = 0; i < vs->conf.num_queues; i++) {
- virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
+ AioContext *ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i];
+ virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], ctx);
}
}
return 0;
@@ -207,7 +256,11 @@ void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
s->dataplane_stopping = true;
if (s->bus.drain_count == 0) {
- aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
+ for (i = 0; i < vs->conf.num_queues + VIRTIO_SCSI_VQ_NUM_FIXED; i++) {
+ VirtQueue *vq = virtio_get_queue(&vs->parent_obj, i);
+ AioContext *ctx = s->vq_aio_context[i];
+ aio_wait_bh_oneshot(ctx, virtio_scsi_dataplane_stop_vq_bh, vq);
+ }
}
blk_drain_all(); /* ensure there are no in-flight requests */
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 9f02cee..34ae14f 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -22,11 +22,12 @@
#include "qemu/error-report.h"
#include "qemu/iov.h"
#include "qemu/module.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/dma.h"
+#include "system/block-backend.h"
+#include "system/dma.h"
#include "hw/qdev-properties.h"
#include "hw/scsi/scsi.h"
#include "scsi/constants.h"
+#include "hw/virtio/iothread-vq-mapping.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
#include "trace.h"
@@ -47,7 +48,7 @@ typedef struct VirtIOSCSIReq {
/* Used for two-stage request submission and TMFs deferred to BH */
QTAILQ_ENTRY(VirtIOSCSIReq) next;
- /* Used for cancellation of request during TMFs */
+ /* Used for cancellation of request during TMFs. Atomic. */
int remaining;
SCSIRequest *sreq;
@@ -102,13 +103,18 @@ static void virtio_scsi_free_req(VirtIOSCSIReq *req)
g_free(req);
}
-static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
+static void virtio_scsi_complete_req(VirtIOSCSIReq *req, QemuMutex *vq_lock)
{
VirtIOSCSI *s = req->dev;
VirtQueue *vq = req->vq;
VirtIODevice *vdev = VIRTIO_DEVICE(s);
qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size);
+
+ if (vq_lock) {
+ qemu_mutex_lock(vq_lock);
+ }
+
virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size);
if (s->dataplane_started && !s->dataplane_fenced) {
virtio_notify_irqfd(vdev, vq);
@@ -116,6 +122,10 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
virtio_notify(vdev, vq);
}
+ if (vq_lock) {
+ qemu_mutex_unlock(vq_lock);
+ }
+
if (req->sreq) {
req->sreq->hba_private = NULL;
scsi_req_unref(req->sreq);
@@ -123,34 +133,20 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
virtio_scsi_free_req(req);
}
-static void virtio_scsi_complete_req_bh(void *opaque)
+static void virtio_scsi_bad_req(VirtIOSCSIReq *req, QemuMutex *vq_lock)
{
- VirtIOSCSIReq *req = opaque;
+ virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers");
- virtio_scsi_complete_req(req);
-}
+ if (vq_lock) {
+ qemu_mutex_lock(vq_lock);
+ }
-/*
- * Called from virtio_scsi_do_one_tmf_bh() in main loop thread. The main loop
- * thread cannot touch the virtqueue since that could race with an IOThread.
- */
-static void virtio_scsi_complete_req_from_main_loop(VirtIOSCSIReq *req)
-{
- VirtIOSCSI *s = req->dev;
+ virtqueue_detach_element(req->vq, &req->elem, 0);
- if (!s->ctx || s->ctx == qemu_get_aio_context()) {
- /* No need to schedule a BH when there is no IOThread */
- virtio_scsi_complete_req(req);
- } else {
- /* Run request completion in the IOThread */
- aio_wait_bh_oneshot(s->ctx, virtio_scsi_complete_req_bh, req);
+ if (vq_lock) {
+ qemu_mutex_unlock(vq_lock);
}
-}
-static void virtio_scsi_bad_req(VirtIOSCSIReq *req)
-{
- virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers");
- virtqueue_detach_element(req->vq, &req->elem, 0);
virtio_scsi_free_req(req);
}
@@ -235,12 +231,21 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
return 0;
}
-static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
+static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq, QemuMutex *vq_lock)
{
VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
VirtIOSCSIReq *req;
+ if (vq_lock) {
+ qemu_mutex_lock(vq_lock);
+ }
+
req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size);
+
+ if (vq_lock) {
+ qemu_mutex_unlock(vq_lock);
+ }
+
if (!req) {
return NULL;
}
@@ -294,137 +299,157 @@ typedef struct {
VirtIOSCSIReq *tmf_req;
} VirtIOSCSICancelNotifier;
+static void virtio_scsi_tmf_dec_remaining(VirtIOSCSIReq *tmf)
+{
+ if (qatomic_fetch_dec(&tmf->remaining) == 1) {
+ trace_virtio_scsi_tmf_resp(virtio_scsi_get_lun(tmf->req.tmf.lun),
+ tmf->req.tmf.tag, tmf->resp.tmf.response);
+
+ virtio_scsi_complete_req(tmf, &tmf->dev->ctrl_lock);
+ }
+}
+
static void virtio_scsi_cancel_notify(Notifier *notifier, void *data)
{
VirtIOSCSICancelNotifier *n = container_of(notifier,
VirtIOSCSICancelNotifier,
notifier);
- if (--n->tmf_req->remaining == 0) {
- VirtIOSCSIReq *req = n->tmf_req;
-
- trace_virtio_scsi_tmf_resp(virtio_scsi_get_lun(req->req.tmf.lun),
- req->req.tmf.tag, req->resp.tmf.response);
- virtio_scsi_complete_req(req);
- }
+ virtio_scsi_tmf_dec_remaining(n->tmf_req);
g_free(n);
}
-static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d)
+static void virtio_scsi_tmf_cancel_req(VirtIOSCSIReq *tmf, SCSIRequest *r)
{
- if (s->dataplane_started && d && blk_is_available(d->conf.blk)) {
- assert(blk_get_aio_context(d->conf.blk) == s->ctx);
- }
+ VirtIOSCSICancelNotifier *notifier;
+
+ assert(r->ctx == qemu_get_current_aio_context());
+
+ /* Decremented in virtio_scsi_cancel_notify() */
+ qatomic_inc(&tmf->remaining);
+
+ notifier = g_new(VirtIOSCSICancelNotifier, 1);
+ notifier->notifier.notify = virtio_scsi_cancel_notify;
+ notifier->tmf_req = tmf;
+ scsi_req_cancel_async(r, &notifier->notifier);
}
-static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req)
+/* Execute a TMF on the requests in the current AioContext */
+static void virtio_scsi_do_tmf_aio_context(void *opaque)
{
- VirtIOSCSI *s = req->dev;
- SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun);
- BusChild *kid;
- int target;
+ AioContext *ctx = qemu_get_current_aio_context();
+ VirtIOSCSIReq *tmf = opaque;
+ VirtIOSCSI *s = tmf->dev;
+ SCSIDevice *d = virtio_scsi_device_get(s, tmf->req.tmf.lun);
+ SCSIRequest *r;
+ bool match_tag;
- switch (req->req.tmf.subtype) {
- case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
- if (!d) {
- req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET;
- goto out;
- }
- if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
- req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN;
- goto out;
- }
- qatomic_inc(&s->resetting);
- device_cold_reset(&d->qdev);
- qatomic_dec(&s->resetting);
+ if (!d) {
+ tmf->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET;
+ virtio_scsi_tmf_dec_remaining(tmf);
+ return;
+ }
+
+ /*
+ * This function could handle other subtypes that need to be processed in
+ * the request's AioContext in the future, but for now only request
+ * cancelation subtypes are performed here.
+ */
+ switch (tmf->req.tmf.subtype) {
+ case VIRTIO_SCSI_T_TMF_ABORT_TASK:
+ match_tag = true;
+ break;
+ case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
+ case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
+ match_tag = false;
break;
+ default:
+ g_assert_not_reached();
+ }
- case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
- target = req->req.tmf.lun[1];
- qatomic_inc(&s->resetting);
+ WITH_QEMU_LOCK_GUARD(&d->requests_lock) {
+ QTAILQ_FOREACH(r, &d->requests, next) {
+ VirtIOSCSIReq *cmd_req = r->hba_private;
+ assert(cmd_req); /* request has hba_private while enqueued */
- rcu_read_lock();
- QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
- SCSIDevice *d1 = SCSI_DEVICE(kid->child);
- if (d1->channel == 0 && d1->id == target) {
- device_cold_reset(&d1->qdev);
+ if (r->ctx != ctx) {
+ continue;
+ }
+ if (match_tag && cmd_req->req.cmd.tag != tmf->req.tmf.tag) {
+ continue;
}
+ virtio_scsi_tmf_cancel_req(tmf, r);
}
- rcu_read_unlock();
-
- qatomic_dec(&s->resetting);
- break;
-
- default:
- g_assert_not_reached();
- break;
}
-out:
- object_unref(OBJECT(d));
- virtio_scsi_complete_req_from_main_loop(req);
+ /* Incremented by virtio_scsi_do_tmf() */
+ virtio_scsi_tmf_dec_remaining(tmf);
+
+ object_unref(d);
}
-/* Some TMFs must be processed from the main loop thread */
-static void virtio_scsi_do_tmf_bh(void *opaque)
+static void dummy_bh(void *opaque)
{
- VirtIOSCSI *s = opaque;
- QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
- VirtIOSCSIReq *req;
- VirtIOSCSIReq *tmp;
+ /* Do nothing */
+}
+/*
+ * Wait for pending virtio_scsi_defer_tmf_to_aio_context() BHs.
+ */
+static void virtio_scsi_flush_defer_tmf_to_aio_context(VirtIOSCSI *s)
+{
GLOBAL_STATE_CODE();
- WITH_QEMU_LOCK_GUARD(&s->tmf_bh_lock) {
- QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) {
- QTAILQ_REMOVE(&s->tmf_bh_list, req, next);
- QTAILQ_INSERT_TAIL(&reqs, req, next);
- }
+ assert(!s->dataplane_started);
- qemu_bh_delete(s->tmf_bh);
- s->tmf_bh = NULL;
- }
+ for (uint32_t i = 0; i < s->parent_obj.conf.num_queues; i++) {
+ AioContext *ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i];
- QTAILQ_FOREACH_SAFE(req, &reqs, next, tmp) {
- QTAILQ_REMOVE(&reqs, req, next);
- virtio_scsi_do_one_tmf_bh(req);
+ /* Our BH only runs after previously scheduled BHs */
+ aio_wait_bh_oneshot(ctx, dummy_bh, NULL);
}
}
-static void virtio_scsi_reset_tmf_bh(VirtIOSCSI *s)
+/*
+ * Run the TMF in a specific AioContext, handling only requests in that
+ * AioContext. This is necessary because requests can run in different
+ * AioContext and it is only possible to cancel them from the AioContext where
+ * they are running.
+ */
+static void virtio_scsi_defer_tmf_to_aio_context(VirtIOSCSIReq *tmf,
+ AioContext *ctx)
{
- VirtIOSCSIReq *req;
- VirtIOSCSIReq *tmp;
+ /* Decremented in virtio_scsi_do_tmf_aio_context() */
+ qatomic_inc(&tmf->remaining);
- GLOBAL_STATE_CODE();
-
- /* Called after ioeventfd has been stopped, so tmf_bh_lock is not needed */
- if (s->tmf_bh) {
- qemu_bh_delete(s->tmf_bh);
- s->tmf_bh = NULL;
- }
-
- QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) {
- QTAILQ_REMOVE(&s->tmf_bh_list, req, next);
-
- /* SAM-6 6.3.2 Hard reset */
- req->resp.tmf.response = VIRTIO_SCSI_S_TARGET_FAILURE;
- virtio_scsi_complete_req(req);
- }
+ /* See virtio_scsi_flush_defer_tmf_to_aio_context() cleanup during reset */
+ aio_bh_schedule_oneshot(ctx, virtio_scsi_do_tmf_aio_context, tmf);
}
-static void virtio_scsi_defer_tmf_to_bh(VirtIOSCSIReq *req)
+/*
+ * Returns the AioContext for a given TMF's tag field or NULL. Note that the
+ * request identified by the tag may have completed by the time you can execute
+ * a BH in the AioContext, so don't assume the request still exists in your BH.
+ */
+static AioContext *find_aio_context_for_tmf_tag(SCSIDevice *d,
+ VirtIOSCSIReq *tmf)
{
- VirtIOSCSI *s = req->dev;
+ WITH_QEMU_LOCK_GUARD(&d->requests_lock) {
+ SCSIRequest *r;
+ SCSIRequest *next;
+
+ QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
+ VirtIOSCSIReq *cmd_req = r->hba_private;
- WITH_QEMU_LOCK_GUARD(&s->tmf_bh_lock) {
- QTAILQ_INSERT_TAIL(&s->tmf_bh_list, req, next);
+ /* hba_private is non-NULL while the request is enqueued */
+ assert(cmd_req);
- if (!s->tmf_bh) {
- s->tmf_bh = qemu_bh_new(virtio_scsi_do_tmf_bh, s);
- qemu_bh_schedule(s->tmf_bh);
+ if (cmd_req->req.cmd.tag == tmf->req.tmf.tag) {
+ return r->ctx;
+ }
}
}
+ return NULL;
}
/* Return 0 if the request is ready to be completed and return to guest;
@@ -434,9 +459,9 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
{
SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun);
SCSIRequest *r, *next;
+ AioContext *ctx;
int ret = 0;
- virtio_scsi_ctx_check(s, d);
/* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
req->resp.tmf.response = VIRTIO_SCSI_S_OK;
@@ -451,7 +476,22 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
req->req.tmf.tag, req->req.tmf.subtype);
switch (req->req.tmf.subtype) {
- case VIRTIO_SCSI_T_TMF_ABORT_TASK:
+ case VIRTIO_SCSI_T_TMF_ABORT_TASK: {
+ if (!d) {
+ goto fail;
+ }
+ if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
+ goto incorrect_lun;
+ }
+
+ ctx = find_aio_context_for_tmf_tag(d, req);
+ if (ctx) {
+ virtio_scsi_defer_tmf_to_aio_context(req, ctx);
+ ret = -EINPROGRESS;
+ }
+ break;
+ }
+
case VIRTIO_SCSI_T_TMF_QUERY_TASK:
if (!d) {
goto fail;
@@ -459,44 +499,82 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
goto incorrect_lun;
}
- QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
- VirtIOSCSIReq *cmd_req = r->hba_private;
- if (cmd_req && cmd_req->req.cmd.tag == req->req.tmf.tag) {
- break;
+
+ WITH_QEMU_LOCK_GUARD(&d->requests_lock) {
+ QTAILQ_FOREACH(r, &d->requests, next) {
+ VirtIOSCSIReq *cmd_req = r->hba_private;
+ assert(cmd_req); /* request has hba_private while enqueued */
+
+ if (cmd_req->req.cmd.tag == req->req.tmf.tag) {
+ /*
+ * "If the specified command is present in the task set,
+ * then return a service response set to FUNCTION
+ * SUCCEEDED".
+ */
+ req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
+ }
}
}
- if (r) {
- /*
- * Assert that the request has not been completed yet, we
- * check for it in the loop above.
- */
- assert(r->hba_private);
- if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
- /* "If the specified command is present in the task set, then
- * return a service response set to FUNCTION SUCCEEDED".
- */
- req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
- } else {
- VirtIOSCSICancelNotifier *notifier;
-
- req->remaining = 1;
- notifier = g_new(VirtIOSCSICancelNotifier, 1);
- notifier->tmf_req = req;
- notifier->notifier.notify = virtio_scsi_cancel_notify;
- scsi_req_cancel_async(r, &notifier->notifier);
- ret = -EINPROGRESS;
+ break;
+
+ case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
+ if (!d) {
+ goto fail;
+ }
+ if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
+ goto incorrect_lun;
+ }
+ qatomic_inc(&s->resetting);
+ device_cold_reset(&d->qdev);
+ qatomic_dec(&s->resetting);
+ break;
+
+ case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: {
+ BusChild *kid;
+ int target = req->req.tmf.lun[1];
+ qatomic_inc(&s->resetting);
+
+ rcu_read_lock();
+ QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
+ SCSIDevice *d1 = SCSI_DEVICE(kid->child);
+ if (d1->channel == 0 && d1->id == target) {
+ device_cold_reset(&d1->qdev);
}
}
+ rcu_read_unlock();
+
+ qatomic_dec(&s->resetting);
break;
+ }
- case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
- case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
- virtio_scsi_defer_tmf_to_bh(req);
+ case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
+ case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: {
+ g_autoptr(GHashTable) aio_contexts = g_hash_table_new(NULL, NULL);
+
+ if (!d) {
+ goto fail;
+ }
+ if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
+ goto incorrect_lun;
+ }
+
+ qatomic_inc(&req->remaining);
+
+ for (uint32_t i = 0; i < s->parent_obj.conf.num_queues; i++) {
+ ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i];
+
+ if (!g_hash_table_add(aio_contexts, ctx)) {
+ continue; /* skip previously added AioContext */
+ }
+
+ virtio_scsi_defer_tmf_to_aio_context(req, ctx);
+ }
+
+ virtio_scsi_tmf_dec_remaining(req);
ret = -EINPROGRESS;
break;
+ }
- case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
- case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
if (!d) {
goto fail;
@@ -505,34 +583,19 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
goto incorrect_lun;
}
- /* Add 1 to "remaining" until virtio_scsi_do_tmf returns.
- * This way, if the bus starts calling back to the notifiers
- * even before we finish the loop, virtio_scsi_cancel_notify
- * will not complete the TMF too early.
- */
- req->remaining = 1;
- QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
- if (r->hba_private) {
- if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
- /* "If there is any command present in the task set, then
- * return a service response set to FUNCTION SUCCEEDED".
- */
- req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
- break;
- } else {
- VirtIOSCSICancelNotifier *notifier;
-
- req->remaining++;
- notifier = g_new(VirtIOSCSICancelNotifier, 1);
- notifier->notifier.notify = virtio_scsi_cancel_notify;
- notifier->tmf_req = req;
- scsi_req_cancel_async(r, &notifier->notifier);
- }
+ WITH_QEMU_LOCK_GUARD(&d->requests_lock) {
+ QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
+ /* Request has hba_private while enqueued */
+ assert(r->hba_private);
+
+ /*
+ * "If there is any command present in the task set, then
+ * return a service response set to FUNCTION SUCCEEDED".
+ */
+ req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
+ break;
}
}
- if (--req->remaining > 0) {
- ret = -EINPROGRESS;
- }
break;
case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
@@ -563,7 +626,7 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
&type, sizeof(type)) < sizeof(type)) {
- virtio_scsi_bad_req(req);
+ virtio_scsi_bad_req(req, &s->ctrl_lock);
return;
}
@@ -571,7 +634,7 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
if (type == VIRTIO_SCSI_T_TMF) {
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq),
sizeof(VirtIOSCSICtrlTMFResp)) < 0) {
- virtio_scsi_bad_req(req);
+ virtio_scsi_bad_req(req, &s->ctrl_lock);
return;
} else {
r = virtio_scsi_do_tmf(s, req);
@@ -581,7 +644,7 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq),
sizeof(VirtIOSCSICtrlANResp)) < 0) {
- virtio_scsi_bad_req(req);
+ virtio_scsi_bad_req(req, &s->ctrl_lock);
return;
} else {
req->req.an.event_requested =
@@ -601,7 +664,7 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
type == VIRTIO_SCSI_T_AN_SUBSCRIBE)
trace_virtio_scsi_an_resp(virtio_scsi_get_lun(req->req.an.lun),
req->resp.an.response);
- virtio_scsi_complete_req(req);
+ virtio_scsi_complete_req(req, &s->ctrl_lock);
} else {
assert(r == -EINPROGRESS);
}
@@ -611,7 +674,7 @@ static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
{
VirtIOSCSIReq *req;
- while ((req = virtio_scsi_pop_req(s, vq))) {
+ while ((req = virtio_scsi_pop_req(s, vq, &s->ctrl_lock))) {
virtio_scsi_handle_ctrl_req(s, req);
}
}
@@ -626,9 +689,12 @@ static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
*/
static bool virtio_scsi_defer_to_dataplane(VirtIOSCSI *s)
{
- if (!s->ctx || s->dataplane_started) {
+ if (s->dataplane_started) {
return false;
}
+ if (s->vq_aio_context[0] == qemu_get_aio_context()) {
+ return false; /* not using IOThreads */
+ }
virtio_device_start_ioeventfd(&s->parent_obj.parent_obj);
return !s->dataplane_fenced;
@@ -655,7 +721,7 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
* in virtio_scsi_command_complete.
*/
req->resp_size = sizeof(VirtIOSCSICmdResp);
- virtio_scsi_complete_req(req);
+ virtio_scsi_complete_req(req, NULL);
}
static void virtio_scsi_command_failed(SCSIRequest *r)
@@ -789,7 +855,7 @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
virtio_scsi_fail_cmd_req(req);
return -ENOTSUP;
} else {
- virtio_scsi_bad_req(req);
+ virtio_scsi_bad_req(req, NULL);
return -EINVAL;
}
}
@@ -802,7 +868,6 @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
virtio_scsi_complete_cmd_req(req);
return -ENOENT;
}
- virtio_scsi_ctx_check(s, d);
req->sreq = scsi_req_new(d, req->req.cmd.tag,
virtio_scsi_get_lun(req->req.cmd.lun),
req->req.cmd.cdb, vs->cdb_size, req);
@@ -844,7 +909,7 @@ static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
virtio_queue_set_notification(vq, 0);
}
- while ((req = virtio_scsi_pop_req(s, vq))) {
+ while ((req = virtio_scsi_pop_req(s, vq, NULL))) {
ret = virtio_scsi_handle_cmd_req_prepare(s, req);
if (!ret) {
QTAILQ_INSERT_TAIL(&reqs, req, next);
@@ -937,7 +1002,7 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
assert(!s->dataplane_started);
- virtio_scsi_reset_tmf_bh(s);
+ virtio_scsi_flush_defer_tmf_to_aio_context(s);
qatomic_inc(&s->resetting);
bus_cold_reset(BUS(&s->bus));
@@ -945,7 +1010,10 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
vs->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
- s->events_dropped = false;
+
+ WITH_QEMU_LOCK_GUARD(&s->event_lock) {
+ s->events_dropped = false;
+ }
}
typedef struct {
@@ -974,19 +1042,21 @@ static void virtio_scsi_push_event(VirtIOSCSI *s,
return;
}
- req = virtio_scsi_pop_req(s, vs->event_vq);
- if (!req) {
- s->events_dropped = true;
- return;
- }
+ req = virtio_scsi_pop_req(s, vs->event_vq, &s->event_lock);
+ WITH_QEMU_LOCK_GUARD(&s->event_lock) {
+ if (!req) {
+ s->events_dropped = true;
+ return;
+ }
- if (s->events_dropped) {
- event |= VIRTIO_SCSI_T_EVENTS_MISSED;
- s->events_dropped = false;
+ if (s->events_dropped) {
+ event |= VIRTIO_SCSI_T_EVENTS_MISSED;
+ s->events_dropped = false;
+ }
}
if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) {
- virtio_scsi_bad_req(req);
+ virtio_scsi_bad_req(req, &s->event_lock);
return;
}
@@ -1006,12 +1076,18 @@ static void virtio_scsi_push_event(VirtIOSCSI *s,
}
trace_virtio_scsi_event(virtio_scsi_get_lun(evt->lun), event, reason);
- virtio_scsi_complete_req(req);
+ virtio_scsi_complete_req(req, &s->event_lock);
}
static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
{
- if (s->events_dropped) {
+ bool events_dropped;
+
+ WITH_QEMU_LOCK_GUARD(&s->event_lock) {
+ events_dropped = s->events_dropped;
+ }
+
+ if (events_dropped) {
VirtIOSCSIEventInfo info = {
.event = VIRTIO_SCSI_T_NO_EVENT,
};
@@ -1062,17 +1138,16 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
{
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+ AioContext *ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED];
SCSIDevice *sd = SCSI_DEVICE(dev);
- int ret;
- if (s->ctx && !s->dataplane_fenced) {
- if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
- return;
- }
- ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp);
- if (ret < 0) {
- return;
- }
+ if (ctx != qemu_get_aio_context() && !s->dataplane_fenced) {
+ /*
+ * Try to make the BlockBackend's AioContext match ours. Ignore failure
+ * because I/O will still work although block jobs and other users
+ * might be slower when multiple AioContexts use a BlockBackend.
+ */
+ blk_set_aio_context(sd->conf.blk, ctx, NULL);
}
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
@@ -1107,7 +1182,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
- if (s->ctx) {
+ if (s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED] != qemu_get_aio_context()) {
/* If other users keep the BlockBackend in the iothread, that's ok */
blk_set_aio_context(sd->conf.blk, qemu_get_aio_context(), NULL);
}
@@ -1141,7 +1216,7 @@ static void virtio_scsi_drained_begin(SCSIBus *bus)
for (uint32_t i = 0; i < total_queues; i++) {
VirtQueue *vq = virtio_get_queue(vdev, i);
- virtio_queue_aio_detach_host_notifier(vq, s->ctx);
+ virtio_queue_aio_detach_host_notifier(vq, s->vq_aio_context[i]);
}
}
@@ -1167,10 +1242,12 @@ static void virtio_scsi_drained_end(SCSIBus *bus)
for (uint32_t i = 0; i < total_queues; i++) {
VirtQueue *vq = virtio_get_queue(vdev, i);
+ AioContext *ctx = s->vq_aio_context[i];
+
if (vq == vs->event_vq) {
- virtio_queue_aio_attach_host_notifier_no_poll(vq, s->ctx);
+ virtio_queue_aio_attach_host_notifier_no_poll(vq, ctx);
} else {
- virtio_queue_aio_attach_host_notifier(vq, s->ctx);
+ virtio_queue_aio_attach_host_notifier(vq, ctx);
}
}
}
@@ -1239,8 +1316,8 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
VirtIOSCSI *s = VIRTIO_SCSI(dev);
Error *err = NULL;
- QTAILQ_INIT(&s->tmf_bh_list);
- qemu_mutex_init(&s->tmf_bh_lock);
+ qemu_mutex_init(&s->ctrl_lock);
+ qemu_mutex_init(&s->event_lock);
virtio_scsi_common_realize(dev,
virtio_scsi_handle_ctrl,
@@ -1275,18 +1352,19 @@ void virtio_scsi_common_unrealize(DeviceState *dev)
virtio_cleanup(vdev);
}
+/* main loop */
static void virtio_scsi_device_unrealize(DeviceState *dev)
{
VirtIOSCSI *s = VIRTIO_SCSI(dev);
- virtio_scsi_reset_tmf_bh(s);
-
+ virtio_scsi_dataplane_cleanup(s);
qbus_set_hotplug_handler(BUS(&s->bus), NULL);
virtio_scsi_common_unrealize(dev);
- qemu_mutex_destroy(&s->tmf_bh_lock);
+ qemu_mutex_destroy(&s->event_lock);
+ qemu_mutex_destroy(&s->ctrl_lock);
}
-static Property virtio_scsi_properties[] = {
+static const Property virtio_scsi_properties[] = {
DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues,
VIRTIO_SCSI_AUTO_NUM_QUEUES),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
@@ -1303,7 +1381,8 @@ static Property virtio_scsi_properties[] = {
VIRTIO_SCSI_F_CHANGE, true),
DEFINE_PROP_LINK("iothread", VirtIOSCSI, parent_obj.conf.iothread,
TYPE_IOTHREAD, IOThread *),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST("iothread-vq-mapping", VirtIOSCSI,
+ parent_obj.conf.iothread_vq_mapping_list),
};
static const VMStateDescription vmstate_virtio_scsi = {
@@ -1316,7 +1395,7 @@ static const VMStateDescription vmstate_virtio_scsi = {
},
};
-static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
+static void virtio_scsi_common_class_init(ObjectClass *klass, const void *data)
{
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1325,7 +1404,7 @@ static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
-static void virtio_scsi_class_init(ObjectClass *klass, void *data)
+static void virtio_scsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -1359,7 +1438,7 @@ static const TypeInfo virtio_scsi_info = {
.parent = TYPE_VIRTIO_SCSI_COMMON,
.instance_size = sizeof(VirtIOSCSI),
.class_init = virtio_scsi_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index cd7bf6a..7c98b1b 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -68,18 +68,7 @@ struct PVSCSIClass {
OBJECT_DECLARE_TYPE(PVSCSIState, PVSCSIClass, PVSCSI)
-/* Compatibility flags for migration */
-#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT 0
-#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION \
- (1 << PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT)
-#define PVSCSI_COMPAT_DISABLE_PCIE_BIT 1
-#define PVSCSI_COMPAT_DISABLE_PCIE \
- (1 << PVSCSI_COMPAT_DISABLE_PCIE_BIT)
-
-#define PVSCSI_USE_OLD_PCI_CONFIGURATION(s) \
- ((s)->compat_flags & PVSCSI_COMPAT_OLD_PCI_CONFIGURATION)
-#define PVSCSI_MSI_OFFSET(s) \
- (PVSCSI_USE_OLD_PCI_CONFIGURATION(s) ? 0x50 : 0x7c)
+#define PVSCSI_MSI_OFFSET (0x7c)
#define PVSCSI_EXP_EP_OFFSET (0x40)
typedef struct PVSCSIRingInfo {
@@ -129,8 +118,6 @@ struct PVSCSIState {
uint8_t msi_used; /* For migration compatibility */
PVSCSIRingInfo rings; /* Data transfer rings manager */
uint32_t resetting; /* Reset in progress */
-
- uint32_t compat_flags;
};
typedef struct PVSCSIRequest {
@@ -1110,7 +1097,7 @@ pvscsi_init_msi(PVSCSIState *s)
int res;
PCIDevice *d = PCI_DEVICE(s);
- res = msi_init(d, PVSCSI_MSI_OFFSET(s), PVSCSI_MSIX_NUM_VECTORS,
+ res = msi_init(d, PVSCSI_MSI_OFFSET, PVSCSI_MSIX_NUM_VECTORS,
PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK, NULL);
if (res < 0) {
trace_pvscsi_init_msi_fail(res);
@@ -1158,15 +1145,11 @@ pvscsi_realizefn(PCIDevice *pci_dev, Error **errp)
trace_pvscsi_state("init");
/* PCI subsystem ID, subsystem vendor ID, revision */
- if (PVSCSI_USE_OLD_PCI_CONFIGURATION(s)) {
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, 0x1000);
- } else {
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
- PCI_VENDOR_ID_VMWARE);
- pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
- PCI_DEVICE_ID_VMWARE_PVSCSI);
- pci_config_set_revision(pci_dev->config, 0x2);
- }
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+ PCI_VENDOR_ID_VMWARE);
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+ PCI_DEVICE_ID_VMWARE_PVSCSI);
+ pci_config_set_revision(pci_dev->config, 0x2);
/* PCI latency timer = 255 */
pci_dev->config[PCI_LATENCY_TIMER] = 0xff;
@@ -1234,21 +1217,8 @@ pvscsi_post_load(void *opaque, int version_id)
return 0;
}
-static bool pvscsi_vmstate_need_pcie_device(void *opaque)
-{
- PVSCSIState *s = PVSCSI(opaque);
-
- return !(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE);
-}
-
-static bool pvscsi_vmstate_test_pci_device(void *opaque, int version_id)
-{
- return !pvscsi_vmstate_need_pcie_device(opaque);
-}
-
static const VMStateDescription vmstate_pvscsi_pcie_device = {
.name = "pvscsi/pcie",
- .needed = pvscsi_vmstate_need_pcie_device,
.fields = (const VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState),
VMSTATE_END_OF_LIST()
@@ -1262,9 +1232,6 @@ static const VMStateDescription vmstate_pvscsi = {
.pre_save = pvscsi_pre_save,
.post_load = pvscsi_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_STRUCT_TEST(parent_obj, PVSCSIState,
- pvscsi_vmstate_test_pci_device, 0,
- vmstate_pci_device, PCIDevice),
VMSTATE_UINT8(msi_used, PVSCSIState),
VMSTATE_UINT32(resetting, PVSCSIState),
VMSTATE_UINT64(reg_interrupt_status, PVSCSIState),
@@ -1296,33 +1263,19 @@ static const VMStateDescription vmstate_pvscsi = {
}
};
-static Property pvscsi_properties[] = {
+static const Property pvscsi_properties[] = {
DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1),
- DEFINE_PROP_BIT("x-old-pci-configuration", PVSCSIState, compat_flags,
- PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT, false),
- DEFINE_PROP_BIT("x-disable-pcie", PVSCSIState, compat_flags,
- PVSCSI_COMPAT_DISABLE_PCIE_BIT, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pvscsi_realize(DeviceState *qdev, Error **errp)
+static void pvscsi_instance_init(Object *obj)
{
- PVSCSIClass *pvs_c = PVSCSI_GET_CLASS(qdev);
- PCIDevice *pci_dev = PCI_DEVICE(qdev);
- PVSCSIState *s = PVSCSI(qdev);
-
- if (!(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE)) {
- pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
- }
-
- pvs_c->parent_dc_realize(qdev, errp);
+ PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
-static void pvscsi_class_init(ObjectClass *klass, void *data)
+static void pvscsi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- PVSCSIClass *pvs_k = PVSCSI_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->realize = pvscsi_realizefn;
@@ -1331,9 +1284,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI;
k->class_id = PCI_CLASS_STORAGE_SCSI;
k->subsystem_id = 0x1000;
- device_class_set_parent_realize(dc, pvscsi_realize,
- &pvs_k->parent_dc_realize);
- dc->reset = pvscsi_reset;
+ device_class_set_legacy_reset(dc, pvscsi_reset);
dc->vmsd = &vmstate_pvscsi;
device_class_set_props(dc, pvscsi_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
@@ -1347,7 +1298,8 @@ static const TypeInfo pvscsi_info = {
.class_size = sizeof(PVSCSIClass),
.instance_size = sizeof(PVSCSIState),
.class_init = pvscsi_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .instance_init = pvscsi_instance_init,
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
diff --git a/hw/scsi/vmw_pvscsi.h b/hw/scsi/vmw_pvscsi.h
index 17fcf66..a3ae517 100644
--- a/hw/scsi/vmw_pvscsi.h
+++ b/hw/scsi/vmw_pvscsi.h
@@ -14,8 +14,8 @@
* details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * along with this program; if not, see
+ * <https://www.gnu.org/licenses/>.
*
* Maintained by: Arvind Kumar <arvindkumar@vmware.com>
*
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
index a1b7230..b31da5c 100644
--- a/hw/sd/allwinner-sdhost.c
+++ b/hw/sd/allwinner-sdhost.c
@@ -22,8 +22,8 @@
#include "qemu/module.h"
#include "qemu/units.h"
#include "qapi/error.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/dma.h"
+#include "system/blockdev.h"
+#include "system/dma.h"
#include "hw/qdev-properties.h"
#include "hw/irq.h"
#include "hw/sd/allwinner-sdhost.h"
@@ -761,7 +761,7 @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_sdhost_ops = {
.read = allwinner_sdhost_read,
.write = allwinner_sdhost_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -808,10 +808,9 @@ static const VMStateDescription vmstate_allwinner_sdhost = {
}
};
-static Property allwinner_sdhost_properties[] = {
+static const Property allwinner_sdhost_properties[] = {
DEFINE_PROP_LINK("dma-memory", AwSdHostState, dma_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
static void allwinner_sdhost_init(Object *obj)
@@ -889,24 +888,26 @@ static void allwinner_sdhost_reset(DeviceState *dev)
}
}
-static void allwinner_sdhost_bus_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_bus_class_init(ObjectClass *klass,
+ const void *data)
{
SDBusClass *sbc = SD_BUS_CLASS(klass);
sbc->set_inserted = allwinner_sdhost_set_inserted;
}
-static void allwinner_sdhost_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_sdhost_reset;
+ device_class_set_legacy_reset(dc, allwinner_sdhost_reset);
dc->vmsd = &vmstate_allwinner_sdhost;
dc->realize = allwinner_sdhost_realize;
device_class_set_props(dc, allwinner_sdhost_properties);
}
-static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass,
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 8 * KiB;
@@ -914,7 +915,8 @@ static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data)
sc->can_calibrate = false;
}
-static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
+static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass,
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 64 * KiB;
@@ -923,7 +925,7 @@ static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
}
static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 64 * KiB;
@@ -932,7 +934,7 @@ static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass,
}
static void allwinner_sdhost_sun50i_a64_emmc_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
sc->max_desc_size = 8 * KiB;
diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c
index 3b63926..fc38ad3 100644
--- a/hw/sd/aspeed_sdhci.c
+++ b/hw/sd/aspeed_sdhci.c
@@ -24,8 +24,10 @@
#define ASPEED_SDHCI_DEBOUNCE_RESET 0x00000005
#define ASPEED_SDHCI_BUS 0x08
#define ASPEED_SDHCI_SDIO_140 0x10
+#define ASPEED_SDHCI_SDIO_144 0x14
#define ASPEED_SDHCI_SDIO_148 0x18
#define ASPEED_SDHCI_SDIO_240 0x20
+#define ASPEED_SDHCI_SDIO_244 0x24
#define ASPEED_SDHCI_SDIO_248 0x28
#define ASPEED_SDHCI_WP_POL 0xec
#define ASPEED_SDHCI_CARD_DET 0xf0
@@ -35,21 +37,27 @@
static uint64_t aspeed_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
{
- uint32_t val = 0;
+ uint64_t val = 0;
AspeedSDHCIState *sdhci = opaque;
switch (addr) {
case ASPEED_SDHCI_SDIO_140:
- val = (uint32_t)sdhci->slots[0].capareg;
+ val = extract64(sdhci->slots[0].capareg, 0, 32);
+ break;
+ case ASPEED_SDHCI_SDIO_144:
+ val = extract64(sdhci->slots[0].capareg, 32, 32);
break;
case ASPEED_SDHCI_SDIO_148:
- val = (uint32_t)sdhci->slots[0].maxcurr;
+ val = extract64(sdhci->slots[0].maxcurr, 0, 32);
break;
case ASPEED_SDHCI_SDIO_240:
- val = (uint32_t)sdhci->slots[1].capareg;
+ val = extract64(sdhci->slots[1].capareg, 0, 32);
+ break;
+ case ASPEED_SDHCI_SDIO_244:
+ val = extract64(sdhci->slots[1].capareg, 32, 32);
break;
case ASPEED_SDHCI_SDIO_248:
- val = (uint32_t)sdhci->slots[1].maxcurr;
+ val = extract64(sdhci->slots[1].maxcurr, 0, 32);
break;
default:
if (addr < ASPEED_SDHCI_REG_SIZE) {
@@ -61,9 +69,9 @@ static uint64_t aspeed_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
}
}
- trace_aspeed_sdhci_read(addr, size, (uint64_t) val);
+ trace_aspeed_sdhci_read(addr, size, val);
- return (uint64_t)val;
+ return val;
}
static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
@@ -79,16 +87,28 @@ static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
sdhci->regs[TO_REG(addr)] = (uint32_t)val & ~ASPEED_SDHCI_INFO_RESET;
break;
case ASPEED_SDHCI_SDIO_140:
- sdhci->slots[0].capareg = (uint64_t)(uint32_t)val;
+ sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg,
+ 0, 32, val);
+ break;
+ case ASPEED_SDHCI_SDIO_144:
+ sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg,
+ 32, 32, val);
break;
case ASPEED_SDHCI_SDIO_148:
- sdhci->slots[0].maxcurr = (uint64_t)(uint32_t)val;
+ sdhci->slots[0].maxcurr = deposit64(sdhci->slots[0].maxcurr,
+ 0, 32, val);
break;
case ASPEED_SDHCI_SDIO_240:
- sdhci->slots[1].capareg = (uint64_t)(uint32_t)val;
+ sdhci->slots[1].capareg = deposit64(sdhci->slots[1].capareg,
+ 0, 32, val);
+ break;
+ case ASPEED_SDHCI_SDIO_244:
+ sdhci->slots[1].capareg = deposit64(sdhci->slots[1].capareg,
+ 32, 32, val);
break;
case ASPEED_SDHCI_SDIO_248:
- sdhci->slots[1].maxcurr = (uint64_t)(uint32_t)val;
+ sdhci->slots[1].maxcurr = deposit64(sdhci->slots[0].maxcurr,
+ 0, 32, val);
break;
default:
if (addr < ASPEED_SDHCI_REG_SIZE) {
@@ -128,6 +148,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_GET_CLASS(sdhci);
/* Create input irqs for the slots */
qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq,
@@ -147,7 +168,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp)
}
if (!object_property_set_uint(sdhci_slot, "capareg",
- ASPEED_SDHCI_CAPABILITIES, errp)) {
+ asc->capareg, errp)) {
return;
}
@@ -183,27 +204,84 @@ static const VMStateDescription vmstate_aspeed_sdhci = {
},
};
-static Property aspeed_sdhci_properties[] = {
+static const Property aspeed_sdhci_properties[] = {
DEFINE_PROP_UINT8("num-slots", AspeedSDHCIState, num_slots, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_sdhci_class_init(ObjectClass *classp, void *data)
+static void aspeed_sdhci_class_init(ObjectClass *classp, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->realize = aspeed_sdhci_realize;
- dc->reset = aspeed_sdhci_reset;
+ device_class_set_legacy_reset(dc, aspeed_sdhci_reset);
dc->vmsd = &vmstate_aspeed_sdhci;
device_class_set_props(dc, aspeed_sdhci_properties);
}
+static void aspeed_2400_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 SDHCI Controller";
+ asc->capareg = 0x0000000001e80080;
+}
+
+static void aspeed_2500_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 SDHCI Controller";
+ asc->capareg = 0x0000000001e80080;
+}
+
+static void aspeed_2600_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 SDHCI Controller";
+ asc->capareg = 0x0000000701f80080;
+}
+
+static void aspeed_2700_sdhci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 SDHCI Controller";
+ asc->capareg = 0x0000000719f80080;
+}
+
static const TypeInfo aspeed_sdhci_types[] = {
{
.name = TYPE_ASPEED_SDHCI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedSDHCIState),
.class_init = aspeed_sdhci_class_init,
+ .class_size = sizeof(AspeedSDHCIClass),
+ .abstract = true,
+ },
+ {
+ .name = TYPE_ASPEED_2400_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2400_sdhci_class_init,
+ },
+ {
+ .name = TYPE_ASPEED_2500_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2500_sdhci_class_init,
+ },
+ {
+ .name = TYPE_ASPEED_2600_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2600_sdhci_class_init,
+ },
+ {
+ .name = TYPE_ASPEED_2700_SDHCI,
+ .parent = TYPE_ASPEED_SDHCI,
+ .class_init = aspeed_2700_sdhci_class_init,
},
};
diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c
index 11c54dd..29debdf 100644
--- a/hw/sd/bcm2835_sdhost.c
+++ b/hw/sd/bcm2835_sdhost.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "hw/irq.h"
#include "hw/sd/bcm2835_sdhost.h"
#include "migration/vmstate.h"
@@ -428,11 +428,11 @@ static void bcm2835_sdhost_reset(DeviceState *dev)
s->fifo_len = 0;
}
-static void bcm2835_sdhost_class_init(ObjectClass *klass, void *data)
+static void bcm2835_sdhost_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_sdhost_reset;
+ device_class_set_legacy_reset(dc, bcm2835_sdhost_reset);
dc->vmsd = &vmstate_bcm2835_sdhost;
}
diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c
index 7c8bc54..d576855 100644
--- a/hw/sd/cadence_sdhci.c
+++ b/hw/sd/cadence_sdhci.c
@@ -165,13 +165,13 @@ static const VMStateDescription vmstate_cadence_sdhci = {
},
};
-static void cadence_sdhci_class_init(ObjectClass *classp, void *data)
+static void cadence_sdhci_class_init(ObjectClass *classp, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->desc = "Cadence SD/SDIO/eMMC Host Controller (SD4HC)";
dc->realize = cadence_sdhci_realize;
- dc->reset = cadence_sdhci_reset;
+ device_class_set_legacy_reset(dc, cadence_sdhci_reset);
dc->vmsd = &vmstate_cadence_sdhci;
}
diff --git a/hw/sd/meson.build b/hw/sd/meson.build
index bbb75af..b43d45b 100644
--- a/hw/sd/meson.build
+++ b/hw/sd/meson.build
@@ -5,7 +5,6 @@ system_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c'))
system_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
diff --git a/hw/sd/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c
index fb51821..0233d7b 100644
--- a/hw/sd/npcm7xx_sdhci.c
+++ b/hw/sd/npcm7xx_sdhci.c
@@ -149,13 +149,13 @@ static const VMStateDescription vmstate_npcm7xx_sdhci = {
},
};
-static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data)
+static void npcm7xx_sdhci_class_init(ObjectClass *classp, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->desc = "NPCM7xx SD/eMMC Host Controller";
dc->realize = npcm7xx_sdhci_realize;
- dc->reset = npcm7xx_sdhci_reset;
+ device_class_set_legacy_reset(dc, npcm7xx_sdhci_reset);
dc->vmsd = &vmstate_npcm7xx_sdhci;
}
diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c
index edd3cf2..b7648d4 100644
--- a/hw/sd/omap_mmc.c
+++ b/hw/sd/omap_mmc.c
@@ -21,17 +21,22 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qapi/error.h"
#include "hw/irq.h"
+#include "hw/sysbus.h"
#include "hw/arm/omap.h"
-#include "hw/sd/sdcard_legacy.h"
+#include "hw/sd/sd.h"
+
+typedef struct OMAPMMCState {
+ SysBusDevice parent_obj;
+
+ SDBus sdbus;
-struct omap_mmc_s {
qemu_irq irq;
- qemu_irq *dma;
- qemu_irq coverswitch;
+ qemu_irq dma_tx_gpio;
+ qemu_irq dma_rx_gpio;
MemoryRegion iomem;
omap_clk clk;
- SDState *card;
uint16_t last_cmd;
uint16_t sdio;
uint16_t rsp[8];
@@ -64,16 +69,15 @@ struct omap_mmc_s {
int cdet_wakeup;
int cdet_enable;
- int cdet_state;
qemu_irq cdet;
-};
+} OMAPMMCState;
-static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
+static void omap_mmc_interrupts_update(OMAPMMCState *s)
{
qemu_set_irq(s->irq, !!(s->status & s->mask));
}
-static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
+static void omap_mmc_fifolevel_update(OMAPMMCState *host)
{
if (!host->transfer && !host->fifo_len) {
host->status &= 0xf3ff;
@@ -83,37 +87,47 @@ static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
if (host->fifo_len > host->af_level && host->ddir) {
if (host->rx_dma) {
host->status &= 0xfbff;
- qemu_irq_raise(host->dma[1]);
+ qemu_irq_raise(host->dma_rx_gpio);
} else
host->status |= 0x0400;
} else {
host->status &= 0xfbff;
- qemu_irq_lower(host->dma[1]);
+ qemu_irq_lower(host->dma_rx_gpio);
}
if (host->fifo_len < host->ae_level && !host->ddir) {
if (host->tx_dma) {
host->status &= 0xf7ff;
- qemu_irq_raise(host->dma[0]);
+ qemu_irq_raise(host->dma_tx_gpio);
} else
host->status |= 0x0800;
} else {
- qemu_irq_lower(host->dma[0]);
+ qemu_irq_lower(host->dma_tx_gpio);
host->status &= 0xf7ff;
}
}
+/* These must match the encoding of the MMC_CMD Response field */
typedef enum {
- sd_nore = 0, /* no response */
- sd_r1, /* normal response command */
- sd_r2, /* CID, CSD registers */
- sd_r3, /* OCR register */
- sd_r6 = 6, /* Published RCA response */
+ sd_nore = 0, /* no response */
+ sd_r1, /* normal response command */
+ sd_r2, /* CID, CSD registers */
+ sd_r3, /* OCR register */
+ sd_r6 = 6, /* Published RCA response */
sd_r1b = -1,
} sd_rsp_type_t;
-static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
- sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
+/* These must match the encoding of the MMC_CMD Type field */
+typedef enum {
+ SD_TYPE_BC = 0, /* broadcast -- no response */
+ SD_TYPE_BCR = 1, /* broadcast with response */
+ SD_TYPE_AC = 2, /* addressed -- no data transfer */
+ SD_TYPE_ADTC = 3, /* addressed with data transfer */
+} MMCCmdType;
+
+static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
+ MMCCmdType type, int busy,
+ sd_rsp_type_t resptype, int init)
{
uint32_t rspstatus, mask;
int rsplen, timeout;
@@ -128,7 +142,7 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
if (resptype == sd_r1 && busy)
resptype = sd_r1b;
- if (type == sd_adtc) {
+ if (type == SD_TYPE_ADTC) {
host->fifo_start = 0;
host->fifo_len = 0;
host->transfer = 1;
@@ -143,7 +157,7 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
request.arg = host->arg;
request.crc = 0; /* FIXME */
- rsplen = sd_do_command(host->card, &request, response);
+ rsplen = sdbus_do_command(&host->sdbus, &request, response);
/* TODO: validate CRCs */
switch (resptype) {
@@ -215,12 +229,12 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
if (timeout)
host->status |= 0x0080;
else if (cmd == 12)
- host->status |= 0x0005; /* Makes it more real */
+ host->status |= 0x0005; /* Makes it more real */
else
host->status |= 0x0001;
}
-static void omap_mmc_transfer(struct omap_mmc_s *host)
+static void omap_mmc_transfer(OMAPMMCState *host)
{
uint8_t value;
@@ -232,10 +246,10 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
if (host->fifo_len > host->af_level)
break;
- value = sd_read_byte(host->card);
+ value = sdbus_read_byte(&host->sdbus);
host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
if (-- host->blen_counter) {
- value = sd_read_byte(host->card);
+ value = sdbus_read_byte(&host->sdbus);
host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
value << 8;
host->blen_counter --;
@@ -247,10 +261,10 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
break;
value = host->fifo[host->fifo_start] & 0xff;
- sd_write_byte(host->card, value);
+ sdbus_write_byte(&host->sdbus, value);
if (-- host->blen_counter) {
value = host->fifo[host->fifo_start] >> 8;
- sd_write_byte(host->card, value);
+ sdbus_write_byte(&host->sdbus, value);
host->blen_counter --;
}
@@ -275,19 +289,19 @@ static void omap_mmc_transfer(struct omap_mmc_s *host)
static void omap_mmc_update(void *opaque)
{
- struct omap_mmc_s *s = opaque;
+ OMAPMMCState *s = opaque;
omap_mmc_transfer(s);
omap_mmc_fifolevel_update(s);
omap_mmc_interrupts_update(s);
}
-static void omap_mmc_pseudo_reset(struct omap_mmc_s *host)
+static void omap_mmc_pseudo_reset(OMAPMMCState *host)
{
host->status = 0;
host->fifo_len = 0;
}
-void omap_mmc_reset(struct omap_mmc_s *host)
+static void omap_mmc_reset(OMAPMMCState *host)
{
host->last_cmd = 0;
memset(host->rsp, 0, sizeof(host->rsp));
@@ -309,54 +323,47 @@ void omap_mmc_reset(struct omap_mmc_s *host)
host->transfer = 0;
host->cdet_wakeup = 0;
host->cdet_enable = 0;
- qemu_set_irq(host->coverswitch, host->cdet_state);
host->clkdiv = 0;
omap_mmc_pseudo_reset(host);
-
- /* Since we're still using the legacy SD API the card is not plugged
- * into any bus, and we must reset it manually. When omap_mmc is
- * QOMified this must move into the QOM reset function.
- */
- device_cold_reset(DEVICE(host->card));
}
static uint64_t omap_mmc_read(void *opaque, hwaddr offset, unsigned size)
{
uint16_t i;
- struct omap_mmc_s *s = opaque;
+ OMAPMMCState *s = opaque;
if (size != 2) {
return omap_badwidth_read16(opaque, offset);
}
switch (offset) {
- case 0x00: /* MMC_CMD */
+ case 0x00: /* MMC_CMD */
return s->last_cmd;
- case 0x04: /* MMC_ARGL */
+ case 0x04: /* MMC_ARGL */
return s->arg & 0x0000ffff;
- case 0x08: /* MMC_ARGH */
+ case 0x08: /* MMC_ARGH */
return s->arg >> 16;
- case 0x0c: /* MMC_CON */
+ case 0x0c: /* MMC_CON */
return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) |
(s->be << 10) | s->clkdiv;
- case 0x10: /* MMC_STAT */
+ case 0x10: /* MMC_STAT */
return s->status;
- case 0x14: /* MMC_IE */
+ case 0x14: /* MMC_IE */
return s->mask;
- case 0x18: /* MMC_CTO */
+ case 0x18: /* MMC_CTO */
return s->cto;
- case 0x1c: /* MMC_DTO */
+ case 0x1c: /* MMC_DTO */
return s->dto;
- case 0x20: /* MMC_DATA */
+ case 0x20: /* MMC_DATA */
/* TODO: support 8-bit access */
i = s->fifo[s->fifo_start];
if (s->fifo_len == 0) {
@@ -371,42 +378,42 @@ static uint64_t omap_mmc_read(void *opaque, hwaddr offset, unsigned size)
omap_mmc_interrupts_update(s);
return i;
- case 0x24: /* MMC_BLEN */
+ case 0x24: /* MMC_BLEN */
return s->blen_counter;
- case 0x28: /* MMC_NBLK */
+ case 0x28: /* MMC_NBLK */
return s->nblk_counter;
- case 0x2c: /* MMC_BUF */
+ case 0x2c: /* MMC_BUF */
return (s->rx_dma << 15) | (s->af_level << 8) |
(s->tx_dma << 7) | s->ae_level;
- case 0x30: /* MMC_SPI */
+ case 0x30: /* MMC_SPI */
return 0x0000;
- case 0x34: /* MMC_SDIO */
+ case 0x34: /* MMC_SDIO */
return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio;
- case 0x38: /* MMC_SYST */
+ case 0x38: /* MMC_SYST */
return 0x0000;
- case 0x3c: /* MMC_REV */
+ case 0x3c: /* MMC_REV */
return s->rev;
- case 0x40: /* MMC_RSP0 */
- case 0x44: /* MMC_RSP1 */
- case 0x48: /* MMC_RSP2 */
- case 0x4c: /* MMC_RSP3 */
- case 0x50: /* MMC_RSP4 */
- case 0x54: /* MMC_RSP5 */
- case 0x58: /* MMC_RSP6 */
- case 0x5c: /* MMC_RSP7 */
+ case 0x40: /* MMC_RSP0 */
+ case 0x44: /* MMC_RSP1 */
+ case 0x48: /* MMC_RSP2 */
+ case 0x4c: /* MMC_RSP3 */
+ case 0x50: /* MMC_RSP4 */
+ case 0x54: /* MMC_RSP5 */
+ case 0x58: /* MMC_RSP6 */
+ case 0x5c: /* MMC_RSP7 */
return s->rsp[(offset - 0x40) >> 2];
/* OMAP2-specific */
- case 0x60: /* MMC_IOSR */
- case 0x64: /* MMC_SYSC */
+ case 0x60: /* MMC_IOSR */
+ case 0x64: /* MMC_SYSC */
return 0;
- case 0x68: /* MMC_SYSS */
- return 1; /* RSTD */
+ case 0x68: /* MMC_SYSS */
+ return 1; /* RSTD */
}
OMAP_BAD_REG(offset);
@@ -417,7 +424,7 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
int i;
- struct omap_mmc_s *s = opaque;
+ OMAPMMCState *s = opaque;
if (size != 2) {
omap_badwidth_write16(opaque, offset, value);
@@ -425,7 +432,7 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
}
switch (offset) {
- case 0x00: /* MMC_CMD */
+ case 0x00: /* MMC_CMD */
if (!s->enable)
break;
@@ -433,24 +440,24 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
for (i = 0; i < 8; i ++)
s->rsp[i] = 0x0000;
omap_mmc_command(s, value & 63, (value >> 15) & 1,
- (sd_cmd_type_t) ((value >> 12) & 3),
- (value >> 11) & 1,
- (sd_rsp_type_t) ((value >> 8) & 7),
- (value >> 7) & 1);
+ (MMCCmdType)((value >> 12) & 3),
+ (value >> 11) & 1,
+ (sd_rsp_type_t) ((value >> 8) & 7),
+ (value >> 7) & 1);
omap_mmc_update(s);
break;
- case 0x04: /* MMC_ARGL */
+ case 0x04: /* MMC_ARGL */
s->arg &= 0xffff0000;
s->arg |= 0x0000ffff & value;
break;
- case 0x08: /* MMC_ARGH */
+ case 0x08: /* MMC_ARGH */
s->arg &= 0x0000ffff;
s->arg |= value << 16;
break;
- case 0x0c: /* MMC_CON */
+ case 0x0c: /* MMC_CON */
s->dw = (value >> 15) & 1;
s->mode = (value >> 12) & 3;
s->enable = (value >> 11) & 1;
@@ -470,27 +477,27 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
omap_mmc_pseudo_reset(s);
break;
- case 0x10: /* MMC_STAT */
+ case 0x10: /* MMC_STAT */
s->status &= ~value;
omap_mmc_interrupts_update(s);
break;
- case 0x14: /* MMC_IE */
+ case 0x14: /* MMC_IE */
s->mask = value & 0x7fff;
omap_mmc_interrupts_update(s);
break;
- case 0x18: /* MMC_CTO */
+ case 0x18: /* MMC_CTO */
s->cto = value & 0xff;
if (s->cto > 0xfd && s->rev <= 1)
printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
break;
- case 0x1c: /* MMC_DTO */
+ case 0x1c: /* MMC_DTO */
s->dto = value & 0xffff;
break;
- case 0x20: /* MMC_DATA */
+ case 0x20: /* MMC_DATA */
/* TODO: support 8-bit access */
if (s->fifo_len == 32)
break;
@@ -501,18 +508,18 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
omap_mmc_interrupts_update(s);
break;
- case 0x24: /* MMC_BLEN */
+ case 0x24: /* MMC_BLEN */
s->blen = (value & 0x07ff) + 1;
s->blen_counter = s->blen;
break;
- case 0x28: /* MMC_NBLK */
+ case 0x28: /* MMC_NBLK */
s->nblk = (value & 0x07ff) + 1;
s->nblk_counter = s->nblk;
s->blen_counter = s->blen;
break;
- case 0x2c: /* MMC_BUF */
+ case 0x2c: /* MMC_BUF */
s->rx_dma = (value >> 15) & 1;
s->af_level = (value >> 8) & 0x1f;
s->tx_dma = (value >> 7) & 1;
@@ -527,38 +534,38 @@ static void omap_mmc_write(void *opaque, hwaddr offset,
break;
/* SPI, SDIO and TEST modes unimplemented */
- case 0x30: /* MMC_SPI (OMAP1 only) */
+ case 0x30: /* MMC_SPI (OMAP1 only) */
break;
- case 0x34: /* MMC_SDIO */
+ case 0x34: /* MMC_SDIO */
s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020);
s->cdet_wakeup = (value >> 9) & 1;
s->cdet_enable = (value >> 2) & 1;
break;
- case 0x38: /* MMC_SYST */
+ case 0x38: /* MMC_SYST */
break;
- case 0x3c: /* MMC_REV */
- case 0x40: /* MMC_RSP0 */
- case 0x44: /* MMC_RSP1 */
- case 0x48: /* MMC_RSP2 */
- case 0x4c: /* MMC_RSP3 */
- case 0x50: /* MMC_RSP4 */
- case 0x54: /* MMC_RSP5 */
- case 0x58: /* MMC_RSP6 */
- case 0x5c: /* MMC_RSP7 */
+ case 0x3c: /* MMC_REV */
+ case 0x40: /* MMC_RSP0 */
+ case 0x44: /* MMC_RSP1 */
+ case 0x48: /* MMC_RSP2 */
+ case 0x4c: /* MMC_RSP3 */
+ case 0x50: /* MMC_RSP4 */
+ case 0x54: /* MMC_RSP5 */
+ case 0x58: /* MMC_RSP6 */
+ case 0x5c: /* MMC_RSP7 */
OMAP_RO_REG(offset);
break;
/* OMAP2-specific */
- case 0x60: /* MMC_IOSR */
+ case 0x60: /* MMC_IOSR */
if (value & 0xf)
printf("MMC: SDIO bits used!\n");
break;
- case 0x64: /* MMC_SYSC */
- if (value & (1 << 2)) /* SRTS */
+ case 0x64: /* MMC_SYSC */
+ if (value & (1 << 2)) /* SRTS */
omap_mmc_reset(s);
break;
- case 0x68: /* MMC_SYSS */
+ case 0x68: /* MMC_SYSS */
OMAP_RO_REG(offset);
break;
@@ -573,92 +580,56 @@ static const MemoryRegionOps omap_mmc_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void omap_mmc_cover_cb(void *opaque, int line, int level)
+void omap_mmc_set_clk(DeviceState *dev, omap_clk clk)
{
- struct omap_mmc_s *host = opaque;
+ OMAPMMCState *s = OMAP_MMC(dev);
- if (!host->cdet_state && level) {
- host->status |= 0x0002;
- omap_mmc_interrupts_update(host);
- if (host->cdet_wakeup) {
- /* TODO: Assert wake-up */
- }
- }
-
- if (host->cdet_state != level) {
- qemu_set_irq(host->coverswitch, level);
- host->cdet_state = level;
- }
+ s->clk = clk;
}
-struct omap_mmc_s *omap_mmc_init(hwaddr base,
- MemoryRegion *sysmem,
- BlockBackend *blk,
- qemu_irq irq, qemu_irq dma[], omap_clk clk)
+static void omap_mmc_reset_hold(Object *obj, ResetType type)
{
- struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->clk = clk;
- s->lines = 1; /* TODO: needs to be settable per-board */
- s->rev = 1;
-
- memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", 0x800);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- /* Instantiate the storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
+ OMAPMMCState *s = OMAP_MMC(obj);
omap_mmc_reset(s);
-
- return s;
}
-struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
- BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
- omap_clk fclk, omap_clk iclk)
+static void omap_mmc_initfn(Object *obj)
{
- struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->clk = fclk;
- s->lines = 4;
- s->rev = 2;
-
- memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- /* Instantiate the storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
+ OMAPMMCState *s = OMAP_MMC(obj);
- s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0);
- sd_set_cb(s->card, NULL, s->cdet);
+ /* In theory these could be settable per-board */
+ s->lines = 1;
+ s->rev = 1;
- omap_mmc_reset(s);
+ memory_region_init_io(&s->iomem, obj, &omap_mmc_ops, s, "omap.mmc", 0x800);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
- return s;
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+ qdev_init_gpio_out_named(DEVICE(obj), &s->dma_tx_gpio, "dma-tx", 1);
+ qdev_init_gpio_out_named(DEVICE(obj), &s->dma_rx_gpio, "dma-rx", 1);
+
+ qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(obj), "sd-bus");
}
-void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
+static void omap_mmc_class_init(ObjectClass *oc, const void *data)
{
- if (s->cdet) {
- sd_set_cb(s->card, ro, s->cdet);
- s->coverswitch = cover;
- qemu_set_irq(cover, s->cdet_state);
- } else
- sd_set_cb(s->card, ro, cover);
+ ResettableClass *rc = RESETTABLE_CLASS(oc);
+
+ rc->phases.hold = omap_mmc_reset_hold;
}
-void omap_mmc_enable(struct omap_mmc_s *s, int enable)
+static const TypeInfo omap_mmc_info = {
+ .name = TYPE_OMAP_MMC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OMAPMMCState),
+ .instance_init = omap_mmc_initfn,
+ .class_init = omap_mmc_class_init,
+};
+
+static void omap_mmc_register_types(void)
{
- sd_enable(s->card, enable);
+ type_register_static(&omap_mmc_info);
}
+
+type_init(omap_mmc_register_types)
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index e3633c2..b8fc9f8 100644
--- a/hw/sd/pl181.c
+++ b/hw/sd/pl181.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
@@ -509,17 +509,17 @@ static void pl181_init(Object *obj)
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_PL181_BUS, dev, "sd-bus");
}
-static void pl181_class_init(ObjectClass *klass, void *data)
+static void pl181_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->vmsd = &vmstate_pl181;
- k->reset = pl181_reset;
+ device_class_set_legacy_reset(k, pl181_reset);
/* Reason: output IRQs should be wired up */
k->user_creatable = false;
}
-static void pl181_bus_class_init(ObjectClass *klass, void *data)
+static void pl181_bus_class_init(ObjectClass *klass, const void *data)
{
SDBusClass *sbc = SD_BUS_CLASS(klass);
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
deleted file mode 100644
index 8252970..0000000
--- a/hw/sd/pxa2xx_mmci.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "hw/sd/sd.h"
-#include "hw/qdev-properties.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "trace.h"
-#include "qom/object.h"
-
-#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus"
-/* This is reusing the SDBus typedef from SD_BUS */
-DECLARE_INSTANCE_CHECKER(SDBus, PXA2XX_MMCI_BUS,
- TYPE_PXA2XX_MMCI_BUS)
-
-struct PXA2xxMMCIState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq rx_dma;
- qemu_irq tx_dma;
- qemu_irq inserted;
- qemu_irq readonly;
-
- BlockBackend *blk;
- SDBus sdbus;
-
- uint32_t status;
- uint32_t clkrt;
- uint32_t spi;
- uint32_t cmdat;
- uint32_t resp_tout;
- uint32_t read_tout;
- int32_t blklen;
- int32_t numblk;
- uint32_t intmask;
- uint32_t intreq;
- int32_t cmd;
- uint32_t arg;
-
- int32_t active;
- int32_t bytesleft;
- uint8_t tx_fifo[64];
- uint32_t tx_start;
- uint32_t tx_len;
- uint8_t rx_fifo[32];
- uint32_t rx_start;
- uint32_t rx_len;
- uint16_t resp_fifo[9];
- uint32_t resp_len;
-
- int32_t cmdreq;
-};
-
-static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxMMCIState *s = opaque;
-
- return s->tx_start < ARRAY_SIZE(s->tx_fifo)
- && s->rx_start < ARRAY_SIZE(s->rx_fifo)
- && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
- && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
- && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
-}
-
-
-static const VMStateDescription vmstate_pxa2xx_mmci = {
- .name = "pxa2xx-mmci",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(status, PXA2xxMMCIState),
- VMSTATE_UINT32(clkrt, PXA2xxMMCIState),
- VMSTATE_UINT32(spi, PXA2xxMMCIState),
- VMSTATE_UINT32(cmdat, PXA2xxMMCIState),
- VMSTATE_UINT32(resp_tout, PXA2xxMMCIState),
- VMSTATE_UINT32(read_tout, PXA2xxMMCIState),
- VMSTATE_INT32(blklen, PXA2xxMMCIState),
- VMSTATE_INT32(numblk, PXA2xxMMCIState),
- VMSTATE_UINT32(intmask, PXA2xxMMCIState),
- VMSTATE_UINT32(intreq, PXA2xxMMCIState),
- VMSTATE_INT32(cmd, PXA2xxMMCIState),
- VMSTATE_UINT32(arg, PXA2xxMMCIState),
- VMSTATE_INT32(cmdreq, PXA2xxMMCIState),
- VMSTATE_INT32(active, PXA2xxMMCIState),
- VMSTATE_INT32(bytesleft, PXA2xxMMCIState),
- VMSTATE_UINT32(tx_start, PXA2xxMMCIState),
- VMSTATE_UINT32(tx_len, PXA2xxMMCIState),
- VMSTATE_UINT32(rx_start, PXA2xxMMCIState),
- VMSTATE_UINT32(rx_len, PXA2xxMMCIState),
- VMSTATE_UINT32(resp_len, PXA2xxMMCIState),
- VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate),
- VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64),
- VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32),
- VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
-#define MMC_STAT 0x04 /* MMC Status register */
-#define MMC_CLKRT 0x08 /* MMC Clock Rate register */
-#define MMC_SPI 0x0c /* MMC SPI Mode register */
-#define MMC_CMDAT 0x10 /* MMC Command/Data register */
-#define MMC_RESTO 0x14 /* MMC Response Time-Out register */
-#define MMC_RDTO 0x18 /* MMC Read Time-Out register */
-#define MMC_BLKLEN 0x1c /* MMC Block Length register */
-#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */
-#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */
-#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */
-#define MMC_I_REG 0x2c /* MMC Interrupt Request register */
-#define MMC_CMD 0x30 /* MMC Command register */
-#define MMC_ARGH 0x34 /* MMC Argument High register */
-#define MMC_ARGL 0x38 /* MMC Argument Low register */
-#define MMC_RES 0x3c /* MMC Response FIFO */
-#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */
-#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */
-#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */
-#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */
-
-/* Bitfield masks */
-#define STRPCL_STOP_CLK (1 << 0)
-#define STRPCL_STRT_CLK (1 << 1)
-#define STAT_TOUT_RES (1 << 1)
-#define STAT_CLK_EN (1 << 8)
-#define STAT_DATA_DONE (1 << 11)
-#define STAT_PRG_DONE (1 << 12)
-#define STAT_END_CMDRES (1 << 13)
-#define SPI_SPI_MODE (1 << 0)
-#define CMDAT_RES_TYPE (3 << 0)
-#define CMDAT_DATA_EN (1 << 2)
-#define CMDAT_WR_RD (1 << 3)
-#define CMDAT_DMA_EN (1 << 7)
-#define CMDAT_STOP_TRAN (1 << 10)
-#define INT_DATA_DONE (1 << 0)
-#define INT_PRG_DONE (1 << 1)
-#define INT_END_CMD (1 << 2)
-#define INT_STOP_CMD (1 << 3)
-#define INT_CLK_OFF (1 << 4)
-#define INT_RXFIFO_REQ (1 << 5)
-#define INT_TXFIFO_REQ (1 << 6)
-#define INT_TINT (1 << 7)
-#define INT_DAT_ERR (1 << 8)
-#define INT_RES_ERR (1 << 9)
-#define INT_RD_STALLED (1 << 10)
-#define INT_SDIO_INT (1 << 11)
-#define INT_SDIO_SACK (1 << 12)
-#define PRTBUF_PRT_BUF (1 << 0)
-
-/* Route internal interrupt lines to the global IC and DMA */
-static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
-{
- uint32_t mask = s->intmask;
- if (s->cmdat & CMDAT_DMA_EN) {
- mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
-
- qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
- qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
- }
-
- qemu_set_irq(s->irq, !!(s->intreq & ~mask));
-}
-
-static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
-{
- if (!s->active)
- return;
-
- if (s->cmdat & CMDAT_WR_RD) {
- while (s->bytesleft && s->tx_len) {
- sdbus_write_byte(&s->sdbus, s->tx_fifo[s->tx_start++]);
- s->tx_start &= 0x1f;
- s->tx_len --;
- s->bytesleft --;
- }
- if (s->bytesleft)
- s->intreq |= INT_TXFIFO_REQ;
- } else
- while (s->bytesleft && s->rx_len < 32) {
- s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
- sdbus_read_byte(&s->sdbus);
- s->bytesleft --;
- s->intreq |= INT_RXFIFO_REQ;
- }
-
- if (!s->bytesleft) {
- s->active = 0;
- s->intreq |= INT_DATA_DONE;
- s->status |= STAT_DATA_DONE;
-
- if (s->cmdat & CMDAT_WR_RD) {
- s->intreq |= INT_PRG_DONE;
- s->status |= STAT_PRG_DONE;
- }
- }
-
- pxa2xx_mmci_int_update(s);
-}
-
-static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
-{
- int rsplen, i;
- SDRequest request;
- uint8_t response[16];
-
- s->active = 1;
- s->rx_len = 0;
- s->tx_len = 0;
- s->cmdreq = 0;
-
- request.cmd = s->cmd;
- request.arg = s->arg;
- request.crc = 0; /* FIXME */
-
- rsplen = sdbus_do_command(&s->sdbus, &request, response);
- s->intreq |= INT_END_CMD;
-
- memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
- switch (s->cmdat & CMDAT_RES_TYPE) {
-#define PXAMMCI_RESP(wd, value0, value1) \
- s->resp_fifo[(wd) + 0] |= (value0); \
- s->resp_fifo[(wd) + 1] |= (value1) << 8;
- case 0: /* No response */
- goto complete;
-
- case 1: /* R1, R4, R5 or R6 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- case 2: /* R2 */
- if (rsplen < 16)
- goto timeout;
- goto complete;
-
- case 3: /* R3 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- complete:
- for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
- PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
- }
- s->status |= STAT_END_CMDRES;
-
- if (!(s->cmdat & CMDAT_DATA_EN))
- s->active = 0;
- else
- s->bytesleft = s->numblk * s->blklen;
-
- s->resp_len = 0;
- break;
-
- timeout:
- s->active = 0;
- s->status |= STAT_TOUT_RES;
- break;
- }
-
- pxa2xx_mmci_fifo_update(s);
-}
-
-static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case MMC_STRPCL:
- break;
- case MMC_STAT:
- ret = s->status;
- break;
- case MMC_CLKRT:
- ret = s->clkrt;
- break;
- case MMC_SPI:
- ret = s->spi;
- break;
- case MMC_CMDAT:
- ret = s->cmdat;
- break;
- case MMC_RESTO:
- ret = s->resp_tout;
- break;
- case MMC_RDTO:
- ret = s->read_tout;
- break;
- case MMC_BLKLEN:
- ret = s->blklen;
- break;
- case MMC_NUMBLK:
- ret = s->numblk;
- break;
- case MMC_PRTBUF:
- break;
- case MMC_I_MASK:
- ret = s->intmask;
- break;
- case MMC_I_REG:
- ret = s->intreq;
- break;
- case MMC_CMD:
- ret = s->cmd | 0x40;
- break;
- case MMC_ARGH:
- ret = s->arg >> 16;
- break;
- case MMC_ARGL:
- ret = s->arg & 0xffff;
- break;
- case MMC_RES:
- ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0;
- break;
- case MMC_RXFIFO:
- while (size-- && s->rx_len) {
- ret |= s->rx_fifo[s->rx_start++] << (size << 3);
- s->rx_start &= 0x1f;
- s->rx_len --;
- }
- s->intreq &= ~INT_RXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- break;
- case MMC_RDWAIT:
- break;
- case MMC_BLKS_REM:
- ret = s->numblk;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
- __func__, offset);
- }
- trace_pxa2xx_mmci_read(size, offset, ret);
-
- return ret;
-}
-
-static void pxa2xx_mmci_write(void *opaque,
- hwaddr offset, uint64_t value, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-
- trace_pxa2xx_mmci_write(size, offset, value);
- switch (offset) {
- case MMC_STRPCL:
- if (value & STRPCL_STRT_CLK) {
- s->status |= STAT_CLK_EN;
- s->intreq &= ~INT_CLK_OFF;
-
- if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
- pxa2xx_mmci_wakequeues(s);
- }
- }
-
- if (value & STRPCL_STOP_CLK) {
- s->status &= ~STAT_CLK_EN;
- s->intreq |= INT_CLK_OFF;
- s->active = 0;
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CLKRT:
- s->clkrt = value & 7;
- break;
-
- case MMC_SPI:
- s->spi = value & 0xf;
- if (value & SPI_SPI_MODE) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: attempted to use card in SPI mode\n", __func__);
- }
- break;
-
- case MMC_CMDAT:
- s->cmdat = value & 0x3dff;
- s->active = 0;
- s->cmdreq = 1;
- if (!(value & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
-
- if (s->status & STAT_CLK_EN)
- pxa2xx_mmci_wakequeues(s);
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_RESTO:
- s->resp_tout = value & 0x7f;
- break;
-
- case MMC_RDTO:
- s->read_tout = value & 0xffff;
- break;
-
- case MMC_BLKLEN:
- s->blklen = value & 0xfff;
- break;
-
- case MMC_NUMBLK:
- s->numblk = value & 0xffff;
- break;
-
- case MMC_PRTBUF:
- if (value & PRTBUF_PRT_BUF) {
- s->tx_start ^= 32;
- s->tx_len = 0;
- }
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_I_MASK:
- s->intmask = value & 0x1fff;
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CMD:
- s->cmd = value & 0x3f;
- break;
-
- case MMC_ARGH:
- s->arg &= 0x0000ffff;
- s->arg |= value << 16;
- break;
-
- case MMC_ARGL:
- s->arg &= 0xffff0000;
- s->arg |= value & 0x0000ffff;
- break;
-
- case MMC_TXFIFO:
- while (size-- && s->tx_len < 0x20)
- s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
- (value >> (size << 3)) & 0xff;
- s->intreq &= ~INT_TXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_RDWAIT:
- case MMC_BLKS_REM:
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: incorrect reg 0x%02" HWADDR_PRIx " "
- "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
- }
-}
-
-static const MemoryRegionOps pxa2xx_mmci_ops = {
- .read = pxa2xx_mmci_read,
- .write = pxa2xx_mmci_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
-{
- DeviceState *dev;
-
- dev = sysbus_create_simple(TYPE_PXA2XX_MMCI, base, irq);
- qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma);
- qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
-
- return PXA2XX_MMCI(dev);
-}
-
-static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->inserted, inserted);
-}
-
-static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->readonly, readonly);
-}
-
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
- qemu_irq coverswitch)
-{
- DeviceState *dev = DEVICE(s);
-
- s->readonly = readonly;
- s->inserted = coverswitch;
-
- pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
- pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
-}
-
-static void pxa2xx_mmci_reset(DeviceState *d)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(d);
-
- s->status = 0;
- s->clkrt = 0;
- s->spi = 0;
- s->cmdat = 0;
- s->resp_tout = 0;
- s->read_tout = 0;
- s->blklen = 0;
- s->numblk = 0;
- s->intmask = 0;
- s->intreq = 0;
- s->cmd = 0;
- s->arg = 0;
- s->active = 0;
- s->bytesleft = 0;
- s->tx_start = 0;
- s->tx_len = 0;
- s->rx_start = 0;
- s->rx_len = 0;
- s->resp_len = 0;
- s->cmdreq = 0;
- memset(s->tx_fifo, 0, sizeof(s->tx_fifo));
- memset(s->rx_fifo, 0, sizeof(s->rx_fifo));
- memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
-}
-
-static void pxa2xx_mmci_instance_init(Object *obj)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- DeviceState *dev = DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s,
- "pxa2xx-mmci", 0x00100000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1);
- qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1);
-
- qbus_init(&s->sdbus, sizeof(s->sdbus),
- TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
-}
-
-static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_pxa2xx_mmci;
- dc->reset = pxa2xx_mmci_reset;
-}
-
-static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data)
-{
- SDBusClass *sbc = SD_BUS_CLASS(klass);
-
- sbc->set_inserted = pxa2xx_mmci_set_inserted;
- sbc->set_readonly = pxa2xx_mmci_set_readonly;
-}
-
-static const TypeInfo pxa2xx_mmci_types[] = {
- {
- .name = TYPE_PXA2XX_MMCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxMMCIState),
- .instance_init = pxa2xx_mmci_instance_init,
- .class_init = pxa2xx_mmci_class_init,
- },
- {
- .name = TYPE_PXA2XX_MMCI_BUS,
- .parent = TYPE_SD_BUS,
- .instance_size = sizeof(SDBus),
- .class_init = pxa2xx_mmci_bus_class_init,
- },
-};
-
-DEFINE_TYPES(pxa2xx_mmci_types)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index a140a32..c275fdd 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -37,9 +37,8 @@
#include "qemu/cutils.h"
#include "hw/irq.h"
#include "hw/registerfields.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "hw/sd/sd.h"
-#include "hw/sd/sdcard_legacy.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/bitmap.h"
@@ -71,6 +70,14 @@ typedef enum {
sd_illegal = -2,
} sd_rsp_type_t;
+typedef enum {
+ sd_spi,
+ sd_bc, /* broadcast -- no response */
+ sd_bcr, /* broadcast with response */
+ sd_ac, /* addressed -- no data transfer */
+ sd_adtc, /* addressed with data transfer */
+} sd_cmd_type_t;
+
enum SDCardModes {
sd_inactive,
sd_card_identification_mode,
@@ -112,10 +119,6 @@ typedef struct SDProto {
struct SDState {
DeviceState parent_obj;
- /* If true, created by sd_init() for a non-qdevified caller */
- /* TODO purge them with fire */
- bool me_no_qdev_me_kill_mammoth_with_rocks;
-
/* SD Memory Card Registers */
uint32_t ocr;
uint8_t scr[8];
@@ -169,10 +172,7 @@ struct SDState {
uint32_t data_offset;
size_t data_size;
uint8_t data[512];
- qemu_irq readonly_cb;
- qemu_irq inserted_cb;
QEMUTimer *ocr_power_timer;
- bool enable;
uint8_t dat_lines;
bool cmd_line;
};
@@ -291,12 +291,12 @@ static const char *sd_acmd_name(SDState *sd, uint8_t cmd)
static uint8_t sd_get_dat_lines(SDState *sd)
{
- return sd->enable ? sd->dat_lines : 0;
+ return sd->dat_lines;
}
static bool sd_get_cmd_line(SDState *sd)
{
- return sd->enable ? sd->cmd_line : false;
+ return sd->cmd_line;
}
static void sd_set_voltage(SDState *sd, uint16_t millivolts)
@@ -774,19 +774,12 @@ static uint32_t sd_blk_len(SDState *sd)
*/
static uint32_t sd_bootpart_offset(SDState *sd)
{
- bool partitions_enabled;
unsigned partition_access;
if (!sd->boot_part_size || !sd_is_emmc(sd)) {
return 0;
}
- partitions_enabled = sd->ext_csd[EXT_CSD_PART_CONFIG]
- & EXT_CSD_PART_CONFIG_EN_MASK;
- if (!partitions_enabled) {
- return 0;
- }
-
partition_access = sd->ext_csd[EXT_CSD_PART_CONFIG]
& EXT_CSD_PART_CONFIG_ACC_MASK;
switch (partition_access) {
@@ -833,7 +826,9 @@ static void sd_reset(DeviceState *dev)
sect = 0;
}
size = sect << HWBLOCK_SHIFT;
- size -= sd_bootpart_offset(sd);
+ if (sd_is_emmc(sd)) {
+ size -= sd->boot_part_size * 2;
+ }
sect = sd_addr_to_wpnum(size) + 1;
@@ -889,17 +884,10 @@ static void sd_cardchange(void *opaque, bool load, Error **errp)
trace_sdcard_ejected();
}
- if (sd->me_no_qdev_me_kill_mammoth_with_rocks) {
- qemu_set_irq(sd->inserted_cb, inserted);
- if (inserted) {
- qemu_set_irq(sd->readonly_cb, readonly);
- }
- } else {
- sdbus = SD_BUS(qdev_get_parent_bus(dev));
- sdbus_set_inserted(sdbus, inserted);
- if (inserted) {
- sdbus_set_readonly(sdbus, readonly);
- }
+ sdbus = SD_BUS(qdev_get_parent_bus(dev));
+ sdbus_set_inserted(sdbus, inserted);
+ if (inserted) {
+ sdbus_set_readonly(sdbus, readonly);
}
}
@@ -987,7 +975,7 @@ static const VMStateDescription sd_vmstate = {
VMSTATE_UINT32(data_offset, SDState),
VMSTATE_UINT8_ARRAY(data, SDState, 512),
VMSTATE_UNUSED_V(1, 512),
- VMSTATE_BOOL(enable, SDState),
+ VMSTATE_UNUSED(1),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
@@ -997,48 +985,6 @@ static const VMStateDescription sd_vmstate = {
},
};
-/* Legacy initialization function for use by non-qdevified callers */
-SDState *sd_init(BlockBackend *blk, bool is_spi)
-{
- Object *obj;
- DeviceState *dev;
- SDState *sd;
- Error *err = NULL;
-
- obj = object_new(is_spi ? TYPE_SD_CARD_SPI : TYPE_SD_CARD);
- dev = DEVICE(obj);
- if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) {
- error_reportf_err(err, "sd_init failed: ");
- return NULL;
- }
-
- /*
- * Realizing the device properly would put it into the QOM
- * composition tree even though it is not plugged into an
- * appropriate bus. That's a no-no. Hide the device from
- * QOM/qdev, and call its qdev realize callback directly.
- */
- object_ref(obj);
- object_unparent(obj);
- sd_realize(dev, &err);
- if (err) {
- error_reportf_err(err, "sd_init failed: ");
- return NULL;
- }
-
- sd = SD_CARD(dev);
- sd->me_no_qdev_me_kill_mammoth_with_rocks = true;
- return sd;
-}
-
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
-{
- sd->readonly_cb = readonly;
- sd->inserted_cb = insert;
- qemu_set_irq(readonly, sd->blk ? !blk_is_writable(sd->blk) : 0);
- qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0);
-}
-
static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
{
trace_sdcard_read_block(addr, len);
@@ -2193,13 +2139,13 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd)
return cmd_class == 0 || cmd_class == 7;
}
-int sd_do_command(SDState *sd, SDRequest *req,
- uint8_t *response) {
+static int sd_do_command(SDState *sd, SDRequest *req,
+ uint8_t *response) {
int last_state;
sd_rsp_type_t rtype;
int rsplen;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable) {
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return 0;
}
@@ -2346,12 +2292,13 @@ static bool sd_generic_read_byte(SDState *sd, uint8_t *value)
return false;
}
-void sd_write_byte(SDState *sd, uint8_t value)
+static void sd_write_byte(SDState *sd, uint8_t value)
{
int i;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return;
+ }
if (sd->state != sd_receivingdata_state) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -2475,15 +2422,16 @@ void sd_write_byte(SDState *sd, uint8_t value)
}
}
-uint8_t sd_read_byte(SDState *sd)
+static uint8_t sd_read_byte(SDState *sd)
{
/* TODO: Append CRCs */
const uint8_t dummy_byte = 0x00;
uint8_t ret;
uint32_t io_len;
- if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
+ if (!sd->blk || !blk_is_inserted(sd->blk)) {
return dummy_byte;
+ }
if (sd->state != sd_sendingdata_state) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -2558,11 +2506,6 @@ static bool sd_data_ready(SDState *sd)
return sd->state == sd_sendingdata_state;
}
-void sd_enable(SDState *sd, bool enable)
-{
- sd->enable = enable;
-}
-
static const SDProto sd_proto_spi = {
.name = "SPI",
.cmd = {
@@ -2722,7 +2665,6 @@ static void sd_instance_init(Object *obj)
sd->proto = sc->proto;
sd->last_cmd_name = "UNSET";
- sd->enable = true;
sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd);
}
@@ -2795,31 +2737,28 @@ static void emmc_realize(DeviceState *dev, Error **errp)
sd_realize(dev, errp);
}
-static Property sdmmc_common_properties[] = {
+static const Property sdmmc_common_properties[] = {
DEFINE_PROP_DRIVE("drive", SDState, blk),
- DEFINE_PROP_END_OF_LIST()
};
-static Property sd_properties[] = {
+static const Property sd_properties[] = {
DEFINE_PROP_UINT8("spec_version", SDState,
spec_version, SD_PHY_SPECv3_01_VERS),
- DEFINE_PROP_END_OF_LIST()
};
-static Property emmc_properties[] = {
+static const Property emmc_properties[] = {
DEFINE_PROP_UINT64("boot-partition-size", SDState, boot_part_size, 0),
DEFINE_PROP_UINT8("boot-config", SDState, boot_config, 0x0),
- DEFINE_PROP_END_OF_LIST()
};
-static void sdmmc_common_class_init(ObjectClass *klass, void *data)
+static void sdmmc_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
device_class_set_props(dc, sdmmc_common_properties);
dc->vmsd = &sd_vmstate;
- dc->reset = sd_reset;
+ device_class_set_legacy_reset(dc, sd_reset);
dc->bus_type = TYPE_SD_BUS;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
@@ -2831,12 +2770,11 @@ static void sdmmc_common_class_init(ObjectClass *klass, void *data)
sc->read_byte = sd_read_byte;
sc->receive_ready = sd_receive_ready;
sc->data_ready = sd_data_ready;
- sc->enable = sd_enable;
sc->get_inserted = sd_get_inserted;
sc->get_readonly = sd_get_readonly;
}
-static void sd_class_init(ObjectClass *klass, void *data)
+static void sd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
@@ -2855,7 +2793,7 @@ static void sd_class_init(ObjectClass *klass, void *data)
* board to ensure that ssi transfers only occur when the chip select
* is asserted.
*/
-static void sd_spi_class_init(ObjectClass *klass, void *data)
+static void sd_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
@@ -2864,7 +2802,7 @@ static void sd_spi_class_init(ObjectClass *klass, void *data)
sc->proto = &sd_proto_spi;
}
-static void emmc_class_init(ObjectClass *klass, void *data)
+static void emmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SDCardClass *sc = SDMMC_COMMON_CLASS(klass);
diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h
index 5f3765f..9f768c4 100644
--- a/hw/sd/sdhci-internal.h
+++ b/hw/sd/sdhci-internal.h
@@ -322,6 +322,6 @@ void sdhci_initfn(SDHCIState *s);
void sdhci_uninitfn(SDHCIState *s);
void sdhci_common_realize(SDHCIState *s, Error **errp);
void sdhci_common_unrealize(SDHCIState *s);
-void sdhci_common_class_init(ObjectClass *klass, void *data);
+void sdhci_common_class_init(ObjectClass *klass, const void *data);
#endif
diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c
index 9b7bee8..c18b91f 100644
--- a/hw/sd/sdhci-pci.c
+++ b/hw/sd/sdhci-pci.c
@@ -18,13 +18,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
+#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/sd/sdhci.h"
#include "sdhci-internal.h"
-static Property sdhci_pci_properties[] = {
+static const Property sdhci_pci_properties[] = {
DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
- DEFINE_PROP_END_OF_LIST(),
};
static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
@@ -49,11 +49,12 @@ static void sdhci_pci_exit(PCIDevice *dev)
{
SDHCIState *s = PCI_SDHCI(dev);
+ qemu_free_irq(s->irq);
sdhci_common_unrealize(s);
sdhci_uninitfn(s);
}
-static void sdhci_pci_class_init(ObjectClass *klass, void *data)
+static void sdhci_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -74,7 +75,7 @@ static const TypeInfo sdhci_pci_types[] = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(SDHCIState),
.class_init = sdhci_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 8293d83..226ff13 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -30,14 +30,13 @@
#include "qapi/error.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/timer.h"
#include "qemu/bitops.h"
#include "hw/sd/sdhci.h"
#include "migration/vmstate.h"
#include "sdhci-internal.h"
#include "qemu/log.h"
-#include "qemu/module.h"
#include "trace.h"
#include "qom/object.h"
@@ -234,7 +233,7 @@ static void sdhci_raise_insertion_irq(void *opaque)
if (s->norintsts & SDHC_NIS_REMOVE) {
timer_mod(s->insert_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
} else {
s->prnsts = 0x1ff0000;
if (s->norintstsen & SDHC_NISEN_INSERT) {
@@ -252,7 +251,7 @@ static void sdhci_set_inserted(DeviceState *dev, bool level)
if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
/* Give target some time to notice card ejection */
timer_mod(s->insert_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY);
} else {
if (level) {
s->prnsts = 0x1ff0000;
@@ -275,6 +274,10 @@ static void sdhci_set_readonly(DeviceState *dev, bool level)
{
SDHCIState *s = (SDHCIState *)dev;
+ if (s->wp_inverted) {
+ level = !level;
+ }
+
if (level) {
s->prnsts &= ~SDHC_WRITE_PROTECT;
} else {
@@ -290,9 +293,11 @@ static void sdhci_reset(SDHCIState *s)
timer_del(s->insert_timer);
timer_del(s->transfer_timer);
- /* Set all registers to 0. Capabilities/Version registers are not cleared
+ /*
+ * Set all registers to 0. Capabilities/Version registers are not cleared
* and assumed to always preserve their value, given to them during
- * initialization */
+ * initialization
+ */
memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
/* Reset other state based on current card insertion/readonly status */
@@ -302,11 +307,16 @@ static void sdhci_reset(SDHCIState *s)
s->data_count = 0;
s->stopped_state = sdhc_not_stopped;
s->pending_insert_state = false;
+ if (s->vendor == SDHCI_VENDOR_FSL) {
+ s->norintstsen = 0x013f;
+ s->errintstsen = 0x117f;
+ }
}
static void sdhci_poweron_reset(DeviceState *dev)
{
- /* QOM (ie power-on) reset. This is identical to reset
+ /*
+ * QOM (ie power-on) reset. This is identical to reset
* commanded via device register apart from handling of the
* 'pending insert on powerup' quirk.
*/
@@ -446,8 +456,10 @@ static void sdhci_read_block_from_card(SDHCIState *s)
s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
}
- /* If stop at block gap request was set and it's not the last block of
- * data - generate Block Event interrupt */
+ /*
+ * If stop at block gap request was set and it's not the last block of
+ * data - generate Block Event interrupt
+ */
if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) &&
s->blkcnt != 1) {
s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
@@ -549,8 +561,10 @@ static void sdhci_write_block_to_card(SDHCIState *s)
sdhci_update_irq(s);
}
-/* Write @size bytes of @value data to host controller @s Buffer Data Port
- * register */
+/*
+ * Write @size bytes of @value data to host controller @s Buffer Data Port
+ * register
+ */
static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
{
unsigned i;
@@ -595,9 +609,11 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
return;
}
- /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
+ /*
+ * XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
* possible stop at page boundary if initial address is not page aligned,
- * allow them to work properly */
+ * allow them to work properly
+ */
if ((s->sdmasysad % boundary_chk) == 0) {
page_aligned = true;
}
@@ -657,12 +673,13 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
}
}
+ if (s->norintstsen & SDHC_NISEN_DMA) {
+ s->norintsts |= SDHC_NIS_DMA;
+ }
+
if (s->blkcnt == 0) {
sdhci_end_transfer(s);
} else {
- if (s->norintstsen & SDHC_NISEN_DMA) {
- s->norintsts |= SDHC_NIS_DMA;
- }
sdhci_update_irq(s);
}
}
@@ -683,9 +700,22 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
}
s->blkcnt--;
+ if (s->norintstsen & SDHC_NISEN_DMA) {
+ s->norintsts |= SDHC_NIS_DMA;
+ }
+
sdhci_end_transfer(s);
}
+static void sdhci_sdma_transfer(SDHCIState *s)
+{
+ if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
+ sdhci_sdma_transfer_single_block(s);
+ } else {
+ sdhci_sdma_transfer_multi_blocks(s);
+ }
+}
+
typedef struct ADMADescr {
hwaddr addr;
uint16_t length;
@@ -703,7 +733,8 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
dma_memory_read(s->dma_as, entry_addr, &adma2, sizeof(adma2),
MEMTXATTRS_UNSPECIFIED);
adma2 = le64_to_cpu(adma2);
- /* The spec does not specify endianness of descriptor table.
+ /*
+ * The spec does not specify endianness of descriptor table.
* We currently assume that it is LE.
*/
dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull;
@@ -747,7 +778,7 @@ static void sdhci_do_adma(SDHCIState *s)
const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
const MemTxAttrs attrs = { .memory = true };
ADMADescr dscr = {};
- MemTxResult res;
+ MemTxResult res = MEMTX_ERROR;
int i;
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN && !s->blkcnt) {
@@ -916,12 +947,7 @@ static void sdhci_data_transfer(void *opaque)
if (s->trnmod & SDHC_TRNS_DMA) {
switch (SDHC_DMA_TYPE(s->hostctl1)) {
case SDHC_CTRL_SDMA:
- if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
- sdhci_sdma_transfer_single_block(s);
- } else {
- sdhci_sdma_transfer_multi_blocks(s);
- }
-
+ sdhci_sdma_transfer(s);
break;
case SDHC_CTRL_ADMA1_32:
if (!(s->capareg & R_SDHC_CAPAB_ADMA1_MASK)) {
@@ -978,8 +1004,10 @@ static bool sdhci_can_issue_command(SDHCIState *s)
return true;
}
-/* The Buffer Data Port register must be accessed in sequential and
- * continuous manner */
+/*
+ * The Buffer Data Port register must be accessed in sequential and
+ * continuous manner
+ */
static inline bool
sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
{
@@ -1163,11 +1191,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
if (!(mask & 0xFF000000) && s->blkcnt &&
(s->blksize & BLOCK_SIZE_MASK) &&
SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA) {
- if (s->trnmod & SDHC_TRNS_MULTI) {
- sdhci_sdma_transfer_multi_blocks(s);
- } else {
- sdhci_sdma_transfer_single_block(s);
- }
+ sdhci_sdma_transfer(s);
}
}
break;
@@ -1207,8 +1231,10 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
MASKED_WRITE(s->argument, mask, value);
break;
case SDHC_TRNMOD:
- /* DMA can be enabled only if it is supported as indicated by
- * capabilities register */
+ /*
+ * DMA can be enabled only if it is supported as indicated by
+ * capabilities register
+ */
if (!(s->capareg & R_SDHC_CAPAB_SDMA_MASK)) {
value &= ~SDHC_TRNS_DMA;
}
@@ -1280,8 +1306,10 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
} else {
s->norintsts &= ~SDHC_NIS_ERR;
}
- /* Quirk for Raspberry Pi: pending card insert interrupt
- * appears when first enabled after power on */
+ /*
+ * Quirk for Raspberry Pi: pending card insert interrupt
+ * appears when first enabled after power on
+ */
if ((s->norintstsen & SDHC_NISEN_INSERT) && s->pending_insert_state) {
assert(s->pending_insert_quirk);
s->norintsts |= SDHC_NIS_INSERT;
@@ -1397,8 +1425,10 @@ void sdhci_initfn(SDHCIState *s)
{
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SDHCI_BUS, DEVICE(s), "sd-bus");
- s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s);
- s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
+ s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ sdhci_raise_insertion_irq, s);
+ s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ sdhci_data_transfer, s);
s->io_ops = &sdhci_mmio_le_ops;
}
@@ -1446,11 +1476,13 @@ void sdhci_common_realize(SDHCIState *s, Error **errp)
void sdhci_common_unrealize(SDHCIState *s)
{
- /* This function is expected to be called only once for each class:
+ /*
+ * This function is expected to be called only once for each class:
* - SysBus: via DeviceClass->unrealize(),
* - PCI: via PCIDeviceClass->exit().
* However to avoid double-free and/or use-after-free we still nullify
- * this variable (better safe than sorry!). */
+ * this variable (better safe than sorry!).
+ */
g_free(s->fifo_buffer);
s->fifo_buffer = NULL;
}
@@ -1514,24 +1546,25 @@ const VMStateDescription sdhci_vmstate = {
},
};
-void sdhci_common_class_init(ObjectClass *klass, void *data)
+void sdhci_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->vmsd = &sdhci_vmstate;
- dc->reset = sdhci_poweron_reset;
+ device_class_set_legacy_reset(dc, sdhci_poweron_reset);
}
/* --- qdev SysBus --- */
-static Property sdhci_sysbus_properties[] = {
+static const Property sdhci_sysbus_properties[] = {
DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk,
false),
DEFINE_PROP_LINK("dma", SDHCIState,
dma_mr, TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BOOL("wp-inverted", SDHCIState,
+ wp_inverted, false),
};
static void sdhci_sysbus_init(Object *obj)
@@ -1587,7 +1620,7 @@ static void sdhci_sysbus_unrealize(DeviceState *dev)
}
}
-static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
+static void sdhci_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1598,18 +1631,9 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
sdhci_common_class_init(klass, data);
}
-static const TypeInfo sdhci_sysbus_info = {
- .name = TYPE_SYSBUS_SDHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SDHCIState),
- .instance_init = sdhci_sysbus_init,
- .instance_finalize = sdhci_sysbus_finalize,
- .class_init = sdhci_sysbus_class_init,
-};
-
/* --- qdev bus master --- */
-static void sdhci_bus_class_init(ObjectClass *klass, void *data)
+static void sdhci_bus_class_init(ObjectClass *klass, const void *data)
{
SDBusClass *sbc = SD_BUS_CLASS(klass);
@@ -1617,13 +1641,6 @@ static void sdhci_bus_class_init(ObjectClass *klass, void *data)
sbc->set_readonly = sdhci_set_readonly;
}
-static const TypeInfo sdhci_bus_info = {
- .name = TYPE_SDHCI_BUS,
- .parent = TYPE_SD_BUS,
- .instance_size = sizeof(SDBus),
- .class_init = sdhci_bus_class_init,
-};
-
/* --- qdev i.MX eSDHC --- */
#define USDHC_MIX_CTRL 0x48
@@ -1718,16 +1735,10 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
case USDHC_VENDOR_SPEC:
s->vendor_spec = value;
- switch (s->vendor) {
- case SDHCI_VENDOR_IMX:
- if (value & USDHC_IMX_FRC_SDCLK_ON) {
- s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
- } else {
- s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
- }
- break;
- default:
- break;
+ if (value & USDHC_IMX_FRC_SDCLK_ON) {
+ s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
+ } else {
+ s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
}
break;
@@ -1882,12 +1893,6 @@ static void imx_usdhc_init(Object *obj)
s->quirks = SDHCI_QUIRK_NO_BUSY_IRQ;
}
-static const TypeInfo imx_usdhc_info = {
- .name = TYPE_IMX_USDHC,
- .parent = TYPE_SYSBUS_SDHCI,
- .instance_init = imx_usdhc_init,
-};
-
/* --- qdev Samsung s3c --- */
#define S3C_SDHCI_CONTROL2 0x80
@@ -1946,18 +1951,31 @@ static void sdhci_s3c_init(Object *obj)
s->io_ops = &sdhci_s3c_mmio_ops;
}
-static const TypeInfo sdhci_s3c_info = {
- .name = TYPE_S3C_SDHCI ,
- .parent = TYPE_SYSBUS_SDHCI,
- .instance_init = sdhci_s3c_init,
+static const TypeInfo sdhci_types[] = {
+ {
+ .name = TYPE_SDHCI_BUS,
+ .parent = TYPE_SD_BUS,
+ .instance_size = sizeof(SDBus),
+ .class_init = sdhci_bus_class_init,
+ },
+ {
+ .name = TYPE_SYSBUS_SDHCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SDHCIState),
+ .instance_init = sdhci_sysbus_init,
+ .instance_finalize = sdhci_sysbus_finalize,
+ .class_init = sdhci_sysbus_class_init,
+ },
+ {
+ .name = TYPE_IMX_USDHC,
+ .parent = TYPE_SYSBUS_SDHCI,
+ .instance_init = imx_usdhc_init,
+ },
+ {
+ .name = TYPE_S3C_SDHCI,
+ .parent = TYPE_SYSBUS_SDHCI,
+ .instance_init = sdhci_s3c_init,
+ },
};
-static void sdhci_register_types(void)
-{
- type_register_static(&sdhci_sysbus_info);
- type_register_static(&sdhci_bus_info);
- type_register_static(&imx_usdhc_info);
- type_register_static(&sdhci_s3c_info);
-}
-
-type_init(sdhci_register_types)
+DEFINE_TYPES(sdhci_types)
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 2dd070f..6c90a86 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -16,7 +16,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "hw/ssi/ssi.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
@@ -389,7 +389,7 @@ static void ssi_sd_reset(DeviceState *dev)
s->stopping = 0;
}
-static void ssi_sd_class_init(ObjectClass *klass, void *data)
+static void ssi_sd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
@@ -398,7 +398,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data)
k->transfer = ssi_sd_transfer;
k->cs_polarity = SSI_CS_LOW;
dc->vmsd = &vmstate_ssi_sd;
- dc->reset = ssi_sd_reset;
+ device_class_set_legacy_reset(dc, ssi_sd_reset);
/* Reason: GPIO chip-select line should be wired up */
dc->user_creatable = false;
}
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index 43671dc..db06442 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -60,10 +60,6 @@ sdcard_set_voltage(uint16_t millivolts) "%u mV"
sdcard_ext_csd_update(unsigned index, uint8_t oval, uint8_t nval) "index %u: 0x%02x -> 0x%02x"
sdcard_switch(unsigned access, unsigned index, unsigned value, unsigned set) "SWITCH acc:%u idx:%u val:%u set:%u"
-# pxa2xx_mmci.c
-pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
-pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
-
# pl181.c
pl181_command_send(uint8_t cmd, uint32_t arg) "sending CMD%02d arg 0x%08" PRIx32
pl181_command_sent(void) "command sent"
diff --git a/hw/sensor/adm1266.c b/hw/sensor/adm1266.c
index 25b87a7..9017ce6 100644
--- a/hw/sensor/adm1266.c
+++ b/hw/sensor/adm1266.c
@@ -223,7 +223,7 @@ static void adm1266_init(Object *obj)
}
}
-static void adm1266_class_init(ObjectClass *klass, void *data)
+static void adm1266_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/sensor/adm1272.c b/hw/sensor/adm1272.c
index 3fc1e5d..0c739aa 100644
--- a/hw/sensor/adm1272.c
+++ b/hw/sensor/adm1272.c
@@ -511,7 +511,7 @@ static void adm1272_init(Object *obj)
}
-static void adm1272_class_init(ObjectClass *klass, void *data)
+static void adm1272_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/sensor/dps310.c b/hw/sensor/dps310.c
index 01c776d..bcf6154 100644
--- a/hw/sensor/dps310.c
+++ b/hw/sensor/dps310.c
@@ -197,7 +197,7 @@ static const VMStateDescription vmstate_dps310 = {
}
};
-static void dps310_class_init(ObjectClass *klass, void *data)
+static void dps310_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -205,7 +205,7 @@ static void dps310_class_init(ObjectClass *klass, void *data)
k->event = dps310_event;
k->recv = dps310_rx;
k->send = dps310_tx;
- dc->reset = dps310_reset;
+ device_class_set_legacy_reset(dc, dps310_reset);
dc->vmsd = &vmstate_dps310;
}
diff --git a/hw/sensor/emc141x.c b/hw/sensor/emc141x.c
index 9507955..7b2ce38 100644
--- a/hw/sensor/emc141x.c
+++ b/hw/sensor/emc141x.c
@@ -265,19 +265,19 @@ static void emc141x_initfn(Object *obj)
emc141x_set_temperature, NULL, NULL);
}
-static void emc141x_class_init(ObjectClass *klass, void *data)
+static void emc141x_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- dc->reset = emc141x_reset;
+ device_class_set_legacy_reset(dc, emc141x_reset);
k->event = emc141x_event;
k->recv = emc141x_rx;
k->send = emc141x_tx;
dc->vmsd = &vmstate_emc141x;
}
-static void emc1413_class_init(ObjectClass *klass, void *data)
+static void emc1413_class_init(ObjectClass *klass, const void *data)
{
EMC141XClass *ec = EMC141X_CLASS(klass);
@@ -286,7 +286,7 @@ static void emc1413_class_init(ObjectClass *klass, void *data)
ec->sensors_count = 3;
}
-static void emc1414_class_init(ObjectClass *klass, void *data)
+static void emc1414_class_init(ObjectClass *klass, const void *data)
{
EMC141XClass *ec = EMC141X_CLASS(klass);
diff --git a/hw/sensor/isl_pmbus_vr.c b/hw/sensor/isl_pmbus_vr.c
index 304a66e..e8d29b0 100644
--- a/hw/sensor/isl_pmbus_vr.c
+++ b/hw/sensor/isl_pmbus_vr.c
@@ -233,7 +233,7 @@ static void raa228000_init(Object *obj)
isl_pmbus_vr_add_props(obj, flags, 1);
}
-static void isl_pmbus_vr_class_init(ObjectClass *klass, void *data,
+static void isl_pmbus_vr_class_init(ObjectClass *klass, const void *data,
uint8_t pages)
{
PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
@@ -242,7 +242,7 @@ static void isl_pmbus_vr_class_init(ObjectClass *klass, void *data,
k->device_num_pages = pages;
}
-static void isl69260_class_init(ObjectClass *klass, void *data)
+static void isl69260_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -251,7 +251,7 @@ static void isl69260_class_init(ObjectClass *klass, void *data)
isl_pmbus_vr_class_init(klass, data, 2);
}
-static void raa228000_class_init(ObjectClass *klass, void *data)
+static void raa228000_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -260,7 +260,7 @@ static void raa228000_class_init(ObjectClass *klass, void *data)
isl_pmbus_vr_class_init(klass, data, 1);
}
-static void raa229004_class_init(ObjectClass *klass, void *data)
+static void raa229004_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -269,7 +269,7 @@ static void raa229004_class_init(ObjectClass *klass, void *data)
isl_pmbus_vr_class_init(klass, data, 2);
}
-static void isl69259_class_init(ObjectClass *klass, void *data)
+static void isl69259_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c
index 343ff98..f9e501d 100644
--- a/hw/sensor/lsm303dlhc_mag.c
+++ b/hw/sensor/lsm303dlhc_mag.c
@@ -530,12 +530,12 @@ static void lsm303dlhc_mag_initfn(Object *obj)
/*
* Set the virtual method pointers (bus state change, tx/rx, etc.).
*/
-static void lsm303dlhc_mag_class_init(ObjectClass *klass, void *data)
+static void lsm303dlhc_mag_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- dc->reset = lsm303dlhc_mag_reset;
+ device_class_set_legacy_reset(dc, lsm303dlhc_mag_reset);
dc->vmsd = &vmstate_lsm303dlhc_mag;
k->event = lsm303dlhc_mag_event;
k->recv = lsm303dlhc_mag_recv;
diff --git a/hw/sensor/max31785.c b/hw/sensor/max31785.c
index 3577a7c..c755814 100644
--- a/hw/sensor/max31785.c
+++ b/hw/sensor/max31785.c
@@ -544,7 +544,7 @@ static void max31785_init(Object *obj)
}
}
-static void max31785_class_init(ObjectClass *klass, void *data)
+static void max31785_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/sensor/max34451.c b/hw/sensor/max34451.c
index 93b53f3..a369d2b 100644
--- a/hw/sensor/max34451.c
+++ b/hw/sensor/max34451.c
@@ -746,7 +746,7 @@ static void max34451_init(Object *obj)
}
-static void max34451_class_init(ObjectClass *klass, void *data)
+static void max34451_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/sensor/tmp105.c b/hw/sensor/tmp105.c
index a8730d0..f5b6110 100644
--- a/hw/sensor/tmp105.c
+++ b/hw/sensor/tmp105.c
@@ -26,22 +26,28 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/module.h"
+#include "hw/registerfields.h"
+#include "trace.h"
+
+FIELD(CONFIG, SHUTDOWN_MODE, 0, 1)
+FIELD(CONFIG, THERMOSTAT_MODE, 1, 1)
+FIELD(CONFIG, POLARITY, 2, 1)
+FIELD(CONFIG, FAULT_QUEUE, 3, 2)
+FIELD(CONFIG, CONVERTER_RESOLUTION, 5, 2)
+FIELD(CONFIG, ONE_SHOT, 7, 1)
static void tmp105_interrupt_update(TMP105State *s)
{
- qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */
+ qemu_set_irq(s->pin, s->alarm ^ FIELD_EX8(~s->config, CONFIG, POLARITY));
}
-static void tmp105_alarm_update(TMP105State *s)
+static void tmp105_alarm_update(TMP105State *s, bool one_shot)
{
- if ((s->config >> 0) & 1) { /* SD */
- if ((s->config >> 7) & 1) /* OS */
- s->config &= ~(1 << 7); /* OS */
- else
- return;
+ if (FIELD_EX8(s->config, CONFIG, SHUTDOWN_MODE) && !one_shot) {
+ return;
}
- if (s->config >> 1 & 1) {
+ if (FIELD_EX8(s->config, CONFIG, THERMOSTAT_MODE)) {
/*
* TM == 1 : Interrupt mode. We signal Alert when the
* temperature rises above T_high, and expect the guest to clear
@@ -89,7 +95,8 @@ static void tmp105_get_temperature(Object *obj, Visitor *v, const char *name,
visit_type_int(v, name, &value, errp);
}
-/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
+/*
+ * Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
* fixed point, so units are 1/256 centigrades. A simple ratio will do.
*/
static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
@@ -109,7 +116,7 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
s->temperature = (int16_t) (temp * 256 / 1000);
- tmp105_alarm_update(s);
+ tmp105_alarm_update(s, false);
}
static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
@@ -118,54 +125,60 @@ static void tmp105_read(TMP105State *s)
{
s->len = 0;
- if ((s->config >> 1) & 1) { /* TM */
+ if (FIELD_EX8(s->config, CONFIG, THERMOSTAT_MODE)) {
s->alarm = 0;
tmp105_interrupt_update(s);
}
switch (s->pointer & 3) {
case TMP105_REG_TEMPERATURE:
- s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
- s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
- (0xf0 << ((~s->config >> 5) & 3)); /* R */
+ s->buf[s->len++] = (((uint16_t) s->temperature) >> 8);
+ s->buf[s->len++] = (((uint16_t) s->temperature) >> 0) &
+ (0xf0 << (FIELD_EX8(~s->config, CONFIG, CONVERTER_RESOLUTION)));
break;
case TMP105_REG_CONFIG:
- s->buf[s->len ++] = s->config;
+ s->buf[s->len++] = s->config;
break;
case TMP105_REG_T_LOW:
- s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
- s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
+ s->buf[s->len++] = ((uint16_t) s->limit[0]) >> 8;
+ s->buf[s->len++] = ((uint16_t) s->limit[0]) >> 0;
break;
case TMP105_REG_T_HIGH:
- s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
- s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
+ s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 8;
+ s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 0;
break;
}
+
+ trace_tmp105_read(s->i2c.address, s->pointer);
}
static void tmp105_write(TMP105State *s)
{
+ trace_tmp105_write(s->i2c.address, s->pointer);
+
switch (s->pointer & 3) {
case TMP105_REG_TEMPERATURE:
break;
case TMP105_REG_CONFIG:
- if (s->buf[0] & ~s->config & (1 << 0)) /* SD */
- printf("%s: TMP105 shutdown\n", __func__);
- s->config = s->buf[0];
- s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
- tmp105_alarm_update(s);
+ if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) {
+ trace_tmp105_write_shutdown(s->i2c.address);
+ }
+ s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0);
+ s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
+ tmp105_alarm_update(s, FIELD_EX8(s->buf[0], CONFIG, ONE_SHOT));
break;
case TMP105_REG_T_LOW:
case TMP105_REG_T_HIGH:
- if (s->len >= 3)
+ if (s->len >= 3) {
s->limit[s->pointer & 1] = (int16_t)
- ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
- tmp105_alarm_update(s);
+ ((((uint16_t) s->buf[0]) << 8) | (s->buf[1] & 0xf0));
+ }
+ tmp105_alarm_update(s, false);
break;
}
}
@@ -175,7 +188,7 @@ static uint8_t tmp105_rx(I2CSlave *i2c)
TMP105State *s = TMP105(i2c);
if (s->len < 2) {
- return s->buf[s->len ++];
+ return s->buf[s->len++];
} else {
return 0xff;
}
@@ -215,7 +228,7 @@ static int tmp105_post_load(void *opaque, int version_id)
{
TMP105State *s = opaque;
- s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
+ s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
tmp105_interrupt_update(s);
return 0;
@@ -273,7 +286,7 @@ static void tmp105_reset(I2CSlave *i2c)
s->temperature = 0;
s->pointer = 0;
s->config = 0;
- s->faults = tmp105_faultq[(s->config >> 3) & 3];
+ s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
s->alarm = 0;
s->detect_falling = false;
@@ -300,7 +313,7 @@ static void tmp105_initfn(Object *obj)
tmp105_set_temperature, NULL, NULL);
}
-static void tmp105_class_init(ObjectClass *klass, void *data)
+static void tmp105_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
diff --git a/hw/sensor/tmp421.c b/hw/sensor/tmp421.c
index b6f0b62..3421c44 100644
--- a/hw/sensor/tmp421.c
+++ b/hw/sensor/tmp421.c
@@ -68,7 +68,7 @@ struct TMP421State {
struct TMP421Class {
I2CSlaveClass parent_class;
- DeviceInfo *dev;
+ const DeviceInfo *dev;
};
#define TYPE_TMP421 "tmp421-generic"
@@ -337,7 +337,7 @@ static void tmp421_realize(DeviceState *dev, Error **errp)
tmp421_reset(&s->i2c);
}
-static void tmp421_class_init(ObjectClass *klass, void *data)
+static void tmp421_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
@@ -382,9 +382,9 @@ static void tmp421_register_types(void)
.name = devices[i].name,
.parent = TYPE_TMP421,
.class_init = tmp421_class_init,
- .class_data = (void *) &devices[i],
+ .class_data = &devices[i],
};
- type_register(&ti);
+ type_register_static(&ti);
}
}
diff --git a/hw/sensor/trace-events b/hw/sensor/trace-events
new file mode 100644
index 0000000..a3fe54f
--- /dev/null
+++ b/hw/sensor/trace-events
@@ -0,0 +1,6 @@
+# See docs/devel/tracing.rst for syntax documentation.
+
+# tmp105.c
+tmp105_read(uint8_t dev, uint8_t addr) "device: 0x%02x, addr: 0x%02x"
+tmp105_write(uint8_t dev, uint8_t addr) "device: 0x%02x, addr 0x%02x"
+tmp105_write_shutdown(uint8_t dev) "device: 0x%02x"
diff --git a/hw/sensor/trace.h b/hw/sensor/trace.h
new file mode 100644
index 0000000..e472156
--- /dev/null
+++ b/hw/sensor/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-hw_sensor.h"
diff --git a/hw/sh4/Kconfig b/hw/sh4/Kconfig
index 99a76a9..1660d29 100644
--- a/hw/sh4/Kconfig
+++ b/hw/sh4/Kconfig
@@ -13,13 +13,6 @@ config R2D
select SH7750
select SH_PCI
-config SHIX
- bool
- default y
- depends on SH4
- select SH7750
- select TC58128
-
config SH7750
bool
select SH_INTC
diff --git a/hw/sh4/meson.build b/hw/sh4/meson.build
index 70e814c..7d27839 100644
--- a/hw/sh4/meson.build
+++ b/hw/sh4/meson.build
@@ -4,6 +4,5 @@ sh4_ss.add(when: 'CONFIG_SH7750', if_true: files(
'sh7750_regnames.c',
))
sh4_ss.add(when: 'CONFIG_R2D', if_true: files('r2d.c'))
-sh4_ss.add(when: 'CONFIG_SHIX', if_true: files('shix.c'))
hw_arch += {'sh4': sh4_ss}
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index e5ac675..d68c94e 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -30,9 +30,9 @@
#include "cpu.h"
#include "hw/sysbus.h"
#include "hw/sh4/sh.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
@@ -43,6 +43,7 @@
#include "hw/loader.h"
#include "hw/usb.h"
#include "hw/block/flash.h"
+#include "exec/tswap.h"
#define FLASH_BASE 0x00000000
#define FLASH_SIZE (16 * MiB)
@@ -62,6 +63,12 @@
#define PA_VERREG 0x32
#define PA_OUTPORT 0x36
+enum r2d_fpga_irq {
+ PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
+ SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
+ NR_IRQS
+};
+
typedef struct {
uint16_t bcr;
uint16_t irlmsk;
@@ -87,15 +94,10 @@ typedef struct {
/* output pin */
qemu_irq irl;
+ IRQState irq[NR_IRQS];
MemoryRegion iomem;
} r2d_fpga_t;
-enum r2d_fpga_irq {
- PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
- SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
- NR_IRQS
-};
-
static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
[CF_IDE] = { 1, 1 << 9 },
[CF_CD] = { 2, 1 << 8 },
@@ -185,8 +187,8 @@ static const MemoryRegionOps r2d_fpga_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem,
- hwaddr base, qemu_irq irl)
+static r2d_fpga_t *r2d_fpga_init(MemoryRegion *sysmem,
+ hwaddr base, qemu_irq irl)
{
r2d_fpga_t *s;
@@ -196,7 +198,10 @@ static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem,
memory_region_init_io(&s->iomem, NULL, &r2d_fpga_ops, s, "r2d-fpga", 0x40);
memory_region_add_subregion(sysmem, base, &s->iomem);
- return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
+
+ qemu_init_irqs(s->irq, NR_IRQS, r2d_fpga_irq_set, s);
+
+ return s;
}
typedef struct ResetData {
@@ -238,13 +243,13 @@ static void r2d_init(MachineState *machine)
ResetData *reset_info;
struct SH7750State *s;
MemoryRegion *sdram = g_new(MemoryRegion, 1);
- qemu_irq *irq;
DriveInfo *dinfo;
DeviceState *dev;
SysBusDevice *busdev;
MemoryRegion *address_space_mem = get_system_memory();
PCIBus *pci_bus;
USBBus *usb_bus;
+ r2d_fpga_t *fpga;
cpu = SUPERH_CPU(cpu_create(machine->cpu_type));
env = &cpu->env;
@@ -259,7 +264,7 @@ static void r2d_init(MachineState *machine)
memory_region_add_subregion(address_space_mem, SDRAM_BASE, sdram);
/* Register peripherals */
s = sh7750_init(cpu, address_space_mem);
- irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s));
+ fpga = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s));
dev = qdev_new("sh_pci");
busdev = SYS_BUS_DEVICE(dev);
@@ -267,10 +272,10 @@ static void r2d_init(MachineState *machine)
pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci"));
sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000));
sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000));
- sysbus_connect_irq(busdev, 0, irq[PCI_INTA]);
- sysbus_connect_irq(busdev, 1, irq[PCI_INTB]);
- sysbus_connect_irq(busdev, 2, irq[PCI_INTC]);
- sysbus_connect_irq(busdev, 3, irq[PCI_INTD]);
+ sysbus_connect_irq(busdev, 0, &fpga->irq[PCI_INTA]);
+ sysbus_connect_irq(busdev, 1, &fpga->irq[PCI_INTB]);
+ sysbus_connect_irq(busdev, 2, &fpga->irq[PCI_INTC]);
+ sysbus_connect_irq(busdev, 3, &fpga->irq[PCI_INTD]);
dev = qdev_new("sysbus-sm501");
busdev = SYS_BUS_DEVICE(dev);
@@ -280,15 +285,15 @@ static void r2d_init(MachineState *machine)
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, 0x10000000);
sysbus_mmio_map(busdev, 1, 0x13e00000);
- sysbus_connect_irq(busdev, 0, irq[SM501]);
+ sysbus_connect_irq(busdev, 0, &fpga->irq[SM501]);
/* onboard CF (True IDE mode, Master only). */
dinfo = drive_get(IF_IDE, 0, 0);
dev = qdev_new("mmio-ide");
busdev = SYS_BUS_DEVICE(dev);
+ sysbus_connect_irq(busdev, 0, &fpga->irq[CF_IDE]);
qdev_prop_set_uint32(dev, "shift", 1);
sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0, irq[CF_IDE]);
sysbus_mmio_map(busdev, 0, 0x14001000);
sysbus_mmio_map(busdev, 1, 0x1400080c);
mmio_ide_init_drives(dev, dinfo, NULL);
diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c
index ebe0fd9..300eabc 100644
--- a/hw/sh4/sh7750.c
+++ b/hw/sh4/sh7750.c
@@ -28,18 +28,17 @@
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/sh4/sh.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
+#include "target/sh4/cpu.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "sh7750_regs.h"
#include "sh7750_regnames.h"
#include "hw/sh4/sh_intc.h"
#include "hw/timer/tmu012.h"
-#include "exec/exec-all.h"
+#include "exec/cputlb.h"
#include "trace.h"
-#define NB_DEVICES 4
-
typedef struct SH7750State {
MemoryRegion iomem;
MemoryRegion iomem_1f0;
@@ -75,7 +74,6 @@ typedef struct SH7750State {
uint16_t periph_portdira; /* Direction seen from the peripherals */
uint16_t periph_pdtrb; /* Imposed by the peripherals */
uint16_t periph_portdirb; /* Direction seen from the peripherals */
- sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */
/* Cache */
uint32_t ccr;
@@ -92,19 +90,6 @@ static inline int has_bcr3_and_bcr4(SH7750State *s)
* I/O ports
*/
-int sh7750_register_io_device(SH7750State *s, sh7750_io_device *device)
-{
- int i;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] == NULL) {
- s->devices[i] = device;
- return 0;
- }
- }
- return -1;
-}
-
static uint16_t portdir(uint32_t v)
{
#define EVENPORTMASK(n) ((v & (1 << ((n) << 1))) >> (n))
@@ -142,63 +127,26 @@ static uint16_t portb_lines(SH7750State *s)
(~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */
}
-static void gen_port_interrupts(SH7750State *s)
-{
- /* XXXXX interrupts not generated */
-}
-
static void porta_changed(SH7750State *s, uint16_t prev)
{
- uint16_t currenta, changes;
- int i, r = 0;
+ uint16_t currenta;
currenta = porta_lines(s);
if (currenta == prev) {
return;
}
trace_sh7750_porta(prev, currenta, s->pdtra, s->pctra);
- changes = currenta ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(currenta, portb_lines(s),
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r) {
- gen_port_interrupts(s);
- }
}
static void portb_changed(SH7750State *s, uint16_t prev)
{
- uint16_t currentb, changes;
- int i, r = 0;
+ uint16_t currentb;
currentb = portb_lines(s);
if (currentb == prev) {
return;
}
trace_sh7750_portb(prev, currentb, s->pdtrb, s->pctrb);
- changes = currentb ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(portb_lines(s), currentb,
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r) {
- gen_port_interrupts(s);
- }
}
/*
diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c
deleted file mode 100644
index eb3150b..0000000
--- a/hw/sh4/shix.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SHIX 2.0 board description
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-/*
- * Shix 2.0 board by Alexis Polti, described at
- * https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20
- *
- * More information in target/sh4/README.sh4
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "hw/sh4/sh.h"
-#include "sysemu/qtest.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "qemu/error-report.h"
-
-#define BIOS_FILENAME "shix_bios.bin"
-#define BIOS_ADDRESS 0xA0000000
-
-static void shix_init(MachineState *machine)
-{
- int ret;
- SuperHCPU *cpu;
- struct SH7750State *s;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- MemoryRegion *sdram = g_new(MemoryRegion, 2);
- const char *bios_name = machine->firmware ?: BIOS_FILENAME;
-
- cpu = SUPERH_CPU(cpu_create(machine->cpu_type));
-
- /* Allocate memory space */
- memory_region_init_rom(rom, NULL, "shix.rom", 0x4000, &error_fatal);
- memory_region_add_subregion(sysmem, 0x00000000, rom);
- memory_region_init_ram(&sdram[0], NULL, "shix.sdram1", 0x01000000,
- &error_fatal);
- memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]);
- memory_region_init_ram(&sdram[1], NULL, "shix.sdram2", 0x01000000,
- &error_fatal);
- memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]);
-
- /* Load BIOS in 0 (and access it through P2, 0xA0000000) */
- ret = load_image_targphys(bios_name, 0, 0x4000);
- if (ret < 0 && !qtest_enabled()) {
- error_report("Could not load SHIX bios '%s'", bios_name);
- exit(1);
- }
-
- /* Register peripherals */
- s = sh7750_init(cpu, sysmem);
- /* XXXXX Check success */
- tc58128_init(s, "shix_linux_nand.bin", NULL);
-}
-
-static void shix_machine_init(MachineClass *mc)
-{
- mc->desc = "shix card";
- mc->init = shix_init;
- mc->is_default = true;
- mc->default_cpu_type = TYPE_SH7750R_CPU;
- mc->deprecation_reason = "old and unmaintained";
-}
-
-DEFINE_MACHINE("shix", shix_machine_init)
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index a394514..ad4cd67 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -21,7 +21,7 @@
#include "qemu/config-file.h"
#include "qemu/module.h"
#include "qemu/option.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/uuid.h"
#include "hw/firmware/smbios.h"
#include "hw/loader.h"
@@ -1285,6 +1285,9 @@ static int save_opt_one(void *opaque,
g_byte_array_append(data, (guint8 *)buf, ret);
}
+ buf[0] = '\0';
+ g_byte_array_append(data, (guint8 *)buf, 1);
+
qemu_close(fd);
*opt->dest = g_renew(char *, *opt->dest, (*opt->ndest) + 1);
diff --git a/hw/smbios/smbios_legacy.c b/hw/smbios/smbios_legacy.c
index c37a8ee..14319d4 100644
--- a/hw/smbios/smbios_legacy.c
+++ b/hw/smbios/smbios_legacy.c
@@ -18,7 +18,7 @@
#include "qemu/osdep.h"
#include "qemu/bswap.h"
#include "hw/firmware/smbios.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qapi/error.h"
struct smbios_header {
diff --git a/hw/smbios/smbios_type_38.c b/hw/smbios/smbios_type_38.c
index 168b886..e9b856f 100644
--- a/hw/smbios/smbios_type_38.c
+++ b/hw/smbios/smbios_type_38.c
@@ -72,7 +72,12 @@ static void smbios_build_one_type_38(IPMIFwInfo *info)
" SMBIOS, ignoring this entry.", info->register_spacing);
return;
}
- t->interrupt_number = info->interrupt_number;
+ if (info->irq_source == IPMI_ISA_IRQ) {
+ t->interrupt_number = info->interrupt_number;
+ } else {
+ /* TODO: How to handle PCI? */
+ t->interrupt_number = 0;
+ }
SMBIOS_BUILD_TABLE_POST;
}
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index 6aaa04c..0aeaad3 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -34,9 +34,9 @@
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
+#include "system/system.h"
+#include "system/qtest.h"
+#include "system/reset.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "elf.h"
@@ -380,7 +380,7 @@ static void leon3_generic_hw_init(MachineState *machine)
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
&entry, NULL, NULL, NULL,
- 1 /* big endian */, EM_SPARC, 0, 0);
+ ELFDATA2MSB, EM_SPARC, 0, 0);
if (kernel_size < 0) {
kernel_size = load_uimage(kernel_filename, NULL, &entry,
NULL, NULL, NULL);
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index d52e6a7..8ac7e62 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -27,6 +27,7 @@
#include "qapi/error.h"
#include "qemu/datadir.h"
#include "cpu.h"
+#include "exec/target_page.h"
#include "hw/sysbus.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
@@ -35,9 +36,9 @@
#include "migration/vmstate.h"
#include "hw/sparc/sparc32_dma.h"
#include "hw/block/fdc.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "net/net.h"
#include "hw/boards.h"
#include "hw/scsi/esp.h"
@@ -233,19 +234,13 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
kernel_size = 0;
if (linux_boot) {
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
kernel_size = load_elf(kernel_filename, NULL,
translate_kernel_address, NULL,
- NULL, NULL, NULL, NULL, 1, EM_SPARC, 0, 0);
+ NULL, NULL, NULL, NULL,
+ ELFDATA2MSB, EM_SPARC, 0, 0);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+ RAM_size - KERNEL_LOAD_ADDR, true,
TARGET_PAGE_SIZE);
if (kernel_size < 0)
kernel_size = load_image_targphys(kernel_filename,
@@ -600,7 +595,7 @@ static void idreg_realize(DeviceState *ds, Error **errp)
sysbus_init_mmio(dev, &s->mem);
}
-static void idreg_class_init(ObjectClass *oc, void *data)
+static void idreg_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -650,7 +645,7 @@ static void afx_realize(DeviceState *ds, Error **errp)
sysbus_init_mmio(dev, &s->mem);
}
-static void afx_class_init(ObjectClass *oc, void *data)
+static void afx_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -703,7 +698,7 @@ static void prom_init(hwaddr addr, const char *bios_name)
if (filename) {
ret = load_elf(filename, NULL,
translate_prom_address, &addr, NULL,
- NULL, NULL, NULL, 1, EM_SPARC, 0, 0);
+ NULL, NULL, NULL, ELFDATA2MSB, EM_SPARC, 0, 0);
if (ret < 0 || ret > PROM_SIZE_MAX) {
ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
}
@@ -732,15 +727,10 @@ static void prom_realize(DeviceState *ds, Error **errp)
sysbus_init_mmio(dev, &s->prom);
}
-static Property prom_properties[] = {
- {/* end of property list */},
-};
-
-static void prom_class_init(ObjectClass *klass, void *data)
+static void prom_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- device_class_set_props(dc, prom_properties);
dc->realize = prom_realize;
}
@@ -781,7 +771,7 @@ static void ram_initfn(Object *obj)
"Valid value is ID of a hostmem backend");
}
-static void ram_class_init(ObjectClass *klass, void *data)
+static void ram_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -979,7 +969,7 @@ static void sun4m_hw_init(MachineState *machine)
sysbus_mmio_map(s, 0, hwdef->ms_kb_base);
/* Logically OR both its IRQs together */
- ms_kb_orgate = DEVICE(object_new(TYPE_OR_IRQ));
+ ms_kb_orgate = qdev_new(TYPE_OR_IRQ);
object_property_set_int(OBJECT(ms_kb_orgate), "num-lines", 2, &error_fatal);
qdev_realize_and_unref(ms_kb_orgate, NULL, &error_fatal);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(ms_kb_orgate, 0));
@@ -1000,7 +990,7 @@ static void sun4m_hw_init(MachineState *machine)
sysbus_mmio_map(s, 0, hwdef->serial_base);
/* Logically OR both its IRQs together */
- serial_orgate = DEVICE(object_new(TYPE_OR_IRQ));
+ serial_orgate = qdev_new(TYPE_OR_IRQ);
object_property_set_int(OBJECT(serial_orgate), "num-lines", 2,
&error_fatal);
qdev_realize_and_unref(serial_orgate, NULL, &error_fatal);
@@ -1108,7 +1098,7 @@ enum {
ss600mp_id,
};
-static void sun4m_machine_class_init(ObjectClass *oc, void *data)
+static void sun4m_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1119,7 +1109,7 @@ static void sun4m_machine_class_init(ObjectClass *oc, void *data)
mc->default_ram_id = "sun4m.ram";
}
-static void ss5_class_init(ObjectClass *oc, void *data)
+static void ss5_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1156,7 +1146,7 @@ static void ss5_class_init(ObjectClass *oc, void *data)
smc->hwdef = &ss5_hwdef;
}
-static void ss10_class_init(ObjectClass *oc, void *data)
+static void ss10_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1191,7 +1181,7 @@ static void ss10_class_init(ObjectClass *oc, void *data)
smc->hwdef = &ss10_hwdef;
}
-static void ss600mp_class_init(ObjectClass *oc, void *data)
+static void ss600mp_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1224,7 +1214,7 @@ static void ss600mp_class_init(ObjectClass *oc, void *data)
smc->hwdef = &ss600mp_hwdef;
}
-static void ss20_class_init(ObjectClass *oc, void *data)
+static void ss20_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1275,7 +1265,7 @@ static void ss20_class_init(ObjectClass *oc, void *data)
smc->hwdef = &ss20_hwdef;
}
-static void voyager_class_init(ObjectClass *oc, void *data)
+static void voyager_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1307,7 +1297,7 @@ static void voyager_class_init(ObjectClass *oc, void *data)
smc->hwdef = &voyager_hwdef;
}
-static void ss_lx_class_init(ObjectClass *oc, void *data)
+static void ss_lx_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1340,7 +1330,7 @@ static void ss_lx_class_init(ObjectClass *oc, void *data)
smc->hwdef = &ss_lx_hwdef;
}
-static void ss4_class_init(ObjectClass *oc, void *data)
+static void ss4_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1373,7 +1363,7 @@ static void ss4_class_init(ObjectClass *oc, void *data)
smc->hwdef = &ss4_hwdef;
}
-static void scls_class_init(ObjectClass *oc, void *data)
+static void scls_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
@@ -1405,7 +1395,7 @@ static void scls_class_init(ObjectClass *oc, void *data)
smc->hwdef = &scls_hwdef;
}
-static void sbook_class_init(ObjectClass *oc, void *data)
+static void sbook_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc);
diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c
index 06703b1..a7ff36e 100644
--- a/hw/sparc/sun4m_iommu.c
+++ b/hw/sparc/sun4m_iommu.c
@@ -29,7 +29,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "trace.h"
/*
@@ -238,7 +238,7 @@ static void iommu_mem_write(void *opaque, hwaddr addr,
static const MemoryRegionOps iommu_mem_ops = {
.read = iommu_mem_read,
.write = iommu_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -368,16 +368,15 @@ static void iommu_init(Object *obj)
sysbus_init_mmio(dev, &s->iomem);
}
-static Property iommu_properties[] = {
+static const Property iommu_properties[] = {
DEFINE_PROP_UINT32("version", IOMMUState, version, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void iommu_class_init(ObjectClass *klass, void *data)
+static void iommu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = iommu_reset;
+ device_class_set_legacy_reset(dc, iommu_reset);
dc->vmsd = &vmstate_iommu;
device_class_set_props(dc, iommu_properties);
}
@@ -390,7 +389,8 @@ static const TypeInfo iommu_info = {
.class_init = iommu_class_init,
};
-static void sun4m_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+static void sun4m_iommu_memory_region_class_init(ObjectClass *klass,
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/sparc64/Kconfig b/hw/sparc64/Kconfig
index 3b948a2..f764c8a 100644
--- a/hw/sparc64/Kconfig
+++ b/hw/sparc64/Kconfig
@@ -10,6 +10,7 @@ config SUN4U
select ISA_BUS
select FDC_ISA
select SERIAL_ISA
+ select SERIAL_MM
select PCI_SABRE
select IDE_CMD646
select PCKBD
diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c
index ab3c4ec..1ffe920 100644
--- a/hw/sparc64/niagara.c
+++ b/hw/sparc64/niagara.c
@@ -27,15 +27,15 @@
#include "qemu/units.h"
#include "cpu.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/misc/unimp.h"
#include "hw/loader.h"
#include "hw/sparc/sparc64.h"
#include "hw/rtc/sun4v-rtc.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
-#include "sysemu/sysemu.h"
+#include "system/qtest.h"
+#include "system/system.h"
#include "qapi/error.h"
typedef struct NiagaraBoardState {
@@ -157,7 +157,7 @@ static void niagara_init(MachineState *machine)
sun4v_rtc_init(NIAGARA_RTC_BASE);
}
-static void niagara_class_init(ObjectClass *oc, void *data)
+static void niagara_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/sparc64/sparc64.c b/hw/sparc64/sparc64.c
index 3091cde..9cffc92 100644
--- a/hw/sparc64/sparc64.c
+++ b/hw/sparc64/sparc64.c
@@ -29,7 +29,7 @@
#include "hw/boards.h"
#include "hw/sparc/sparc64.h"
#include "qemu/timer.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "trace.h"
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 4ece1ac..e9f9b0a 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -28,13 +28,15 @@
#include "qapi/error.h"
#include "qemu/datadir.h"
#include "cpu.h"
+#include "exec/target_page.h"
#include "hw/irq.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
#include "hw/qdev-properties.h"
#include "hw/pci-host/sabre.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
+#include "hw/char/serial-mm.h"
#include "hw/char/parallel-isa.h"
#include "hw/rtc/m48t59.h"
#include "migration/vmstate.h"
@@ -42,8 +44,8 @@
#include "hw/block/fdc.h"
#include "net/net.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/nvram/sun_nvram.h"
#include "hw/nvram/chrp_nvram.h"
@@ -167,21 +169,14 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
kernel_size = 0;
if (linux_boot) {
- int bswap_needed;
-
-#ifdef BSWAP_NEEDED
- bswap_needed = 1;
-#else
- bswap_needed = 0;
-#endif
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, kernel_entry,
- kernel_addr, &kernel_top, NULL, 1, EM_SPARCV9, 0,
- 0);
+ kernel_addr, &kernel_top, NULL,
+ ELFDATA2MSB, EM_SPARCV9, 0, 0);
if (kernel_size < 0) {
*kernel_addr = KERNEL_LOAD_ADDR;
*kernel_entry = KERNEL_LOAD_ADDR;
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+ RAM_size - KERNEL_LOAD_ADDR, true,
TARGET_PAGE_SIZE);
}
if (kernel_size < 0) {
@@ -253,7 +248,7 @@ static void power_mem_write(void *opaque, hwaddr addr,
static const MemoryRegionOps power_mem_ops = {
.read = power_mem_read,
.write = power_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -271,7 +266,7 @@ static void power_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &d->power_mmio);
}
-static void power_class_init(ObjectClass *klass, void *data)
+static void power_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -373,13 +368,12 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp)
pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
}
-static Property ebus_properties[] = {
+static const Property ebus_properties[] = {
DEFINE_PROP_UINT64("console-serial-base", EbusState,
console_serial_base, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ebus_class_init(ObjectClass *klass, void *data)
+static void ebus_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -397,7 +391,7 @@ static const TypeInfo ebus_info = {
.parent = TYPE_PCI_DEVICE,
.class_init = ebus_class_init,
.instance_size = sizeof(EbusState),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -441,7 +435,7 @@ static void prom_init(hwaddr addr, const char *bios_name)
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
ret = load_elf(filename, NULL, translate_prom_address, &addr,
- NULL, NULL, NULL, NULL, 1, EM_SPARCV9, 0, 0);
+ NULL, NULL, NULL, NULL, ELFDATA2MSB, EM_SPARCV9, 0, 0);
if (ret < 0 || ret > PROM_SIZE_MAX) {
ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
}
@@ -470,15 +464,10 @@ static void prom_realize(DeviceState *ds, Error **errp)
sysbus_init_mmio(dev, &s->prom);
}
-static Property prom_properties[] = {
- {/* end of property list */},
-};
-
-static void prom_class_init(ObjectClass *klass, void *data)
+static void prom_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- device_class_set_props(dc, prom_properties);
dc->realize = prom_realize;
}
@@ -531,12 +520,11 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size)
sysbus_mmio_map(s, 0, addr);
}
-static Property ram_properties[] = {
+static const Property ram_properties[] = {
DEFINE_PROP_UINT64("size", RamDevice, size, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ram_class_init(ObjectClass *klass, void *data)
+static void ram_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -799,7 +787,7 @@ static GlobalProperty hw_compat_sparc64[] = {
};
static const size_t hw_compat_sparc64_len = G_N_ELEMENTS(hw_compat_sparc64);
-static void sun4u_class_init(ObjectClass *oc, void *data)
+static void sun4u_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
@@ -823,13 +811,13 @@ static const TypeInfo sun4u_type = {
.name = MACHINE_TYPE_NAME("sun4u"),
.parent = TYPE_MACHINE,
.class_init = sun4u_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
{ }
},
};
-static void sun4v_class_init(ObjectClass *oc, void *data)
+static void sun4v_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c
index 1c1dca7..14645f4 100644
--- a/hw/sparc64/sun4u_iommu.c
+++ b/hw/sparc64/sun4u_iommu.c
@@ -27,7 +27,7 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/sparc/sun4u_iommu.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
@@ -305,11 +305,11 @@ static void iommu_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void iommu_class_init(ObjectClass *klass, void *data)
+static void iommu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = iommu_reset;
+ device_class_set_legacy_reset(dc, iommu_reset);
}
static const TypeInfo iommu_info = {
@@ -320,7 +320,8 @@ static const TypeInfo iommu_info = {
.class_init = iommu_class_init,
};
-static void sun4u_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+static void sun4u_iommu_memory_region_class_init(ObjectClass *klass,
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig
index 8d180de..1bd5646 100644
--- a/hw/ssi/Kconfig
+++ b/hw/ssi/Kconfig
@@ -28,3 +28,7 @@ config BCM2835_SPI
config PNV_SPI
bool
select SSI
+
+config ALLWINNER_A10_SPI
+ bool
+ select SSI
diff --git a/hw/ssi/allwinner-a10-spi.c b/hw/ssi/allwinner-a10-spi.c
new file mode 100644
index 0000000..6b7cca8
--- /dev/null
+++ b/hw/ssi/allwinner-a10-spi.c
@@ -0,0 +1,561 @@
+/*
+ * Allwinner SPI Bus Serial Interface Emulation
+ *
+ * Copyright (C) 2024 Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/ssi/allwinner-a10-spi.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "trace.h"
+
+/* Allwinner SPI memory map */
+#define SPI_RXDATA_REG 0x00 /* receive data register */
+#define SPI_TXDATA_REG 0x04 /* transmit data register */
+#define SPI_CTL_REG 0x08 /* control register */
+#define SPI_INTCTL_REG 0x0c /* interrupt control register */
+#define SPI_INT_STA_REG 0x10 /* interrupt status register */
+#define SPI_DMACTL_REG 0x14 /* DMA control register */
+#define SPI_WAIT_REG 0x18 /* wait clock counter register */
+#define SPI_CCTL_REG 0x1c /* clock rate control register */
+#define SPI_BC_REG 0x20 /* burst control register */
+#define SPI_TC_REG 0x24 /* transmit counter register */
+#define SPI_FIFO_STA_REG 0x28 /* FIFO status register */
+
+/* Data register */
+#define SPI_DATA_RESET 0
+
+/* Control register */
+#define SPI_CTL_SDC (1 << 19)
+#define SPI_CTL_TP_EN (1 << 18)
+#define SPI_CTL_SS_LEVEL (1 << 17)
+#define SPI_CTL_SS_CTRL (1 << 16)
+#define SPI_CTL_DHB (1 << 15)
+#define SPI_CTL_DDB (1 << 14)
+#define SPI_CTL_SS (3 << 12)
+#define SPI_CTL_SS_SHIFT 12
+#define SPI_CTL_RPSM (1 << 11)
+#define SPI_CTL_XCH (1 << 10)
+#define SPI_CTL_RF_RST (1 << 9)
+#define SPI_CTL_TF_RST (1 << 8)
+#define SPI_CTL_SSCTL (1 << 7)
+#define SPI_CTL_LMTF (1 << 6)
+#define SPI_CTL_DMAMC (1 << 5)
+#define SPI_CTL_SSPOL (1 << 4)
+#define SPI_CTL_POL (1 << 3)
+#define SPI_CTL_PHA (1 << 2)
+#define SPI_CTL_MODE (1 << 1)
+#define SPI_CTL_EN (1 << 0)
+#define SPI_CTL_MASK 0xFFFFFu
+#define SPI_CTL_RESET 0x0002001Cu
+
+/* Interrupt control register */
+#define SPI_INTCTL_SS_INT_EN (1 << 17)
+#define SPI_INTCTL_TX_INT_EN (1 << 16)
+#define SPI_INTCTL_TF_UR_INT_EN (1 << 14)
+#define SPI_INTCTL_TF_OF_INT_EN (1 << 13)
+#define SPI_INTCTL_TF_E34_INT_EN (1 << 12)
+#define SPI_INTCTL_TF_E14_INT_EN (1 << 11)
+#define SPI_INTCTL_TF_FL_INT_EN (1 << 10)
+#define SPI_INTCTL_TF_HALF_EMP_INT_EN (1 << 9)
+#define SPI_INTCTL_TF_EMP_INT_EN (1 << 8)
+#define SPI_INTCTL_RF_UR_INT_EN (1 << 6)
+#define SPI_INTCTL_RF_OF_INT_EN (1 << 5)
+#define SPI_INTCTL_RF_E34_INT_EN (1 << 4)
+#define SPI_INTCTL_RF_E14_INT_EN (1 << 3)
+#define SPI_INTCTL_RF_FU_INT_EN (1 << 2)
+#define SPI_INTCTL_RF_HALF_FU_INT_EN (1 << 1)
+#define SPI_INTCTL_RF_RDY_INT_EN (1 << 0)
+#define SPI_INTCTL_MASK 0x37F7Fu
+#define SPI_INTCTL_RESET 0
+
+/* Interrupt status register */
+#define SPI_INT_STA_INT_CBF (1 << 31)
+#define SPI_INT_STA_SSI (1 << 17)
+#define SPI_INT_STA_TC (1 << 16)
+#define SPI_INT_STA_TU (1 << 14)
+#define SPI_INT_STA_TO (1 << 13)
+#define SPI_INT_STA_TE34 (1 << 12)
+#define SPI_INT_STA_TE14 (1 << 11)
+#define SPI_INT_STA_TF (1 << 10)
+#define SPI_INT_STA_THE (1 << 9)
+#define SPI_INT_STA_TE (1 << 8)
+#define SPI_INT_STA_RU (1 << 6)
+#define SPI_INT_STA_RO (1 << 5)
+#define SPI_INT_STA_RF34 (1 << 4)
+#define SPI_INT_STA_RF14 (1 << 3)
+#define SPI_INT_STA_RF (1 << 2)
+#define SPI_INT_STA_RHF (1 << 1)
+#define SPI_INT_STA_RR (1 << 0)
+#define SPI_INT_STA_MASK 0x80037F7Fu
+#define SPI_INT_STA_RESET 0x00001B00u
+
+/* DMA control register - not implemented */
+#define SPI_DMACTL_RESET 0
+
+/* Wait clock register */
+#define SPI_WAIT_REG_WCC_MASK 0xFFFFu
+#define SPI_WAIT_RESET 0
+
+/* Clock control register - not implemented */
+#define SPI_CCTL_RESET 2
+
+/* Burst count register */
+#define SPI_BC_BC_MASK 0xFFFFFFu
+#define SPI_BC_RESET 0
+
+/* Transmi counter register */
+#define SPI_TC_WTC_MASK 0xFFFFFFu
+#define SPI_TC_RESET 0
+
+/* FIFO status register */
+#define SPI_FIFO_STA_CNT_MASK 0x7F
+#define SPI_FIFO_STA_TF_CNT_SHIFT 16
+#define SPI_FIFO_STA_RF_CNT_SHIFT 0
+#define SPI_FIFO_STA_RESET 0
+
+#define REG_INDEX(offset) (offset / sizeof(uint32_t))
+
+
+static const char *allwinner_a10_spi_get_regname(unsigned offset)
+{
+ switch (offset) {
+ case SPI_RXDATA_REG:
+ return "RXDATA";
+ case SPI_TXDATA_REG:
+ return "TXDATA";
+ case SPI_CTL_REG:
+ return "CTL";
+ case SPI_INTCTL_REG:
+ return "INTCTL";
+ case SPI_INT_STA_REG:
+ return "INT_STA";
+ case SPI_DMACTL_REG:
+ return "DMACTL";
+ case SPI_WAIT_REG:
+ return "WAIT";
+ case SPI_CCTL_REG:
+ return "CCTL";
+ case SPI_BC_REG:
+ return "BC";
+ case SPI_TC_REG:
+ return "TC";
+ case SPI_FIFO_STA_REG:
+ return "FIFO_STA";
+ default:
+ return "[?]";
+ }
+}
+
+static bool allwinner_a10_spi_is_enabled(AWA10SPIState *s)
+{
+ return s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_EN;
+}
+
+static void allwinner_a10_spi_txfifo_reset(AWA10SPIState *s)
+{
+ fifo8_reset(&s->tx_fifo);
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= (SPI_INT_STA_TE | SPI_INT_STA_TE14 |
+ SPI_INT_STA_THE | SPI_INT_STA_TE34);
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~(SPI_INT_STA_TU | SPI_INT_STA_TO);
+}
+
+static void allwinner_a10_spi_rxfifo_reset(AWA10SPIState *s)
+{
+ fifo8_reset(&s->rx_fifo);
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &=
+ ~(SPI_INT_STA_RU | SPI_INT_STA_RO | SPI_INT_STA_RF | SPI_INT_STA_RR |
+ SPI_INT_STA_RHF | SPI_INT_STA_RF14 | SPI_INT_STA_RF34);
+}
+
+static uint8_t allwinner_a10_spi_selected_channel(AWA10SPIState *s)
+{
+ return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SS) >> SPI_CTL_SS_SHIFT;
+}
+
+static void allwinner_a10_spi_reset_hold(Object *obj, ResetType type)
+{
+ AWA10SPIState *s = AW_A10_SPI(obj);
+
+ s->regs[REG_INDEX(SPI_RXDATA_REG)] = SPI_DATA_RESET;
+ s->regs[REG_INDEX(SPI_TXDATA_REG)] = SPI_DATA_RESET;
+ s->regs[REG_INDEX(SPI_CTL_REG)] = SPI_CTL_RESET;
+ s->regs[REG_INDEX(SPI_INTCTL_REG)] = SPI_INTCTL_RESET;
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] = SPI_INT_STA_RESET;
+ s->regs[REG_INDEX(SPI_DMACTL_REG)] = SPI_DMACTL_RESET;
+ s->regs[REG_INDEX(SPI_WAIT_REG)] = SPI_WAIT_RESET;
+ s->regs[REG_INDEX(SPI_CCTL_REG)] = SPI_CCTL_RESET;
+ s->regs[REG_INDEX(SPI_BC_REG)] = SPI_BC_RESET;
+ s->regs[REG_INDEX(SPI_TC_REG)] = SPI_TC_RESET;
+ s->regs[REG_INDEX(SPI_FIFO_STA_REG)] = SPI_FIFO_STA_RESET;
+
+ allwinner_a10_spi_txfifo_reset(s);
+ allwinner_a10_spi_rxfifo_reset(s);
+}
+
+static void allwinner_a10_spi_update_irq(AWA10SPIState *s)
+{
+ bool level;
+
+ if (fifo8_is_empty(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RR;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RR;
+ }
+
+ if (fifo8_num_used(&s->rx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF14;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF14;
+ }
+
+ if (fifo8_num_used(&s->rx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 1)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RHF;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RHF;
+ }
+
+ if (fifo8_num_free(&s->rx_fifo) <= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF34;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF34;
+ }
+
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF;
+ }
+
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE;
+ }
+
+ if (fifo8_num_free(&s->tx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE14;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE14;
+ }
+
+ if (fifo8_num_free(&s->tx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 1)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_THE;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_THE;
+ }
+
+ if (fifo8_num_used(&s->tx_fifo) <= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE34;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE34;
+ }
+
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TF;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TF;
+ }
+
+ level = (s->regs[REG_INDEX(SPI_INT_STA_REG)] &
+ s->regs[REG_INDEX(SPI_INTCTL_REG)]) != 0;
+
+ qemu_set_irq(s->irq, level);
+
+ trace_allwinner_a10_spi_update_irq(level);
+}
+
+static void allwinner_a10_spi_flush_txfifo(AWA10SPIState *s)
+{
+ uint32_t burst_count = s->regs[REG_INDEX(SPI_BC_REG)];
+ uint32_t tx_burst = s->regs[REG_INDEX(SPI_TC_REG)];
+ trace_allwinner_a10_spi_burst_length(tx_burst);
+
+ trace_allwinner_a10_spi_flush_txfifo_begin(fifo8_num_used(&s->tx_fifo),
+ fifo8_num_used(&s->rx_fifo));
+
+ while (!fifo8_is_empty(&s->tx_fifo)) {
+ uint8_t tx = fifo8_pop(&s->tx_fifo);
+ uint8_t rx = 0;
+ bool fill_rx = true;
+
+ trace_allwinner_a10_spi_tx(tx);
+
+ /* Write one byte at a time */
+ rx = ssi_transfer(s->bus, tx);
+
+ trace_allwinner_a10_spi_rx(rx);
+
+ /* Check DHB here to determine if RX bytes should be stored */
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_DHB) {
+ /* Store rx bytes only after WTC transfers */
+ if (tx_burst > 0u) {
+ fill_rx = false;
+ tx_burst--;
+ }
+ }
+
+ if (fill_rx) {
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF;
+ } else {
+ fifo8_push(&s->rx_fifo, rx);
+ }
+ }
+
+ allwinner_a10_spi_update_irq(s);
+
+ burst_count--;
+
+ if (burst_count == 0) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TC;
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_XCH;
+ break;
+ }
+ }
+
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TC;
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_XCH;
+ }
+
+ trace_allwinner_a10_spi_flush_txfifo_end(fifo8_num_used(&s->tx_fifo),
+ fifo8_num_used(&s->rx_fifo));
+}
+
+static uint64_t allwinner_a10_spi_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ uint32_t value = 0;
+ AWA10SPIState *s = opaque;
+ uint32_t index = offset >> 2;
+
+ if (offset > SPI_FIFO_STA_REG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
+ TYPE_AW_A10_SPI, __func__, offset);
+ return 0;
+ }
+
+ value = s->regs[index];
+
+ if (allwinner_a10_spi_is_enabled(s)) {
+ switch (offset) {
+ case SPI_RXDATA_REG:
+ if (fifo8_is_empty(&s->rx_fifo)) {
+ /* value is undefined */
+ value = 0xdeadbeef;
+ } else {
+ /* read from the RX FIFO */
+ value = fifo8_pop(&s->rx_fifo);
+ }
+ break;
+ case SPI_TXDATA_REG:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: Trying to read from TX FIFO\n",
+ TYPE_AW_A10_SPI, __func__);
+
+ /* Reading from TXDATA gives 0 */
+ break;
+ case SPI_FIFO_STA_REG:
+ /* Read current tx/rx fifo data count */
+ value = fifo8_num_used(&s->tx_fifo) << SPI_FIFO_STA_TF_CNT_SHIFT |
+ fifo8_num_used(&s->rx_fifo) << SPI_FIFO_STA_RF_CNT_SHIFT;
+ break;
+ case SPI_CTL_REG:
+ case SPI_INTCTL_REG:
+ case SPI_INT_STA_REG:
+ case SPI_DMACTL_REG:
+ case SPI_WAIT_REG:
+ case SPI_CCTL_REG:
+ case SPI_BC_REG:
+ case SPI_TC_REG:
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad offset 0x%x\n", __func__,
+ (uint32_t)offset);
+ break;
+ }
+
+ allwinner_a10_spi_update_irq(s);
+ }
+ trace_allwinner_a10_spi_read(allwinner_a10_spi_get_regname(offset), value);
+
+ return value;
+}
+
+static bool allwinner_a10_spi_update_cs_level(AWA10SPIState *s, int cs_line_nr)
+{
+ if (cs_line_nr == allwinner_a10_spi_selected_channel(s)) {
+ return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SS_LEVEL) != 0;
+ } else {
+ return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SSPOL) != 0;
+ }
+}
+
+static void allwinner_a10_spi_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ AWA10SPIState *s = opaque;
+ uint32_t index = offset >> 2;
+ int i = 0;
+
+ if (offset > SPI_FIFO_STA_REG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
+ TYPE_AW_A10_SPI, __func__, offset);
+ return;
+ }
+
+ trace_allwinner_a10_spi_write(allwinner_a10_spi_get_regname(offset),
+ (uint32_t)value);
+
+ if (!allwinner_a10_spi_is_enabled(s)) {
+ /* Block is disabled */
+ if (offset != SPI_CTL_REG) {
+ /* Ignore access */
+ return;
+ }
+ }
+
+ switch (offset) {
+ case SPI_RXDATA_REG:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to write to RX FIFO\n",
+ TYPE_AW_A10_SPI, __func__);
+ break;
+ case SPI_TXDATA_REG:
+ if (fifo8_is_full(&s->tx_fifo)) {
+ /* Ignore writes if queue is full */
+ break;
+ }
+
+ fifo8_push(&s->tx_fifo, (uint8_t)value);
+
+ break;
+ case SPI_INT_STA_REG:
+ /* Handle W1C bits - everything except SPI_INT_STA_INT_CBF. */
+ value &= ~SPI_INT_STA_INT_CBF;
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~(value & SPI_INT_STA_MASK);
+ break;
+ case SPI_CTL_REG:
+ s->regs[REG_INDEX(SPI_CTL_REG)] = value;
+
+ for (i = 0; i < AW_A10_SPI_CS_LINES_NR; i++) {
+ qemu_set_irq(
+ s->cs_lines[i],
+ allwinner_a10_spi_update_cs_level(s, i));
+ }
+
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_XCH) {
+ /* Request to start emitting */
+ allwinner_a10_spi_flush_txfifo(s);
+ }
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_TF_RST) {
+ allwinner_a10_spi_txfifo_reset(s);
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_TF_RST;
+ }
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_RF_RST) {
+ allwinner_a10_spi_rxfifo_reset(s);
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_RF_RST;
+ }
+ break;
+ case SPI_INTCTL_REG:
+ case SPI_DMACTL_REG:
+ case SPI_WAIT_REG:
+ case SPI_CCTL_REG:
+ case SPI_BC_REG:
+ case SPI_TC_REG:
+ case SPI_FIFO_STA_REG:
+ s->regs[index] = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad offset 0x%x\n", __func__,
+ (uint32_t)offset);
+ break;
+ }
+
+ allwinner_a10_spi_update_irq(s);
+}
+
+static const MemoryRegionOps allwinner_a10_spi_ops = {
+ .read = allwinner_a10_spi_read,
+ .write = allwinner_a10_spi_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const VMStateDescription allwinner_a10_spi_vmstate = {
+ .name = TYPE_AW_A10_SPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_FIFO8(tx_fifo, AWA10SPIState),
+ VMSTATE_FIFO8(rx_fifo, AWA10SPIState),
+ VMSTATE_UINT32_ARRAY(regs, AWA10SPIState, AW_A10_SPI_REGS_NUM),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void allwinner_a10_spi_realize(DeviceState *dev, Error **errp)
+{
+ AWA10SPIState *s = AW_A10_SPI(dev);
+ int i = 0;
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_a10_spi_ops, s,
+ TYPE_AW_A10_SPI, AW_A10_SPI_IOSIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+
+ s->bus = ssi_create_bus(dev, "spi");
+ for (i = 0; i < AW_A10_SPI_CS_LINES_NR; i++) {
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
+ }
+ fifo8_create(&s->tx_fifo, AW_A10_SPI_FIFO_SIZE);
+ fifo8_create(&s->rx_fifo, AW_A10_SPI_FIFO_SIZE);
+}
+
+static void allwinner_a10_spi_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = allwinner_a10_spi_reset_hold;
+ dc->vmsd = &allwinner_a10_spi_vmstate;
+ dc->realize = allwinner_a10_spi_realize;
+ dc->desc = "Allwinner A10 SPI Controller";
+}
+
+static const TypeInfo allwinner_a10_spi_type_info = {
+ .name = TYPE_AW_A10_SPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AWA10SPIState),
+ .class_init = allwinner_a10_spi_class_init,
+};
+
+static void allwinner_a10_spi_register_types(void)
+{
+ type_register_static(&allwinner_a10_spi_type_info);
+}
+
+type_init(allwinner_a10_spi_register_types)
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index f39fb85..614528b 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -359,7 +359,7 @@ static const MemoryRegionOps aspeed_smc_flash_default_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
- .max_access_size = 4,
+ .max_access_size = 8,
},
};
@@ -417,7 +417,7 @@ static void aspeed_smc_flash_do_select(AspeedSMCFlash *fl, bool unselect)
AspeedSMCState *s = fl->controller;
trace_aspeed_smc_flash_select(fl->cs, unselect ? "un" : "");
-
+ s->unselect = unselect;
qemu_set_irq(s->cs_lines[fl->cs], unselect);
}
@@ -670,29 +670,42 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
- .max_access_size = 4,
+ .max_access_size = 8,
},
};
static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value)
{
AspeedSMCState *s = fl->controller;
- bool unselect;
+ bool unselect = false;
+ uint32_t old_mode;
+ uint32_t new_mode;
- /* User mode selects the CS, other modes unselect */
- unselect = (value & CTRL_CMD_MODE_MASK) != CTRL_USERMODE;
+ old_mode = s->regs[s->r_ctrl0 + fl->cs] & CTRL_CMD_MODE_MASK;
+ new_mode = value & CTRL_CMD_MODE_MASK;
- /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
- if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
- value & CTRL_CE_STOP_ACTIVE) {
- unselect = true;
+ if (old_mode == CTRL_USERMODE) {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
+
+ /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
+ if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
+ value & CTRL_CE_STOP_ACTIVE) {
+ unselect = true;
+ }
+ } else {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
}
s->regs[s->r_ctrl0 + fl->cs] = value;
- s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
-
- aspeed_smc_flash_do_select(fl, unselect);
+ if (unselect != s->unselect) {
+ s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
+ aspeed_smc_flash_do_select(fl, unselect);
+ }
}
static void aspeed_smc_reset(DeviceState *d)
@@ -729,6 +742,8 @@ static void aspeed_smc_reset(DeviceState *d)
qemu_set_irq(s->cs_lines[i], true);
}
+ s->unselect = true;
+
/* setup the default segment register values and regions for all */
for (i = 0; i < asc->cs_num_max; ++i) {
aspeed_smc_flash_set_segment_region(s, i,
@@ -1261,30 +1276,30 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_aspeed_smc = {
.name = "aspeed.smc",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
VMSTATE_UINT8(snoop_index, AspeedSMCState),
VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
+ VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
VMSTATE_END_OF_LIST()
}
};
-static Property aspeed_smc_properties[] = {
+static const Property aspeed_smc_properties[] = {
DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure, false),
DEFINE_PROP_UINT64("dram-base", AspeedSMCState, dram_base, 0),
DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_smc_class_init(ObjectClass *klass, void *data)
+static void aspeed_smc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_smc_realize;
- dc->reset = aspeed_smc_reset;
+ device_class_set_legacy_reset(dc, aspeed_smc_reset);
device_class_set_props(dc, aspeed_smc_properties);
dc->vmsd = &vmstate_aspeed_smc;
}
@@ -1320,14 +1335,13 @@ static void aspeed_smc_flash_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
}
-static Property aspeed_smc_flash_properties[] = {
+static const Property aspeed_smc_flash_properties[] = {
DEFINE_PROP_UINT8("cs", AspeedSMCFlash, cs, 0),
DEFINE_PROP_LINK("controller", AspeedSMCFlash, controller, TYPE_ASPEED_SMC,
AspeedSMCState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_smc_flash_class_init(ObjectClass *klass, void *data)
+static void aspeed_smc_flash_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1369,7 +1383,7 @@ static const AspeedSegments aspeed_2400_smc_segments[] = {
{ 0x10000000, 32 * MiB },
};
-static void aspeed_2400_smc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_smc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1415,7 +1429,7 @@ static const AspeedSegments aspeed_2400_fmc_segments[] = {
{ 0x2A000000, 32 * MiB }
};
-static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_fmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1459,7 +1473,7 @@ static int aspeed_2400_spi1_addr_width(const AspeedSMCState *s)
return s->regs[R_SPI_CTRL0] & CTRL_AST2400_SPI_4BYTE ? 4 : 3;
}
-static void aspeed_2400_spi1_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_spi1_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1501,7 +1515,7 @@ static const AspeedSegments aspeed_2500_fmc_segments[] = {
{ 0x2A000000, 32 * MiB },
};
-static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_fmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1541,7 +1555,7 @@ static const AspeedSegments aspeed_2500_spi1_segments[] = {
{ 0x32000000, 96 * MiB }, /* end address is readonly */
};
-static void aspeed_2500_spi1_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_spi1_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1577,7 +1591,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[] = {
{ 0x3A000000, 96 * MiB }, /* end address is readonly */
};
-static void aspeed_2500_spi2_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_spi2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1660,7 +1674,7 @@ static const AspeedSegments aspeed_2600_fmc_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_fmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1701,7 +1715,7 @@ static const AspeedSegments aspeed_2600_spi1_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_spi1_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1742,7 +1756,7 @@ static const AspeedSegments aspeed_2600_spi2_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_spi2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1825,7 +1839,7 @@ static const AspeedSegments aspeed_1030_fmc_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_1030_fmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_fmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1865,7 +1879,7 @@ static const AspeedSegments aspeed_1030_spi1_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_1030_spi1_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_spi1_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -1903,7 +1917,7 @@ static const AspeedSegments aspeed_1030_spi2_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_1030_spi2_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_spi2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -2008,7 +2022,7 @@ static const AspeedSegments aspeed_2700_fmc_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_2700_fmc_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_fmc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -2050,7 +2064,7 @@ static const AspeedSegments aspeed_2700_spi0_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_2700_spi0_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_spi0_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -2090,7 +2104,7 @@ static const AspeedSegments aspeed_2700_spi1_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_2700_spi1_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_spi1_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
@@ -2130,7 +2144,7 @@ static const AspeedSegments aspeed_2700_spi2_segments[] = {
{ 0x0, 0 }, /* disabled */
};
-static void aspeed_2700_spi2_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_spi2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
diff --git a/hw/ssi/bcm2835_spi.c b/hw/ssi/bcm2835_spi.c
index 6ecb42d..bf8ba35 100644
--- a/hw/ssi/bcm2835_spi.c
+++ b/hw/ssi/bcm2835_spi.c
@@ -264,11 +264,11 @@ static const VMStateDescription vmstate_bcm2835_spi = {
}
};
-static void bcm2835_spi_class_init(ObjectClass *klass, void *data)
+static void bcm2835_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_spi_reset;
+ device_class_set_legacy_reset(dc, bcm2835_spi_reset);
dc->realize = bcm2835_spi_realize;
dc->vmsd = &vmstate_bcm2835_spi;
}
diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c
index 863b5fd..f05be68 100644
--- a/hw/ssi/ibex_spi_host.c
+++ b/hw/ssi/ibex_spi_host.c
@@ -154,7 +154,6 @@ static void ibex_spi_host_reset(DeviceState *dev)
ibex_spi_txfifo_reset(s);
s->init_status = true;
- return;
}
/*
@@ -561,9 +560,8 @@ static const MemoryRegionOps ibex_spi_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static Property ibex_spi_properties[] = {
+static const Property ibex_spi_properties[] = {
DEFINE_PROP_UINT32("num_cs", IbexSPIHostState, num_cs, 1),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_ibex = {
@@ -624,11 +622,11 @@ static void ibex_spi_host_init(Object *obj)
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
-static void ibex_spi_host_class_init(ObjectClass *klass, void *data)
+static void ibex_spi_host_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ibex_spi_host_realize;
- dc->reset = ibex_spi_host_reset;
+ device_class_set_legacy_reset(dc, ibex_spi_host_reset);
dc->vmsd = &vmstate_ibex;
device_class_set_props(dc, ibex_spi_properties);
}
diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 12d897d..1312f58 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -475,13 +475,13 @@ static void imx_spi_realize(DeviceState *dev, Error **errp)
fifo32_create(&s->rx_fifo, ECSPI_FIFO_SIZE);
}
-static void imx_spi_class_init(ObjectClass *klass, void *data)
+static void imx_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_spi_realize;
dc->vmsd = &vmstate_imx_spi;
- dc->reset = imx_spi_reset;
+ device_class_set_legacy_reset(dc, imx_spi_reset);
dc->desc = "i.MX SPI Controller";
}
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index b7ad7fc..6afb1ea 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -1,3 +1,4 @@
+system_ss.add(when: 'CONFIG_ALLWINNER_A10_SPI', if_true: files('allwinner-a10-spi.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c'))
system_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c', 'npcm_pspi.c'))
@@ -9,7 +10,6 @@ system_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c'))
system_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c'))
system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c'))
system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c'))
system_ss.add(when: 'CONFIG_PNV_SPI', if_true: files('pnv_spi.c'))
diff --git a/hw/ssi/mss-spi.c b/hw/ssi/mss-spi.c
index 1d25ba2..fd7ba7e 100644
--- a/hw/ssi/mss-spi.c
+++ b/hw/ssi/mss-spi.c
@@ -398,12 +398,12 @@ static const VMStateDescription vmstate_mss_spi = {
}
};
-static void mss_spi_class_init(ObjectClass *klass, void *data)
+static void mss_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mss_spi_realize;
- dc->reset = mss_spi_reset;
+ device_class_set_legacy_reset(dc, mss_spi_reset);
dc->vmsd = &vmstate_mss_spi;
}
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
index 119c38c..056ce13 100644
--- a/hw/ssi/npcm7xx_fiu.c
+++ b/hw/ssi/npcm7xx_fiu.c
@@ -29,7 +29,7 @@
#include "trace.h"
/* Up to 128 MiB of flash may be accessed directly as memory. */
-#define NPCM7XX_FIU_FLASH_WINDOW_SIZE (128 * MiB)
+#define NPCM7XX_FIU_MAX_FLASH_WINDOW_SIZE (128 * MiB)
/* Each module has 4 KiB of register space. Only a fraction of it is used. */
#define NPCM7XX_FIU_CTRL_REGS_SIZE (4 * KiB)
@@ -507,6 +507,17 @@ static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
return;
}
+ if (s->flash_size == 0) {
+ error_setg(errp, "%s: flash size must be set", dev->canonical_path);
+ return;
+ }
+
+ if (s->flash_size > NPCM7XX_FIU_MAX_FLASH_WINDOW_SIZE) {
+ error_setg(errp, "%s: flash size should not exceed 128 MiB",
+ dev->canonical_path);
+ return;
+ }
+
s->spi = ssi_create_bus(dev, "spi");
s->cs_lines = g_new0(qemu_irq, s->cs_count);
qdev_init_gpio_out_named(DEVICE(s), s->cs_lines, "cs", s->cs_count);
@@ -525,7 +536,7 @@ static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
flash->fiu = s;
memory_region_init_io(&flash->direct_access, OBJECT(s),
&npcm7xx_fiu_flash_ops, &s->flash[i], "flash",
- NPCM7XX_FIU_FLASH_WINDOW_SIZE);
+ s->flash_size);
sysbus_init_mmio(sbd, &flash->direct_access);
}
}
@@ -541,12 +552,12 @@ static const VMStateDescription vmstate_npcm7xx_fiu = {
},
};
-static Property npcm7xx_fiu_properties[] = {
+static const Property npcm7xx_fiu_properties[] = {
DEFINE_PROP_INT32("cs-count", NPCM7xxFIUState, cs_count, 0),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_SIZE("flash-size", NPCM7xxFIUState, flash_size, 0),
};
-static void npcm7xx_fiu_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_fiu_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ssi/npcm_pspi.c b/hw/ssi/npcm_pspi.c
index 41a5323..a31dcc0 100644
--- a/hw/ssi/npcm_pspi.c
+++ b/hw/ssi/npcm_pspi.c
@@ -199,7 +199,7 @@ static const VMStateDescription vmstate_npcm_pspi = {
};
-static void npcm_pspi_class_init(ObjectClass *klass, void *data)
+static void npcm_pspi_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ssi/omap_spi.c b/hw/ssi/omap_spi.c
deleted file mode 100644
index 8f85c3e..0000000
--- a/hw/ssi/omap_spi.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * TI OMAP processor's Multichannel SPI emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/arm/omap.h"
-
-/* Multichannel SPI */
-struct omap_mcspi_s {
- MemoryRegion iomem;
- qemu_irq irq;
- int chnum;
-
- uint32_t sysconfig;
- uint32_t systest;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t wken;
- uint32_t control;
-
- struct omap_mcspi_ch_s {
- qemu_irq txdrq;
- qemu_irq rxdrq;
- uint32_t (*txrx)(void *opaque, uint32_t, int);
- void *opaque;
-
- uint32_t tx;
- uint32_t rx;
-
- uint32_t config;
- uint32_t status;
- uint32_t control;
- } ch[4];
-};
-
-static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
-{
- qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
-{
- qemu_set_irq(ch->txdrq,
- (ch->control & 1) && /* EN */
- (ch->config & (1 << 14)) && /* DMAW */
- (ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1); /* TRM */
- qemu_set_irq(ch->rxdrq,
- (ch->control & 1) && /* EN */
- (ch->config & (1 << 15)) && /* DMAW */
- (ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2); /* TRM */
-}
-
-static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
-{
- struct omap_mcspi_ch_s *ch = s->ch + chnum;
-
- if (!(ch->control & 1)) /* EN */
- return;
- if ((ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2 && /* TRM */
- !(ch->config & (1 << 19))) /* TURBO */
- goto intr_update;
- if ((ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1) /* TRM */
- goto intr_update;
-
- if (!(s->control & 1) || /* SINGLE */
- (ch->config & (1 << 20))) { /* FORCE */
- if (ch->txrx)
- ch->rx = ch->txrx(ch->opaque, ch->tx, /* WL */
- 1 + (0x1f & (ch->config >> 7)));
- }
-
- ch->tx = 0;
- ch->status |= 1 << 2; /* EOT */
- ch->status |= 1 << 1; /* TXS */
- if (((ch->config >> 12) & 3) != 2) /* TRM */
- ch->status |= 1 << 0; /* RXS */
-
-intr_update:
- if ((ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2 && /* TRM */
- !(ch->config & (1 << 19))) /* TURBO */
- s->irqst |= 1 << (2 + 4 * chnum); /* RX_FULL */
- if ((ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1) /* TRM */
- s->irqst |= 1 << (0 + 4 * chnum); /* TX_EMPTY */
- omap_mcspi_interrupt_update(s);
- omap_mcspi_dmarequest_update(ch);
-}
-
-void omap_mcspi_reset(struct omap_mcspi_s *s)
-{
- int ch;
-
- s->sysconfig = 0;
- s->systest = 0;
- s->irqst = 0;
- s->irqen = 0;
- s->wken = 0;
- s->control = 4;
-
- for (ch = 0; ch < 4; ch ++) {
- s->ch[ch].config = 0x060000;
- s->ch[ch].status = 2; /* TXS */
- s->ch[ch].control = 0;
-
- omap_mcspi_dmarequest_update(s->ch + ch);
- }
-
- omap_mcspi_interrupt_update(s);
-}
-
-static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_mcspi_s *s = opaque;
- int ch = 0;
- uint32_t ret;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* MCSPI_REVISION */
- return 0x91;
-
- case 0x10: /* MCSPI_SYSCONFIG */
- return s->sysconfig;
-
- case 0x14: /* MCSPI_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x18: /* MCSPI_IRQSTATUS */
- return s->irqst;
-
- case 0x1c: /* MCSPI_IRQENABLE */
- return s->irqen;
-
- case 0x20: /* MCSPI_WAKEUPENABLE */
- return s->wken;
-
- case 0x24: /* MCSPI_SYST */
- return s->systest;
-
- case 0x28: /* MCSPI_MODULCTRL */
- return s->control;
-
- case 0x68: ch ++;
- /* fall through */
- case 0x54: ch ++;
- /* fall through */
- case 0x40: ch ++;
- /* fall through */
- case 0x2c: /* MCSPI_CHCONF */
- return s->ch[ch].config;
-
- case 0x6c: ch ++;
- /* fall through */
- case 0x58: ch ++;
- /* fall through */
- case 0x44: ch ++;
- /* fall through */
- case 0x30: /* MCSPI_CHSTAT */
- return s->ch[ch].status;
-
- case 0x70: ch ++;
- /* fall through */
- case 0x5c: ch ++;
- /* fall through */
- case 0x48: ch ++;
- /* fall through */
- case 0x34: /* MCSPI_CHCTRL */
- return s->ch[ch].control;
-
- case 0x74: ch ++;
- /* fall through */
- case 0x60: ch ++;
- /* fall through */
- case 0x4c: ch ++;
- /* fall through */
- case 0x38: /* MCSPI_TX */
- return s->ch[ch].tx;
-
- case 0x78: ch ++;
- /* fall through */
- case 0x64: ch ++;
- /* fall through */
- case 0x50: ch ++;
- /* fall through */
- case 0x3c: /* MCSPI_RX */
- s->ch[ch].status &= ~(1 << 0); /* RXS */
- ret = s->ch[ch].rx;
- omap_mcspi_transfer_run(s, ch);
- return ret;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mcspi_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mcspi_s *s = opaque;
- int ch = 0;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* MCSPI_REVISION */
- case 0x14: /* MCSPI_SYSSTATUS */
- case 0x30: /* MCSPI_CHSTAT0 */
- case 0x3c: /* MCSPI_RX0 */
- case 0x44: /* MCSPI_CHSTAT1 */
- case 0x50: /* MCSPI_RX1 */
- case 0x58: /* MCSPI_CHSTAT2 */
- case 0x64: /* MCSPI_RX2 */
- case 0x6c: /* MCSPI_CHSTAT3 */
- case 0x78: /* MCSPI_RX3 */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* MCSPI_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_mcspi_reset(s);
- s->sysconfig = value & 0x31d;
- break;
-
- case 0x18: /* MCSPI_IRQSTATUS */
- if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
- s->irqst &= ~value;
- omap_mcspi_interrupt_update(s);
- }
- break;
-
- case 0x1c: /* MCSPI_IRQENABLE */
- s->irqen = value & 0x1777f;
- omap_mcspi_interrupt_update(s);
- break;
-
- case 0x20: /* MCSPI_WAKEUPENABLE */
- s->wken = value & 1;
- break;
-
- case 0x24: /* MCSPI_SYST */
- if (s->control & (1 << 3)) /* SYSTEM_TEST */
- if (value & (1 << 11)) { /* SSB */
- s->irqst |= 0x1777f;
- omap_mcspi_interrupt_update(s);
- }
- s->systest = value & 0xfff;
- break;
-
- case 0x28: /* MCSPI_MODULCTRL */
- if (value & (1 << 3)) /* SYSTEM_TEST */
- if (s->systest & (1 << 11)) { /* SSB */
- s->irqst |= 0x1777f;
- omap_mcspi_interrupt_update(s);
- }
- s->control = value & 0xf;
- break;
-
- case 0x68: ch ++;
- /* fall through */
- case 0x54: ch ++;
- /* fall through */
- case 0x40: ch ++;
- /* fall through */
- case 0x2c: /* MCSPI_CHCONF */
- if ((value ^ s->ch[ch].config) & (3 << 14)) /* DMAR | DMAW */
- omap_mcspi_dmarequest_update(s->ch + ch);
- if (((value >> 12) & 3) == 3) { /* TRM */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid TRM value (3)\n",
- __func__);
- }
- if (((value >> 7) & 0x1f) < 3) { /* WL */
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: invalid WL value (%" PRIx64 ")\n",
- __func__, (value >> 7) & 0x1f);
- }
- s->ch[ch].config = value & 0x7fffff;
- break;
-
- case 0x70: ch ++;
- /* fall through */
- case 0x5c: ch ++;
- /* fall through */
- case 0x48: ch ++;
- /* fall through */
- case 0x34: /* MCSPI_CHCTRL */
- if (value & ~s->ch[ch].control & 1) { /* EN */
- s->ch[ch].control |= 1;
- omap_mcspi_transfer_run(s, ch);
- } else
- s->ch[ch].control = value & 1;
- break;
-
- case 0x74: ch ++;
- /* fall through */
- case 0x60: ch ++;
- /* fall through */
- case 0x4c: ch ++;
- /* fall through */
- case 0x38: /* MCSPI_TX */
- s->ch[ch].tx = value;
- s->ch[ch].status &= ~(1 << 1); /* TXS */
- omap_mcspi_transfer_run(s, ch);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_mcspi_ops = {
- .read = omap_mcspi_read,
- .write = omap_mcspi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
- qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_mcspi_s *s = g_new0(struct omap_mcspi_s, 1);
- struct omap_mcspi_ch_s *ch = s->ch;
-
- s->irq = irq;
- s->chnum = chnum;
- while (chnum --) {
- ch->txdrq = *drq ++;
- ch->rxdrq = *drq ++;
- ch ++;
- }
- omap_mcspi_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mcspi_ops, s, "omap.mcspi",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-void omap_mcspi_attach(struct omap_mcspi_s *s,
- uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
- int chipselect)
-{
- if (chipselect < 0 || chipselect >= s->chnum)
- hw_error("%s: Bad chipselect %i\n", __func__, chipselect);
-
- s->ch[chipselect].txrx = txrx;
- s->ch[chipselect].opaque = opaque;
-}
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
index b8be8dd..1dc0bcb 100644
--- a/hw/ssi/pl022.c
+++ b/hw/ssi/pl022.c
@@ -292,11 +292,11 @@ static void pl022_realize(DeviceState *dev, Error **errp)
s->ssi = ssi_create_bus(dev, "ssi");
}
-static void pl022_class_init(ObjectClass *klass, void *data)
+static void pl022_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pl022_reset;
+ device_class_set_legacy_reset(dc, pl022_reset);
dc->vmsd = &vmstate_pl022;
dc->realize = pl022_realize;
}
diff --git a/hw/ssi/pnv_spi.c b/hw/ssi/pnv_spi.c
index c1297ab..f40e883 100644
--- a/hw/ssi/pnv_spi.c
+++ b/hw/ssi/pnv_spi.c
@@ -19,6 +19,8 @@
#define PNV_SPI_OPCODE_LO_NIBBLE(x) (x & 0x0F)
#define PNV_SPI_MASKED_OPCODE(x) (x & 0xF0)
+#define PNV_SPI_FIFO_SIZE 16
+#define RDR_MATCH_FAILURE_LIMIT 16
/*
* Macro from include/hw/ppc/fdt.h
@@ -35,48 +37,14 @@
} \
} while (0)
-/* PnvXferBuffer */
-typedef struct PnvXferBuffer {
-
- uint32_t len;
- uint8_t *data;
-
-} PnvXferBuffer;
-
-/* pnv_spi_xfer_buffer_methods */
-static PnvXferBuffer *pnv_spi_xfer_buffer_new(void)
-{
- PnvXferBuffer *payload = g_malloc0(sizeof(*payload));
-
- return payload;
-}
-
-static void pnv_spi_xfer_buffer_free(PnvXferBuffer *payload)
-{
- free(payload->data);
- free(payload);
-}
-
-static uint8_t *pnv_spi_xfer_buffer_write_ptr(PnvXferBuffer *payload,
- uint32_t offset, uint32_t length)
-{
- if (payload->len < (offset + length)) {
- payload->len = offset + length;
- payload->data = g_realloc(payload->data, payload->len);
- }
- return &payload->data[offset];
-}
-
static bool does_rdr_match(PnvSpi *s)
{
/*
* According to spec, the mask bits that are 0 are compared and the
* bits that are 1 are ignored.
*/
- uint16_t rdr_match_mask = GETFIELD(SPI_MM_RDR_MATCH_MASK,
- s->regs[SPI_MM_REG]);
- uint16_t rdr_match_val = GETFIELD(SPI_MM_RDR_MATCH_VAL,
- s->regs[SPI_MM_REG]);
+ uint16_t rdr_match_mask = GETFIELD(SPI_MM_RDR_MATCH_MASK, s->regs[SPI_MM_REG]);
+ uint16_t rdr_match_val = GETFIELD(SPI_MM_RDR_MATCH_VAL, s->regs[SPI_MM_REG]);
if ((~rdr_match_mask & rdr_match_val) == ((~rdr_match_mask) &
GETFIELD(PPC_BITMASK(48, 63), s->regs[SPI_RCV_DATA_REG]))) {
@@ -107,8 +75,8 @@ static uint8_t get_from_offset(PnvSpi *s, uint8_t offset)
return byte;
}
-static uint8_t read_from_frame(PnvSpi *s, uint8_t *read_buf, uint8_t nr_bytes,
- uint8_t ecc_count, uint8_t shift_in_count)
+static uint8_t read_from_frame(PnvSpi *s, uint8_t nr_bytes, uint8_t ecc_count,
+ uint8_t shift_in_count)
{
uint8_t byte;
int count = 0;
@@ -118,20 +86,24 @@ static uint8_t read_from_frame(PnvSpi *s, uint8_t *read_buf, uint8_t nr_bytes,
if ((ecc_count != 0) &&
(shift_in_count == (PNV_SPI_REG_SIZE + ecc_count))) {
shift_in_count = 0;
- } else {
- byte = read_buf[count];
+ } else if (!fifo8_is_empty(&s->rx_fifo)) {
+ byte = fifo8_pop(&s->rx_fifo);
trace_pnv_spi_shift_rx(byte, count);
s->regs[SPI_RCV_DATA_REG] = (s->regs[SPI_RCV_DATA_REG] << 8) | byte;
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: Reading empty RX_FIFO\n");
}
count++;
} /* end of while */
return shift_in_count;
}
-static void spi_response(PnvSpi *s, int bits, PnvXferBuffer *rsp_payload)
+static void spi_response(PnvSpi *s)
{
uint8_t ecc_count;
uint8_t shift_in_count;
+ uint32_t rx_len;
+ int i;
/*
* Processing here must handle:
@@ -144,13 +116,14 @@ static void spi_response(PnvSpi *s, int bits, PnvXferBuffer *rsp_payload)
* First check that the response payload is the exact same
* number of bytes as the request payload was
*/
- if (rsp_payload->len != (s->N1_bytes + s->N2_bytes)) {
+ rx_len = fifo8_num_used(&s->rx_fifo);
+ if (rx_len != (s->N1_bytes + s->N2_bytes)) {
qemu_log_mask(LOG_GUEST_ERROR, "Invalid response payload size in "
"bytes, expected %d, got %d\n",
- (s->N1_bytes + s->N2_bytes), rsp_payload->len);
+ (s->N1_bytes + s->N2_bytes), rx_len);
} else {
uint8_t ecc_control;
- trace_pnv_spi_rx_received(rsp_payload->len);
+ trace_pnv_spi_rx_received(rx_len);
trace_pnv_spi_log_Ncounts(s->N1_bits, s->N1_bytes, s->N1_tx,
s->N1_rx, s->N2_bits, s->N2_bytes, s->N2_tx, s->N2_rx);
/*
@@ -175,15 +148,23 @@ static void spi_response(PnvSpi *s, int bits, PnvXferBuffer *rsp_payload)
/* Handle the N1 portion of the frame first */
if (s->N1_rx != 0) {
trace_pnv_spi_rx_read_N1frame();
- shift_in_count = read_from_frame(s, &rsp_payload->data[0],
- s->N1_bytes, ecc_count, shift_in_count);
+ shift_in_count = read_from_frame(s, s->N1_bytes, ecc_count, shift_in_count);
}
/* Handle the N2 portion of the frame */
if (s->N2_rx != 0) {
+ /* pop out N1_bytes from rx_fifo if not already */
+ if (s->N1_rx == 0) {
+ for (i = 0; i < s->N1_bytes; i++) {
+ if (!fifo8_is_empty(&s->rx_fifo)) {
+ fifo8_pop(&s->rx_fifo);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: Reading empty"
+ " RX_FIFO\n");
+ }
+ }
+ }
trace_pnv_spi_rx_read_N2frame();
- shift_in_count = read_from_frame(s,
- &rsp_payload->data[s->N1_bytes], s->N2_bytes,
- ecc_count, shift_in_count);
+ shift_in_count = read_from_frame(s, s->N2_bytes, ecc_count, shift_in_count);
}
if ((s->N1_rx + s->N2_rx) > 0) {
/*
@@ -210,46 +191,41 @@ static void spi_response(PnvSpi *s, int bits, PnvXferBuffer *rsp_payload)
} /* end of else */
} /* end of spi_response() */
-static void transfer(PnvSpi *s, PnvXferBuffer *payload)
+static void transfer(PnvSpi *s)
{
- uint32_t tx;
- uint32_t rx;
- PnvXferBuffer *rsp_payload = NULL;
+ uint32_t tx, rx, payload_len;
+ uint8_t rx_byte;
- rsp_payload = pnv_spi_xfer_buffer_new();
- for (int offset = 0; offset < payload->len; offset += s->transfer_len) {
+ payload_len = fifo8_num_used(&s->tx_fifo);
+ for (int offset = 0; offset < payload_len; offset += s->transfer_len) {
tx = 0;
for (int i = 0; i < s->transfer_len; i++) {
- if ((offset + i) >= payload->len) {
+ if ((offset + i) >= payload_len) {
tx <<= 8;
+ } else if (!fifo8_is_empty(&s->tx_fifo)) {
+ tx = (tx << 8) | fifo8_pop(&s->tx_fifo);
} else {
- tx = (tx << 8) | payload->data[offset + i];
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: TX_FIFO underflow\n");
}
}
rx = ssi_transfer(s->ssi_bus, tx);
for (int i = 0; i < s->transfer_len; i++) {
- if ((offset + i) >= payload->len) {
+ if ((offset + i) >= payload_len) {
+ break;
+ }
+ rx_byte = (rx >> (8 * (s->transfer_len - 1) - i * 8)) & 0xFF;
+ if (!fifo8_is_full(&s->rx_fifo)) {
+ fifo8_push(&s->rx_fifo, rx_byte);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: RX_FIFO is full\n");
break;
}
- *(pnv_spi_xfer_buffer_write_ptr(rsp_payload, rsp_payload->len, 1)) =
- (rx >> (8 * (s->transfer_len - 1) - i * 8)) & 0xFF;
}
}
- if (rsp_payload != NULL) {
- spi_response(s, s->N1_bits, rsp_payload);
- }
-}
-
-static inline uint8_t get_seq_index(PnvSpi *s)
-{
- return GETFIELD(SPI_STS_SEQ_INDEX, s->status);
-}
-
-static inline void next_sequencer_fsm(PnvSpi *s)
-{
- uint8_t seq_index = get_seq_index(s);
- s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, (seq_index + 1));
- s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_INDEX_INCREMENT);
+ spi_response(s);
+ /* Reset fifo for next frame */
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
}
/*
@@ -308,13 +284,11 @@ static void calculate_N1(PnvSpi *s, uint8_t opcode)
* If Forced Implicit mode and count control doesn't
* indicate transmit then reset the tx count to 0
*/
- if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B2,
- s->regs[SPI_CTR_CFG_REG]) == 0) {
+ if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B2, s->regs[SPI_CTR_CFG_REG]) == 0) {
s->N1_tx = 0;
}
/* If rx count control for N1 is set, load the rx value */
- if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B3,
- s->regs[SPI_CTR_CFG_REG]) == 1) {
+ if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B3, s->regs[SPI_CTR_CFG_REG]) == 1) {
s->N1_rx = s->N1_bytes;
}
}
@@ -326,8 +300,7 @@ static void calculate_N1(PnvSpi *s, uint8_t opcode)
* cap the size at a max of 64 bits or 72 bits and set the sequencer FSM
* error bit.
*/
- uint8_t ecc_control = GETFIELD(SPI_CLK_CFG_ECC_CTRL,
- s->regs[SPI_CLK_CFG_REG]);
+ uint8_t ecc_control = GETFIELD(SPI_CLK_CFG_ECC_CTRL, s->regs[SPI_CLK_CFG_REG]);
if (ecc_control == 0 || ecc_control == 2) {
if (s->N1_bytes > (PNV_SPI_REG_SIZE + 1)) {
qemu_log_mask(LOG_GUEST_ERROR, "Unsupported N1 shift size when "
@@ -338,8 +311,7 @@ static void calculate_N1(PnvSpi *s, uint8_t opcode)
}
} else if (s->N1_bytes > PNV_SPI_REG_SIZE) {
qemu_log_mask(LOG_GUEST_ERROR, "Unsupported N1 shift size, "
- "bytes = 0x%x, bits = 0x%x\n",
- s->N1_bytes, s->N1_bits);
+ "bytes = 0x%x, bits = 0x%x\n", s->N1_bytes, s->N1_bits);
s->N1_bytes = PNV_SPI_REG_SIZE;
s->N1_bits = s->N1_bytes * 8;
}
@@ -348,19 +320,10 @@ static void calculate_N1(PnvSpi *s, uint8_t opcode)
/*
* Shift_N1 operation handler method
*/
-static bool operation_shiftn1(PnvSpi *s, uint8_t opcode,
- PnvXferBuffer **payload, bool send_n1_alone)
+static bool operation_shiftn1(PnvSpi *s, uint8_t opcode, bool send_n1_alone)
{
uint8_t n1_count;
bool stop = false;
-
- /*
- * If there isn't a current payload left over from a stopped sequence
- * create a new one.
- */
- if (*payload == NULL) {
- *payload = pnv_spi_xfer_buffer_new();
- }
/*
* Use a combination of N1 counters to build the N1 portion of the
* transmit payload.
@@ -411,9 +374,13 @@ static bool operation_shiftn1(PnvSpi *s, uint8_t opcode,
*/
uint8_t n1_byte = 0x00;
n1_byte = get_from_offset(s, n1_count);
- trace_pnv_spi_tx_append("n1_byte", n1_byte, n1_count);
- *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1)) =
- n1_byte;
+ if (!fifo8_is_full(&s->tx_fifo)) {
+ trace_pnv_spi_tx_append("n1_byte", n1_byte, n1_count);
+ fifo8_push(&s->tx_fifo, n1_byte);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: TX_FIFO is full\n");
+ break;
+ }
} else {
/*
* We hit a shift_n1 opcode TX but the TDR is empty, tell the
@@ -434,16 +401,17 @@ static bool operation_shiftn1(PnvSpi *s, uint8_t opcode,
* - we are receiving and the RDR is empty so we allow the operation
* to proceed.
*/
- if ((s->N1_rx != 0) && (GETFIELD(SPI_STS_RDR_FULL,
- s->status) == 1)) {
+ if ((s->N1_rx != 0) && (GETFIELD(SPI_STS_RDR_FULL, s->status) == 1)) {
trace_pnv_spi_sequencer_stop_requested("shift N1"
"set for receive but RDR is full");
stop = true;
break;
- } else {
+ } else if (!fifo8_is_full(&s->tx_fifo)) {
trace_pnv_spi_tx_append_FF("n1_byte");
- *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1))
- = 0xff;
+ fifo8_push(&s->tx_fifo, 0xff);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: TX_FIFO is full\n");
+ break;
}
}
n1_count++;
@@ -484,15 +452,13 @@ static bool operation_shiftn1(PnvSpi *s, uint8_t opcode,
*/
if (send_n1_alone && !stop) {
/* We have a TX and a full TDR or an RX and an empty RDR */
- trace_pnv_spi_tx_request("Shifting N1 frame", (*payload)->len);
- transfer(s, *payload);
+ trace_pnv_spi_tx_request("Shifting N1 frame", fifo8_num_used(&s->tx_fifo));
+ transfer(s);
/* The N1 frame shift is complete so reset the N1 counters */
s->N2_bits = 0;
s->N2_bytes = 0;
s->N2_tx = 0;
s->N2_rx = 0;
- pnv_spi_xfer_buffer_free(*payload);
- *payload = NULL;
}
return stop;
} /* end of operation_shiftn1() */
@@ -550,13 +516,11 @@ static void calculate_N2(PnvSpi *s, uint8_t opcode)
* If Forced Implicit mode and count control doesn't
* indicate a receive then reset the rx count to 0
*/
- if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B3,
- s->regs[SPI_CTR_CFG_REG]) == 0) {
+ if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B3, s->regs[SPI_CTR_CFG_REG]) == 0) {
s->N2_rx = 0;
}
/* If tx count control for N2 is set, load the tx value */
- if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B2,
- s->regs[SPI_CTR_CFG_REG]) == 1) {
+ if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B2, s->regs[SPI_CTR_CFG_REG]) == 1) {
s->N2_tx = s->N2_bytes;
}
}
@@ -569,8 +533,7 @@ static void calculate_N2(PnvSpi *s, uint8_t opcode)
* cap the size at a max of 64 bits or 72 bits and set the sequencer FSM
* error bit.
*/
- uint8_t ecc_control = GETFIELD(SPI_CLK_CFG_ECC_CTRL,
- s->regs[SPI_CLK_CFG_REG]);
+ uint8_t ecc_control = GETFIELD(SPI_CLK_CFG_ECC_CTRL, s->regs[SPI_CLK_CFG_REG]);
if (ecc_control == 0 || ecc_control == 2) {
if (s->N2_bytes > (PNV_SPI_REG_SIZE + 1)) {
/* Unsupported N2 shift size when ECC enabled */
@@ -588,19 +551,10 @@ static void calculate_N2(PnvSpi *s, uint8_t opcode)
* Shift_N2 operation handler method
*/
-static bool operation_shiftn2(PnvSpi *s, uint8_t opcode,
- PnvXferBuffer **payload)
+static bool operation_shiftn2(PnvSpi *s, uint8_t opcode)
{
uint8_t n2_count;
bool stop = false;
-
- /*
- * If there isn't a current payload left over from a stopped sequence
- * create a new one.
- */
- if (*payload == NULL) {
- *payload = pnv_spi_xfer_buffer_new();
- }
/*
* Use a combination of N2 counters to build the N2 portion of the
* transmit payload.
@@ -627,44 +581,47 @@ static bool operation_shiftn2(PnvSpi *s, uint8_t opcode,
* code continue will end up building the payload twice in the same
* buffer since RDR full causes a sequence stop and restart.
*/
- if ((s->N2_rx != 0) &&
- (GETFIELD(SPI_STS_RDR_FULL, s->status) == 1)) {
+ if ((s->N2_rx != 0) && (GETFIELD(SPI_STS_RDR_FULL, s->status) == 1)) {
trace_pnv_spi_sequencer_stop_requested("shift N2 set"
"for receive but RDR is full");
stop = true;
break;
}
- if ((s->N2_tx != 0) && ((s->N1_tx + n2_count) <
- PNV_SPI_REG_SIZE)) {
+ if ((s->N2_tx != 0) && ((s->N1_tx + n2_count) < PNV_SPI_REG_SIZE)) {
/* Always append data for the N2 segment if it is set for TX */
uint8_t n2_byte = 0x00;
n2_byte = get_from_offset(s, (s->N1_tx + n2_count));
- trace_pnv_spi_tx_append("n2_byte", n2_byte, (s->N1_tx + n2_count));
- *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1))
- = n2_byte;
- } else {
+ if (!fifo8_is_full(&s->tx_fifo)) {
+ trace_pnv_spi_tx_append("n2_byte", n2_byte, (s->N1_tx + n2_count));
+ fifo8_push(&s->tx_fifo, n2_byte);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: TX_FIFO is full\n");
+ break;
+ }
+ } else if (!fifo8_is_full(&s->tx_fifo)) {
/*
* Regardless of whether or not N2 is set for TX or RX, we need
* the number of bytes in the payload to match the overall length
* of the operation.
*/
trace_pnv_spi_tx_append_FF("n2_byte");
- *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1))
- = 0xff;
+ fifo8_push(&s->tx_fifo, 0xff);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: TX_FIFO is full\n");
+ break;
}
n2_count++;
} /* end of while */
if (!stop) {
/* We have a TX and a full TDR or an RX and an empty RDR */
- trace_pnv_spi_tx_request("Shifting N2 frame", (*payload)->len);
- transfer(s, *payload);
+ trace_pnv_spi_tx_request("Shifting N2 frame", fifo8_num_used(&s->tx_fifo));
+ transfer(s);
/*
* If we are doing an N2 TX and the TDR is full we need to clear the
* TDR_full status. Do this here instead of up in the loop above so we
* don't log the message in every loop iteration.
*/
- if ((s->N2_tx != 0) &&
- (GETFIELD(SPI_STS_TDR_FULL, s->status) == 1)) {
+ if ((s->N2_tx != 0) && (GETFIELD(SPI_STS_TDR_FULL, s->status) == 1)) {
s->status = SETFIELD(SPI_STS_TDR_FULL, s->status, 0);
}
/*
@@ -680,8 +637,6 @@ static bool operation_shiftn2(PnvSpi *s, uint8_t opcode,
s->N1_bytes = 0;
s->N1_tx = 0;
s->N1_rx = 0;
- pnv_spi_xfer_buffer_free(*payload);
- *payload = NULL;
}
return stop;
} /* end of operation_shiftn2()*/
@@ -698,21 +653,9 @@ static void operation_sequencer(PnvSpi *s)
bool stop = false; /* Flag to stop the sequencer */
uint8_t opcode = 0;
uint8_t masked_opcode = 0;
+ uint8_t seq_index;
/*
- * PnvXferBuffer for containing the payload of the SPI frame.
- * This is a static because there are cases where a sequence has to stop
- * and wait for the target application to unload the RDR. If this occurs
- * during a sequence where N1 is not sent alone and instead combined with
- * N2 since the N1 tx length + the N2 tx length is less than the size of
- * the TDR.
- */
- static PnvXferBuffer *payload;
-
- if (payload == NULL) {
- payload = pnv_spi_xfer_buffer_new();
- }
- /*
* Clear the sequencer FSM error bit - general_SPI_status[3]
* before starting a sequence.
*/
@@ -725,11 +668,16 @@ static void operation_sequencer(PnvSpi *s)
s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, 0);
}
/*
+ * SPI_STS_SEQ_INDEX of status register is kept in seq_index variable and
+ * updated back to status register at the end of operation_sequencer().
+ */
+ seq_index = GETFIELD(SPI_STS_SEQ_INDEX, s->status);
+ /*
* There are only 8 possible operation IDs to iterate through though
* some operations may cause more than one frame to be sequenced.
*/
- while (get_seq_index(s) < NUM_SEQ_OPS) {
- opcode = s->seq_op[get_seq_index(s)];
+ while (seq_index < NUM_SEQ_OPS) {
+ opcode = s->seq_op[seq_index];
/* Set sequencer state to decode */
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_DECODE);
/*
@@ -746,7 +694,7 @@ static void operation_sequencer(PnvSpi *s)
case SEQ_OP_STOP:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
/* A stop operation in any position stops the sequencer */
- trace_pnv_spi_sequencer_op("STOP", get_seq_index(s));
+ trace_pnv_spi_sequencer_op("STOP", seq_index);
stop = true;
s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_IDLE);
@@ -757,7 +705,7 @@ static void operation_sequencer(PnvSpi *s)
case SEQ_OP_SELECT_SLAVE:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
- trace_pnv_spi_sequencer_op("SELECT_SLAVE", get_seq_index(s));
+ trace_pnv_spi_sequencer_op("SELECT_SLAVE", seq_index);
/*
* This device currently only supports a single responder
* connection at position 0. De-selecting a responder is fine
@@ -768,15 +716,12 @@ static void operation_sequencer(PnvSpi *s)
if (s->responder_select == 0) {
trace_pnv_spi_shifter_done();
qemu_set_irq(s->cs_line[0], 1);
- s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
- (get_seq_index(s) + 1));
+ seq_index++;
s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_DONE);
} else if (s->responder_select != 1) {
qemu_log_mask(LOG_GUEST_ERROR, "Slave selection other than 1 "
- "not supported, select = 0x%x\n",
- s->responder_select);
- trace_pnv_spi_sequencer_stop_requested("invalid "
- "responder select");
+ "not supported, select = 0x%x\n", s->responder_select);
+ trace_pnv_spi_sequencer_stop_requested("invalid responder select");
s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_IDLE);
stop = true;
} else {
@@ -796,13 +741,15 @@ static void operation_sequencer(PnvSpi *s)
* applies once a valid responder select has occurred.
*/
s->shift_n1_done = false;
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status,
+ SEQ_STATE_INDEX_INCREMENT);
}
break;
case SEQ_OP_SHIFT_N1:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
- trace_pnv_spi_sequencer_op("SHIFT_N1", get_seq_index(s));
+ trace_pnv_spi_sequencer_op("SHIFT_N1", seq_index);
/*
* Only allow a shift_n1 when the state is not IDLE or DONE.
* In either of those two cases the sequencer is not in a proper
@@ -834,13 +781,13 @@ static void operation_sequencer(PnvSpi *s)
* transmission to the responder without requiring a refill of
* the TDR between the two operations.
*/
- if (PNV_SPI_MASKED_OPCODE(s->seq_op[get_seq_index(s) + 1])
- == SEQ_OP_SHIFT_N2) {
+ if ((seq_index != 7) &&
+ PNV_SPI_MASKED_OPCODE(s->seq_op[(seq_index + 1)]) ==
+ SEQ_OP_SHIFT_N2) {
send_n1_alone = false;
}
- s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
- FSM_SHIFT_N1);
- stop = operation_shiftn1(s, opcode, &payload, send_n1_alone);
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_SHIFT_N1);
+ stop = operation_shiftn1(s, opcode, send_n1_alone);
if (stop) {
/*
* The operation code says to stop, this can occur if:
@@ -857,27 +804,27 @@ static void operation_sequencer(PnvSpi *s)
s->shift_n1_done = true;
s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
FSM_SHIFT_N2);
- s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
- (get_seq_index(s) + 1));
+ seq_index++;
} else {
/*
* This is case (1) or (2) so the sequencer needs to
* wait and NOT go to the next sequence yet.
*/
- s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
- FSM_WAIT);
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_WAIT);
}
} else {
/* Ok to move on to the next index */
s->shift_n1_done = true;
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status,
+ SEQ_STATE_INDEX_INCREMENT);
}
}
break;
case SEQ_OP_SHIFT_N2:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
- trace_pnv_spi_sequencer_op("SHIFT_N2", get_seq_index(s));
+ trace_pnv_spi_sequencer_op("SHIFT_N2", seq_index);
if (!s->shift_n1_done) {
qemu_log_mask(LOG_GUEST_ERROR, "Shift_N2 is not allowed if a "
"Shift_N1 is not done, shifter state = 0x%llx",
@@ -888,31 +835,30 @@ static void operation_sequencer(PnvSpi *s)
* error bit 3 (general_SPI_status[3]) in status reg.
*/
s->status = SETFIELD(SPI_STS_GEN_STATUS_B3, s->status, 1);
- trace_pnv_spi_sequencer_stop_requested("shift_n2 "
- "w/no shift_n1 done");
+ trace_pnv_spi_sequencer_stop_requested("shift_n2 w/no shift_n1 done");
stop = true;
} else {
/* Ok to do a Shift_N2 */
- s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
- FSM_SHIFT_N2);
- stop = operation_shiftn2(s, opcode, &payload);
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_SHIFT_N2);
+ stop = operation_shiftn2(s, opcode);
/*
* If the operation code says to stop set the shifter state to
* wait and stop
*/
if (stop) {
- s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
- FSM_WAIT);
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_WAIT);
} else {
/* Ok to move on to the next index */
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status,
+ SEQ_STATE_INDEX_INCREMENT);
}
}
break;
case SEQ_OP_BRANCH_IFNEQ_RDR:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
- trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_RDR", get_seq_index(s));
+ trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_RDR", seq_index);
/*
* The memory mapping register RDR match value is compared against
* the 16 rightmost bytes of the RDR (potentially with masking).
@@ -927,16 +873,26 @@ static void operation_sequencer(PnvSpi *s)
rdr_matched = does_rdr_match(s);
if (rdr_matched) {
trace_pnv_spi_RDR_match("success");
+ s->fail_count = 0;
/* A match occurred, increment the sequencer index. */
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status,
+ SEQ_STATE_INDEX_INCREMENT);
} else {
trace_pnv_spi_RDR_match("failed");
+ s->fail_count++;
/*
* Branch the sequencer to the index coded into the op
* code.
*/
- s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
- PNV_SPI_OPCODE_LO_NIBBLE(opcode));
+ seq_index = PNV_SPI_OPCODE_LO_NIBBLE(opcode);
+ }
+ if (s->fail_count >= RDR_MATCH_FAILURE_LIMIT) {
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi: RDR match failure"
+ " limit crossed %d times hence requesting "
+ "sequencer to stop.\n",
+ RDR_MATCH_FAILURE_LIMIT);
+ stop = true;
}
/*
* Regardless of where the branch ended up we want the
@@ -955,12 +911,13 @@ static void operation_sequencer(PnvSpi *s)
case SEQ_OP_TRANSFER_TDR:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
qemu_log_mask(LOG_GUEST_ERROR, "Transfer TDR is not supported\n");
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_INDEX_INCREMENT);
break;
case SEQ_OP_BRANCH_IFNEQ_INC_1:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
- trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_1", get_seq_index(s));
+ trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_1", seq_index);
/*
* The spec says the loop should execute count compare + 1 times.
* However we learned from engineering that we really only loop
@@ -974,18 +931,19 @@ static void operation_sequencer(PnvSpi *s)
* mask off all but the first three bits so we don't try to
* access beyond the sequencer_operation_reg boundary.
*/
- s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
- PNV_SPI_OPCODE_LO_NIBBLE(opcode));
+ seq_index = PNV_SPI_OPCODE_LO_NIBBLE(opcode);
s->loop_counter_1++;
} else {
/* Continue to next index if loop counter is reached */
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status,
+ SEQ_STATE_INDEX_INCREMENT);
}
break;
case SEQ_OP_BRANCH_IFNEQ_INC_2:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
- trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_2", get_seq_index(s));
+ trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_2", seq_index);
uint8_t condition2 = GETFIELD(SPI_CTR_CFG_CMP2,
s->regs[SPI_CTR_CFG_REG]);
/*
@@ -1000,19 +958,21 @@ static void operation_sequencer(PnvSpi *s)
* mask off all but the first three bits so we don't try to
* access beyond the sequencer_operation_reg boundary.
*/
- s->status = SETFIELD(SPI_STS_SEQ_INDEX,
- s->status, PNV_SPI_OPCODE_LO_NIBBLE(opcode));
+ seq_index = PNV_SPI_OPCODE_LO_NIBBLE(opcode);
s->loop_counter_2++;
} else {
/* Continue to next index if loop counter is reached */
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status,
+ SEQ_STATE_INDEX_INCREMENT);
}
break;
default:
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
/* Ignore unsupported operations. */
- next_sequencer_fsm(s);
+ seq_index++;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_INDEX_INCREMENT);
break;
} /* end of switch */
/*
@@ -1020,10 +980,10 @@ static void operation_sequencer(PnvSpi *s)
* we need to go ahead and end things as if there was a STOP at the
* end.
*/
- if (get_seq_index(s) == NUM_SEQ_OPS) {
+ if (seq_index == NUM_SEQ_OPS) {
/* All 8 opcodes completed, sequencer idling */
s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_IDLE);
- s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, 0);
+ seq_index = 0;
s->loop_counter_1 = 0;
s->loop_counter_2 = 0;
s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_IDLE);
@@ -1034,7 +994,8 @@ static void operation_sequencer(PnvSpi *s)
break;
}
} /* end of while */
- return;
+ /* Update sequencer index field in status.*/
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, seq_index);
} /* end of operation_sequencer() */
/*
@@ -1180,7 +1141,6 @@ static void pnv_spi_xscom_write(void *opaque, hwaddr addr,
qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi_regs: Invalid xscom "
"write at 0x%" PRIx32 "\n", reg);
}
- return;
}
static const MemoryRegionOps pnv_spi_xscom_ops = {
@@ -1193,21 +1153,24 @@ static const MemoryRegionOps pnv_spi_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static Property pnv_spi_properties[] = {
+static const Property pnv_spi_properties[] = {
DEFINE_PROP_UINT32("spic_num", PnvSpi, spic_num, 0),
+ DEFINE_PROP_UINT32("chip-id", PnvSpi, chip_id, 0),
DEFINE_PROP_UINT8("transfer_len", PnvSpi, transfer_len, 4),
- DEFINE_PROP_END_OF_LIST(),
};
static void pnv_spi_realize(DeviceState *dev, Error **errp)
{
PnvSpi *s = PNV_SPI(dev);
- g_autofree char *name = g_strdup_printf(TYPE_PNV_SPI_BUS ".%d",
- s->spic_num);
+ g_autofree char *name = g_strdup_printf("chip%d." TYPE_PNV_SPI_BUS ".%d",
+ s->chip_id, s->spic_num);
s->ssi_bus = ssi_create_bus(dev, name);
s->cs_line = g_new0(qemu_irq, 1);
qdev_init_gpio_out_named(DEVICE(s), s->cs_line, "cs", 1);
+ fifo8_create(&s->tx_fifo, PNV_SPI_FIFO_SIZE);
+ fifo8_create(&s->rx_fifo, PNV_SPI_FIFO_SIZE);
+
/* spi scoms */
pnv_xscom_region_init(&s->xscom_spic_regs, OBJECT(s), &pnv_spi_xscom_ops,
s, "xscom-spi", PNV10_XSCOM_PIB_SPIC_SIZE);
@@ -1236,7 +1199,7 @@ static int pnv_spi_dt_xscom(PnvXScomInterface *dev, void *fdt,
return 0;
}
-static void pnv_spi_class_init(ObjectClass *klass, void *data)
+static void pnv_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass);
@@ -1245,7 +1208,7 @@ static void pnv_spi_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV SPI";
dc->realize = pnv_spi_realize;
- dc->reset = do_reset;
+ device_class_set_legacy_reset(dc, do_reset);
device_class_set_props(dc, pnv_spi_properties);
}
@@ -1254,7 +1217,7 @@ static const TypeInfo pnv_spi_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(PnvSpi),
.class_init = pnv_spi_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c
index 1b4a401..3e01fef 100644
--- a/hw/ssi/sifive_spi.c
+++ b/hw/ssi/sifive_spi.c
@@ -328,17 +328,16 @@ static void sifive_spi_realize(DeviceState *dev, Error **errp)
fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
}
-static Property sifive_spi_properties[] = {
+static const Property sifive_spi_properties[] = {
DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sifive_spi_class_init(ObjectClass *klass, void *data)
+static void sifive_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, sifive_spi_properties);
- dc->reset = sifive_spi_reset;
+ device_class_set_legacy_reset(dc, sifive_spi_reset);
dc->realize = sifive_spi_realize;
}
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
index 3f357e8..d0de640 100644
--- a/hw/ssi/ssi.c
+++ b/hw/ssi/ssi.c
@@ -55,7 +55,7 @@ static bool ssi_bus_check_address(BusState *b, DeviceState *dev, Error **errp)
return true;
}
-static void ssi_bus_class_init(ObjectClass *klass, void *data)
+static void ssi_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
@@ -108,12 +108,11 @@ static void ssi_peripheral_realize(DeviceState *dev, Error **errp)
ssc->realize(s, errp);
}
-static Property ssi_peripheral_properties[] = {
+static const Property ssi_peripheral_properties[] = {
DEFINE_PROP_UINT8("cs", SSIPeripheral, cs_index, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ssi_peripheral_class_init(ObjectClass *klass, void *data)
+static void ssi_peripheral_class_init(ObjectClass *klass, const void *data)
{
SSIPeripheralClass *ssc = SSI_PERIPHERAL_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ssi/stm32f2xx_spi.c b/hw/ssi/stm32f2xx_spi.c
index a37139f..871d573 100644
--- a/hw/ssi/stm32f2xx_spi.c
+++ b/hw/ssi/stm32f2xx_spi.c
@@ -202,11 +202,11 @@ static void stm32f2xx_spi_init(Object *obj)
s->ssi = ssi_create_bus(dev, "ssi");
}
-static void stm32f2xx_spi_class_init(ObjectClass *klass, void *data)
+static void stm32f2xx_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_spi_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_spi_reset);
dc->vmsd = &vmstate_stm32f2xx_spi;
}
diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
index 089d269..2f36cf9 100644
--- a/hw/ssi/trace-events
+++ b/hw/ssi/trace-events
@@ -53,3 +53,13 @@ pnv_spi_rx_read_N2frame(void) ""
pnv_spi_shift_rx(uint8_t byte, uint32_t index) "byte = 0x%2.2x into RDR from payload index %d"
pnv_spi_sequencer_stop_requested(const char* reason) "due to %s"
pnv_spi_RDR_match(const char* result) "%s"
+
+# allwinner_a10_spi.c
+allwinner_a10_spi_update_irq(uint32_t level) "IRQ level is %d"
+allwinner_a10_spi_flush_txfifo_begin(uint32_t tx, uint32_t rx) "Begin: TX Fifo Size = %d, RX Fifo Size = %d"
+allwinner_a10_spi_flush_txfifo_end(uint32_t tx, uint32_t rx) "End: TX Fifo Size = %d, RX Fifo Size = %d"
+allwinner_a10_spi_burst_length(uint32_t len) "Burst length = %d"
+allwinner_a10_spi_tx(uint8_t byte) "write 0x%02x"
+allwinner_a10_spi_rx(uint8_t byte) "read 0x%02x"
+allwinner_a10_spi_read(const char* regname, uint32_t value) "reg[%s] => 0x%08x"
+allwinner_a10_spi_write(const char* regname, uint32_t value) "reg[%s] <= 0x%08x"
diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c
index 2e0687a..4144c8a 100644
--- a/hw/ssi/xilinx_spi.c
+++ b/hw/ssi/xilinx_spi.c
@@ -25,6 +25,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
@@ -32,6 +33,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/ssi/ssi.h"
#include "qom/object.h"
@@ -83,6 +85,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(XilinxSPI, XILINX_SPI)
struct XilinxSPI {
SysBusDevice parent_obj;
+ EndianMode model_endianness;
MemoryRegion mmio;
qemu_irq irq;
@@ -313,14 +316,17 @@ done:
xlx_spi_update_irq(s);
}
-static const MemoryRegionOps spi_ops = {
- .read = spi_read,
- .write = spi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
+static const MemoryRegionOps spi_ops[2] = {
+ [0 ... 1] = {
+ .read = spi_read,
+ .write = spi_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ },
+ [0].endianness = DEVICE_LITTLE_ENDIAN,
+ [1].endianness = DEVICE_BIG_ENDIAN,
};
static void xilinx_spi_realize(DeviceState *dev, Error **errp)
@@ -329,6 +335,12 @@ static void xilinx_spi_realize(DeviceState *dev, Error **errp)
XilinxSPI *s = XILINX_SPI(dev);
int i;
+ if (s->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
+ error_setg(errp, TYPE_XILINX_SPI " property 'endianness'"
+ " must be set to 'big' or 'little'");
+ return;
+ }
+
DB_PRINT("\n");
s->spi = ssi_create_bus(dev, "spi");
@@ -339,7 +351,8 @@ static void xilinx_spi_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->cs_lines[i]);
}
- memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
+ memory_region_init_io(&s->mmio, OBJECT(s),
+ &spi_ops[s->model_endianness == ENDIAN_MODE_BIG], s,
"xilinx-spi", R_MAX * 4);
sysbus_init_mmio(sbd, &s->mmio);
@@ -361,17 +374,17 @@ static const VMStateDescription vmstate_xilinx_spi = {
}
};
-static Property xilinx_spi_properties[] = {
+static const Property xilinx_spi_properties[] = {
+ DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XilinxSPI, model_endianness),
DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xilinx_spi_class_init(ObjectClass *klass, void *data)
+static void xilinx_spi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = xilinx_spi_realize;
- dc->reset = xlx_spi_reset;
+ device_class_set_legacy_reset(dc, xlx_spi_reset);
device_class_set_props(dc, xilinx_spi_properties);
dc->vmsd = &vmstate_xilinx_spi;
}
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 71952a4..a79f3b8 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -33,7 +33,7 @@
#include "hw/ssi/xilinx_spips.h"
#include "qapi/error.h"
#include "hw/register.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "migration/blocker.h"
#include "migration/vmstate.h"
@@ -620,7 +620,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
} else if (s->snoop_state == SNOOP_STRIPING ||
s->snoop_state == SNOOP_NONE) {
for (i = 0; i < num_effective_busses(s); ++i) {
- tx_rx[i] = fifo8_pop(&s->tx_fifo);
+ if (!fifo8_is_empty(&s->tx_fifo)) {
+ tx_rx[i] = fifo8_pop(&s->tx_fifo);
+ }
}
stripe8(tx_rx, num_effective_busses(s), false);
} else if (s->snoop_state >= SNOOP_ADDR) {
@@ -1418,19 +1420,17 @@ static const VMStateDescription vmstate_xlnx_zynqmp_qspips = {
}
};
-static Property xilinx_zynqmp_qspips_properties[] = {
+static const Property xilinx_zynqmp_qspips_properties[] = {
DEFINE_PROP_UINT32("dma-burst-size", XlnxZynqMPQSPIPS, dma_burst_size, 64),
- DEFINE_PROP_END_OF_LIST(),
};
-static Property xilinx_spips_properties[] = {
+static const Property xilinx_spips_properties[] = {
DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1),
DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4),
DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xilinx_qspips_class_init(ObjectClass *klass, void * data)
+static void xilinx_qspips_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
@@ -1442,13 +1442,13 @@ static void xilinx_qspips_class_init(ObjectClass *klass, void * data)
xsc->tx_fifo_size = TXFF_A_Q;
}
-static void xilinx_spips_class_init(ObjectClass *klass, void *data)
+static void xilinx_spips_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
dc->realize = xilinx_spips_realize;
- dc->reset = xilinx_spips_reset;
+ device_class_set_legacy_reset(dc, xilinx_spips_reset);
device_class_set_props(dc, xilinx_spips_properties);
dc->vmsd = &vmstate_xilinx_spips;
@@ -1458,13 +1458,13 @@ static void xilinx_spips_class_init(ObjectClass *klass, void *data)
xsc->tx_fifo_size = TXFF_A;
}
-static void xlnx_zynqmp_qspips_class_init(ObjectClass *klass, void * data)
+static void xlnx_zynqmp_qspips_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
dc->realize = xlnx_zynqmp_qspips_realize;
- dc->reset = xlnx_zynqmp_qspips_reset;
+ device_class_set_legacy_reset(dc, xlnx_zynqmp_qspips_reset);
dc->vmsd = &vmstate_xlnx_zynqmp_qspips;
device_class_set_props(dc, xilinx_zynqmp_qspips_properties);
xsc->reg_ops = &xlnx_zynqmp_qspips_ops;
diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c
index c479138..56d51ce 100644
--- a/hw/ssi/xlnx-versal-ospi.c
+++ b/hw/ssi/xlnx-versal-ospi.c
@@ -1825,18 +1825,17 @@ static const VMStateDescription vmstate_xlnx_versal_ospi = {
}
};
-static Property xlnx_versal_ospi_properties[] = {
+static const Property xlnx_versal_ospi_properties[] = {
DEFINE_PROP_BOOL("dac-with-indac", XlnxVersalOspi, dac_with_indac, false),
DEFINE_PROP_BOOL("indac-write-disabled", XlnxVersalOspi,
ind_write_disabled, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xlnx_versal_ospi_class_init(ObjectClass *klass, void *data)
+static void xlnx_versal_ospi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_versal_ospi_reset;
+ device_class_set_legacy_reset(dc, xlnx_versal_ospi_reset);
dc->realize = xlnx_versal_ospi_realize;
dc->vmsd = &vmstate_xlnx_versal_ospi;
device_class_set_props(dc, xlnx_versal_ospi_properties);
diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig
index 61fbb62..b3d823c 100644
--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -12,6 +12,12 @@ config A9_GTIMER
config HPET
bool
default y if PC
+ # The HPET has both a Rust and a C implementation
+ select HPET_C if !HAVE_RUST
+ select X_HPET_RUST if HAVE_RUST
+
+config HPET_C
+ bool
config I8254
bool
@@ -21,6 +27,9 @@ config ALLWINNER_A10_PIT
bool
select PTIMER
+config PXA2XX_TIMER
+ bool
+
config SIFIVE_PWM
bool
diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c
index 64d80cd..690140f 100644
--- a/hw/timer/a9gtimer.c
+++ b/hw/timer/a9gtimer.c
@@ -32,7 +32,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/core/cpu.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#ifndef A9_GTIMER_ERR_DEBUG
#define A9_GTIMER_ERR_DEBUG 0
@@ -373,18 +373,17 @@ static const VMStateDescription vmstate_a9_gtimer = {
}
};
-static Property a9_gtimer_properties[] = {
+static const Property a9_gtimer_properties[] = {
DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void a9_gtimer_class_init(ObjectClass *klass, void *data)
+static void a9_gtimer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = a9_gtimer_realize;
dc->vmsd = &vmstate_a9_gtimer;
- dc->reset = a9_gtimer_reset;
+ device_class_set_legacy_reset(dc, a9_gtimer_reset);
device_class_set_props(dc, a9_gtimer_properties);
}
diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
index a524de1..e4c3532 100644
--- a/hw/timer/allwinner-a10-pit.c
+++ b/hw/timer/allwinner-a10-pit.c
@@ -185,15 +185,14 @@ static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
static const MemoryRegionOps a10_pit_ops = {
.read = a10_pit_read,
.write = a10_pit_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
-static Property a10_pit_properties[] = {
+static const Property a10_pit_properties[] = {
DEFINE_PROP_UINT32("clk0-freq", AwA10PITState, clk_freq[0], 0),
DEFINE_PROP_UINT32("clk1-freq", AwA10PITState, clk_freq[1], 0),
DEFINE_PROP_UINT32("clk2-freq", AwA10PITState, clk_freq[2], 0),
DEFINE_PROP_UINT32("clk3-freq", AwA10PITState, clk_freq[3], 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_a10_pit = {
@@ -289,11 +288,11 @@ static void a10_pit_finalize(Object *obj)
}
}
-static void a10_pit_class_init(ObjectClass *klass, void *data)
+static void a10_pit_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = a10_pit_reset;
+ device_class_set_legacy_reset(dc, a10_pit_reset);
device_class_set_props(dc, a10_pit_properties);
dc->desc = "allwinner a10 timer";
dc->vmsd = &vmstate_a10_pit;
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index bca4cee..7cc5915 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -300,18 +300,17 @@ static const VMStateDescription vmstate_arm_mptimer = {
}
};
-static Property arm_mptimer_properties[] = {
+static const Property arm_mptimer_properties[] = {
DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void arm_mptimer_class_init(ObjectClass *klass, void *data)
+static void arm_mptimer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = arm_mptimer_realize;
dc->vmsd = &vmstate_arm_mptimer;
- dc->reset = arm_mptimer_reset;
+ device_class_set_legacy_reset(dc, arm_mptimer_reset);
device_class_set_props(dc, arm_mptimer_properties);
}
diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
index 0940e03..56638ff 100644
--- a/hw/timer/arm_timer.c
+++ b/hw/timer/arm_timer.c
@@ -387,13 +387,12 @@ static const TypeInfo icp_pit_info = {
.instance_init = icp_pit_init,
};
-static Property sp804_properties[] = {
+static const Property sp804_properties[] = {
DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000),
DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sp804_class_init(ObjectClass *klass, void *data)
+static void sp804_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
index f6b1ace..7e4ddcd 100644
--- a/hw/timer/armv7m_systick.c
+++ b/hw/timer/armv7m_systick.c
@@ -285,12 +285,12 @@ static const VMStateDescription vmstate_systick = {
}
};
-static void systick_class_init(ObjectClass *klass, void *data)
+static void systick_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_systick;
- dc->reset = systick_reset;
+ device_class_set_legacy_reset(dc, systick_reset);
dc->realize = systick_realize;
}
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index fc5c94b..57db035 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -239,9 +239,8 @@ static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
return value;
}
-static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
+static uint64_t aspeed_timer_read_common(AspeedTimerCtrlState *s, hwaddr offset)
{
- AspeedTimerCtrlState *s = opaque;
const int reg = (offset & 0xf) / 4;
uint64_t value;
@@ -256,10 +255,11 @@ static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg);
break;
default:
- value = ASPEED_TIMER_GET_CLASS(s)->read(s, offset);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ value = 0;
break;
}
- trace_aspeed_timer_read(offset, size, value);
return value;
}
@@ -276,7 +276,8 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
old_reload = t->reload;
t->reload = calculate_min_ticks(t, value);
- /* If the reload value was not previously set, or zero, and
+ /*
+ * If the reload value was not previously set, or zero, and
* the current value is valid, try to start the timer if it is
* enabled.
*/
@@ -312,7 +313,8 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
}
}
-/* Control register operations are broken out into helpers that can be
+/*
+ * Control register operations are broken out into helpers that can be
* explicitly called on aspeed_timer_reset(), but also from
* aspeed_timer_ctrl_op().
*/
@@ -396,7 +398,8 @@ static void aspeed_timer_set_ctrl(AspeedTimerCtrlState *s, uint32_t reg)
AspeedTimer *t;
const uint8_t enable_mask = BIT(op_enable);
- /* Handle a dependency between the 'enable' and remaining three
+ /*
+ * Handle a dependency between the 'enable' and remaining three
* configuration bits - i.e. if more than one bit in the control set has
* changed, including the 'enable' bit, then we want either disable the
* timer and perform configuration, or perform configuration and then
@@ -428,12 +431,11 @@ static void aspeed_timer_set_ctrl2(AspeedTimerCtrlState *s, uint32_t value)
trace_aspeed_timer_set_ctrl2(value);
}
-static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
+static void aspeed_timer_write_common(AspeedTimerCtrlState *s, hwaddr offset,
+ uint64_t value)
{
const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
const int reg = (offset & 0xf) / 4;
- AspeedTimerCtrlState *s = opaque;
switch (offset) {
/* Control Registers */
@@ -448,11 +450,25 @@ static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv);
break;
default:
- ASPEED_TIMER_GET_CLASS(s)->write(s, offset, value);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
break;
}
}
+static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AspeedTimerCtrlState *s = ASPEED_TIMER(opaque);
+ return ASPEED_TIMER_GET_CLASS(s)->read(s, offset);
+}
+
+static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ AspeedTimerCtrlState *s = ASPEED_TIMER(opaque);
+ ASPEED_TIMER_GET_CLASS(s)->write(s, offset, value);
+}
+
static const MemoryRegionOps aspeed_timer_ops = {
.read = aspeed_timer_read,
.write = aspeed_timer_write,
@@ -472,12 +488,15 @@ static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
break;
case 0x38:
case 0x3C:
- default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
value = 0;
break;
+ default:
+ value = aspeed_timer_read_common(s, offset);
+ break;
}
+ trace_aspeed_timer_read(offset, value);
return value;
}
@@ -492,10 +511,12 @@ static void aspeed_2400_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
break;
case 0x38:
case 0x3C:
- default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
+ default:
+ aspeed_timer_write_common(s, offset, value);
+ break;
}
}
@@ -511,12 +532,15 @@ static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
value = s->ctrl3 & BIT(0);
break;
case 0x3C:
- default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
value = 0;
break;
+ default:
+ value = aspeed_timer_read_common(s, offset);
+ break;
}
+ trace_aspeed_timer_read(offset, value);
return value;
}
@@ -545,8 +569,7 @@ static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
- __func__, offset);
+ aspeed_timer_write_common(s, offset, value);
break;
}
}
@@ -561,12 +584,15 @@ static uint64_t aspeed_2600_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
break;
case 0x38:
case 0x3C:
- default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
value = 0;
break;
+ default:
+ value = aspeed_timer_read_common(s, offset);
+ break;
}
+ trace_aspeed_timer_read(offset, value);
return value;
}
@@ -577,17 +603,209 @@ static void aspeed_2600_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
switch (offset) {
case 0x34:
- s->irq_sts &= tv;
+ s->irq_sts &= ~tv;
break;
case 0x3C:
aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
break;
-
case 0x38:
- default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
+ default:
+ aspeed_timer_write_common(s, offset, value);
+ break;
+ }
+}
+
+static void aspeed_2700_timer_set_ctrl(AspeedTimerCtrlState *s, int index,
+ uint32_t reg)
+{
+ const uint8_t overflow_interrupt_mask = BIT(op_overflow_interrupt);
+ const uint8_t external_clock_mask = BIT(op_external_clock);
+ const uint8_t pulse_enable_mask = BIT(op_pulse_enable);
+ const uint8_t enable_mask = BIT(op_enable);
+ AspeedTimer *t;
+ uint8_t t_old;
+ uint8_t t_new;
+ int shift;
+
+ /*
+ * Only 1 will set the specific bits to 1
+ * Handle a dependency between the 'enable' and remaining three
+ * configuration bits - i.e. if more than one bit in the control set has
+ * set, including the 'enable' bit, perform configuration and then
+ * enable the timer.
+ * Interrupt Status bit should not be set.
+ */
+
+ t = &s->timers[index];
+ shift = index * TIMER_CTRL_BITS;
+
+ t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK;
+ t_new = reg & TIMER_CTRL_MASK;
+
+ if (!(t_old & external_clock_mask) &&
+ (t_new & external_clock_mask)) {
+ aspeed_timer_ctrl_external_clock(t, true);
+ s->ctrl = deposit32(s->ctrl, shift + op_external_clock, 1, 1);
+ }
+
+ if (!(t_old & overflow_interrupt_mask) &&
+ (t_new & overflow_interrupt_mask)) {
+ aspeed_timer_ctrl_overflow_interrupt(t, true);
+ s->ctrl = deposit32(s->ctrl, shift + op_overflow_interrupt, 1, 1);
+ }
+
+
+ if (!(t_old & pulse_enable_mask) &&
+ (t_new & pulse_enable_mask)) {
+ aspeed_timer_ctrl_pulse_enable(t, true);
+ s->ctrl = deposit32(s->ctrl, shift + op_pulse_enable, 1, 1);
+ }
+
+ /* If we are enabling, do so last */
+ if (!(t_old & enable_mask) &&
+ (t_new & enable_mask)) {
+ aspeed_timer_ctrl_enable(t, true);
+ s->ctrl = deposit32(s->ctrl, shift + op_enable, 1, 1);
+ }
+}
+
+static void aspeed_2700_timer_clear_ctrl(AspeedTimerCtrlState *s, int index,
+ uint32_t reg)
+{
+ const uint8_t overflow_interrupt_mask = BIT(op_overflow_interrupt);
+ const uint8_t external_clock_mask = BIT(op_external_clock);
+ const uint8_t pulse_enable_mask = BIT(op_pulse_enable);
+ const uint8_t enable_mask = BIT(op_enable);
+ AspeedTimer *t;
+ uint8_t t_old;
+ uint8_t t_new;
+ int shift;
+
+ /*
+ * Only 1 will clear the specific bits to 0
+ * Handle a dependency between the 'enable' and remaining three
+ * configuration bits - i.e. if more than one bit in the control set has
+ * clear, including the 'enable' bit, then disable the timer and perform
+ * configuration
+ */
+
+ t = &s->timers[index];
+ shift = index * TIMER_CTRL_BITS;
+
+ t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK;
+ t_new = reg & TIMER_CTRL_MASK;
+
+ /* If we are disabling, do so first */
+ if ((t_old & enable_mask) &&
+ (t_new & enable_mask)) {
+ aspeed_timer_ctrl_enable(t, false);
+ s->ctrl = deposit32(s->ctrl, shift + op_enable, 1, 0);
+ }
+
+ if ((t_old & external_clock_mask) &&
+ (t_new & external_clock_mask)) {
+ aspeed_timer_ctrl_external_clock(t, false);
+ s->ctrl = deposit32(s->ctrl, shift + op_external_clock, 1, 0);
+ }
+
+ if ((t_old & overflow_interrupt_mask) &&
+ (t_new & overflow_interrupt_mask)) {
+ aspeed_timer_ctrl_overflow_interrupt(t, false);
+ s->ctrl = deposit32(s->ctrl, shift + op_overflow_interrupt, 1, 0);
+ }
+
+ if ((t_old & pulse_enable_mask) &&
+ (t_new & pulse_enable_mask)) {
+ aspeed_timer_ctrl_pulse_enable(t, false);
+ s->ctrl = deposit32(s->ctrl, shift + op_pulse_enable, 1, 0);
+ }
+
+ /* Clear interrupt status */
+ if (reg & 0x10000) {
+ s->irq_sts = deposit32(s->irq_sts, index, 1, 0);
+ }
+}
+
+static uint64_t aspeed_2700_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
+{
+ uint32_t timer_offset = offset & 0x3f;
+ int timer_index = offset >> 6;
+ uint64_t value = 0;
+
+ if (timer_index >= ASPEED_TIMER_NR_TIMERS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (timer_offset) {
+ /*
+ * Counter Status
+ * Counter Reload
+ * Counter First Matching
+ * Counter Second Matching
+ */
+ case 0x00 ... 0x0C:
+ value = aspeed_timer_get_value(&s->timers[timer_index],
+ timer_offset >> 2);
+ break;
+ /* Counter Control and Interrupt Status */
+ case 0x10:
+ value = deposit64(value, 0, 4,
+ extract32(s->ctrl, timer_index * 4, 4));
+ value = deposit64(value, 16, 1,
+ extract32(s->irq_sts, timer_index, 1));
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ value = 0;
+ break;
+ }
+ trace_aspeed_timer_read(offset, value);
+ return value;
+}
+
+static void aspeed_2700_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
+ uint64_t value)
+{
+ const uint32_t timer_value = (uint32_t)(value & 0xFFFFFFFF);
+ uint32_t timer_offset = offset & 0x3f;
+ int timer_index = offset >> 6;
+
+ if (timer_index >= ASPEED_TIMER_NR_TIMERS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ }
+
+ switch (timer_offset) {
+ /*
+ * Counter Status
+ * Counter Reload
+ * Counter First Matching
+ * Counter Second Matching
+ */
+ case 0x00 ... 0x0C:
+ aspeed_timer_set_value(s, timer_index, timer_offset >> 2,
+ timer_value);
+ break;
+ /* Counter Control Set and Interrupt Status */
+ case 0x10:
+ aspeed_2700_timer_set_ctrl(s, timer_index, timer_value);
+ break;
+ /* Counter Control Clear and Interrupr Status */
+ case 0x14:
+ aspeed_2700_timer_clear_ctrl(s, timer_index, timer_value);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ break;
}
}
@@ -623,7 +841,8 @@ static void aspeed_timer_reset(DeviceState *dev)
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
AspeedTimer *t = &s->timers[i];
- /* Explicitly call helpers to avoid any conditional behaviour through
+ /*
+ * Explicitly call helpers to avoid any conditional behaviour through
* aspeed_timer_set_ctrl().
*/
aspeed_timer_ctrl_enable(t, false);
@@ -671,18 +890,17 @@ static const VMStateDescription vmstate_aspeed_timer_state = {
}
};
-static Property aspeed_timer_properties[] = {
+static const Property aspeed_timer_properties[] = {
DEFINE_PROP_LINK("scu", AspeedTimerCtrlState, scu, TYPE_ASPEED_SCU,
AspeedSCUState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void timer_class_init(ObjectClass *klass, void *data)
+static void timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_timer_realize;
- dc->reset = aspeed_timer_reset;
+ device_class_set_legacy_reset(dc, aspeed_timer_reset);
dc->desc = "ASPEED Timer";
dc->vmsd = &vmstate_aspeed_timer_state;
device_class_set_props(dc, aspeed_timer_properties);
@@ -697,7 +915,7 @@ static const TypeInfo aspeed_timer_info = {
.abstract = true,
};
-static void aspeed_2400_timer_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
@@ -713,7 +931,7 @@ static const TypeInfo aspeed_2400_timer_info = {
.class_init = aspeed_2400_timer_class_init,
};
-static void aspeed_2500_timer_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
@@ -729,7 +947,7 @@ static const TypeInfo aspeed_2500_timer_info = {
.class_init = aspeed_2500_timer_class_init,
};
-static void aspeed_2600_timer_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
@@ -745,7 +963,7 @@ static const TypeInfo aspeed_2600_timer_info = {
.class_init = aspeed_2600_timer_class_init,
};
-static void aspeed_1030_timer_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
@@ -761,6 +979,22 @@ static const TypeInfo aspeed_1030_timer_info = {
.class_init = aspeed_1030_timer_class_init,
};
+static void aspeed_2700_timer_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 Timer";
+ awc->read = aspeed_2700_timer_read;
+ awc->write = aspeed_2700_timer_write;
+}
+
+static const TypeInfo aspeed_2700_timer_info = {
+ .name = TYPE_ASPEED_2700_TIMER,
+ .parent = TYPE_ASPEED_TIMER,
+ .class_init = aspeed_2700_timer_class_init,
+};
+
static void aspeed_timer_register_types(void)
{
type_register_static(&aspeed_timer_info);
@@ -768,6 +1002,7 @@ static void aspeed_timer_register_types(void)
type_register_static(&aspeed_2500_timer_info);
type_register_static(&aspeed_2600_timer_info);
type_register_static(&aspeed_1030_timer_info);
+ type_register_static(&aspeed_2700_timer_info);
}
type_init(aspeed_timer_register_types)
diff --git a/hw/timer/avr_timer16.c b/hw/timer/avr_timer16.c
index c48555d..012d829 100644
--- a/hw/timer/avr_timer16.c
+++ b/hw/timer/avr_timer16.c
@@ -542,11 +542,10 @@ static const MemoryRegionOps avr_timer16_ifr_ops = {
.impl = {.max_access_size = 1}
};
-static Property avr_timer16_properties[] = {
+static const Property avr_timer16_properties[] = {
DEFINE_PROP_UINT8("id", struct AVRTimer16State, id, 0),
DEFINE_PROP_UINT64("cpu-frequency-hz", struct AVRTimer16State,
cpu_freq_hz, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static void avr_timer16_pr(void *opaque, int irq, int level)
@@ -596,11 +595,11 @@ static void avr_timer16_realize(DeviceState *dev, Error **errp)
s->enabled = true;
}
-static void avr_timer16_class_init(ObjectClass *klass, void *data)
+static void avr_timer16_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = avr_timer16_reset;
+ device_class_set_legacy_reset(dc, avr_timer16_reset);
dc->realize = avr_timer16_realize;
device_class_set_props(dc, avr_timer16_properties);
}
diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c
index 3ec6460..7929aaa 100644
--- a/hw/timer/bcm2835_systmr.c
+++ b/hw/timer/bcm2835_systmr.c
@@ -154,12 +154,12 @@ static const VMStateDescription bcm2835_systmr_vmstate = {
}
};
-static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
+static void bcm2835_systmr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_systmr_realize;
- dc->reset = bcm2835_systmr_reset;
+ device_class_set_legacy_reset(dc, bcm2835_systmr_reset);
dc->vmsd = &bcm2835_systmr_vmstate;
}
diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c
index 54dbd4c..9c7ba16 100644
--- a/hw/timer/cadence_ttc.c
+++ b/hw/timer/cadence_ttc.c
@@ -451,7 +451,7 @@ static const VMStateDescription vmstate_cadence_ttc = {
}
};
-static void cadence_ttc_class_init(ObjectClass *klass, void *data)
+static void cadence_ttc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
index ddf9070..34c550a 100644
--- a/hw/timer/cmsdk-apb-dualtimer.c
+++ b/hw/timer/cmsdk-apb-dualtimer.c
@@ -534,13 +534,13 @@ static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
}
};
-static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
+static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cmsdk_apb_dualtimer_realize;
dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
- dc->reset = cmsdk_apb_dualtimer_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_dualtimer_reset);
}
static const TypeInfo cmsdk_apb_dualtimer_info = {
diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
index 814545c..4095267 100644
--- a/hw/timer/cmsdk-apb-timer.c
+++ b/hw/timer/cmsdk-apb-timer.c
@@ -261,13 +261,13 @@ static const VMStateDescription cmsdk_apb_timer_vmstate = {
}
};
-static void cmsdk_apb_timer_class_init(ObjectClass *klass, void *data)
+static void cmsdk_apb_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cmsdk_apb_timer_realize;
dc->vmsd = &cmsdk_apb_timer_vmstate;
- dc->reset = cmsdk_apb_timer_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_timer_reset);
}
static const TypeInfo cmsdk_apb_timer_info = {
diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c
index 9fc5c1d..355138d 100644
--- a/hw/timer/digic-timer.c
+++ b/hw/timer/digic-timer.c
@@ -161,11 +161,11 @@ static void digic_timer_finalize(Object *obj)
ptimer_free(s->ptimer);
}
-static void digic_timer_class_init(ObjectClass *klass, void *class_data)
+static void digic_timer_class_init(ObjectClass *klass, const void *class_data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = digic_timer_reset;
+ device_class_set_legacy_reset(dc, digic_timer_reset);
dc->vmsd = &vmstate_digic_timer;
}
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
deleted file mode 100644
index dd6d96b..0000000
--- a/hw/timer/etraxfs_timer.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * QEMU ETRAX Timers
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "qemu/timer.h"
-#include "hw/irq.h"
-#include "hw/ptimer.h"
-#include "qom/object.h"
-
-#define D(x)
-
-#define RW_TMR0_DIV 0x00
-#define R_TMR0_DATA 0x04
-#define RW_TMR0_CTRL 0x08
-#define RW_TMR1_DIV 0x10
-#define R_TMR1_DATA 0x14
-#define RW_TMR1_CTRL 0x18
-#define R_TIME 0x38
-#define RW_WD_CTRL 0x40
-#define R_WD_STAT 0x44
-#define RW_INTR_MASK 0x48
-#define RW_ACK_INTR 0x4c
-#define R_INTR 0x50
-#define R_MASKED_INTR 0x54
-
-#define TYPE_ETRAX_FS_TIMER "etraxfs-timer"
-typedef struct ETRAXTimerState ETRAXTimerState;
-DECLARE_INSTANCE_CHECKER(ETRAXTimerState, ETRAX_TIMER,
- TYPE_ETRAX_FS_TIMER)
-
-struct ETRAXTimerState {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq irq;
- qemu_irq nmi;
-
- ptimer_state *ptimer_t0;
- ptimer_state *ptimer_t1;
- ptimer_state *ptimer_wd;
-
- uint32_t wd_hits;
-
- /* Control registers. */
- uint32_t rw_tmr0_div;
- uint32_t r_tmr0_data;
- uint32_t rw_tmr0_ctrl;
-
- uint32_t rw_tmr1_div;
- uint32_t r_tmr1_data;
- uint32_t rw_tmr1_ctrl;
-
- uint32_t rw_wd_ctrl;
-
- uint32_t rw_intr_mask;
- uint32_t rw_ack_intr;
- uint32_t r_intr;
- uint32_t r_masked_intr;
-};
-
-static const VMStateDescription vmstate_etraxfs = {
- .name = "etraxfs",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_PTIMER(ptimer_t0, ETRAXTimerState),
- VMSTATE_PTIMER(ptimer_t1, ETRAXTimerState),
- VMSTATE_PTIMER(ptimer_wd, ETRAXTimerState),
-
- VMSTATE_UINT32(wd_hits, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_tmr0_div, ETRAXTimerState),
- VMSTATE_UINT32(r_tmr0_data, ETRAXTimerState),
- VMSTATE_UINT32(rw_tmr0_ctrl, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_tmr1_div, ETRAXTimerState),
- VMSTATE_UINT32(r_tmr1_data, ETRAXTimerState),
- VMSTATE_UINT32(rw_tmr1_ctrl, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_wd_ctrl, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_intr_mask, ETRAXTimerState),
- VMSTATE_UINT32(rw_ack_intr, ETRAXTimerState),
- VMSTATE_UINT32(r_intr, ETRAXTimerState),
- VMSTATE_UINT32(r_masked_intr, ETRAXTimerState),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint64_t
-timer_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXTimerState *t = opaque;
- uint32_t r = 0;
-
- switch (addr) {
- case R_TMR0_DATA:
- r = ptimer_get_count(t->ptimer_t0);
- break;
- case R_TMR1_DATA:
- r = ptimer_get_count(t->ptimer_t1);
- break;
- case R_TIME:
- r = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 10;
- break;
- case RW_INTR_MASK:
- r = t->rw_intr_mask;
- break;
- case R_MASKED_INTR:
- r = t->r_intr & t->rw_intr_mask;
- break;
- default:
- D(printf ("%s %x\n", __func__, addr));
- break;
- }
- return r;
-}
-
-static void update_ctrl(ETRAXTimerState *t, int tnum)
-{
- unsigned int op;
- unsigned int freq;
- unsigned int freq_hz;
- unsigned int div;
- uint32_t ctrl;
-
- ptimer_state *timer;
-
- if (tnum == 0) {
- ctrl = t->rw_tmr0_ctrl;
- div = t->rw_tmr0_div;
- timer = t->ptimer_t0;
- } else {
- ctrl = t->rw_tmr1_ctrl;
- div = t->rw_tmr1_div;
- timer = t->ptimer_t1;
- }
-
-
- op = ctrl & 3;
- freq = ctrl >> 2;
- freq_hz = 32000000;
-
- switch (freq)
- {
- case 0:
- case 1:
- D(printf ("extern or disabled timer clock?\n"));
- break;
- case 4: freq_hz = 29493000; break;
- case 5: freq_hz = 32000000; break;
- case 6: freq_hz = 32768000; break;
- case 7: freq_hz = 100000000; break;
- default:
- abort();
- break;
- }
-
- D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
- ptimer_transaction_begin(timer);
- ptimer_set_freq(timer, freq_hz);
- ptimer_set_limit(timer, div, 0);
-
- switch (op)
- {
- case 0:
- /* Load. */
- ptimer_set_limit(timer, div, 1);
- break;
- case 1:
- /* Hold. */
- ptimer_stop(timer);
- break;
- case 2:
- /* Run. */
- ptimer_run(timer, 0);
- break;
- default:
- abort();
- break;
- }
- ptimer_transaction_commit(timer);
-}
-
-static void timer_update_irq(ETRAXTimerState *t)
-{
- t->r_intr &= ~(t->rw_ack_intr);
- t->r_masked_intr = t->r_intr & t->rw_intr_mask;
-
- D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
- qemu_set_irq(t->irq, !!t->r_masked_intr);
-}
-
-static void timer0_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- t->r_intr |= 1;
- timer_update_irq(t);
-}
-
-static void timer1_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- t->r_intr |= 2;
- timer_update_irq(t);
-}
-
-static void watchdog_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- if (t->wd_hits == 0) {
- /* real hw gives a single tick before resetting but we are
- a bit friendlier to compensate for our slower execution. */
- ptimer_set_count(t->ptimer_wd, 10);
- ptimer_run(t->ptimer_wd, 1);
- qemu_irq_raise(t->nmi);
- }
- else
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
-
- t->wd_hits++;
-}
-
-static inline void timer_watchdog_update(ETRAXTimerState *t, uint32_t value)
-{
- unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
- unsigned int wd_key = t->rw_wd_ctrl >> 9;
- unsigned int wd_cnt = t->rw_wd_ctrl & 511;
- unsigned int new_key = value >> 9 & ((1 << 7) - 1);
- unsigned int new_cmd = (value >> 8) & 1;
-
- /* If the watchdog is enabled, they written key must match the
- complement of the previous. */
- wd_key = ~wd_key & ((1 << 7) - 1);
-
- if (wd_en && wd_key != new_key)
- return;
-
- D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n",
- wd_en, new_key, wd_key, new_cmd, wd_cnt));
-
- if (t->wd_hits)
- qemu_irq_lower(t->nmi);
-
- t->wd_hits = 0;
-
- ptimer_transaction_begin(t->ptimer_wd);
- ptimer_set_freq(t->ptimer_wd, 760);
- if (wd_cnt == 0)
- wd_cnt = 256;
- ptimer_set_count(t->ptimer_wd, wd_cnt);
- if (new_cmd)
- ptimer_run(t->ptimer_wd, 1);
- else
- ptimer_stop(t->ptimer_wd);
-
- t->rw_wd_ctrl = value;
- ptimer_transaction_commit(t->ptimer_wd);
-}
-
-static void
-timer_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXTimerState *t = opaque;
- uint32_t value = val64;
-
- switch (addr)
- {
- case RW_TMR0_DIV:
- t->rw_tmr0_div = value;
- break;
- case RW_TMR0_CTRL:
- D(printf ("RW_TMR0_CTRL=%x\n", value));
- t->rw_tmr0_ctrl = value;
- update_ctrl(t, 0);
- break;
- case RW_TMR1_DIV:
- t->rw_tmr1_div = value;
- break;
- case RW_TMR1_CTRL:
- D(printf ("RW_TMR1_CTRL=%x\n", value));
- t->rw_tmr1_ctrl = value;
- update_ctrl(t, 1);
- break;
- case RW_INTR_MASK:
- D(printf ("RW_INTR_MASK=%x\n", value));
- t->rw_intr_mask = value;
- timer_update_irq(t);
- break;
- case RW_WD_CTRL:
- timer_watchdog_update(t, value);
- break;
- case RW_ACK_INTR:
- t->rw_ack_intr = value;
- timer_update_irq(t);
- t->rw_ack_intr = 0;
- break;
- default:
- printf("%s " HWADDR_FMT_plx " %x\n", __func__, addr, value);
- break;
- }
-}
-
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void etraxfs_timer_reset_enter(Object *obj, ResetType type)
-{
- ETRAXTimerState *t = ETRAX_TIMER(obj);
-
- ptimer_transaction_begin(t->ptimer_t0);
- ptimer_stop(t->ptimer_t0);
- ptimer_transaction_commit(t->ptimer_t0);
- ptimer_transaction_begin(t->ptimer_t1);
- ptimer_stop(t->ptimer_t1);
- ptimer_transaction_commit(t->ptimer_t1);
- ptimer_transaction_begin(t->ptimer_wd);
- ptimer_stop(t->ptimer_wd);
- ptimer_transaction_commit(t->ptimer_wd);
- t->rw_wd_ctrl = 0;
- t->r_intr = 0;
- t->rw_intr_mask = 0;
-}
-
-static void etraxfs_timer_reset_hold(Object *obj, ResetType type)
-{
- ETRAXTimerState *t = ETRAX_TIMER(obj);
-
- qemu_irq_lower(t->irq);
-}
-
-static void etraxfs_timer_realize(DeviceState *dev, Error **errp)
-{
- ETRAXTimerState *t = ETRAX_TIMER(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_LEGACY);
- t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_LEGACY);
- t->ptimer_wd = ptimer_init(watchdog_hit, t, PTIMER_POLICY_LEGACY);
-
- sysbus_init_irq(sbd, &t->irq);
- sysbus_init_irq(sbd, &t->nmi);
-
- memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
- "etraxfs-timer", 0x5c);
- sysbus_init_mmio(sbd, &t->mmio);
-}
-
-static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ResettableClass *rc = RESETTABLE_CLASS(klass);
-
- dc->realize = etraxfs_timer_realize;
- dc->vmsd = &vmstate_etraxfs;
- rc->phases.enter = etraxfs_timer_reset_enter;
- rc->phases.hold = etraxfs_timer_reset_hold;
-}
-
-static const TypeInfo etraxfs_timer_info = {
- .name = TYPE_ETRAX_FS_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXTimerState),
- .class_init = etraxfs_timer_class_init,
-};
-
-static void etraxfs_timer_register_types(void)
-{
- type_register_static(&etraxfs_timer_info);
-}
-
-type_init(etraxfs_timer_register_types)
diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c
index 75098cd..bb0f9c8 100644
--- a/hw/timer/exynos4210_mct.c
+++ b/hw/timer/exynos4210_mct.c
@@ -815,7 +815,7 @@ static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
/* Both are counting */
icnto = remain / s->tcntb;
if (icnto) {
- tcnto = remain % (icnto * s->tcntb);
+ tcnto = remain % ((uint64_t)icnto * s->tcntb);
} else {
tcnto = remain % s->tcntb;
}
@@ -1546,11 +1546,11 @@ static void exynos4210_mct_finalize(Object *obj)
}
}
-static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
+static void exynos4210_mct_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_mct_reset;
+ device_class_set_legacy_reset(dc, exynos4210_mct_reset);
dc->vmsd = &vmstate_exynos4210_mct_state;
}
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
index ca330e9..69f737a 100644
--- a/hw/timer/exynos4210_pwm.c
+++ b/hw/timer/exynos4210_pwm.c
@@ -420,11 +420,11 @@ static void exynos4210_pwm_finalize(Object *obj)
}
}
-static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
+static void exynos4210_pwm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_pwm_reset;
+ device_class_set_legacy_reset(dc, exynos4210_pwm_reset);
dc->vmsd = &vmstate_exynos4210_pwm_state;
}
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
index 4990885..0e06fa0 100644
--- a/hw/timer/grlib_gptimer.c
+++ b/hw/timer/grlib_gptimer.c
@@ -403,19 +403,18 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &unit->iomem);
}
-static Property grlib_gptimer_properties[] = {
+static const Property grlib_gptimer_properties[] = {
DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
- DEFINE_PROP_END_OF_LIST(),
};
-static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+static void grlib_gptimer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = grlib_gptimer_realize;
- dc->reset = grlib_gptimer_reset;
+ device_class_set_legacy_reset(dc, grlib_gptimer_reset);
device_class_set_props(dc, grlib_gptimer_properties);
}
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 471950a..cb48cc1 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -36,10 +36,12 @@
#include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h"
#include "hw/timer/i8254.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qom/object.h"
#include "trace.h"
+struct hpet_fw_config hpet_fw_cfg = {.count = UINT8_MAX};
+
#define HPET_MSI_SUPPORT 0
OBJECT_DECLARE_SIMPLE_TYPE(HPETState, HPET)
@@ -75,6 +77,7 @@ struct HPETState {
uint8_t rtc_irq_level;
qemu_irq pit_enabled;
uint8_t num_timers;
+ uint8_t num_timers_save;
uint32_t intcap;
HPETTimer timer[HPET_MAX_TIMERS];
@@ -235,15 +238,12 @@ static int hpet_pre_save(void *opaque)
s->hpet_counter = hpet_get_ticks(s);
}
- return 0;
-}
-
-static int hpet_pre_load(void *opaque)
-{
- HPETState *s = opaque;
-
- /* version 1 only supports 3, later versions will load the actual value */
- s->num_timers = HPET_MIN_TIMERS;
+ /*
+ * The number of timers must match on source and destination, but it was
+ * also added to the migration stream. Check that it matches the value
+ * that was configured.
+ */
+ s->num_timers_save = s->num_timers;
return 0;
}
@@ -251,12 +251,7 @@ static bool hpet_validate_num_timers(void *opaque, int version_id)
{
HPETState *s = opaque;
- if (s->num_timers < HPET_MIN_TIMERS) {
- return false;
- } else if (s->num_timers > HPET_MAX_TIMERS) {
- return false;
- }
- return true;
+ return s->num_timers == s->num_timers_save;
}
static int hpet_post_load(void *opaque, int version_id)
@@ -275,16 +270,6 @@ static int hpet_post_load(void *opaque, int version_id)
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
- /* Push number of timers into capability returned via HPET_ID */
- s->capability &= ~HPET_ID_NUM_TIM_MASK;
- s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
- hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
-
- /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */
- s->flags &= ~(1 << HPET_MSI_SUPPORT);
- if (s->timer[0].config & HPET_TN_FSB_CAP) {
- s->flags |= 1 << HPET_MSI_SUPPORT;
- }
return 0;
}
@@ -343,17 +328,16 @@ static const VMStateDescription vmstate_hpet_timer = {
static const VMStateDescription vmstate_hpet = {
.name = "hpet",
.version_id = 2,
- .minimum_version_id = 1,
+ .minimum_version_id = 2,
.pre_save = hpet_pre_save,
- .pre_load = hpet_pre_load,
.post_load = hpet_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT64(config, HPETState),
VMSTATE_UINT64(isr, HPETState),
VMSTATE_UINT64(hpet_counter, HPETState),
- VMSTATE_UINT8_V(num_timers, HPETState, 2),
- VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers),
- VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
+ VMSTATE_UINT8(num_timers_save, HPETState),
+ VMSTATE_VALIDATE("num_timers must match", hpet_validate_num_timers),
+ VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers_save, 0,
vmstate_hpet_timer, HPETTimer),
VMSTATE_END_OF_LIST()
},
@@ -442,30 +426,11 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
uint64_t cur_tick;
trace_hpet_ram_read(addr);
+ addr &= ~4;
- /*address range of all TN regs*/
- if (addr >= 0x100 && addr <= 0x3ff) {
- uint8_t timer_id = (addr - 0x100) / 0x20;
- HPETTimer *timer = &s->timer[timer_id];
-
- if (timer_id > s->num_timers) {
- trace_hpet_timer_id_out_of_range(timer_id);
- return 0;
- }
-
- switch (addr & 0x18) {
- case HPET_TN_CFG: // including interrupt capabilities
- return timer->config >> shift;
- case HPET_TN_CMP: // comparator register
- return timer->cmp >> shift;
- case HPET_TN_ROUTE:
- return timer->fsb >> shift;
- default:
- trace_hpet_ram_read_invalid();
- break;
- }
- } else {
- switch (addr & ~4) {
+ /*address range of all global regs*/
+ if (addr <= 0xff) {
+ switch (addr) {
case HPET_ID: // including HPET_PERIOD
return s->capability >> shift;
case HPET_CFG:
@@ -484,6 +449,26 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
trace_hpet_ram_read_invalid();
break;
}
+ } else {
+ uint8_t timer_id = (addr - 0x100) / 0x20;
+ HPETTimer *timer = &s->timer[timer_id];
+
+ if (timer_id > s->num_timers) {
+ trace_hpet_timer_id_out_of_range(timer_id);
+ return 0;
+ }
+
+ switch (addr & 0x1f) {
+ case HPET_TN_CFG: // including interrupt capabilities
+ return timer->config >> shift;
+ case HPET_TN_CMP: // comparator register
+ return timer->cmp >> shift;
+ case HPET_TN_ROUTE:
+ return timer->fsb >> shift;
+ default:
+ trace_hpet_ram_read_invalid();
+ break;
+ }
}
return 0;
}
@@ -498,9 +483,67 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
uint64_t old_val, new_val, cleared;
trace_hpet_ram_write(addr, value);
+ addr &= ~4;
- /*address range of all TN regs*/
- if (addr >= 0x100 && addr <= 0x3ff) {
+ /*address range of all global regs*/
+ if (addr <= 0xff) {
+ switch (addr) {
+ case HPET_ID:
+ return;
+ case HPET_CFG:
+ old_val = s->config;
+ new_val = deposit64(old_val, shift, len, value);
+ new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
+ s->config = new_val;
+ if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+ /* Enable main counter and interrupt generation. */
+ s->hpet_offset =
+ ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ for (i = 0; i < s->num_timers; i++) {
+ if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
+ update_irq(&s->timer[i], 1);
+ }
+ hpet_set_timer(&s->timer[i]);
+ }
+ } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+ /* Halt main counter and disable interrupt generation. */
+ s->hpet_counter = hpet_get_ticks(s);
+ for (i = 0; i < s->num_timers; i++) {
+ hpet_del_timer(&s->timer[i]);
+ }
+ }
+ /* i8254 and RTC output pins are disabled
+ * when HPET is in legacy mode */
+ if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+ qemu_set_irq(s->pit_enabled, 0);
+ qemu_irq_lower(s->irqs[0]);
+ qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
+ } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+ qemu_irq_lower(s->irqs[0]);
+ qemu_set_irq(s->pit_enabled, 1);
+ qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
+ }
+ break;
+ case HPET_STATUS:
+ new_val = value << shift;
+ cleared = new_val & s->isr;
+ for (i = 0; i < s->num_timers; i++) {
+ if (cleared & (1 << i)) {
+ update_irq(&s->timer[i], 0);
+ }
+ }
+ break;
+ case HPET_COUNTER:
+ if (hpet_enabled(s)) {
+ trace_hpet_ram_write_counter_write_while_enabled();
+ }
+ s->hpet_counter = deposit64(s->hpet_counter, shift, len, value);
+ break;
+ default:
+ trace_hpet_ram_write_invalid();
+ break;
+ }
+ } else {
uint8_t timer_id = (addr - 0x100) / 0x20;
HPETTimer *timer = &s->timer[timer_id];
@@ -566,63 +609,6 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
break;
}
return;
- } else {
- switch (addr & ~4) {
- case HPET_ID:
- return;
- case HPET_CFG:
- old_val = s->config;
- new_val = deposit64(old_val, shift, len, value);
- new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
- s->config = new_val;
- if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
- /* Enable main counter and interrupt generation. */
- s->hpet_offset =
- ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- for (i = 0; i < s->num_timers; i++) {
- if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
- update_irq(&s->timer[i], 1);
- }
- hpet_set_timer(&s->timer[i]);
- }
- } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
- /* Halt main counter and disable interrupt generation. */
- s->hpet_counter = hpet_get_ticks(s);
- for (i = 0; i < s->num_timers; i++) {
- hpet_del_timer(&s->timer[i]);
- }
- }
- /* i8254 and RTC output pins are disabled
- * when HPET is in legacy mode */
- if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
- qemu_set_irq(s->pit_enabled, 0);
- qemu_irq_lower(s->irqs[0]);
- qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
- } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
- qemu_irq_lower(s->irqs[0]);
- qemu_set_irq(s->pit_enabled, 1);
- qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
- }
- break;
- case HPET_STATUS:
- new_val = value << shift;
- cleared = new_val & s->isr;
- for (i = 0; i < s->num_timers; i++) {
- if (cleared & (1 << i)) {
- update_irq(&s->timer[i], 0);
- }
- }
- break;
- case HPET_COUNTER:
- if (hpet_enabled(s)) {
- trace_hpet_ram_write_counter_write_while_enabled();
- }
- s->hpet_counter = deposit64(s->hpet_counter, shift, len, value);
- break;
- default:
- trace_hpet_ram_write_invalid();
- break;
- }
}
}
@@ -665,8 +651,8 @@ static void hpet_reset(DeviceState *d)
s->hpet_counter = 0ULL;
s->hpet_offset = 0ULL;
s->config = 0ULL;
- hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
- hpet_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr;
+ hpet_fw_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
+ hpet_fw_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr;
/* to document that the RTC lowers its output on reset as well */
s->rtc_irq_level = 0;
@@ -705,30 +691,31 @@ static void hpet_realize(DeviceState *dev, Error **errp)
int i;
HPETTimer *timer;
+ if (s->num_timers < HPET_MIN_TIMERS || s->num_timers > HPET_MAX_TIMERS) {
+ error_setg(errp, "hpet.num_timers must be between %d and %d",
+ HPET_MIN_TIMERS, HPET_MAX_TIMERS);
+ return;
+ }
if (!s->intcap) {
- warn_report("Hpet's intcap not initialized");
+ error_setg(errp, "hpet.hpet-intcap not initialized");
+ return;
}
- if (hpet_cfg.count == UINT8_MAX) {
+ if (hpet_fw_cfg.count == UINT8_MAX) {
/* first instance */
- hpet_cfg.count = 0;
+ hpet_fw_cfg.count = 0;
}
- if (hpet_cfg.count == 8) {
- error_setg(errp, "Only 8 instances of HPET is allowed");
+ if (hpet_fw_cfg.count == 8) {
+ error_setg(errp, "Only 8 instances of HPET are allowed");
return;
}
- s->hpet_id = hpet_cfg.count++;
+ s->hpet_id = hpet_fw_cfg.count++;
for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
sysbus_init_irq(sbd, &s->irqs[i]);
}
- if (s->num_timers < HPET_MIN_TIMERS) {
- s->num_timers = HPET_MIN_TIMERS;
- } else if (s->num_timers > HPET_MAX_TIMERS) {
- s->num_timers = HPET_MAX_TIMERS;
- }
for (i = 0; i < HPET_MAX_TIMERS; i++) {
timer = &s->timer[i];
timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer);
@@ -736,7 +723,7 @@ static void hpet_realize(DeviceState *dev, Error **errp)
timer->state = s;
}
- /* 64-bit main counter; LegacyReplacementRoute. */
+ /* 64-bit General Capabilities and ID Register; LegacyReplacementRoute. */
s->capability = 0x8086a001ULL;
s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
s->capability |= ((uint64_t)(HPET_CLK_PERIOD * FS_PER_NS) << 32);
@@ -745,20 +732,19 @@ static void hpet_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out(dev, &s->pit_enabled, 1);
}
-static Property hpet_device_properties[] = {
+static const Property hpet_device_properties[] = {
DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0),
DEFINE_PROP_BOOL("hpet-offset-saved", HPETState, hpet_offset_saved, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void hpet_device_class_init(ObjectClass *klass, void *data)
+static void hpet_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = hpet_realize;
- dc->reset = hpet_reset;
+ device_class_set_legacy_reset(dc, hpet_reset);
dc->vmsd = &vmstate_hpet;
device_class_set_props(dc, hpet_device_properties);
}
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
index c235496..4b25c48 100644
--- a/hw/timer/i8254.c
+++ b/hw/timer/i8254.c
@@ -350,7 +350,7 @@ static void pit_realizefn(DeviceState *dev, Error **errp)
pc->parent_realize(dev, errp);
}
-static void pit_class_initfn(ObjectClass *klass, void *data)
+static void pit_class_initfn(ObjectClass *klass, const void *data)
{
PITClass *pc = PIT_CLASS(klass);
PITCommonClass *k = PIT_COMMON_CLASS(klass);
@@ -360,7 +360,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data)
k->set_channel_gate = pit_set_channel_gate;
k->get_channel_info = pit_get_channel_info_common;
k->post_load = pit_post_load;
- dc->reset = pit_reset;
+ device_class_set_legacy_reset(dc, pit_reset);
}
static const TypeInfo pit_info = {
diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c
index 28fdabc..ad09159 100644
--- a/hw/timer/i8254_common.c
+++ b/hw/timer/i8254_common.c
@@ -238,12 +238,11 @@ static const VMStateDescription vmstate_pit_common = {
}
};
-static Property pit_common_properties[] = {
+static const Property pit_common_properties[] = {
DEFINE_PROP_UINT32("iobase", PITCommonState, iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pit_common_class_init(ObjectClass *klass, void *data)
+static void pit_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c
index 4917388..c7320ef 100644
--- a/hw/timer/ibex_timer.c
+++ b/hw/timer/ibex_timer.c
@@ -263,9 +263,8 @@ static const VMStateDescription vmstate_ibex_timer = {
}
};
-static Property ibex_timer_properties[] = {
+static const Property ibex_timer_properties[] = {
DEFINE_PROP_UINT32("timebase-freq", IbexTimerState, timebase_freq, 10000),
- DEFINE_PROP_END_OF_LIST(),
};
static void ibex_timer_init(Object *obj)
@@ -287,11 +286,11 @@ static void ibex_timer_realize(DeviceState *dev, Error **errp)
}
-static void ibex_timer_class_init(ObjectClass *klass, void *data)
+static void ibex_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ibex_timer_reset;
+ device_class_set_legacy_reset(dc, ibex_timer_reset);
dc->vmsd = &vmstate_ibex_timer;
dc->realize = ibex_timer_realize;
device_class_set_props(dc, ibex_timer_properties);
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index bd62520..6123321 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -427,12 +427,12 @@ static void imx_epit_dev_reset(DeviceState *dev)
imx_epit_reset(s, true);
}
-static void imx_epit_class_init(ObjectClass *klass, void *data)
+static void imx_epit_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_epit_realize;
- dc->reset = imx_epit_dev_reset;
+ device_class_set_legacy_reset(dc, imx_epit_dev_reset);
dc->vmsd = &vmstate_imx_timer_epit;
dc->desc = "i.MX periodic timer";
}
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index a8edaec..8c7cbfd 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -18,18 +18,7 @@
#include "migration/vmstate.h"
#include "qemu/module.h"
#include "qemu/log.h"
-
-#ifndef DEBUG_IMX_GPT
-#define DEBUG_IMX_GPT 0
-#endif
-
-#define DPRINTF(fmt, args...) \
- do { \
- if (DEBUG_IMX_GPT) { \
- fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \
- __func__, ##args); \
- } \
- } while (0)
+#include "trace.h"
static const char *imx_gpt_reg_name(uint32_t reg)
{
@@ -137,6 +126,17 @@ static const IMXClk imx7_gpt_clocks[] = {
CLK_NONE, /* 111 not defined */
};
+static const IMXClk imx8mp_gpt_clocks[] = {
+ CLK_NONE, /* 000 No clock source */
+ CLK_IPG, /* 001 ipg_clk, 532MHz */
+ CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
+ CLK_EXT, /* 011 External clock */
+ CLK_32k, /* 100 ipg_clk_32k */
+ CLK_HIGH, /* 101 ipg_clk_16M */
+ CLK_NONE, /* 110 not defined */
+ CLK_NONE, /* 111 not defined */
+};
+
/* Must be called from within ptimer_transaction_begin/commit block */
static void imx_gpt_set_freq(IMXGPTState *s)
{
@@ -145,7 +145,7 @@ static void imx_gpt_set_freq(IMXGPTState *s)
s->freq = imx_ccm_get_clock_frequency(s->ccm,
s->clocks[clksrc]) / (1 + s->pr);
- DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq);
+ trace_imx_gpt_set_freq(clksrc, s->freq);
if (s->freq) {
ptimer_set_freq(s->timer, s->freq);
@@ -317,7 +317,7 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size)
break;
}
- DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value);
+ trace_imx_gpt_read(imx_gpt_reg_name(offset >> 2), reg_value);
return reg_value;
}
@@ -384,8 +384,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
IMXGPTState *s = IMX_GPT(opaque);
uint32_t oldreg;
- DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2),
- (uint32_t)value);
+ trace_imx_gpt_write(imx_gpt_reg_name(offset >> 2), (uint32_t)value);
switch (offset >> 2) {
case 0:
@@ -485,7 +484,7 @@ static void imx_gpt_timeout(void *opaque)
{
IMXGPTState *s = IMX_GPT(opaque);
- DPRINTF("\n");
+ trace_imx_gpt_timeout();
s->sr |= s->next_int;
s->next_int = 0;
@@ -519,12 +518,12 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp)
s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_LEGACY);
}
-static void imx_gpt_class_init(ObjectClass *klass, void *data)
+static void imx_gpt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_gpt_realize;
- dc->reset = imx_gpt_reset;
+ device_class_set_legacy_reset(dc, imx_gpt_reset);
dc->vmsd = &vmstate_imx_timer_gpt;
dc->desc = "i.MX general timer";
}
@@ -564,6 +563,13 @@ static void imx7_gpt_init(Object *obj)
s->clocks = imx7_gpt_clocks;
}
+static void imx8mp_gpt_init(Object *obj)
+{
+ IMXGPTState *s = IMX_GPT(obj);
+
+ s->clocks = imx8mp_gpt_clocks;
+}
+
static const TypeInfo imx25_gpt_info = {
.name = TYPE_IMX25_GPT,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -596,6 +602,12 @@ static const TypeInfo imx7_gpt_info = {
.instance_init = imx7_gpt_init,
};
+static const TypeInfo imx8mp_gpt_info = {
+ .name = TYPE_IMX8MP_GPT,
+ .parent = TYPE_IMX25_GPT,
+ .instance_init = imx8mp_gpt_init,
+};
+
static void imx_gpt_register_types(void)
{
type_register_static(&imx25_gpt_info);
@@ -603,6 +615,7 @@ static void imx_gpt_register_types(void)
type_register_static(&imx6_gpt_info);
type_register_static(&imx6ul_gpt_info);
type_register_static(&imx7_gpt_info);
+ type_register_static(&imx8mp_gpt_info);
}
type_init(imx_gpt_register_types)
diff --git a/hw/timer/meson.build b/hw/timer/meson.build
index 8042785..178321c 100644
--- a/hw/timer/meson.build
+++ b/hw/timer/meson.build
@@ -10,11 +10,10 @@ system_ss.add(when: 'CONFIG_CMSDK_APB_TIMER', if_true: files('cmsdk-apb-timer.c'
system_ss.add(when: 'CONFIG_RENESAS_TMR', if_true: files('renesas_tmr.c'))
system_ss.add(when: 'CONFIG_RENESAS_CMT', if_true: files('renesas_cmt.c'))
system_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic-timer.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_timer.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pwm.c'))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_gptimer.c'))
-system_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c'))
+system_ss.add(when: 'CONFIG_HPET_C', if_true: files('hpet.c'))
system_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c'))
@@ -22,9 +21,7 @@ system_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c'))
system_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-timer.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_timer.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gptimer.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c'))
+system_ss.add(when: 'CONFIG_PXA2XX_TIMER', if_true: files('pxa2xx_timer.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c'))
system_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c'))
system_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_timer.c'))
diff --git a/hw/timer/mss-timer.c b/hw/timer/mss-timer.c
index b66aed5..2ce8211 100644
--- a/hw/timer/mss-timer.c
+++ b/hw/timer/mss-timer.c
@@ -279,14 +279,13 @@ static const VMStateDescription vmstate_mss_timer = {
}
};
-static Property mss_timer_properties[] = {
+static const Property mss_timer_properties[] = {
/* Libero GUI shows 100Mhz as default for clocks */
DEFINE_PROP_UINT32("clock-frequency", MSSTimerState, freq_hz,
100 * 1000000),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mss_timer_class_init(ObjectClass *klass, void *data)
+static void mss_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
index c55ba02..6a116ad 100644
--- a/hw/timer/npcm7xx_timer.c
+++ b/hw/timer/npcm7xx_timer.c
@@ -689,7 +689,7 @@ static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
},
};
-static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
+static void npcm7xx_timer_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
index a33166a..e228fde 100644
--- a/hw/timer/nrf51_timer.c
+++ b/hw/timer/nrf51_timer.c
@@ -379,16 +379,15 @@ static const VMStateDescription vmstate_nrf51_timer = {
}
};
-static Property nrf51_timer_properties[] = {
+static const Property nrf51_timer_properties[] = {
DEFINE_PROP_UINT8("id", NRF51TimerState, id, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nrf51_timer_class_init(ObjectClass *klass, void *data)
+static void nrf51_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = nrf51_timer_reset;
+ device_class_set_legacy_reset(dc, nrf51_timer_reset);
dc->vmsd = &vmstate_nrf51_timer;
device_class_set_props(dc, nrf51_timer_properties);
}
diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c
deleted file mode 100644
index 34e6af7..0000000
--- a/hw/timer/omap_gptimer.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * TI OMAP2 general purpose timers emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-
-/* GP timers */
-struct omap_gp_timer_s {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq wkup;
- qemu_irq in;
- qemu_irq out;
- omap_clk clk;
- QEMUTimer *timer;
- QEMUTimer *match;
- struct omap_target_agent_s *ta;
-
- int in_val;
- int out_val;
- int64_t time;
- int64_t rate;
- int64_t ticks_per_sec;
-
- int16_t config;
- int status;
- int it_ena;
- int wu_ena;
- int enable;
- int inout;
- int capt2;
- int pt;
- enum {
- gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
- } trigger;
- enum {
- gpt_capture_none, gpt_capture_rising,
- gpt_capture_falling, gpt_capture_both
- } capture;
- int scpwm;
- int ce;
- int pre;
- int ptv;
- int ar;
- int st;
- int posted;
- uint32_t val;
- uint32_t load_val;
- uint32_t capture_val[2];
- uint32_t match_val;
- int capt_num;
-
- uint16_t writeh; /* LSB */
- uint16_t readh; /* MSB */
-};
-
-#define GPT_TCAR_IT (1 << 2)
-#define GPT_OVF_IT (1 << 1)
-#define GPT_MAT_IT (1 << 0)
-
-static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
-{
- if (timer->it_ena & it) {
- if (!timer->status)
- qemu_irq_raise(timer->irq);
-
- timer->status |= it;
- /* Or are the status bits set even when masked?
- * i.e. is masking applied before or after the status register? */
- }
-
- if (timer->wu_ena & it)
- qemu_irq_pulse(timer->wkup);
-}
-
-static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
-{
- if (!timer->inout && timer->out_val != level) {
- timer->out_val = level;
- qemu_set_irq(timer->out, level);
- }
-}
-
-static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
-{
- uint64_t distance;
-
- if (timer->st && timer->rate) {
- distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
- distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
-
- if (distance >= 0xffffffff - timer->val)
- return 0xffffffff;
- else
- return timer->val + distance;
- } else
- return timer->val;
-}
-
-static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
-{
- if (timer->st) {
- timer->val = omap_gp_timer_read(timer);
- timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
-}
-
-static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
-{
- int64_t expires, matches;
-
- if (timer->st && timer->rate) {
- expires = muldiv64(0x100000000ll - timer->val,
- timer->ticks_per_sec, timer->rate);
- timer_mod(timer->timer, timer->time + expires);
-
- if (timer->ce && timer->match_val >= timer->val) {
- matches = muldiv64(timer->ticks_per_sec,
- timer->match_val - timer->val, timer->rate);
- timer_mod(timer->match, timer->time + matches);
- } else
- timer_del(timer->match);
- } else {
- timer_del(timer->timer);
- timer_del(timer->match);
- omap_gp_timer_out(timer, timer->scpwm);
- }
-}
-
-static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
-{
- if (timer->pt)
- /* TODO in overflow-and-match mode if the first event to
- * occur is the match, don't toggle. */
- omap_gp_timer_out(timer, !timer->out_val);
- else
- /* TODO inverted pulse on timer->out_val == 1? */
- qemu_irq_pulse(timer->out);
-}
-
-static void omap_gp_timer_tick(void *opaque)
-{
- struct omap_gp_timer_s *timer = opaque;
-
- if (!timer->ar) {
- timer->st = 0;
- timer->val = 0;
- } else {
- timer->val = timer->load_val;
- timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
-
- if (timer->trigger == gpt_trigger_overflow ||
- timer->trigger == gpt_trigger_both)
- omap_gp_timer_trigger(timer);
-
- omap_gp_timer_intr(timer, GPT_OVF_IT);
- omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_match(void *opaque)
-{
- struct omap_gp_timer_s *timer = opaque;
-
- if (timer->trigger == gpt_trigger_both)
- omap_gp_timer_trigger(timer);
-
- omap_gp_timer_intr(timer, GPT_MAT_IT);
-}
-
-static void omap_gp_timer_input(void *opaque, int line, int on)
-{
- struct omap_gp_timer_s *s = opaque;
- int trigger;
-
- switch (s->capture) {
- default:
- case gpt_capture_none:
- trigger = 0;
- break;
- case gpt_capture_rising:
- trigger = !s->in_val && on;
- break;
- case gpt_capture_falling:
- trigger = s->in_val && !on;
- break;
- case gpt_capture_both:
- trigger = (s->in_val == !on);
- break;
- }
- s->in_val = on;
-
- if (s->inout && trigger && s->capt_num < 2) {
- s->capture_val[s->capt_num] = omap_gp_timer_read(s);
-
- if (s->capt2 == s->capt_num ++)
- omap_gp_timer_intr(s, GPT_TCAR_IT);
- }
-}
-
-static void omap_gp_timer_clk_update(void *opaque, int line, int on)
-{
- struct omap_gp_timer_s *timer = opaque;
-
- omap_gp_timer_sync(timer);
- timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
- omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
-{
- omap_clk_adduser(timer->clk,
- qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0));
- timer->rate = omap_clk_getrate(timer->clk);
-}
-
-void omap_gp_timer_reset(struct omap_gp_timer_s *s)
-{
- s->config = 0x000;
- s->status = 0;
- s->it_ena = 0;
- s->wu_ena = 0;
- s->inout = 0;
- s->capt2 = 0;
- s->capt_num = 0;
- s->pt = 0;
- s->trigger = gpt_trigger_none;
- s->capture = gpt_capture_none;
- s->scpwm = 0;
- s->ce = 0;
- s->pre = 0;
- s->ptv = 0;
- s->ar = 0;
- s->st = 0;
- s->posted = 1;
- s->val = 0x00000000;
- s->load_val = 0x00000000;
- s->capture_val[0] = 0x00000000;
- s->capture_val[1] = 0x00000000;
- s->match_val = 0x00000000;
- omap_gp_timer_update(s);
-}
-
-static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
-{
- struct omap_gp_timer_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* TIDR */
- return 0x21;
-
- case 0x10: /* TIOCP_CFG */
- return s->config;
-
- case 0x14: /* TISTAT */
- /* ??? When's this bit reset? */
- return 1; /* RESETDONE */
-
- case 0x18: /* TISR */
- return s->status;
-
- case 0x1c: /* TIER */
- return s->it_ena;
-
- case 0x20: /* TWER */
- return s->wu_ena;
-
- case 0x24: /* TCLR */
- return (s->inout << 14) |
- (s->capt2 << 13) |
- (s->pt << 12) |
- (s->trigger << 10) |
- (s->capture << 8) |
- (s->scpwm << 7) |
- (s->ce << 6) |
- (s->pre << 5) |
- (s->ptv << 2) |
- (s->ar << 1) |
- (s->st << 0);
-
- case 0x28: /* TCRR */
- return omap_gp_timer_read(s);
-
- case 0x2c: /* TLDR */
- return s->load_val;
-
- case 0x30: /* TTGR */
- return 0xffffffff;
-
- case 0x34: /* TWPS */
- return 0x00000000; /* No posted writes pending. */
-
- case 0x38: /* TMAR */
- return s->match_val;
-
- case 0x3c: /* TCAR1 */
- return s->capture_val[0];
-
- case 0x40: /* TSICR */
- return s->posted << 2;
-
- case 0x44: /* TCAR2 */
- return s->capture_val[1];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
-{
- struct omap_gp_timer_s *s = opaque;
- uint32_t ret;
-
- if (addr & 2)
- return s->readh;
- else {
- ret = omap_gp_timer_readw(opaque, addr);
- s->readh = ret >> 16;
- return ret & 0xffff;
- }
-}
-
-static void omap_gp_timer_write(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_gp_timer_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* TIDR */
- case 0x14: /* TISTAT */
- case 0x34: /* TWPS */
- case 0x3c: /* TCAR1 */
- case 0x44: /* TCAR2 */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* TIOCP_CFG */
- s->config = value & 0x33d;
- if (((value >> 3) & 3) == 3) /* IDLEMODE */
- fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
- __func__);
- if (value & 2) /* SOFTRESET */
- omap_gp_timer_reset(s);
- break;
-
- case 0x18: /* TISR */
- if (value & GPT_TCAR_IT)
- s->capt_num = 0;
- if (s->status && !(s->status &= ~value))
- qemu_irq_lower(s->irq);
- break;
-
- case 0x1c: /* TIER */
- s->it_ena = value & 7;
- break;
-
- case 0x20: /* TWER */
- s->wu_ena = value & 7;
- break;
-
- case 0x24: /* TCLR */
- omap_gp_timer_sync(s);
- s->inout = (value >> 14) & 1;
- s->capt2 = (value >> 13) & 1;
- s->pt = (value >> 12) & 1;
- s->trigger = (value >> 10) & 3;
- if (s->capture == gpt_capture_none &&
- ((value >> 8) & 3) != gpt_capture_none)
- s->capt_num = 0;
- s->capture = (value >> 8) & 3;
- s->scpwm = (value >> 7) & 1;
- s->ce = (value >> 6) & 1;
- s->pre = (value >> 5) & 1;
- s->ptv = (value >> 2) & 7;
- s->ar = (value >> 1) & 1;
- s->st = (value >> 0) & 1;
- if (s->inout && s->trigger != gpt_trigger_none)
- fprintf(stderr, "%s: GP timer pin must be an output "
- "for this trigger mode\n", __func__);
- if (!s->inout && s->capture != gpt_capture_none)
- fprintf(stderr, "%s: GP timer pin must be an input "
- "for this capture mode\n", __func__);
- if (s->trigger == gpt_trigger_none)
- omap_gp_timer_out(s, s->scpwm);
- /* TODO: make sure this doesn't overflow 32-bits */
- s->ticks_per_sec = NANOSECONDS_PER_SECOND << (s->pre ? s->ptv + 1 : 0);
- omap_gp_timer_update(s);
- break;
-
- case 0x28: /* TCRR */
- s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->val = value;
- omap_gp_timer_update(s);
- break;
-
- case 0x2c: /* TLDR */
- s->load_val = value;
- break;
-
- case 0x30: /* TTGR */
- s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->val = s->load_val;
- omap_gp_timer_update(s);
- break;
-
- case 0x38: /* TMAR */
- omap_gp_timer_sync(s);
- s->match_val = value;
- omap_gp_timer_update(s);
- break;
-
- case 0x40: /* TSICR */
- s->posted = (value >> 2) & 1;
- if (value & 2) /* How much exactly are we supposed to reset? */
- omap_gp_timer_reset(s);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static void omap_gp_timer_writeh(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_gp_timer_s *s = opaque;
-
- if (addr & 2)
- omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
- else
- s->writeh = (uint16_t) value;
-}
-
-static uint64_t omap_gp_timer_readfn(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return omap_badwidth_read32(opaque, addr);
- case 2:
- return omap_gp_timer_readh(opaque, addr);
- case 4:
- return omap_gp_timer_readw(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void omap_gp_timer_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 1:
- omap_badwidth_write32(opaque, addr, value);
- break;
- case 2:
- omap_gp_timer_writeh(opaque, addr, value);
- break;
- case 4:
- omap_gp_timer_write(opaque, addr, value);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static const MemoryRegionOps omap_gp_timer_ops = {
- .read = omap_gp_timer_readfn,
- .write = omap_gp_timer_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
-
- s->ta = ta;
- s->irq = irq;
- s->clk = fclk;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s);
- s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s);
- s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0);
- omap_gp_timer_reset(s);
- omap_gp_timer_clk_setup(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
diff --git a/hw/timer/omap_synctimer.c b/hw/timer/omap_synctimer.c
deleted file mode 100644
index d93a934..0000000
--- a/hw/timer/omap_synctimer.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * TI OMAP2 32kHz sync timer emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-struct omap_synctimer_s {
- MemoryRegion iomem;
- uint32_t val;
- uint16_t readh;
-};
-
-/* 32-kHz Sync Timer of the OMAP2 */
-static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
- return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 0x8000,
- NANOSECONDS_PER_SECOND);
-}
-
-void omap_synctimer_reset(struct omap_synctimer_s *s)
-{
- s->val = omap_synctimer_read(s);
-}
-
-static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
-{
- struct omap_synctimer_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* 32KSYNCNT_REV */
- return 0x21;
-
- case 0x10: /* CR */
- return omap_synctimer_read(s) - s->val;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
-{
- struct omap_synctimer_s *s = opaque;
- uint32_t ret;
-
- if (addr & 2)
- return s->readh;
- else {
- ret = omap_synctimer_readw(opaque, addr);
- s->readh = ret >> 16;
- return ret & 0xffff;
- }
-}
-
-static uint64_t omap_synctimer_readfn(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return omap_badwidth_read32(opaque, addr);
- case 2:
- return omap_synctimer_readh(opaque, addr);
- case 4:
- return omap_synctimer_readw(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void omap_synctimer_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_synctimer_ops = {
- .read = omap_synctimer_readfn,
- .write = omap_synctimer_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
-{
- struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
-
- omap_synctimer_reset(s);
- memory_region_init_io(&s->iomem, NULL, &omap_synctimer_ops, s, "omap.synctimer",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c
index 6479ab1..6d4ac31 100644
--- a/hw/timer/pxa2xx_timer.c
+++ b/hw/timer/pxa2xx_timer.c
@@ -11,51 +11,49 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
-#include "hw/arm/pxa.h"
+#include "system/runstate.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qom/object.h"
-#include "sysemu/watchdog.h"
-
-#define OSMR0 0x00
-#define OSMR1 0x04
-#define OSMR2 0x08
-#define OSMR3 0x0c
-#define OSMR4 0x80
-#define OSMR5 0x84
-#define OSMR6 0x88
-#define OSMR7 0x8c
-#define OSMR8 0x90
-#define OSMR9 0x94
-#define OSMR10 0x98
-#define OSMR11 0x9c
-#define OSCR 0x10 /* OS Timer Count */
-#define OSCR4 0x40
-#define OSCR5 0x44
-#define OSCR6 0x48
-#define OSCR7 0x4c
-#define OSCR8 0x50
-#define OSCR9 0x54
-#define OSCR10 0x58
-#define OSCR11 0x5c
-#define OSSR 0x14 /* Timer status register */
-#define OWER 0x18
-#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */
-#define OMCR4 0xc0 /* OS Match Control registers */
-#define OMCR5 0xc4
-#define OMCR6 0xc8
-#define OMCR7 0xcc
-#define OMCR8 0xd0
-#define OMCR9 0xd4
-#define OMCR10 0xd8
-#define OMCR11 0xdc
-#define OSNR 0x20
-
-#define PXA25X_FREQ 3686400 /* 3.6864 MHz */
-#define PXA27X_FREQ 3250000 /* 3.25 MHz */
+#include "system/watchdog.h"
+
+#define OSMR0 0x00
+#define OSMR1 0x04
+#define OSMR2 0x08
+#define OSMR3 0x0c
+#define OSMR4 0x80
+#define OSMR5 0x84
+#define OSMR6 0x88
+#define OSMR7 0x8c
+#define OSMR8 0x90
+#define OSMR9 0x94
+#define OSMR10 0x98
+#define OSMR11 0x9c
+#define OSCR 0x10 /* OS Timer Count */
+#define OSCR4 0x40
+#define OSCR5 0x44
+#define OSCR6 0x48
+#define OSCR7 0x4c
+#define OSCR8 0x50
+#define OSCR9 0x54
+#define OSCR10 0x58
+#define OSCR11 0x5c
+#define OSSR 0x14 /* Timer status register */
+#define OWER 0x18
+#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */
+#define OMCR4 0xc0 /* OS Match Control registers */
+#define OMCR5 0xc4
+#define OMCR6 0xc8
+#define OMCR7 0xcc
+#define OMCR8 0xd0
+#define OMCR9 0xd4
+#define OMCR10 0xd8
+#define OMCR11 0xdc
+#define OSNR 0x20
+
+#define PXA25X_FREQ 3686400 /* 3.6864 MHz */
static int pxa2xx_timer4_freq[8] = {
[0] = 0,
@@ -108,7 +106,7 @@ struct PXA2xxTimerInfo {
PXA2xxTimer4 tm4[8];
};
-#define PXA2XX_TIMER_HAVE_TM4 0
+#define PXA2XX_TIMER_HAVE_TM4 0
static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
{
@@ -232,7 +230,7 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
NANOSECONDS_PER_SECOND);
case OIER:
return s->irq_enabled;
- case OSSR: /* Status register */
+ case OSSR: /* Status register */
return s->events;
case OWER:
return s->reset3;
@@ -338,7 +336,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset,
case OIER:
s->irq_enabled = value & 0xfff;
break;
- case OSSR: /* Status register */
+ case OSSR: /* Status register */
value &= s->events;
s->events &= ~value;
for (i = 0; i < 4; i ++, value >>= 1)
@@ -347,7 +345,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset,
if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
qemu_irq_lower(s->irq4);
break;
- case OWER: /* XXX: Reset on OSMR3 match? */
+ case OWER: /* XXX: Reset on OSMR3 match? */
s->reset3 = value;
break;
case OMCR7: tm ++;
@@ -551,14 +549,13 @@ static const VMStateDescription vmstate_pxa2xx_timer_regs = {
}
};
-static Property pxa25x_timer_dev_properties[] = {
+static const Property pxa25x_timer_dev_properties[] = {
DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
PXA2XX_TIMER_HAVE_TM4, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
+static void pxa25x_timer_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -573,29 +570,7 @@ static const TypeInfo pxa25x_timer_dev_info = {
.class_init = pxa25x_timer_dev_class_init,
};
-static Property pxa27x_timer_dev_properties[] = {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA27x timer";
- device_class_set_props(dc, pxa27x_timer_dev_properties);
-}
-
-static const TypeInfo pxa27x_timer_dev_info = {
- .name = "pxa27x-timer",
- .parent = TYPE_PXA2XX_TIMER,
- .instance_size = sizeof(PXA2xxTimerInfo),
- .class_init = pxa27x_timer_dev_class_init,
-};
-
-static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
+static void pxa2xx_timer_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -616,7 +591,6 @@ static void pxa2xx_timer_register_types(void)
{
type_register_static(&pxa2xx_timer_type_info);
type_register_static(&pxa25x_timer_dev_info);
- type_register_static(&pxa27x_timer_dev_info);
}
type_init(pxa2xx_timer_register_types)
diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c
index 0883293..cdff7f4 100644
--- a/hw/timer/renesas_cmt.c
+++ b/hw/timer/renesas_cmt.c
@@ -253,17 +253,16 @@ static const VMStateDescription vmstate_rcmt = {
}
};
-static Property rcmt_properties[] = {
+static const Property rcmt_properties[] = {
DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void rcmt_class_init(ObjectClass *klass, void *data)
+static void rcmt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_rcmt;
- dc->reset = rcmt_reset;
+ device_class_set_legacy_reset(dc, rcmt_reset);
device_class_set_props(dc, rcmt_properties);
}
diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c
index 1d47d06..95707f2 100644
--- a/hw/timer/renesas_tmr.c
+++ b/hw/timer/renesas_tmr.c
@@ -463,17 +463,16 @@ static const VMStateDescription vmstate_rtmr = {
}
};
-static Property rtmr_properties[] = {
+static const Property rtmr_properties[] = {
DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void rtmr_class_init(ObjectClass *klass, void *data)
+static void rtmr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_rtmr;
- dc->reset = rtmr_reset;
+ device_class_set_legacy_reset(dc, rtmr_reset);
device_class_set_props(dc, rtmr_properties);
}
diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c
index 7788939..d4fa32c 100644
--- a/hw/timer/sh_timer.c
+++ b/hw/timer/sh_timer.c
@@ -9,7 +9,7 @@
*/
#include "qemu/osdep.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qemu/log.h"
#include "hw/irq.h"
#include "hw/sh4/sh.h"
diff --git a/hw/timer/sifive_pwm.c b/hw/timer/sifive_pwm.c
index e8610c3..e85e389 100644
--- a/hw/timer/sifive_pwm.c
+++ b/hw/timer/sifive_pwm.c
@@ -404,11 +404,10 @@ static const VMStateDescription vmstate_sifive_pwm = {
}
};
-static Property sifive_pwm_properties[] = {
+static const Property sifive_pwm_properties[] = {
/* 0.5Ghz per spec after FSBL */
DEFINE_PROP_UINT64("clock-frequency", struct SiFivePwmState,
freq_hz, 500000000ULL),
- DEFINE_PROP_END_OF_LIST(),
};
static void sifive_pwm_init(Object *obj)
@@ -442,11 +441,11 @@ static void sifive_pwm_realize(DeviceState *dev, Error **errp)
sifive_pwm_interrupt_3, s);
}
-static void sifive_pwm_class_init(ObjectClass *klass, void *data)
+static void sifive_pwm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = sifive_pwm_reset;
+ device_class_set_legacy_reset(dc, sifive_pwm_reset);
device_class_set_props(dc, sifive_pwm_properties);
dc->vmsd = &vmstate_sifive_pwm;
dc->realize = sifive_pwm_realize;
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index 5507b01..3e071fb 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -420,16 +420,15 @@ static void slavio_timer_init(Object *obj)
}
}
-static Property slavio_timer_properties[] = {
+static const Property slavio_timer_properties[] = {
DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void slavio_timer_class_init(ObjectClass *klass, void *data)
+static void slavio_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = slavio_timer_reset;
+ device_class_set_legacy_reset(dc, slavio_timer_reset);
dc->vmsd = &vmstate_slavio_timer;
device_class_set_props(dc, slavio_timer_properties);
}
diff --git a/hw/timer/sse-counter.c b/hw/timer/sse-counter.c
index daceedf..31f77ac 100644
--- a/hw/timer/sse-counter.c
+++ b/hw/timer/sse-counter.c
@@ -448,13 +448,13 @@ static const VMStateDescription sse_counter_vmstate = {
}
};
-static void sse_counter_class_init(ObjectClass *klass, void *data)
+static void sse_counter_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sse_counter_realize;
dc->vmsd = &sse_counter_vmstate;
- dc->reset = sse_counter_reset;
+ device_class_set_legacy_reset(dc, sse_counter_reset);
}
static const TypeInfo sse_counter_info = {
diff --git a/hw/timer/sse-timer.c b/hw/timer/sse-timer.c
index cb20a9e..866d5ee 100644
--- a/hw/timer/sse-timer.c
+++ b/hw/timer/sse-timer.c
@@ -440,18 +440,17 @@ static const VMStateDescription sse_timer_vmstate = {
}
};
-static Property sse_timer_properties[] = {
+static const Property sse_timer_properties[] = {
DEFINE_PROP_LINK("counter", SSETimer, counter, TYPE_SSE_COUNTER, SSECounter *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void sse_timer_class_init(ObjectClass *klass, void *data)
+static void sse_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sse_timer_realize;
dc->vmsd = &sse_timer_vmstate;
- dc->reset = sse_timer_reset;
+ device_class_set_legacy_reset(dc, sse_timer_reset);
device_class_set_props(dc, sse_timer_properties);
}
diff --git a/hw/timer/stellaris-gptm.c b/hw/timer/stellaris-gptm.c
index f28958c..d97b2f8 100644
--- a/hw/timer/stellaris-gptm.c
+++ b/hw/timer/stellaris-gptm.c
@@ -308,7 +308,7 @@ static void stellaris_gptm_realize(DeviceState *dev, Error **errp)
s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]);
}
-static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
+static void stellaris_gptm_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
index de4208b..be844e7 100644
--- a/hw/timer/stm32f2xx_timer.c
+++ b/hw/timer/stm32f2xx_timer.c
@@ -298,10 +298,9 @@ static const VMStateDescription vmstate_stm32f2xx_timer = {
}
};
-static Property stm32f2xx_timer_properties[] = {
+static const Property stm32f2xx_timer_properties[] = {
DEFINE_PROP_UINT64("clock-frequency", struct STM32F2XXTimerState,
freq_hz, 1000000000),
- DEFINE_PROP_END_OF_LIST(),
};
static void stm32f2xx_timer_init(Object *obj)
@@ -321,11 +320,11 @@ static void stm32f2xx_timer_realize(DeviceState *dev, Error **errp)
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s);
}
-static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data)
+static void stm32f2xx_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_timer_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_timer_reset);
device_class_set_props(dc, stm32f2xx_timer_properties);
dc->vmsd = &vmstate_stm32f2xx_timer;
dc->realize = stm32f2xx_timer_realize;
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index f48a712..c5b6db4 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -31,7 +31,7 @@ aspeed_timer_ctrl_overflow_interrupt(uint8_t i, bool enable) "Timer %" PRIu8 ":
aspeed_timer_ctrl_pulse_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
aspeed_timer_set_ctrl2(uint32_t value) "Value: 0x%" PRIx32
aspeed_timer_set_value(int timer, int reg, uint32_t value) "Timer %d register %d: 0x%" PRIx32
-aspeed_timer_read(uint64_t offset, unsigned size, uint64_t value) "From 0x%" PRIx64 ": of size %u: 0x%" PRIx64
+aspeed_timer_read(uint64_t offset, uint64_t value) "From 0x%" PRIx64 ": 0x%" PRIx64
# armv7m_systick.c
systick_reload(void) "systick reload"
@@ -49,6 +49,12 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A
cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
+# imx_gpt.c
+imx_gpt_set_freq(uint32_t clksrc, uint32_t freq) "Setting clksrc %u to %u Hz"
+imx_gpt_read(const char *name, uint64_t value) "%s -> 0x%08" PRIx64
+imx_gpt_write(const char *name, uint64_t value) "%s <- 0x%08" PRIx64
+imx_gpt_timeout(void) ""
+
# npcm7xx_timer.c
npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c
index 32a9df6..ff4a224 100644
--- a/hw/timer/xilinx_timer.c
+++ b/hw/timer/xilinx_timer.c
@@ -3,6 +3,9 @@
*
* Copyright (c) 2009 Edgar E. Iglesias.
*
+ * DS573: https://docs.amd.com/v/u/en-US/xps_timer
+ * LogiCORE IP XPS Timer/Counter (v1.02a)
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -23,10 +26,12 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qom/object.h"
@@ -69,6 +74,7 @@ struct XpsTimerState
{
SysBusDevice parent_obj;
+ EndianMode model_endianness;
MemoryRegion mmio;
qemu_irq irq;
uint8_t one_timer_only;
@@ -189,14 +195,21 @@ timer_write(void *opaque, hwaddr addr,
timer_update_irq(t);
}
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
+static const MemoryRegionOps timer_ops[2] = {
+ [0 ... 1] = {
+ .read = timer_read,
+ .write = timer_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ },
+ [0].endianness = DEVICE_LITTLE_ENDIAN,
+ [1].endianness = DEVICE_BIG_ENDIAN,
};
static void timer_hit(void *opaque)
@@ -216,6 +229,12 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp)
XpsTimerState *t = XILINX_TIMER(dev);
unsigned int i;
+ if (t->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
+ error_setg(errp, TYPE_XILINX_TIMER " property 'endianness'"
+ " must be set to 'big' or 'little'");
+ return;
+ }
+
/* Init all the ptimers. */
t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t));
for (i = 0; i < num_timers(t); i++) {
@@ -229,8 +248,9 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp)
ptimer_transaction_commit(xt->ptimer);
}
- memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "xlnx.xps-timer",
- R_MAX * 4 * num_timers(t));
+ memory_region_init_io(&t->mmio, OBJECT(t),
+ &timer_ops[t->model_endianness == ENDIAN_MODE_BIG],
+ t, "xlnx.xps-timer", R_MAX * 4 * num_timers(t));
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &t->mmio);
}
@@ -242,13 +262,13 @@ static void xilinx_timer_init(Object *obj)
sysbus_init_irq(SYS_BUS_DEVICE(obj), &t->irq);
}
-static Property xilinx_timer_properties[] = {
+static const Property xilinx_timer_properties[] = {
+ DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XpsTimerState, model_endianness),
DEFINE_PROP_UINT32("clock-frequency", XpsTimerState, freq_hz, 62 * 1000000),
DEFINE_PROP_UINT8("one-timer-only", XpsTimerState, one_timer_only, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xilinx_timer_class_init(ObjectClass *klass, void *data)
+static void xilinx_timer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index 5cd5a25..bc7a78f 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -18,15 +18,15 @@
#include "qemu/module.h"
#include "qapi/error.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/qdev-properties.h"
#include "hw/pci/pci_ids.h"
#include "hw/acpi/tpm.h"
#include "migration/vmstate.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/tpm_util.h"
-#include "sysemu/reset.h"
-#include "sysemu/xen.h"
+#include "system/tpm_backend.h"
+#include "system/tpm_util.h"
+#include "system/reset.h"
+#include "system/xen.h"
#include "tpm_prop.h"
#include "tpm_ppi.h"
#include "trace.h"
@@ -226,10 +226,9 @@ static const VMStateDescription vmstate_tpm_crb = {
}
};
-static Property tpm_crb_properties[] = {
+static const Property tpm_crb_properties[] = {
DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true),
- DEFINE_PROP_END_OF_LIST(),
};
static void tpm_crb_reset(void *dev)
@@ -316,7 +315,7 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
}
}
-static void tpm_crb_class_init(ObjectClass *klass, void *data)
+static void tpm_crb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
TPMIfClass *tc = TPM_IF_CLASS(klass);
@@ -338,7 +337,7 @@ static const TypeInfo tpm_crb_info = {
.parent = TYPE_DEVICE,
.instance_size = sizeof(CRBState),
.class_init = tpm_crb_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_TPM_IF },
{ }
}
diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c
index f27ed6c..984d3d1 100644
--- a/hw/tpm/tpm_ppi.c
+++ b/hw/tpm/tpm_ppi.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "qemu/memalign.h"
#include "qapi/error.h"
-#include "sysemu/memory_mapping.h"
+#include "system/memory_mapping.h"
#include "migration/vmstate.h"
#include "hw/qdev-core.h"
#include "hw/acpi/tpm.h"
diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h
index bf5d4a3..88f316e 100644
--- a/hw/tpm/tpm_ppi.h
+++ b/hw/tpm/tpm_ppi.h
@@ -12,7 +12,7 @@
#ifndef TPM_TPM_PPI_H
#define TPM_TPM_PPI_H
-#include "exec/memory.h"
+#include "system/memory.h"
typedef struct TPMPPI {
MemoryRegion ram;
diff --git a/hw/tpm/tpm_prop.h b/hw/tpm/tpm_prop.h
index bbd4225..c4df748 100644
--- a/hw/tpm/tpm_prop.h
+++ b/hw/tpm/tpm_prop.h
@@ -22,7 +22,7 @@
#ifndef HW_TPM_PROP_H
#define HW_TPM_PROP_H
-#include "sysemu/tpm_backend.h"
+#include "system/tpm_backend.h"
#include "hw/qdev-properties.h"
extern const PropertyInfo qdev_prop_tpm;
diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c
index e084e98..ea608ba 100644
--- a/hw/tpm/tpm_spapr.c
+++ b/hw/tpm/tpm_spapr.c
@@ -19,8 +19,8 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/tpm_util.h"
+#include "system/tpm_backend.h"
+#include "system/tpm_util.h"
#include "tpm_prop.h"
#include "hw/ppc/spapr.h"
@@ -206,7 +206,6 @@ static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
break;
default:
g_assert_not_reached();
- break;
}
trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data));
spapr_tpm_send_crq(dev, &local_crq);
@@ -365,10 +364,9 @@ static const VMStateDescription vmstate_spapr_vtpm = {
}
};
-static Property tpm_spapr_properties[] = {
+static const Property tpm_spapr_properties[] = {
DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev),
DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver),
- DEFINE_PROP_END_OF_LIST(),
};
static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
@@ -389,7 +387,7 @@ static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX);
}
-static void tpm_spapr_class_init(ObjectClass *klass, void *data)
+static void tpm_spapr_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
@@ -416,7 +414,7 @@ static const TypeInfo tpm_spapr_info = {
.parent = TYPE_VIO_SPAPR_DEVICE,
.instance_size = sizeof(SpaprTpmState),
.class_init = tpm_spapr_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_TPM_IF },
{ }
}
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
index 6f14896..184632f 100644
--- a/hw/tpm/tpm_tis.h
+++ b/hw/tpm/tpm_tis.h
@@ -24,7 +24,7 @@
#ifndef TPM_TPM_TIS_H
#define TPM_TPM_TIS_H
-#include "sysemu/tpm_backend.h"
+#include "system/tpm_backend.h"
#include "tpm_ppi.h"
#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c
index 1bfa28b..cdd0df1 100644
--- a/hw/tpm/tpm_tis_common.c
+++ b/hw/tpm/tpm_tis_common.c
@@ -34,8 +34,8 @@
#include "hw/pci/pci_ids.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/tpm_util.h"
+#include "system/tpm_backend.h"
+#include "system/tpm_util.h"
#include "tpm_ppi.h"
#include "trace.h"
diff --git a/hw/tpm/tpm_tis_i2c.c b/hw/tpm/tpm_tis_i2c.c
index 4bb0965..5ce84dc 100644
--- a/hw/tpm/tpm_tis_i2c.c
+++ b/hw/tpm/tpm_tis_i2c.c
@@ -211,8 +211,6 @@ static inline void tpm_tis_i2c_clear_data(TPMStateI2C *i2cst)
i2cst->tis_addr = 0xffffffff;
i2cst->reg_name = NULL;
memset(i2cst->data, 0, sizeof(i2cst->data));
-
- return;
}
/* Send data to TPM */
@@ -281,8 +279,6 @@ static inline void tpm_tis_i2c_tpm_send(TPMStateI2C *i2cst)
tpm_tis_i2c_clear_data(i2cst);
}
-
- return;
}
/* Callback from TPM to indicate that response is copied */
@@ -491,9 +487,8 @@ static int tpm_tis_i2c_send(I2CSlave *i2c, uint8_t data)
return 1;
}
-static Property tpm_tis_i2c_properties[] = {
+static const Property tpm_tis_i2c_properties[] = {
DEFINE_PROP_TPMBE("tpmdev", TPMStateI2C, state.be_driver),
- DEFINE_PROP_END_OF_LIST(),
};
static void tpm_tis_i2c_realizefn(DeviceState *dev, Error **errp)
@@ -531,14 +526,14 @@ static void tpm_tis_i2c_reset(DeviceState *dev)
return tpm_tis_reset(s);
}
-static void tpm_tis_i2c_class_init(ObjectClass *klass, void *data)
+static void tpm_tis_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
TPMIfClass *tc = TPM_IF_CLASS(klass);
dc->realize = tpm_tis_i2c_realizefn;
- dc->reset = tpm_tis_i2c_reset;
+ device_class_set_legacy_reset(dc, tpm_tis_i2c_reset);
dc->vmsd = &vmstate_tpm_tis_i2c;
device_class_set_props(dc, tpm_tis_i2c_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
@@ -557,7 +552,7 @@ static const TypeInfo tpm_tis_i2c_info = {
.parent = TYPE_I2C_SLAVE,
.instance_size = sizeof(TPMStateI2C),
.class_init = tpm_tis_i2c_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_TPM_IF },
{ }
}
diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c
index 8887b3c..dce8305 100644
--- a/hw/tpm/tpm_tis_isa.c
+++ b/hw/tpm/tpm_tis_isa.c
@@ -91,11 +91,10 @@ static void tpm_tis_isa_reset(DeviceState *dev)
return tpm_tis_reset(s);
}
-static Property tpm_tis_isa_properties[] = {
+static const Property tpm_tis_isa_properties[] = {
DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ),
DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver),
DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true),
- DEFINE_PROP_END_OF_LIST(),
};
static void tpm_tis_isa_initfn(Object *obj)
@@ -167,7 +166,7 @@ static void build_tpm_tis_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(scope, dev);
}
-static void tpm_tis_isa_class_init(ObjectClass *klass, void *data)
+static void tpm_tis_isa_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
TPMIfClass *tc = TPM_IF_CLASS(klass);
@@ -177,7 +176,7 @@ static void tpm_tis_isa_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_tpm_tis_isa;
tc->model = TPM_MODEL_TPM_TIS;
dc->realize = tpm_tis_isa_realizefn;
- dc->reset = tpm_tis_isa_reset;
+ device_class_set_legacy_reset(dc, tpm_tis_isa_reset);
tc->request_completed = tpm_tis_isa_request_completed;
tc->get_version = tpm_tis_isa_get_tpm_version;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
@@ -190,7 +189,7 @@ static const TypeInfo tpm_tis_isa_info = {
.instance_size = sizeof(TPMStateISA),
.instance_init = tpm_tis_isa_initfn,
.class_init = tpm_tis_isa_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_TPM_IF },
{ TYPE_ACPI_DEV_AML_IF },
{ }
diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c
index 941f7f7..2ffa858 100644
--- a/hw/tpm/tpm_tis_sysbus.c
+++ b/hw/tpm/tpm_tis_sysbus.c
@@ -90,10 +90,9 @@ static void tpm_tis_sysbus_reset(DeviceState *dev)
return tpm_tis_reset(s);
}
-static Property tpm_tis_sysbus_properties[] = {
+static const Property tpm_tis_sysbus_properties[] = {
DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ),
DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver),
- DEFINE_PROP_END_OF_LIST(),
};
static void tpm_tis_sysbus_initfn(Object *obj)
@@ -125,7 +124,7 @@ static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp)
}
}
-static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data)
+static void tpm_tis_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
TPMIfClass *tc = TPM_IF_CLASS(klass);
@@ -134,8 +133,7 @@ static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_tpm_tis_sysbus;
tc->model = TPM_MODEL_TPM_TIS;
dc->realize = tpm_tis_sysbus_realizefn;
- dc->user_creatable = true;
- dc->reset = tpm_tis_sysbus_reset;
+ device_class_set_legacy_reset(dc, tpm_tis_sysbus_reset);
tc->request_completed = tpm_tis_sysbus_request_completed;
tc->get_version = tpm_tis_sysbus_get_tpm_version;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
@@ -143,11 +141,11 @@ static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data)
static const TypeInfo tpm_tis_sysbus_info = {
.name = TYPE_TPM_TIS_SYSBUS,
- .parent = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
.instance_size = sizeof(TPMStateSysBus),
.instance_init = tpm_tis_sysbus_initfn,
.class_init = tpm_tis_sysbus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_TPM_IF },
{ }
}
diff --git a/hw/tricore/tc27x_soc.c b/hw/tricore/tc27x_soc.c
index ecd9271..f3b8498 100644
--- a/hw/tricore/tc27x_soc.c
+++ b/hw/tricore/tc27x_soc.c
@@ -201,19 +201,14 @@ static void tc27x_soc_init(Object *obj)
object_initialize_child(obj, "tc27x", &s->cpu, sc->cpu_type);
}
-static Property tc27x_soc_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void tc27x_soc_class_init(ObjectClass *klass, void *data)
+static void tc27x_soc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = tc27x_soc_realize;
- device_class_set_props(dc, tc27x_soc_properties);
}
-static void tc277d_soc_class_init(ObjectClass *oc, void *data)
+static void tc277d_soc_class_init(ObjectClass *oc, const void *data)
{
TC27XSoCClass *sc = TC27X_SOC_CLASS(oc);
diff --git a/hw/tricore/triboard.c b/hw/tricore/triboard.c
index 4dba025..cb45b01 100644
--- a/hw/tricore/triboard.c
+++ b/hw/tricore/triboard.c
@@ -31,22 +31,20 @@
#include "hw/tricore/triboard.h"
#include "hw/tricore/tc27x_soc.h"
-static void tricore_load_kernel(const char *kernel_filename)
+static void tricore_load_kernel(TriCoreCPU *cpu, const char *kernel_filename)
{
uint64_t entry;
long kernel_size;
- TriCoreCPU *cpu;
CPUTriCoreState *env;
kernel_size = load_elf(kernel_filename, NULL,
NULL, NULL, &entry, NULL,
- NULL, NULL, 0,
+ NULL, NULL, ELFDATA2LSB,
EM_TRICORE, 1, 0);
if (kernel_size <= 0) {
error_report("no kernel file '%s'", kernel_filename);
exit(1);
}
- cpu = TRICORE_CPU(first_cpu);
env = &cpu->env;
env->PC = entry;
}
@@ -62,12 +60,12 @@ static void triboard_machine_init(MachineState *machine)
sysbus_realize(SYS_BUS_DEVICE(&ms->tc27x_soc), &error_fatal);
if (machine->kernel_filename) {
- tricore_load_kernel(machine->kernel_filename);
+ tricore_load_kernel(&ms->tc27x_soc.cpu, machine->kernel_filename);
}
}
static void triboard_machine_tc277d_class_init(ObjectClass *oc,
- void *data)
+ const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
TriBoardMachineClass *amc = TRIBOARD_MACHINE_CLASS(oc);
diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c
index c29db8b..3facfdf 100644
--- a/hw/tricore/tricore_testboard.c
+++ b/hw/tricore/tricore_testboard.c
@@ -42,7 +42,7 @@ static void tricore_load_kernel(CPUTriCoreState *env)
kernel_size = load_elf(tricoretb_binfo.kernel_filename, NULL,
NULL, NULL, &entry, NULL,
- NULL, NULL, 0,
+ NULL, NULL, ELFDATA2LSB,
EM_TRICORE, 1, 0);
if (kernel_size <= 0) {
error_report("no kernel file '%s'",
diff --git a/hw/tricore/tricore_testdevice.c b/hw/tricore/tricore_testdevice.c
index 9028d97..e8daf95 100644
--- a/hw/tricore/tricore_testdevice.c
+++ b/hw/tricore/tricore_testdevice.c
@@ -47,7 +47,7 @@ static const MemoryRegionOps tricore_testdevice_ops = {
.min_access_size = 4,
.max_access_size = 4,
},
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void tricore_testdevice_init(Object *obj)
@@ -58,16 +58,11 @@ static void tricore_testdevice_init(Object *obj)
"tricore_testdevice", 0x4);
}
-static Property tricore_testdevice_properties[] = {
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void tricore_testdevice_class_init(ObjectClass *klass, void *data)
+static void tricore_testdevice_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- device_class_set_props(dc, tricore_testdevice_properties);
- dc->reset = tricore_testdevice_reset;
+ device_class_set_legacy_reset(dc, tricore_testdevice_reset);
}
static const TypeInfo tricore_testdevice_info = {
diff --git a/hw/uefi/Kconfig b/hw/uefi/Kconfig
new file mode 100644
index 0000000..046d553
--- /dev/null
+++ b/hw/uefi/Kconfig
@@ -0,0 +1,3 @@
+config UEFI_VARS
+ bool
+ default y if X86_64 || AARCH64 || RISCV64 || LOONGARCH64
diff --git a/hw/uefi/LIMITATIONS.md b/hw/uefi/LIMITATIONS.md
new file mode 100644
index 0000000..29308bd
--- /dev/null
+++ b/hw/uefi/LIMITATIONS.md
@@ -0,0 +1,7 @@
+known issues and limitations
+----------------------------
+
+* works only on little endian hosts
+ - accessing structs in guest ram is done without endian conversion.
+* works only for 64-bit guests
+ - UINTN is mapped to uint64_t, for 32-bit guests that would be uint32_t
diff --git a/hw/uefi/hardware-info.c b/hw/uefi/hardware-info.c
new file mode 100644
index 0000000..930502a
--- /dev/null
+++ b/hw/uefi/hardware-info.c
@@ -0,0 +1,31 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * pass hardware information to uefi
+ *
+ * see OvmfPkg/Library/HardwareInfoLib/ in edk2
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/nvram/fw_cfg.h"
+#include "hw/uefi/hardware-info.h"
+
+static void *blob;
+static uint64_t blobsize;
+
+void hardware_info_register(HARDWARE_INFO_TYPE type, void *info, uint64_t infosize)
+{
+ HARDWARE_INFO_HEADER hdr = {
+ .type.value = cpu_to_le64(type),
+ .size = cpu_to_le64(infosize),
+ };
+
+ blob = g_realloc(blob, blobsize + sizeof(hdr) + infosize);
+ memcpy(blob + blobsize, &hdr, sizeof(hdr));
+ blobsize += sizeof(hdr);
+ memcpy(blob + blobsize, info, infosize);
+ blobsize += infosize;
+
+ fw_cfg_modify_file(fw_cfg_find(), "etc/hardware-info", blob, blobsize);
+}
diff --git a/hw/uefi/meson.build b/hw/uefi/meson.build
new file mode 100644
index 0000000..91eb95f
--- /dev/null
+++ b/hw/uefi/meson.build
@@ -0,0 +1,21 @@
+system_ss.add(files('hardware-info.c'))
+
+uefi_vars_ss = ss.source_set()
+if (config_all_devices.has_key('CONFIG_UEFI_VARS'))
+ uefi_vars_ss.add(files('var-service-core.c',
+ 'var-service-json.c',
+ 'var-service-vars.c',
+ 'var-service-auth.c',
+ 'var-service-guid.c',
+ 'var-service-utils.c',
+ 'var-service-policy.c',
+ 'var-service-sysbus.c'))
+ uefi_vars_ss.add(when: gnutls,
+ if_true: files('var-service-pkcs7.c'),
+ if_false: files('var-service-pkcs7-stub.c'))
+ uefi_vars_ss.add(files('var-service-siglist.c'))
+endif
+
+modules += { 'hw-uefi' : {
+ 'vars' : uefi_vars_ss,
+}}
diff --git a/hw/uefi/trace-events b/hw/uefi/trace-events
new file mode 100644
index 0000000..3694712
--- /dev/null
+++ b/hw/uefi/trace-events
@@ -0,0 +1,17 @@
+# device
+uefi_reg_read(uint64_t addr, unsigned size) "addr 0x%" PRIx64 ", size %u"
+uefi_reg_write(uint64_t addr, uint64_t val, unsigned size) "addr 0x%" PRIx64 ", val 0x%" PRIx64 ", size %d"
+uefi_hard_reset(void) ""
+
+# generic uefi
+uefi_variable(const char *context, const char *name, uint64_t size, const char *uuid) "context %s, name %s, size %" PRIu64 ", uuid %s"
+uefi_status(const char *context, const char *name) "context %s, status %s"
+uefi_event(const char *name) "event %s"
+
+# variable protocol
+uefi_vars_proto_cmd(const char *cmd) "cmd %s"
+uefi_vars_security_violation(const char *reason) "reason %s"
+
+# variable policy protocol
+uefi_vars_policy_cmd(const char *cmd) "cmd %s"
+uefi_vars_policy_deny(const char *reason) "reason %s"
diff --git a/hw/uefi/var-service-auth.c b/hw/uefi/var-service-auth.c
new file mode 100644
index 0000000..fba5a09
--- /dev/null
+++ b/hw/uefi/var-service-auth.c
@@ -0,0 +1,361 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - AuthVariableLib
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "system/dma.h"
+
+#include "hw/uefi/var-service.h"
+
+static const uint16_t name_pk[] = u"PK";
+static const uint16_t name_kek[] = u"KEK";
+static const uint16_t name_db[] = u"db";
+static const uint16_t name_dbx[] = u"dbx";
+static const uint16_t name_setup_mode[] = u"SetupMode";
+static const uint16_t name_sigs_support[] = u"SignatureSupport";
+static const uint16_t name_sb[] = u"SecureBoot";
+static const uint16_t name_sb_enable[] = u"SecureBootEnable";
+static const uint16_t name_custom_mode[] = u"CustomMode";
+static const uint16_t name_vk[] = u"VendorKeys";
+static const uint16_t name_vk_nv[] = u"VendorKeysNv";
+
+static const uint32_t sigdb_attrs =
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+
+static void set_secure_boot(uefi_vars_state *uv, uint8_t sb)
+{
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
+ name_sb, sizeof(name_sb),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ &sb, sizeof(sb));
+}
+
+static void set_secure_boot_enable(uefi_vars_state *uv, uint8_t sbe)
+{
+ uefi_vars_set_variable(uv, EfiSecureBootEnableDisable,
+ name_sb_enable, sizeof(name_sb_enable),
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ &sbe, sizeof(sbe));
+}
+
+static void set_setup_mode(uefi_vars_state *uv, uint8_t sm)
+{
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
+ name_setup_mode, sizeof(name_setup_mode),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ &sm, sizeof(sm));
+}
+
+static void set_custom_mode(uefi_vars_state *uv, uint8_t cm)
+{
+ uefi_vars_set_variable(uv, EfiCustomModeEnable,
+ name_custom_mode, sizeof(name_custom_mode),
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ &cm, sizeof(cm));
+}
+
+static void set_signature_support(uefi_vars_state *uv)
+{
+ QemuUUID sigs_support[5];
+
+ sigs_support[0] = EfiCertSha256Guid;
+ sigs_support[1] = EfiCertSha384Guid;
+ sigs_support[2] = EfiCertSha512Guid;
+ sigs_support[3] = EfiCertRsa2048Guid;
+ sigs_support[4] = EfiCertX509Guid;
+
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
+ name_sigs_support, sizeof(name_sigs_support),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sigs_support, sizeof(sigs_support));
+}
+
+static bool setup_mode_is_active(uefi_vars_state *uv)
+{
+ uefi_variable *var;
+ uint8_t *value;
+
+ var = uefi_vars_find_variable(uv, EfiGlobalVariable,
+ name_setup_mode, sizeof(name_setup_mode));
+ if (var) {
+ value = var->data;
+ if (value[0] == SETUP_MODE) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool custom_mode_is_active(uefi_vars_state *uv)
+{
+ uefi_variable *var;
+ uint8_t *value;
+
+ var = uefi_vars_find_variable(uv, EfiCustomModeEnable,
+ name_custom_mode, sizeof(name_custom_mode));
+ if (var) {
+ value = var->data;
+ if (value[0] == CUSTOM_SECURE_BOOT_MODE) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool uefi_vars_is_sb_pk(uefi_variable *var)
+{
+ if (qemu_uuid_is_equal(&var->guid, &EfiGlobalVariable) &&
+ uefi_str_equal(var->name, var->name_size, name_pk, sizeof(name_pk))) {
+ return true;
+ }
+ return false;
+}
+
+static bool uefi_vars_is_sb_kek(uefi_variable *var)
+{
+ if (qemu_uuid_is_equal(&var->guid, &EfiGlobalVariable) &&
+ uefi_str_equal(var->name, var->name_size, name_kek, sizeof(name_kek))) {
+ return true;
+ }
+ return false;
+}
+
+static bool uefi_vars_is_sb_db(uefi_variable *var)
+{
+ if (!qemu_uuid_is_equal(&var->guid, &EfiImageSecurityDatabase)) {
+ return false;
+ }
+ if (uefi_str_equal(var->name, var->name_size, name_db, sizeof(name_db))) {
+ return true;
+ }
+ if (uefi_str_equal(var->name, var->name_size, name_dbx, sizeof(name_dbx))) {
+ return true;
+ }
+ return false;
+}
+
+bool uefi_vars_is_sb_any(uefi_variable *var)
+{
+ if (uefi_vars_is_sb_pk(var) ||
+ uefi_vars_is_sb_kek(var) ||
+ uefi_vars_is_sb_db(var)) {
+ return true;
+ }
+ return false;
+}
+
+static uefi_variable *uefi_vars_find_siglist(uefi_vars_state *uv,
+ uefi_variable *var)
+{
+ if (uefi_vars_is_sb_pk(var)) {
+ return uefi_vars_find_variable(uv, EfiGlobalVariable,
+ name_pk, sizeof(name_pk));
+ }
+ if (uefi_vars_is_sb_kek(var)) {
+ return uefi_vars_find_variable(uv, EfiGlobalVariable,
+ name_pk, sizeof(name_pk));
+ }
+ if (uefi_vars_is_sb_db(var)) {
+ return uefi_vars_find_variable(uv, EfiGlobalVariable,
+ name_kek, sizeof(name_kek));
+ }
+
+ return NULL;
+}
+
+static efi_status uefi_vars_check_auth_2_sb(uefi_vars_state *uv,
+ uefi_variable *var,
+ mm_variable_access *va,
+ void *data,
+ uint64_t data_offset)
+{
+ variable_auth_2 *auth = data;
+ uefi_variable *siglist;
+
+ if (custom_mode_is_active(uv)) {
+ /* no authentication in custom mode */
+ return EFI_SUCCESS;
+ }
+
+ if (setup_mode_is_active(uv) && !uefi_vars_is_sb_pk(var)) {
+ /* no authentication in setup mode (except PK) */
+ return EFI_SUCCESS;
+ }
+
+ if (auth->hdr_length == 24) {
+ /* no signature (auth->cert_data is empty) */
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ siglist = uefi_vars_find_siglist(uv, var);
+ if (!siglist && setup_mode_is_active(uv) && uefi_vars_is_sb_pk(var)) {
+ /* check PK is self-signed */
+ uefi_variable tmp = {
+ .guid = EfiGlobalVariable,
+ .name = (uint16_t *)name_pk,
+ .name_size = sizeof(name_pk),
+ .attributes = sigdb_attrs,
+ .data = data + data_offset,
+ .data_size = va->data_size - data_offset,
+ };
+ return uefi_vars_check_pkcs7_2(&tmp, NULL, NULL, va, data);
+ }
+
+ return uefi_vars_check_pkcs7_2(siglist, NULL, NULL, va, data);
+}
+
+efi_status uefi_vars_check_auth_2(uefi_vars_state *uv, uefi_variable *var,
+ mm_variable_access *va, void *data)
+{
+ variable_auth_2 *auth = data;
+ uint64_t data_offset;
+ efi_status status;
+
+ if (va->data_size < sizeof(*auth)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (uadd64_overflow(sizeof(efi_time), auth->hdr_length, &data_offset)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ if (va->data_size < data_offset) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (auth->hdr_revision != 0x0200 ||
+ auth->hdr_cert_type != WIN_CERT_TYPE_EFI_GUID ||
+ !qemu_uuid_is_equal(&auth->guid_cert_type, &EfiCertTypePkcs7Guid)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (uefi_vars_is_sb_any(var)) {
+ /* secure boot variables */
+ status = uefi_vars_check_auth_2_sb(uv, var, va, data, data_offset);
+ if (status != EFI_SUCCESS) {
+ return status;
+ }
+ } else {
+ /* other authenticated variables */
+ status = uefi_vars_check_pkcs7_2(NULL,
+ &var->digest, &var->digest_size,
+ va, data);
+ if (status != EFI_SUCCESS) {
+ return status;
+ }
+ }
+
+ /* checks passed, set variable data */
+ var->time = auth->timestamp;
+ if (va->data_size - data_offset > 0) {
+ var->data = g_malloc(va->data_size - data_offset);
+ memcpy(var->data, data + data_offset, va->data_size - data_offset);
+ var->data_size = va->data_size - data_offset;
+ }
+
+ return EFI_SUCCESS;
+}
+
+efi_status uefi_vars_check_secure_boot(uefi_vars_state *uv, uefi_variable *var)
+{
+ uint8_t *value = var->data;
+
+ if (uefi_vars_is_sb_any(var)) {
+ if (var->attributes != sigdb_attrs) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ /* reject SecureBootEnable updates if force_secure_boot is set */
+ if (qemu_uuid_is_equal(&var->guid, &EfiSecureBootEnableDisable) &&
+ uefi_str_equal(var->name, var->name_size,
+ name_sb_enable, sizeof(name_sb_enable)) &&
+ uv->force_secure_boot &&
+ value[0] != SECURE_BOOT_ENABLE) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ /* reject CustomMode updates if disable_custom_mode is set */
+ if (qemu_uuid_is_equal(&var->guid, &EfiCustomModeEnable) &&
+ uefi_str_equal(var->name, var->name_size,
+ name_custom_mode, sizeof(name_custom_mode)) &&
+ uv->disable_custom_mode) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* AuthVariableLibInitialize */
+void uefi_vars_auth_init(uefi_vars_state *uv)
+{
+ uefi_variable *pk_var, *sbe_var;
+ uint8_t platform_mode, sb, sbe, vk;
+
+ /* SetupMode */
+ pk_var = uefi_vars_find_variable(uv, EfiGlobalVariable,
+ name_pk, sizeof(name_pk));
+ if (!pk_var) {
+ platform_mode = SETUP_MODE;
+ } else {
+ platform_mode = USER_MODE;
+ }
+ set_setup_mode(uv, platform_mode);
+
+ /* SignatureSupport */
+ set_signature_support(uv);
+
+ /* SecureBootEnable */
+ sbe = SECURE_BOOT_DISABLE;
+ sbe_var = uefi_vars_find_variable(uv, EfiSecureBootEnableDisable,
+ name_sb_enable, sizeof(name_sb_enable));
+ if (sbe_var) {
+ if (platform_mode == USER_MODE) {
+ sbe = ((uint8_t *)sbe_var->data)[0];
+ }
+ } else if (platform_mode == USER_MODE) {
+ sbe = SECURE_BOOT_ENABLE;
+ set_secure_boot_enable(uv, sbe);
+ }
+
+ if (uv->force_secure_boot && sbe != SECURE_BOOT_ENABLE) {
+ sbe = SECURE_BOOT_ENABLE;
+ set_secure_boot_enable(uv, sbe);
+ }
+
+ /* SecureBoot */
+ if ((sbe == SECURE_BOOT_ENABLE) && (platform_mode == USER_MODE)) {
+ sb = SECURE_BOOT_MODE_ENABLE;
+ } else {
+ sb = SECURE_BOOT_MODE_DISABLE;
+ }
+ set_secure_boot(uv, sb);
+
+ /* CustomMode */
+ set_custom_mode(uv, STANDARD_SECURE_BOOT_MODE);
+
+ vk = 0;
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
+ name_vk_nv, sizeof(name_vk_nv),
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
+ &vk, sizeof(vk));
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
+ name_vk, sizeof(name_vk),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ &vk, sizeof(vk));
+
+ /* flush to disk */
+ uefi_vars_json_save(uv);
+}
diff --git a/hw/uefi/var-service-core.c b/hw/uefi/var-service-core.c
new file mode 100644
index 0000000..4836a0c
--- /dev/null
+++ b/hw/uefi/var-service-core.c
@@ -0,0 +1,322 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device
+ */
+#include "qemu/osdep.h"
+#include "qemu/crc32c.h"
+#include "system/dma.h"
+#include "migration/vmstate.h"
+
+#include "hw/uefi/var-service.h"
+#include "hw/uefi/var-service-api.h"
+#include "hw/uefi/var-service-edk2.h"
+
+#include "trace/trace-hw_uefi.h"
+
+static int uefi_vars_pre_load(void *opaque)
+{
+ uefi_vars_state *uv = opaque;
+
+ uefi_vars_clear_all(uv);
+ uefi_vars_policies_clear(uv);
+ g_free(uv->buffer);
+ return 0;
+}
+
+static int uefi_vars_post_load(void *opaque, int version_id)
+{
+ uefi_vars_state *uv = opaque;
+
+ uefi_vars_update_storage(uv);
+ uefi_vars_json_save(uv);
+ uv->buffer = g_malloc(uv->buf_size);
+ return 0;
+}
+
+const VMStateDescription vmstate_uefi_vars = {
+ .name = "uefi-vars",
+ .pre_load = uefi_vars_pre_load,
+ .post_load = uefi_vars_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(sts, uefi_vars_state),
+ VMSTATE_UINT32(buf_size, uefi_vars_state),
+ VMSTATE_UINT32(buf_addr_lo, uefi_vars_state),
+ VMSTATE_UINT32(buf_addr_hi, uefi_vars_state),
+ VMSTATE_UINT32(pio_xfer_offset, uefi_vars_state),
+ VMSTATE_VBUFFER_ALLOC_UINT32(pio_xfer_buffer, uefi_vars_state,
+ 0, NULL, buf_size),
+ VMSTATE_BOOL(end_of_dxe, uefi_vars_state),
+ VMSTATE_BOOL(ready_to_boot, uefi_vars_state),
+ VMSTATE_BOOL(exit_boot_service, uefi_vars_state),
+ VMSTATE_BOOL(policy_locked, uefi_vars_state),
+ VMSTATE_UINT64(used_storage, uefi_vars_state),
+ VMSTATE_QTAILQ_V(variables, uefi_vars_state, 0,
+ vmstate_uefi_variable, uefi_variable, next),
+ VMSTATE_QTAILQ_V(var_policies, uefi_vars_state, 0,
+ vmstate_uefi_var_policy, uefi_var_policy, next),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static uint32_t uefi_vars_cmd_mm(uefi_vars_state *uv, bool dma_mode)
+{
+ hwaddr dma;
+ mm_header *mhdr;
+ uint64_t size;
+ uint32_t retval;
+
+ dma = uv->buf_addr_lo | ((hwaddr)uv->buf_addr_hi << 32);
+ mhdr = (mm_header *) uv->buffer;
+
+ if (!uv->buffer || uv->buf_size < sizeof(*mhdr)) {
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
+ }
+
+ /* read header */
+ if (dma_mode) {
+ dma_memory_read(&address_space_memory, dma,
+ uv->buffer, sizeof(*mhdr),
+ MEMTXATTRS_UNSPECIFIED);
+ } else {
+ memcpy(uv->buffer, uv->pio_xfer_buffer, sizeof(*mhdr));
+ }
+
+ if (uadd64_overflow(sizeof(*mhdr), mhdr->length, &size)) {
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
+ }
+ if (uv->buf_size < size) {
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
+ }
+
+ /* read buffer (excl header) */
+ if (dma_mode) {
+ dma_memory_read(&address_space_memory, dma + sizeof(*mhdr),
+ uv->buffer + sizeof(*mhdr), mhdr->length,
+ MEMTXATTRS_UNSPECIFIED);
+ } else {
+ memcpy(uv->buffer + sizeof(*mhdr),
+ uv->pio_xfer_buffer + sizeof(*mhdr),
+ mhdr->length);
+ }
+ memset(uv->buffer + size, 0, uv->buf_size - size);
+
+ /* dispatch */
+ if (qemu_uuid_is_equal(&mhdr->guid, &EfiSmmVariableProtocolGuid)) {
+ retval = uefi_vars_mm_vars_proto(uv);
+
+ } else if (qemu_uuid_is_equal(&mhdr->guid, &VarCheckPolicyLibMmiHandlerGuid)) {
+ retval = uefi_vars_mm_check_policy_proto(uv);
+
+ } else if (qemu_uuid_is_equal(&mhdr->guid, &EfiEndOfDxeEventGroupGuid)) {
+ trace_uefi_event("end-of-dxe");
+ uv->end_of_dxe = true;
+ retval = UEFI_VARS_STS_SUCCESS;
+
+ } else if (qemu_uuid_is_equal(&mhdr->guid, &EfiEventReadyToBootGuid)) {
+ trace_uefi_event("ready-to-boot");
+ uv->ready_to_boot = true;
+ retval = UEFI_VARS_STS_SUCCESS;
+
+ } else if (qemu_uuid_is_equal(&mhdr->guid, &EfiEventExitBootServicesGuid)) {
+ trace_uefi_event("exit-boot-service");
+ uv->exit_boot_service = true;
+ retval = UEFI_VARS_STS_SUCCESS;
+
+ } else {
+ retval = UEFI_VARS_STS_ERR_NOT_SUPPORTED;
+ }
+
+ /* write buffer */
+ if (dma_mode) {
+ dma_memory_write(&address_space_memory, dma,
+ uv->buffer, sizeof(*mhdr) + mhdr->length,
+ MEMTXATTRS_UNSPECIFIED);
+ } else {
+ memcpy(uv->pio_xfer_buffer + sizeof(*mhdr),
+ uv->buffer + sizeof(*mhdr),
+ sizeof(*mhdr) + mhdr->length);
+ }
+
+ return retval;
+}
+
+static void uefi_vars_soft_reset(uefi_vars_state *uv)
+{
+ g_free(uv->buffer);
+ uv->buffer = NULL;
+ uv->buf_size = 0;
+ uv->buf_addr_lo = 0;
+ uv->buf_addr_hi = 0;
+}
+
+void uefi_vars_hard_reset(uefi_vars_state *uv)
+{
+ trace_uefi_hard_reset();
+ uefi_vars_soft_reset(uv);
+
+ uv->end_of_dxe = false;
+ uv->ready_to_boot = false;
+ uv->exit_boot_service = false;
+ uv->policy_locked = false;
+
+ uefi_vars_clear_volatile(uv);
+ uefi_vars_policies_clear(uv);
+ uefi_vars_auth_init(uv);
+}
+
+static uint32_t uefi_vars_cmd(uefi_vars_state *uv, uint32_t cmd)
+{
+ switch (cmd) {
+ case UEFI_VARS_CMD_RESET:
+ uefi_vars_soft_reset(uv);
+ return UEFI_VARS_STS_SUCCESS;
+ case UEFI_VARS_CMD_DMA_MM:
+ return uefi_vars_cmd_mm(uv, true);
+ case UEFI_VARS_CMD_PIO_MM:
+ return uefi_vars_cmd_mm(uv, false);
+ case UEFI_VARS_CMD_PIO_ZERO_OFFSET:
+ uv->pio_xfer_offset = 0;
+ return UEFI_VARS_STS_SUCCESS;
+ default:
+ return UEFI_VARS_STS_ERR_NOT_SUPPORTED;
+ }
+}
+
+static uint64_t uefi_vars_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uefi_vars_state *uv = opaque;
+ uint64_t retval = -1;
+ void *xfer_ptr;
+
+ trace_uefi_reg_read(addr, size);
+
+ switch (addr) {
+ case UEFI_VARS_REG_MAGIC:
+ retval = UEFI_VARS_MAGIC_VALUE;
+ break;
+ case UEFI_VARS_REG_CMD_STS:
+ retval = uv->sts;
+ break;
+ case UEFI_VARS_REG_BUFFER_SIZE:
+ retval = uv->buf_size;
+ break;
+ case UEFI_VARS_REG_DMA_BUFFER_ADDR_LO:
+ retval = uv->buf_addr_lo;
+ break;
+ case UEFI_VARS_REG_DMA_BUFFER_ADDR_HI:
+ retval = uv->buf_addr_hi;
+ break;
+ case UEFI_VARS_REG_PIO_BUFFER_TRANSFER:
+ if (uv->pio_xfer_offset + size > uv->buf_size) {
+ retval = 0;
+ break;
+ }
+ xfer_ptr = uv->pio_xfer_buffer + uv->pio_xfer_offset;
+ switch (size) {
+ case 1:
+ retval = *(uint8_t *)xfer_ptr;
+ break;
+ case 2:
+ retval = *(uint16_t *)xfer_ptr;
+ break;
+ case 4:
+ retval = *(uint32_t *)xfer_ptr;
+ break;
+ case 8:
+ retval = *(uint64_t *)xfer_ptr;
+ break;
+ }
+ uv->pio_xfer_offset += size;
+ break;
+ case UEFI_VARS_REG_PIO_BUFFER_CRC32C:
+ retval = crc32c(0xffffffff, uv->pio_xfer_buffer, uv->pio_xfer_offset);
+ break;
+ case UEFI_VARS_REG_FLAGS:
+ retval = 0;
+ if (uv->use_pio) {
+ retval |= UEFI_VARS_FLAG_USE_PIO;
+ }
+ }
+ return retval;
+}
+
+static void uefi_vars_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ uefi_vars_state *uv = opaque;
+ void *xfer_ptr;
+
+ trace_uefi_reg_write(addr, val, size);
+
+ switch (addr) {
+ case UEFI_VARS_REG_CMD_STS:
+ uv->sts = uefi_vars_cmd(uv, val);
+ break;
+ case UEFI_VARS_REG_BUFFER_SIZE:
+ if (val > MAX_BUFFER_SIZE) {
+ val = MAX_BUFFER_SIZE;
+ }
+ uv->buf_size = val;
+ g_free(uv->buffer);
+ g_free(uv->pio_xfer_buffer);
+ uv->buffer = g_malloc(uv->buf_size);
+ uv->pio_xfer_buffer = g_malloc(uv->buf_size);
+ break;
+ case UEFI_VARS_REG_DMA_BUFFER_ADDR_LO:
+ uv->buf_addr_lo = val;
+ break;
+ case UEFI_VARS_REG_DMA_BUFFER_ADDR_HI:
+ uv->buf_addr_hi = val;
+ break;
+ case UEFI_VARS_REG_PIO_BUFFER_TRANSFER:
+ if (uv->pio_xfer_offset + size > uv->buf_size) {
+ break;
+ }
+ xfer_ptr = uv->pio_xfer_buffer + uv->pio_xfer_offset;
+ switch (size) {
+ case 1:
+ *(uint8_t *)xfer_ptr = val;
+ break;
+ case 2:
+ *(uint16_t *)xfer_ptr = val;
+ break;
+ case 4:
+ *(uint32_t *)xfer_ptr = val;
+ break;
+ case 8:
+ *(uint64_t *)xfer_ptr = val;
+ break;
+ }
+ uv->pio_xfer_offset += size;
+ break;
+ case UEFI_VARS_REG_PIO_BUFFER_CRC32C:
+ case UEFI_VARS_REG_FLAGS:
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps uefi_vars_ops = {
+ .read = uefi_vars_read,
+ .write = uefi_vars_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 2,
+ .max_access_size = 4,
+ },
+};
+
+void uefi_vars_init(Object *obj, uefi_vars_state *uv)
+{
+ QTAILQ_INIT(&uv->variables);
+ QTAILQ_INIT(&uv->var_policies);
+ uv->jsonfd = -1;
+ memory_region_init_io(&uv->mr, obj, &uefi_vars_ops, uv,
+ "uefi-vars", UEFI_VARS_REGS_SIZE);
+}
+
+void uefi_vars_realize(uefi_vars_state *uv, Error **errp)
+{
+ uefi_vars_json_init(uv, errp);
+ uefi_vars_json_load(uv, errp);
+}
diff --git a/hw/uefi/var-service-guid.c b/hw/uefi/var-service-guid.c
new file mode 100644
index 0000000..eba3655
--- /dev/null
+++ b/hw/uefi/var-service-guid.c
@@ -0,0 +1,99 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - GUIDs
+ */
+
+#include "qemu/osdep.h"
+#include "system/dma.h"
+
+#include "hw/uefi/var-service.h"
+
+/* variable namespaces */
+
+const QemuUUID EfiGlobalVariable = {
+ .data = UUID_LE(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d,
+ 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
+};
+
+const QemuUUID EfiImageSecurityDatabase = {
+ .data = UUID_LE(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc,
+ 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
+};
+
+const QemuUUID EfiCustomModeEnable = {
+ .data = UUID_LE(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72,
+ 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
+};
+
+const QemuUUID EfiSecureBootEnableDisable = {
+ .data = UUID_LE(0xf0a30bc7, 0xaf08, 0x4556, 0x99, 0xc4,
+ 0x0, 0x10, 0x9, 0xc9, 0x3a, 0x44)
+};
+
+/* signatures */
+
+const QemuUUID EfiCertSha256Guid = {
+ .data = UUID_LE(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9,
+ 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)
+};
+
+const QemuUUID EfiCertSha384Guid = {
+ .data = UUID_LE(0xff3e5307, 0x9fd0, 0x48c9, 0x85, 0xf1,
+ 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1)
+};
+
+const QemuUUID EfiCertSha512Guid = {
+ .data = UUID_LE(0x93e0fae, 0xa6c4, 0x4f50, 0x9f, 0x1b,
+ 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a)
+};
+
+const QemuUUID EfiCertRsa2048Guid = {
+ .data = UUID_LE(0x3c5766e8, 0x269c, 0x4e34, 0xaa, 0x14,
+ 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6)
+};
+
+const QemuUUID EfiCertX509Guid = {
+ .data = UUID_LE(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5,
+ 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
+};
+
+const QemuUUID EfiCertTypePkcs7Guid = {
+ .data = UUID_LE(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9,
+ 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
+};
+
+/*
+ * mm_header.guid values that the guest DXE/BDS phases use for
+ * sending requests to management mode
+ */
+
+const QemuUUID EfiSmmVariableProtocolGuid = {
+ .data = UUID_LE(0xed32d533, 0x99e6, 0x4209, 0x9c, 0xc0,
+ 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7)
+};
+
+const QemuUUID VarCheckPolicyLibMmiHandlerGuid = {
+ .data = UUID_LE(0xda1b0d11, 0xd1a7, 0x46c4, 0x9d, 0xc9,
+ 0xf3, 0x71, 0x48, 0x75, 0xc6, 0xeb)
+};
+
+/*
+ * mm_header.guid values that the guest DXE/BDS phases use for
+ * reporting event groups being signaled to management mode
+ */
+
+const QemuUUID EfiEndOfDxeEventGroupGuid = {
+ .data = UUID_LE(0x02ce967a, 0xdd7e, 0x4FFc, 0x9e, 0xe7,
+ 0x81, 0x0c, 0xF0, 0x47, 0x08, 0x80)
+};
+
+const QemuUUID EfiEventReadyToBootGuid = {
+ .data = UUID_LE(0x7ce88Fb3, 0x4bd7, 0x4679, 0x87, 0xa8,
+ 0xa8, 0xd8, 0xde, 0xe5, 0x0d, 0x2b)
+};
+
+const QemuUUID EfiEventExitBootServicesGuid = {
+ .data = UUID_LE(0x27abF055, 0xb1b8, 0x4c26, 0x80, 0x48,
+ 0x74, 0x8F, 0x37, 0xba, 0xa2, 0xdF)
+};
diff --git a/hw/uefi/var-service-json.c b/hw/uefi/var-service-json.c
new file mode 100644
index 0000000..ad3462c
--- /dev/null
+++ b/hw/uefi/var-service-json.c
@@ -0,0 +1,257 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - serialize non-volatile varstore from/to json,
+ * using qapi
+ *
+ * tools which can read/write these json files:
+ * - https://gitlab.com/kraxel/virt-firmware
+ * - https://github.com/awslabs/python-uefivars
+ */
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "system/dma.h"
+
+#include "hw/uefi/var-service.h"
+
+#include "qobject/qobject.h"
+#include "qobject/qjson.h"
+
+#include "qapi/dealloc-visitor.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
+#include "qapi/qapi-types-uefi.h"
+#include "qapi/qapi-visit-uefi.h"
+
+static char *generate_hexstr(void *data, size_t len)
+{
+ static const char hex[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+ };
+ uint8_t *src = data;
+ char *dest;
+ size_t i;
+
+ dest = g_malloc(len * 2 + 1);
+ for (i = 0; i < len * 2;) {
+ dest[i++] = hex[*src >> 4];
+ dest[i++] = hex[*src & 15];
+ src++;
+ }
+ dest[i++] = 0;
+
+ return dest;
+}
+
+static UefiVarStore *uefi_vars_to_qapi(uefi_vars_state *uv)
+{
+ UefiVarStore *vs;
+ UefiVariableList **tail;
+ UefiVariable *v;
+ QemuUUID be;
+ uefi_variable *var;
+
+ vs = g_new0(UefiVarStore, 1);
+ vs->version = 2;
+ tail = &vs->variables;
+
+ QTAILQ_FOREACH(var, &uv->variables, next) {
+ if (!(var->attributes & EFI_VARIABLE_NON_VOLATILE)) {
+ continue;
+ }
+
+ v = g_new0(UefiVariable, 1);
+ be = qemu_uuid_bswap(var->guid);
+ v->guid = qemu_uuid_unparse_strdup(&be);
+ v->name = uefi_ucs2_to_ascii(var->name, var->name_size);
+ v->attr = var->attributes;
+
+ v->data = generate_hexstr(var->data, var->data_size);
+
+ if (var->attributes &
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+ v->time = generate_hexstr(&var->time, sizeof(var->time));
+ if (var->digest && var->digest_size) {
+ v->digest = generate_hexstr(var->digest, var->digest_size);
+ }
+ }
+
+ QAPI_LIST_APPEND(tail, v);
+ }
+ return vs;
+}
+
+static unsigned parse_hexchar(char c)
+{
+ switch (c) {
+ case '0' ... '9': return c - '0';
+ case 'a' ... 'f': return c - 'a' + 0xa;
+ case 'A' ... 'F': return c - 'A' + 0xA;
+ default: return 0;
+ }
+}
+
+static void parse_hexstr(void *dest, char *src, int len)
+{
+ uint8_t *data = dest;
+ size_t i;
+
+ for (i = 0; i < len; i += 2) {
+ *(data++) =
+ parse_hexchar(src[i]) << 4 |
+ parse_hexchar(src[i + 1]);
+ }
+}
+
+static void uefi_vars_from_qapi(uefi_vars_state *uv, UefiVarStore *vs)
+{
+ UefiVariableList *item;
+ UefiVariable *v;
+ QemuUUID be;
+ uefi_variable *var;
+ uint8_t *data;
+ size_t i, len;
+
+ for (item = vs->variables; item != NULL; item = item->next) {
+ v = item->value;
+
+ var = g_new0(uefi_variable, 1);
+ var->attributes = v->attr;
+ qemu_uuid_parse(v->guid, &be);
+ var->guid = qemu_uuid_bswap(be);
+
+ len = strlen(v->name);
+ var->name_size = len * 2 + 2;
+ var->name = g_malloc(var->name_size);
+ for (i = 0; i <= len; i++) {
+ var->name[i] = v->name[i];
+ }
+
+ len = strlen(v->data);
+ var->data_size = len / 2;
+ var->data = data = g_malloc(var->data_size);
+ parse_hexstr(var->data, v->data, len);
+
+ if (v->time && strlen(v->time) == 32) {
+ parse_hexstr(&var->time, v->time, 32);
+ }
+
+ if (v->digest) {
+ len = strlen(v->digest);
+ var->digest_size = len / 2;
+ var->digest = g_malloc(var->digest_size);
+ parse_hexstr(var->digest, v->digest, len);
+ }
+
+ QTAILQ_INSERT_TAIL(&uv->variables, var, next);
+ }
+}
+
+static GString *uefi_vars_to_json(uefi_vars_state *uv)
+{
+ UefiVarStore *vs = uefi_vars_to_qapi(uv);
+ QObject *qobj = NULL;
+ Visitor *v;
+ GString *gstr;
+
+ v = qobject_output_visitor_new(&qobj);
+ if (visit_type_UefiVarStore(v, NULL, &vs, NULL)) {
+ visit_complete(v, &qobj);
+ }
+ visit_free(v);
+ qapi_free_UefiVarStore(vs);
+
+ gstr = qobject_to_json_pretty(qobj, true);
+ qobject_unref(qobj);
+
+ return gstr;
+}
+
+void uefi_vars_json_init(uefi_vars_state *uv, Error **errp)
+{
+ if (uv->jsonfile) {
+ uv->jsonfd = qemu_create(uv->jsonfile, O_RDWR, 0666, errp);
+ }
+}
+
+void uefi_vars_json_save(uefi_vars_state *uv)
+{
+ g_autoptr(GString) gstr = NULL;
+ int rc;
+
+ if (uv->jsonfd == -1) {
+ return;
+ }
+
+ gstr = uefi_vars_to_json(uv);
+
+ rc = lseek(uv->jsonfd, 0, SEEK_SET);
+ if (rc < 0) {
+ warn_report("%s: lseek error", __func__);
+ return;
+ }
+
+ rc = ftruncate(uv->jsonfd, 0);
+ if (rc != 0) {
+ warn_report("%s: ftruncate error", __func__);
+ return;
+ }
+
+ rc = write(uv->jsonfd, gstr->str, gstr->len);
+ if (rc != gstr->len) {
+ warn_report("%s: write error", __func__);
+ return;
+ }
+
+ fsync(uv->jsonfd);
+}
+
+void uefi_vars_json_load(uefi_vars_state *uv, Error **errp)
+{
+ UefiVarStore *vs;
+ QObject *qobj;
+ Visitor *v;
+ char *str;
+ ssize_t len;
+ int rc;
+
+ if (uv->jsonfd == -1) {
+ return;
+ }
+
+ len = lseek(uv->jsonfd, 0, SEEK_END);
+ if (len < 0) {
+ warn_report("%s: lseek error", __func__);
+ return;
+ }
+ if (len == 0) {
+ /* empty file */
+ return;
+ }
+
+ str = g_malloc(len + 1);
+ lseek(uv->jsonfd, 0, SEEK_SET);
+ rc = read(uv->jsonfd, str, len);
+ if (rc != len) {
+ warn_report("%s: read error", __func__);
+ g_free(str);
+ return;
+ }
+ str[len] = 0;
+
+ qobj = qobject_from_json(str, errp);
+ v = qobject_input_visitor_new(qobj);
+ visit_type_UefiVarStore(v, NULL, &vs, errp);
+ visit_free(v);
+
+ if (!(*errp)) {
+ uefi_vars_from_qapi(uv, vs);
+ uefi_vars_update_storage(uv);
+ }
+
+ qapi_free_UefiVarStore(vs);
+ qobject_unref(qobj);
+ g_free(str);
+}
diff --git a/hw/uefi/var-service-pkcs7-stub.c b/hw/uefi/var-service-pkcs7-stub.c
new file mode 100644
index 0000000..118cba4
--- /dev/null
+++ b/hw/uefi/var-service-pkcs7-stub.c
@@ -0,0 +1,16 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - pkcs7 stubs
+ */
+#include "qemu/osdep.h"
+#include "system/dma.h"
+
+#include "hw/uefi/var-service.h"
+
+efi_status uefi_vars_check_pkcs7_2(uefi_variable *siglist,
+ void **digest, uint32_t *digest_size,
+ mm_variable_access *va, void *data)
+{
+ return EFI_WRITE_PROTECTED;
+}
diff --git a/hw/uefi/var-service-pkcs7.c b/hw/uefi/var-service-pkcs7.c
new file mode 100644
index 0000000..32accf4
--- /dev/null
+++ b/hw/uefi/var-service-pkcs7.c
@@ -0,0 +1,436 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - pkcs7 verification
+ */
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "system/dma.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/pkcs7.h>
+#include <gnutls/crypto.h>
+
+#include "hw/uefi/var-service.h"
+
+#define AUTHVAR_DIGEST_ALGO GNUTLS_DIG_SHA256
+#define AUTHVAR_DIGEST_SIZE 32
+
+/*
+ * Replicate the signed data for signature verification.
+ */
+static gnutls_datum_t *build_signed_data(mm_variable_access *va, void *data)
+{
+ variable_auth_2 *auth = data;
+ uint64_t data_offset = sizeof(efi_time) + auth->hdr_length;
+ uint16_t *name = (void *)va + sizeof(mm_variable_access);
+ gnutls_datum_t *sdata;
+ uint64_t pos = 0;
+
+ sdata = g_new(gnutls_datum_t, 1);
+ sdata->size = (va->name_size - 2
+ + sizeof(QemuUUID)
+ + sizeof(va->attributes)
+ + sizeof(auth->timestamp)
+ + va->data_size - data_offset);
+ sdata->data = g_malloc(sdata->size);
+
+ /* Variable Name (without terminating \0) */
+ memcpy(sdata->data + pos, name, va->name_size - 2);
+ pos += va->name_size - 2;
+
+ /* Variable Namespace Guid */
+ memcpy(sdata->data + pos, &va->guid, sizeof(va->guid));
+ pos += sizeof(va->guid);
+
+ /* Attributes */
+ memcpy(sdata->data + pos, &va->attributes, sizeof(va->attributes));
+ pos += sizeof(va->attributes);
+
+ /* TimeStamp */
+ memcpy(sdata->data + pos, &auth->timestamp, sizeof(auth->timestamp));
+ pos += sizeof(auth->timestamp);
+
+ /* Variable Content */
+ memcpy(sdata->data + pos, data + data_offset, va->data_size - data_offset);
+ pos += va->data_size - data_offset;
+
+ assert(pos == sdata->size);
+ return sdata;
+}
+
+/*
+ * See WrapPkcs7Data() in edk2.
+ *
+ * UEFI spec allows pkcs7 signatures being used without the envelope which
+ * identifies them as pkcs7 signatures. openssl and gnutls will not parse them
+ * without the envelope though. So add it if needed.
+ */
+static void wrap_pkcs7(gnutls_datum_t *pkcs7)
+{
+ static uint8_t signed_data_oid[9] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02
+ };
+ gnutls_datum_t wrap;
+
+ if (pkcs7->data[4] == 0x06 &&
+ pkcs7->data[5] == 0x09 &&
+ memcmp(pkcs7->data + 6, signed_data_oid, sizeof(signed_data_oid)) == 0 &&
+ pkcs7->data[15] == 0x0a &&
+ pkcs7->data[16] == 0x82) {
+ return;
+ }
+
+ wrap.size = pkcs7->size + 19;
+ wrap.data = g_malloc(wrap.size);
+
+ wrap.data[0] = 0x30;
+ wrap.data[1] = 0x82;
+ wrap.data[2] = (wrap.size - 4) >> 8;
+ wrap.data[3] = (wrap.size - 4) & 0xff;
+ wrap.data[4] = 0x06;
+ wrap.data[5] = 0x09;
+ memcpy(wrap.data + 6, signed_data_oid, sizeof(signed_data_oid));
+
+ wrap.data[15] = 0xa0;
+ wrap.data[16] = 0x82;
+ wrap.data[17] = pkcs7->size >> 8;
+ wrap.data[18] = pkcs7->size & 0xff;
+ memcpy(wrap.data + 19, pkcs7->data, pkcs7->size);
+
+ g_free(pkcs7->data);
+ *pkcs7 = wrap;
+}
+
+static gnutls_datum_t *build_pkcs7(void *data)
+{
+ variable_auth_2 *auth = data;
+ gnutls_datum_t *pkcs7;
+
+ pkcs7 = g_new(gnutls_datum_t, 1);
+ pkcs7->size = auth->hdr_length - 24;
+ pkcs7->data = g_malloc(pkcs7->size);
+ memcpy(pkcs7->data, data + 16 + 24, pkcs7->size);
+
+ wrap_pkcs7(pkcs7);
+
+ return pkcs7;
+}
+
+/*
+ * Read UEFI signature database, store x509 all certificates found in
+ * gnutls_x509_trust_list_t.
+ */
+static gnutls_x509_trust_list_t build_trust_list_sb(uefi_variable *var)
+{
+ gnutls_x509_trust_list_t tlist;
+ gnutls_datum_t cert_data;
+ gnutls_x509_crt_t cert;
+ uefi_vars_siglist siglist;
+ uefi_vars_cert *c;
+ int rc;
+
+ rc = gnutls_x509_trust_list_init(&tlist, 0);
+ if (rc < 0) {
+ warn_report("gnutls_x509_trust_list_init error: %s",
+ gnutls_strerror(rc));
+ return NULL;
+ }
+
+ uefi_vars_siglist_init(&siglist);
+ uefi_vars_siglist_parse(&siglist, var->data, var->data_size);
+
+ QTAILQ_FOREACH(c, &siglist.x509, next) {
+ cert_data.size = c->size;
+ cert_data.data = c->data;
+
+ rc = gnutls_x509_crt_init(&cert);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
+ break;
+ }
+ rc = gnutls_x509_crt_import(cert, &cert_data, GNUTLS_X509_FMT_DER);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_import error: %s",
+ gnutls_strerror(rc));
+ gnutls_x509_crt_deinit(cert);
+ break;
+ }
+ rc = gnutls_x509_trust_list_add_cas(tlist, &cert, 1, 0);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_import error: %s",
+ gnutls_strerror(rc));
+ gnutls_x509_crt_deinit(cert);
+ break;
+ }
+ }
+
+ uefi_vars_siglist_free(&siglist);
+
+ return tlist;
+}
+
+static int build_digest_authvar(gnutls_x509_crt_t signer,
+ gnutls_x509_crt_t root,
+ uint8_t *hash_digest)
+{
+ char *cn;
+ size_t cn_size = 0;
+ uint8_t fp[AUTHVAR_DIGEST_SIZE];
+ size_t fp_size = sizeof(fp);
+ gnutls_hash_hd_t hash;
+ int rc;
+
+ /* get signer CN */
+ rc = gnutls_x509_crt_get_dn_by_oid(signer, GNUTLS_OID_X520_COMMON_NAME,
+ 0, 0, NULL, &cn_size);
+ if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ warn_report("gnutls_x509_crt_get_dn_by_oid error #1: %s",
+ gnutls_strerror(rc));
+ return rc;
+ }
+
+ cn = g_malloc(cn_size);
+ rc = gnutls_x509_crt_get_dn_by_oid(signer, GNUTLS_OID_X520_COMMON_NAME,
+ 0, 0, cn, &cn_size);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_get_dn_by_oid error #2: %s",
+ gnutls_strerror(rc));
+ goto err;
+ }
+
+ /* get root certificate fingerprint */
+ rc = gnutls_x509_crt_get_fingerprint(root, AUTHVAR_DIGEST_ALGO,
+ fp, &fp_size);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_get_fingerprint error: %s",
+ gnutls_strerror(rc));
+ goto err;
+ }
+
+ /* digest both items */
+ rc = gnutls_hash_init(&hash, AUTHVAR_DIGEST_ALGO);
+ if (rc < 0) {
+ warn_report("gnutls_hash_init error: %s",
+ gnutls_strerror(rc));
+ goto err;
+ }
+ rc = gnutls_hash(hash, cn, cn_size);
+ if (rc < 0) {
+ warn_report("gnutls_hash error: %s",
+ gnutls_strerror(rc));
+ goto err;
+ }
+ rc = gnutls_hash(hash, fp, fp_size);
+ if (rc < 0) {
+ warn_report("gnutls_hash error: %s",
+ gnutls_strerror(rc));
+ goto err;
+ }
+ gnutls_hash_deinit(hash, hash_digest);
+
+ return 0;
+
+err:
+ g_free(cn);
+ return rc;
+}
+
+/*
+ * uefi spec 2.9, section 8.2.2
+ *
+ * For EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS variables which are
+ * NOT secure boot variables we should track the root certificate of the trust
+ * chain, and the subject CN of the signer certificate.
+ *
+ * So we'll go store a digest of these two items so we can verify this. Also
+ * create a gnutls_x509_trust_list_t with the root certificate, so
+ * gnutls_pkcs7_verify() will pass (assuming the signature is otherwise
+ * correct).
+ */
+static gnutls_x509_trust_list_t build_trust_list_authvar(gnutls_pkcs7_t pkcs7,
+ uint8_t *hash_digest)
+{
+ gnutls_datum_t signer_data = { 0 };
+ gnutls_datum_t root_data = { 0 };
+ gnutls_x509_crt_t signer = NULL;
+ gnutls_x509_crt_t root = NULL;
+ gnutls_x509_trust_list_t tlist = NULL;
+ int n, rc;
+
+ n = gnutls_pkcs7_get_crt_count(pkcs7);
+
+ /* first is signer certificate */
+ rc = gnutls_pkcs7_get_crt_raw2(pkcs7, 0, &signer_data);
+ if (rc < 0) {
+ warn_report("gnutls_pkcs7_get_crt_raw2(0) error: %s",
+ gnutls_strerror(rc));
+ goto done;
+ }
+ rc = gnutls_x509_crt_init(&signer);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
+ goto done;
+ }
+ rc = gnutls_x509_crt_import(signer, &signer_data, GNUTLS_X509_FMT_DER);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_import error: %s",
+ gnutls_strerror(rc));
+ gnutls_x509_crt_deinit(signer);
+ goto done;
+ }
+
+ /* last is root-of-trust certificate (can be identical to signer) */
+ rc = gnutls_pkcs7_get_crt_raw2(pkcs7, n - 1, &root_data);
+ if (rc < 0) {
+ warn_report("gnutls_pkcs7_get_crt_raw2(%d) error: %s",
+ n - 1, gnutls_strerror(rc));
+ goto done;
+ }
+ rc = gnutls_x509_crt_init(&root);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
+ goto done;
+ }
+ rc = gnutls_x509_crt_import(root, &root_data, GNUTLS_X509_FMT_DER);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_import error: %s",
+ gnutls_strerror(rc));
+ goto done;
+ }
+
+ /* calc digest for signer CN + root cert */
+ rc = build_digest_authvar(signer, root, hash_digest);
+ if (rc < 0) {
+ goto done;
+ }
+
+ /* add root to trust list */
+ rc = gnutls_x509_trust_list_init(&tlist, 0);
+ if (rc < 0) {
+ warn_report("gnutls_x509_trust_list_init error: %s",
+ gnutls_strerror(rc));
+ goto done;
+ }
+ rc = gnutls_x509_trust_list_add_cas(tlist, &root, 1, 0);
+ if (rc < 0) {
+ warn_report("gnutls_x509_crt_import error: %s",
+ gnutls_strerror(rc));
+ gnutls_x509_trust_list_deinit(tlist, 1);
+ tlist = NULL;
+ goto done;
+ } else {
+ /* ownership passed to tlist */
+ root = NULL;
+ }
+
+done:
+ if (signer_data.data) {
+ gnutls_free(signer_data.data);
+ }
+ if (root_data.data) {
+ gnutls_free(root_data.data);
+ }
+ if (signer) {
+ gnutls_x509_crt_deinit(signer);
+ }
+ if (root) {
+ gnutls_x509_crt_deinit(root);
+ }
+ return tlist;
+}
+
+static void free_datum(gnutls_datum_t *ptr)
+{
+ if (!ptr) {
+ return;
+ }
+ g_free(ptr->data);
+ g_free(ptr);
+}
+
+static void gnutls_log_stderr(int level, const char *msg)
+{
+ if (strncmp(msg, "ASSERT:", 7) == 0) {
+ return;
+ }
+ fprintf(stderr, " %d: %s", level, msg);
+}
+
+/*
+ * pkcs7 signature verification (EFI_VARIABLE_AUTHENTICATION_2).
+ */
+efi_status uefi_vars_check_pkcs7_2(uefi_variable *siglist,
+ void **digest, uint32_t *digest_size,
+ mm_variable_access *va, void *data)
+{
+ gnutls_x509_trust_list_t tlist = NULL;
+ gnutls_datum_t *signed_data = NULL;
+ gnutls_datum_t *pkcs7_data = NULL;
+ gnutls_pkcs7_t pkcs7 = NULL;
+ efi_status status = EFI_SECURITY_VIOLATION;
+ int rc;
+
+ if (0) {
+ /* gnutls debug logging */
+ static bool first = true;
+
+ if (first) {
+ first = false;
+ gnutls_global_set_log_function(gnutls_log_stderr);
+ gnutls_global_set_log_level(99);
+ }
+ }
+
+ signed_data = build_signed_data(va, data);
+ pkcs7_data = build_pkcs7(data);
+
+ rc = gnutls_pkcs7_init(&pkcs7);
+ if (rc < 0) {
+ warn_report("gnutls_pkcs7_init error: %s", gnutls_strerror(rc));
+ goto out;
+ }
+
+ rc = gnutls_pkcs7_import(pkcs7, pkcs7_data, GNUTLS_X509_FMT_DER);
+ if (rc < 0) {
+ warn_report("gnutls_pkcs7_import error: %s", gnutls_strerror(rc));
+ goto out;
+ }
+
+ if (siglist) {
+ /* secure boot variables */
+ tlist = build_trust_list_sb(siglist);
+ } else if (digest && digest_size) {
+ /* other authenticated variables */
+ *digest_size = AUTHVAR_DIGEST_SIZE;
+ *digest = g_malloc(*digest_size);
+ tlist = build_trust_list_authvar(pkcs7, *digest);
+ } else {
+ /* should not happen */
+ goto out;
+ }
+
+ rc = gnutls_pkcs7_verify(pkcs7, tlist,
+ NULL, 0,
+ 0, signed_data,
+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS |
+ GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS);
+ if (rc < 0) {
+ warn_report("gnutls_pkcs7_verify error: %s", gnutls_strerror(rc));
+ goto out;
+ }
+
+ /* check passed */
+ status = EFI_SUCCESS;
+
+out:
+ free_datum(signed_data);
+ free_datum(pkcs7_data);
+ if (tlist) {
+ gnutls_x509_trust_list_deinit(tlist, 1);
+ }
+ if (pkcs7) {
+ gnutls_pkcs7_deinit(pkcs7);
+ }
+ return status;
+}
diff --git a/hw/uefi/var-service-policy.c b/hw/uefi/var-service-policy.c
new file mode 100644
index 0000000..3b1155f
--- /dev/null
+++ b/hw/uefi/var-service-policy.c
@@ -0,0 +1,370 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - VarCheckPolicyLibMmiHandler implementation
+ *
+ * variable policy specs:
+ * https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md
+ */
+#include "qemu/osdep.h"
+#include "system/dma.h"
+#include "migration/vmstate.h"
+
+#include "hw/uefi/var-service.h"
+#include "hw/uefi/var-service-api.h"
+#include "hw/uefi/var-service-edk2.h"
+
+#include "trace/trace-hw_uefi.h"
+
+static void calc_policy(uefi_var_policy *pol);
+
+static int uefi_var_policy_post_load(void *opaque, int version_id)
+{
+ uefi_var_policy *pol = opaque;
+
+ calc_policy(pol);
+ return 0;
+}
+
+const VMStateDescription vmstate_uefi_var_policy = {
+ .name = "uefi-var-policy",
+ .post_load = uefi_var_policy_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(entry_size, uefi_var_policy),
+ VMSTATE_VBUFFER_ALLOC_UINT32(entry, uefi_var_policy,
+ 0, NULL, entry_size),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void print_policy_entry(variable_policy_entry *pe)
+{
+ uint16_t *name = (void *)pe + pe->offset_to_name;
+
+ fprintf(stderr, "%s:\n", __func__);
+
+ fprintf(stderr, " name ´");
+ while (*name) {
+ fprintf(stderr, "%c", *name);
+ name++;
+ }
+ fprintf(stderr, "', version=%d.%d, size=%d\n",
+ pe->version >> 16, pe->version & 0xffff, pe->size);
+
+ if (pe->min_size) {
+ fprintf(stderr, " size min=%d\n", pe->min_size);
+ }
+ if (pe->max_size != UINT32_MAX) {
+ fprintf(stderr, " size max=%u\n", pe->max_size);
+ }
+ if (pe->attributes_must_have) {
+ fprintf(stderr, " attr must=0x%x\n", pe->attributes_must_have);
+ }
+ if (pe->attributes_cant_have) {
+ fprintf(stderr, " attr cant=0x%x\n", pe->attributes_cant_have);
+ }
+ if (pe->lock_policy_type) {
+ fprintf(stderr, " lock policy type %d\n", pe->lock_policy_type);
+ }
+}
+
+static gboolean wildcard_str_equal(uefi_var_policy *pol,
+ uefi_variable *var)
+{
+ return uefi_str_equal_ex(pol->name, pol->name_size,
+ var->name, var->name_size,
+ true);
+}
+
+static uefi_var_policy *find_policy(uefi_vars_state *uv, QemuUUID guid,
+ uint16_t *name, uint64_t name_size)
+{
+ uefi_var_policy *pol;
+
+ QTAILQ_FOREACH(pol, &uv->var_policies, next) {
+ if (!qemu_uuid_is_equal(&pol->entry->namespace, &guid)) {
+ continue;
+ }
+ if (!uefi_str_equal(pol->name, pol->name_size,
+ name, name_size)) {
+ continue;
+ }
+ return pol;
+ }
+ return NULL;
+}
+
+static uefi_var_policy *wildcard_find_policy(uefi_vars_state *uv,
+ uefi_variable *var)
+{
+ uefi_var_policy *pol;
+
+ QTAILQ_FOREACH(pol, &uv->var_policies, next) {
+ if (!qemu_uuid_is_equal(&pol->entry->namespace, &var->guid)) {
+ continue;
+ }
+ if (!wildcard_str_equal(pol, var)) {
+ continue;
+ }
+ return pol;
+ }
+ return NULL;
+}
+
+static void calc_policy(uefi_var_policy *pol)
+{
+ variable_policy_entry *pe = pol->entry;
+ unsigned int i;
+
+ pol->name = (void *)pol->entry + pe->offset_to_name;
+ pol->name_size = pe->size - pe->offset_to_name;
+
+ for (i = 0; i < pol->name_size / 2; i++) {
+ if (pol->name[i] == '#') {
+ pol->hashmarks++;
+ }
+ }
+}
+
+uefi_var_policy *uefi_vars_add_policy(uefi_vars_state *uv,
+ variable_policy_entry *pe)
+{
+ uefi_var_policy *pol, *p;
+
+ pol = g_new0(uefi_var_policy, 1);
+ pol->entry = g_malloc(pe->size);
+ memcpy(pol->entry, pe, pe->size);
+ pol->entry_size = pe->size;
+
+ calc_policy(pol);
+
+ /* keep list sorted by priority, add to tail of priority group */
+ QTAILQ_FOREACH(p, &uv->var_policies, next) {
+ if ((p->hashmarks > pol->hashmarks) ||
+ (!p->name_size && pol->name_size)) {
+ QTAILQ_INSERT_BEFORE(p, pol, next);
+ return pol;
+ }
+ }
+
+ QTAILQ_INSERT_TAIL(&uv->var_policies, pol, next);
+ return pol;
+}
+
+efi_status uefi_vars_policy_check(uefi_vars_state *uv,
+ uefi_variable *var,
+ gboolean is_newvar)
+{
+ uefi_var_policy *pol;
+ variable_policy_entry *pe;
+ variable_lock_on_var_state *lvarstate;
+ uint16_t *lvarname;
+ size_t lvarnamesize;
+ uefi_variable *lvar;
+
+ if (!uv->end_of_dxe) {
+ return EFI_SUCCESS;
+ }
+
+ pol = wildcard_find_policy(uv, var);
+ if (!pol) {
+ return EFI_SUCCESS;
+ }
+ pe = pol->entry;
+
+ uefi_trace_variable(__func__, var->guid, var->name, var->name_size);
+ print_policy_entry(pe);
+
+ if ((var->attributes & pe->attributes_must_have) != pe->attributes_must_have) {
+ trace_uefi_vars_policy_deny("must-have-attr");
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((var->attributes & pe->attributes_cant_have) != 0) {
+ trace_uefi_vars_policy_deny("cant-have-attr");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (var->data_size < pe->min_size) {
+ trace_uefi_vars_policy_deny("min-size");
+ return EFI_INVALID_PARAMETER;
+ }
+ if (var->data_size > pe->max_size) {
+ trace_uefi_vars_policy_deny("max-size");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (pe->lock_policy_type) {
+ case VARIABLE_POLICY_TYPE_NO_LOCK:
+ break;
+
+ case VARIABLE_POLICY_TYPE_LOCK_NOW:
+ trace_uefi_vars_policy_deny("lock-now");
+ return EFI_WRITE_PROTECTED;
+
+ case VARIABLE_POLICY_TYPE_LOCK_ON_CREATE:
+ if (!is_newvar) {
+ trace_uefi_vars_policy_deny("lock-on-create");
+ return EFI_WRITE_PROTECTED;
+ }
+ break;
+
+ case VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE:
+ lvarstate = (void *)pol->entry + sizeof(*pe);
+ lvarname = (void *)pol->entry + sizeof(*pe) + sizeof(*lvarstate);
+ lvarnamesize = pe->offset_to_name - sizeof(*pe) - sizeof(*lvarstate);
+
+ uefi_trace_variable(__func__, lvarstate->namespace,
+ lvarname, lvarnamesize);
+ lvar = uefi_vars_find_variable(uv, lvarstate->namespace,
+ lvarname, lvarnamesize);
+ if (lvar && lvar->data_size == 1) {
+ uint8_t *value = lvar->data;
+ if (lvarstate->value == *value) {
+ return EFI_WRITE_PROTECTED;
+ }
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+void uefi_vars_policies_clear(uefi_vars_state *uv)
+{
+ uefi_var_policy *pol;
+
+ while (!QTAILQ_EMPTY(&uv->var_policies)) {
+ pol = QTAILQ_FIRST(&uv->var_policies);
+ QTAILQ_REMOVE(&uv->var_policies, pol, next);
+ g_free(pol->entry);
+ g_free(pol);
+ }
+}
+
+static size_t uefi_vars_mm_policy_error(mm_header *mhdr,
+ mm_check_policy *mchk,
+ uint64_t status)
+{
+ mchk->result = status;
+ return sizeof(*mchk);
+}
+
+static uint32_t uefi_vars_mm_check_policy_is_enabled(uefi_vars_state *uv,
+ mm_header *mhdr,
+ mm_check_policy *mchk,
+ void *func)
+{
+ mm_check_policy_is_enabled *mpar = func;
+ size_t length;
+
+ length = sizeof(*mchk) + sizeof(*mpar);
+ if (mhdr->length < length) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
+ }
+
+ mpar->state = TRUE;
+ mchk->result = EFI_SUCCESS;
+ return sizeof(*mchk);
+}
+
+static uint32_t uefi_vars_mm_check_policy_register(uefi_vars_state *uv,
+ mm_header *mhdr,
+ mm_check_policy *mchk,
+ void *func)
+{
+ variable_policy_entry *pe = func;
+ uefi_var_policy *pol;
+ uint64_t length;
+
+ if (uadd64_overflow(sizeof(*mchk), pe->size, &length)) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
+ }
+ if (mhdr->length < length) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
+ }
+ if (pe->size < sizeof(*pe)) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
+ }
+ if (pe->offset_to_name < sizeof(*pe)) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
+ }
+
+ if (pe->lock_policy_type == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE &&
+ pe->offset_to_name < sizeof(*pe) + sizeof(variable_lock_on_var_state)) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
+ }
+
+ /* check space for minimum string length */
+ if (pe->size < (size_t)pe->offset_to_name) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
+ }
+
+ if (!uefi_str_is_valid((void *)pe + pe->offset_to_name,
+ pe->size - pe->offset_to_name,
+ false)) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_INVALID_PARAMETER);
+ }
+
+ pol = find_policy(uv, pe->namespace,
+ (void *)pe + pe->offset_to_name,
+ pe->size - pe->offset_to_name);
+ if (pol) {
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_ALREADY_STARTED);
+ }
+
+ uefi_vars_add_policy(uv, pe);
+
+ mchk->result = EFI_SUCCESS;
+ return sizeof(*mchk);
+}
+
+uint32_t uefi_vars_mm_check_policy_proto(uefi_vars_state *uv)
+{
+ static const char *fnames[] = {
+ "zero",
+ "disable",
+ "is-enabled",
+ "register",
+ "dump",
+ "lock",
+ };
+ const char *fname;
+ mm_header *mhdr = (mm_header *) uv->buffer;
+ mm_check_policy *mchk = (mm_check_policy *) (uv->buffer + sizeof(*mhdr));
+ void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mchk));
+
+ if (mhdr->length < sizeof(*mchk)) {
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
+ }
+
+ fname = mchk->command < ARRAY_SIZE(fnames)
+ ? fnames[mchk->command]
+ : "unknown";
+ trace_uefi_vars_policy_cmd(fname);
+
+ switch (mchk->command) {
+ case VAR_CHECK_POLICY_COMMAND_DISABLE:
+ mchk->result = EFI_UNSUPPORTED;
+ break;
+ case VAR_CHECK_POLICY_COMMAND_IS_ENABLED:
+ uefi_vars_mm_check_policy_is_enabled(uv, mhdr, mchk, func);
+ break;
+ case VAR_CHECK_POLICY_COMMAND_REGISTER:
+ if (uv->policy_locked) {
+ mchk->result = EFI_WRITE_PROTECTED;
+ } else {
+ uefi_vars_mm_check_policy_register(uv, mhdr, mchk, func);
+ }
+ break;
+ case VAR_CHECK_POLICY_COMMAND_LOCK:
+ uv->policy_locked = true;
+ mchk->result = EFI_SUCCESS;
+ break;
+ default:
+ mchk->result = EFI_UNSUPPORTED;
+ break;
+ }
+
+ uefi_trace_status(__func__, mchk->result);
+ return UEFI_VARS_STS_SUCCESS;
+}
diff --git a/hw/uefi/var-service-siglist.c b/hw/uefi/var-service-siglist.c
new file mode 100644
index 0000000..8948f1b
--- /dev/null
+++ b/hw/uefi/var-service-siglist.c
@@ -0,0 +1,212 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - parse and generate efi signature databases
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "system/dma.h"
+
+#include "hw/uefi/var-service.h"
+
+/*
+ * Add x509 certificate to list (with duplicate check).
+ */
+static void uefi_vars_siglist_add_x509(uefi_vars_siglist *siglist,
+ QemuUUID *owner,
+ void *data, uint64_t size)
+{
+ uefi_vars_cert *c;
+
+ QTAILQ_FOREACH(c, &siglist->x509, next) {
+ if (c->size != size) {
+ continue;
+ }
+ if (memcmp(c->data, data, size) != 0) {
+ continue;
+ }
+ return;
+ }
+
+ c = g_malloc(sizeof(*c) + size);
+ c->owner = *owner;
+ c->size = size;
+ memcpy(c->data, data, size);
+ QTAILQ_INSERT_TAIL(&siglist->x509, c, next);
+}
+
+/*
+ * Add sha256 hash to list (with duplicate check).
+ */
+static void uefi_vars_siglist_add_sha256(uefi_vars_siglist *siglist,
+ QemuUUID *owner,
+ void *data)
+{
+ uefi_vars_hash *h;
+
+ QTAILQ_FOREACH(h, &siglist->sha256, next) {
+ if (memcmp(h->data, data, 32) != 0) {
+ continue;
+ }
+ return;
+ }
+
+ h = g_malloc(sizeof(*h) + 32);
+ h->owner = *owner;
+ memcpy(h->data, data, 32);
+ QTAILQ_INSERT_TAIL(&siglist->sha256, h, next);
+}
+
+void uefi_vars_siglist_init(uefi_vars_siglist *siglist)
+{
+ memset(siglist, 0, sizeof(*siglist));
+ QTAILQ_INIT(&siglist->x509);
+ QTAILQ_INIT(&siglist->sha256);
+}
+
+void uefi_vars_siglist_free(uefi_vars_siglist *siglist)
+{
+ uefi_vars_cert *c, *cs;
+ uefi_vars_hash *h, *hs;
+
+ QTAILQ_FOREACH_SAFE(c, &siglist->x509, next, cs) {
+ QTAILQ_REMOVE(&siglist->x509, c, next);
+ g_free(c);
+ }
+ QTAILQ_FOREACH_SAFE(h, &siglist->sha256, next, hs) {
+ QTAILQ_REMOVE(&siglist->sha256, h, next);
+ g_free(h);
+ }
+}
+
+/*
+ * Parse UEFI signature list.
+ */
+void uefi_vars_siglist_parse(uefi_vars_siglist *siglist,
+ void *data, uint64_t size)
+{
+ efi_siglist *efilist;
+ uint64_t start;
+
+ while (size) {
+ if (size < sizeof(*efilist)) {
+ break;
+ }
+ efilist = data;
+ if (size < efilist->siglist_size) {
+ break;
+ }
+
+ if (uadd64_overflow(sizeof(*efilist), efilist->header_size, &start)) {
+ break;
+ }
+ if (efilist->sig_size <= sizeof(QemuUUID)) {
+ break;
+ }
+
+ if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertX509Guid)) {
+ if (start + efilist->sig_size != efilist->siglist_size) {
+ break;
+ }
+ uefi_vars_siglist_add_x509(siglist,
+ (QemuUUID *)(data + start),
+ data + start + sizeof(QemuUUID),
+ efilist->sig_size - sizeof(QemuUUID));
+
+ } else if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertSha256Guid)) {
+ if (efilist->sig_size != sizeof(QemuUUID) + 32) {
+ break;
+ }
+ if (start + efilist->sig_size > efilist->siglist_size) {
+ break;
+ }
+ while (start <= efilist->siglist_size - efilist->sig_size) {
+ uefi_vars_siglist_add_sha256(siglist,
+ (QemuUUID *)(data + start),
+ data + start + sizeof(QemuUUID));
+ start += efilist->sig_size;
+ }
+
+ } else {
+ QemuUUID be = qemu_uuid_bswap(efilist->guid_type);
+ char *str_uuid = qemu_uuid_unparse_strdup(&be);
+ warn_report("%s: unknown type (%s)", __func__, str_uuid);
+ g_free(str_uuid);
+ }
+
+ data += efilist->siglist_size;
+ size -= efilist->siglist_size;
+ }
+}
+
+uint64_t uefi_vars_siglist_blob_size(uefi_vars_siglist *siglist)
+{
+ uefi_vars_cert *c;
+ uefi_vars_hash *h;
+ uint64_t size = 0;
+
+ QTAILQ_FOREACH(c, &siglist->x509, next) {
+ size += sizeof(efi_siglist) + sizeof(QemuUUID) + c->size;
+ }
+
+ if (!QTAILQ_EMPTY(&siglist->sha256)) {
+ size += sizeof(efi_siglist);
+ QTAILQ_FOREACH(h, &siglist->sha256, next) {
+ size += sizeof(QemuUUID) + 32;
+ }
+ }
+
+ return size;
+}
+
+/*
+ * Generate UEFI signature list.
+ */
+void uefi_vars_siglist_blob_generate(uefi_vars_siglist *siglist,
+ void *data, uint64_t size)
+{
+ uefi_vars_cert *c;
+ uefi_vars_hash *h;
+ efi_siglist *efilist;
+ uint64_t pos = 0, start;
+ uint32_t i;
+
+ QTAILQ_FOREACH(c, &siglist->x509, next) {
+ efilist = data + pos;
+ efilist->guid_type = EfiCertX509Guid;
+ efilist->sig_size = sizeof(QemuUUID) + c->size;
+ efilist->header_size = 0;
+
+ start = pos + sizeof(efi_siglist);
+ memcpy(data + start,
+ &c->owner, sizeof(QemuUUID));
+ memcpy(data + start + sizeof(QemuUUID),
+ c->data, c->size);
+
+ efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size;
+ pos += efilist->siglist_size;
+ }
+
+ if (!QTAILQ_EMPTY(&siglist->sha256)) {
+ efilist = data + pos;
+ efilist->guid_type = EfiCertSha256Guid;
+ efilist->sig_size = sizeof(QemuUUID) + 32;
+ efilist->header_size = 0;
+
+ i = 0;
+ start = pos + sizeof(efi_siglist);
+ QTAILQ_FOREACH(h, &siglist->sha256, next) {
+ memcpy(data + start + efilist->sig_size * i,
+ &h->owner, sizeof(QemuUUID));
+ memcpy(data + start + efilist->sig_size * i + sizeof(QemuUUID),
+ h->data, 32);
+ i++;
+ }
+
+ efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size * i;
+ pos += efilist->siglist_size;
+ }
+
+ assert(pos == size);
+}
diff --git a/hw/uefi/var-service-sysbus.c b/hw/uefi/var-service-sysbus.c
new file mode 100644
index 0000000..a5aa218
--- /dev/null
+++ b/hw/uefi/var-service-sysbus.c
@@ -0,0 +1,124 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - sysbus variant.
+ */
+#include "qemu/osdep.h"
+#include "migration/vmstate.h"
+
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+
+#include "hw/uefi/hardware-info.h"
+#include "hw/uefi/var-service.h"
+#include "hw/uefi/var-service-api.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(uefi_vars_sysbus_state, UEFI_VARS_SYSBUS)
+
+struct uefi_vars_sysbus_state {
+ SysBusDevice parent_obj;
+ struct uefi_vars_state state;
+};
+
+static const VMStateDescription vmstate_uefi_vars_sysbus = {
+ .name = TYPE_UEFI_VARS_SYSBUS,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(state, uefi_vars_sysbus_state, 0,
+ vmstate_uefi_vars, uefi_vars_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property uefi_vars_sysbus_properties[] = {
+ DEFINE_PROP_SIZE("size", uefi_vars_sysbus_state, state.max_storage,
+ 256 * 1024),
+ DEFINE_PROP_STRING("jsonfile", uefi_vars_sysbus_state, state.jsonfile),
+ DEFINE_PROP_BOOL("force-secure-boot", uefi_vars_sysbus_state,
+ state.force_secure_boot, false),
+ DEFINE_PROP_BOOL("disable-custom-mode", uefi_vars_sysbus_state,
+ state.disable_custom_mode, false),
+ DEFINE_PROP_BOOL("use-pio", uefi_vars_sysbus_state,
+ state.use_pio, false),
+};
+
+static void uefi_vars_sysbus_init(Object *obj)
+{
+ uefi_vars_sysbus_state *uv = UEFI_VARS_SYSBUS(obj);
+
+ uefi_vars_init(obj, &uv->state);
+}
+
+static void uefi_vars_sysbus_reset(DeviceState *dev)
+{
+ uefi_vars_sysbus_state *uv = UEFI_VARS_SYSBUS(dev);
+
+ uefi_vars_hard_reset(&uv->state);
+}
+
+static void uefi_vars_sysbus_realize(DeviceState *dev, Error **errp)
+{
+ uefi_vars_sysbus_state *uv = UEFI_VARS_SYSBUS(dev);
+ SysBusDevice *sysbus = SYS_BUS_DEVICE(dev);
+
+ sysbus_init_mmio(sysbus, &uv->state.mr);
+ uefi_vars_realize(&uv->state, errp);
+}
+
+static void uefi_vars_sysbus_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = uefi_vars_sysbus_realize;
+ dc->vmsd = &vmstate_uefi_vars_sysbus;
+ dc->user_creatable = true;
+ device_class_set_legacy_reset(dc, uefi_vars_sysbus_reset);
+ device_class_set_props(dc, uefi_vars_sysbus_properties);
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+/* generic: hardware discovery via FDT */
+static const TypeInfo uefi_vars_sysbus_info = {
+ .name = TYPE_UEFI_VARS_SYSBUS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(uefi_vars_sysbus_state),
+ .instance_init = uefi_vars_sysbus_init,
+ .class_init = uefi_vars_sysbus_class_init,
+};
+module_obj(TYPE_UEFI_VARS_SYSBUS);
+
+static void uefi_vars_x64_realize(DeviceState *dev, Error **errp)
+{
+ HARDWARE_INFO_SIMPLE_DEVICE hwinfo = {
+ .mmio_address = cpu_to_le64(0xfef10000),
+ };
+ SysBusDevice *sysbus = SYS_BUS_DEVICE(dev);
+
+ uefi_vars_sysbus_realize(dev, errp);
+
+ hardware_info_register(HardwareInfoQemuUefiVars,
+ &hwinfo, sizeof(hwinfo));
+ sysbus_mmio_map(sysbus, 0, hwinfo.mmio_address);
+}
+
+static void uefi_vars_x64_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = uefi_vars_x64_realize;
+}
+
+/* x64: hardware discovery via etc/hardware-info fw_cfg */
+static const TypeInfo uefi_vars_x64_info = {
+ .name = TYPE_UEFI_VARS_X64,
+ .parent = TYPE_UEFI_VARS_SYSBUS,
+ .class_init = uefi_vars_x64_class_init,
+};
+module_obj(TYPE_UEFI_VARS_X64);
+
+static void uefi_vars_sysbus_register_types(void)
+{
+ type_register_static(&uefi_vars_sysbus_info);
+ type_register_static(&uefi_vars_x64_info);
+}
+
+type_init(uefi_vars_sysbus_register_types)
diff --git a/hw/uefi/var-service-utils.c b/hw/uefi/var-service-utils.c
new file mode 100644
index 0000000..c9ef465
--- /dev/null
+++ b/hw/uefi/var-service-utils.c
@@ -0,0 +1,241 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - helper functions for ucs2 strings and tracing
+ */
+#include "qemu/osdep.h"
+#include "system/dma.h"
+
+#include "hw/uefi/var-service.h"
+
+#include "trace/trace-hw_uefi.h"
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * string helper functions.
+ *
+ * Most of the time uefi ucs2 strings are NULL-terminated, except
+ * sometimes when they are not (for example in variable policies).
+ */
+
+gboolean uefi_str_is_valid(const uint16_t *str, size_t len,
+ gboolean must_be_null_terminated)
+{
+ size_t pos = 0;
+
+ for (;;) {
+ if (pos == len) {
+ if (must_be_null_terminated) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ switch (str[pos]) {
+ case 0:
+ /* end of string */
+ return true;
+ case 0xd800 ... 0xdfff:
+ /* reject surrogates */
+ return false;
+ default:
+ /* char is good, check next */
+ break;
+ }
+ pos++;
+ }
+}
+
+size_t uefi_strlen(const uint16_t *str, size_t len)
+{
+ size_t pos = 0;
+
+ for (;;) {
+ if (pos == len) {
+ return pos;
+ }
+ if (str[pos] == 0) {
+ return pos;
+ }
+ pos++;
+ }
+}
+
+gboolean uefi_str_equal_ex(const uint16_t *a, size_t alen,
+ const uint16_t *b, size_t blen,
+ gboolean wildcards_in_a)
+{
+ size_t pos = 0;
+
+ alen = alen / 2;
+ blen = blen / 2;
+ for (;;) {
+ if (pos == alen && pos == blen) {
+ return true;
+ }
+ if (pos == alen && b[pos] == 0) {
+ return true;
+ }
+ if (pos == blen && a[pos] == 0) {
+ return true;
+ }
+ if (pos == alen || pos == blen) {
+ return false;
+ }
+ if (a[pos] == 0 && b[pos] == 0) {
+ return true;
+ }
+
+ if (wildcards_in_a && a[pos] == '#') {
+ if (!isxdigit(b[pos])) {
+ return false;
+ }
+ } else {
+ if (a[pos] != b[pos]) {
+ return false;
+ }
+ }
+ pos++;
+ }
+}
+
+gboolean uefi_str_equal(const uint16_t *a, size_t alen,
+ const uint16_t *b, size_t blen)
+{
+ return uefi_str_equal_ex(a, alen, b, blen, false);
+}
+
+char *uefi_ucs2_to_ascii(const uint16_t *ucs2, uint64_t ucs2_size)
+{
+ char *str = g_malloc0(ucs2_size / 2 + 1);
+ int i;
+
+ for (i = 0; i * 2 < ucs2_size; i++) {
+ if (ucs2[i] == 0) {
+ break;
+ }
+ if (ucs2[i] < 128) {
+ str[i] = ucs2[i];
+ } else {
+ str[i] = '?';
+ }
+ }
+ str[i] = 0;
+ return str;
+}
+
+/* ------------------------------------------------------------------ */
+/* time helper functions */
+
+int uefi_time_compare(efi_time *a, efi_time *b)
+{
+ if (a->year < b->year) {
+ return -1;
+ }
+ if (a->year > b->year) {
+ return 1;
+ }
+
+ if (a->month < b->month) {
+ return -1;
+ }
+ if (a->month > b->month) {
+ return 1;
+ }
+
+ if (a->day < b->day) {
+ return -1;
+ }
+ if (a->day > b->day) {
+ return 1;
+ }
+
+ if (a->hour < b->hour) {
+ return -1;
+ }
+ if (a->hour > b->hour) {
+ return 1;
+ }
+
+ if (a->minute < b->minute) {
+ return -1;
+ }
+ if (a->minute > b->minute) {
+ return 1;
+ }
+
+ if (a->second < b->second) {
+ return -1;
+ }
+ if (a->second > b->second) {
+ return 1;
+ }
+
+ if (a->nanosecond < b->nanosecond) {
+ return -1;
+ }
+ if (a->nanosecond > b->nanosecond) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* tracing helper functions */
+
+void uefi_trace_variable(const char *action, QemuUUID guid,
+ const uint16_t *name, uint64_t name_size)
+{
+ QemuUUID be = qemu_uuid_bswap(guid);
+ char *str_uuid = qemu_uuid_unparse_strdup(&be);
+ char *str_name = uefi_ucs2_to_ascii(name, name_size);
+
+ trace_uefi_variable(action, str_name, name_size, str_uuid);
+
+ g_free(str_name);
+ g_free(str_uuid);
+}
+
+void uefi_trace_status(const char *action, efi_status status)
+{
+ switch (status) {
+ case EFI_SUCCESS:
+ trace_uefi_status(action, "success");
+ break;
+ case EFI_INVALID_PARAMETER:
+ trace_uefi_status(action, "invalid parameter");
+ break;
+ case EFI_UNSUPPORTED:
+ trace_uefi_status(action, "unsupported");
+ break;
+ case EFI_BAD_BUFFER_SIZE:
+ trace_uefi_status(action, "bad buffer size");
+ break;
+ case EFI_BUFFER_TOO_SMALL:
+ trace_uefi_status(action, "buffer too small");
+ break;
+ case EFI_WRITE_PROTECTED:
+ trace_uefi_status(action, "write protected");
+ break;
+ case EFI_OUT_OF_RESOURCES:
+ trace_uefi_status(action, "out of resources");
+ break;
+ case EFI_NOT_FOUND:
+ trace_uefi_status(action, "not found");
+ break;
+ case EFI_ACCESS_DENIED:
+ trace_uefi_status(action, "access denied");
+ break;
+ case EFI_ALREADY_STARTED:
+ trace_uefi_status(action, "already started");
+ break;
+ case EFI_SECURITY_VIOLATION:
+ trace_uefi_status(action, "security violation");
+ break;
+ default:
+ trace_uefi_status(action, "unknown error");
+ break;
+ }
+}
diff --git a/hw/uefi/var-service-vars.c b/hw/uefi/var-service-vars.c
new file mode 100644
index 0000000..7f98d77
--- /dev/null
+++ b/hw/uefi/var-service-vars.c
@@ -0,0 +1,725 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * uefi vars device - EfiSmmVariableProtocol implementation
+ */
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "system/dma.h"
+#include "migration/vmstate.h"
+
+#include "hw/uefi/var-service.h"
+#include "hw/uefi/var-service-api.h"
+#include "hw/uefi/var-service-edk2.h"
+
+#include "trace/trace-hw_uefi.h"
+
+#define EFI_VARIABLE_ATTRIBUTE_SUPPORTED \
+ (EFI_VARIABLE_NON_VOLATILE | \
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS | \
+ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
+ EFI_VARIABLE_APPEND_WRITE)
+
+
+const VMStateDescription vmstate_uefi_time = {
+ .name = "uefi-time",
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(year, efi_time),
+ VMSTATE_UINT8(month, efi_time),
+ VMSTATE_UINT8(day, efi_time),
+ VMSTATE_UINT8(hour, efi_time),
+ VMSTATE_UINT8(minute, efi_time),
+ VMSTATE_UINT8(second, efi_time),
+ VMSTATE_UINT32(nanosecond, efi_time),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+const VMStateDescription vmstate_uefi_variable = {
+ .name = "uefi-variable",
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8_ARRAY_V(guid.data, uefi_variable, sizeof(QemuUUID), 0),
+ VMSTATE_UINT32(name_size, uefi_variable),
+ VMSTATE_UINT32(data_size, uefi_variable),
+ VMSTATE_UINT32(attributes, uefi_variable),
+ VMSTATE_VBUFFER_ALLOC_UINT32(name, uefi_variable, 0, NULL, name_size),
+ VMSTATE_VBUFFER_ALLOC_UINT32(data, uefi_variable, 0, NULL, data_size),
+ VMSTATE_STRUCT(time, uefi_variable, 0, vmstate_uefi_time, efi_time),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+uefi_variable *uefi_vars_find_variable(uefi_vars_state *uv, QemuUUID guid,
+ const uint16_t *name, uint64_t name_size)
+{
+ uefi_variable *var;
+
+ QTAILQ_FOREACH(var, &uv->variables, next) {
+ if (!uefi_str_equal(var->name, var->name_size,
+ name, name_size)) {
+ continue;
+ }
+ if (!qemu_uuid_is_equal(&var->guid, &guid)) {
+ continue;
+ }
+ if (!var->data_size) {
+ /* in process of being created/updated */
+ continue;
+ }
+ return var;
+ }
+ return NULL;
+}
+
+static uefi_variable *add_variable(uefi_vars_state *uv, QemuUUID guid,
+ const uint16_t *name, uint64_t name_size,
+ uint32_t attributes)
+{
+ uefi_variable *var;
+
+ var = g_new0(uefi_variable, 1);
+ var->guid = guid;
+ var->name = g_malloc(name_size);
+ memcpy(var->name, name, name_size);
+ var->name_size = name_size;
+ var->attributes = attributes;
+
+ var->attributes &= ~EFI_VARIABLE_APPEND_WRITE;
+
+ QTAILQ_INSERT_TAIL(&uv->variables, var, next);
+ return var;
+}
+
+static void del_variable(uefi_vars_state *uv, uefi_variable *var)
+{
+ if (!var) {
+ return;
+ }
+
+ QTAILQ_REMOVE(&uv->variables, var, next);
+ g_free(var->data);
+ g_free(var->name);
+ g_free(var->digest);
+ g_free(var);
+}
+
+static size_t variable_size(uefi_variable *var)
+{
+ size_t size;
+
+ size = sizeof(*var);
+ size += var->name_size;
+ size += var->data_size;
+ size += var->digest_size;
+ return size;
+}
+
+void uefi_vars_set_variable(uefi_vars_state *uv, QemuUUID guid,
+ const uint16_t *name, uint64_t name_size,
+ uint32_t attributes,
+ void *data, uint64_t data_size)
+{
+ uefi_variable *old_var, *new_var;
+
+ uefi_trace_variable(__func__, guid, name, name_size);
+
+ old_var = uefi_vars_find_variable(uv, guid, name, name_size);
+ if (old_var) {
+ uv->used_storage -= variable_size(old_var);
+ del_variable(uv, old_var);
+ }
+
+ new_var = add_variable(uv, guid, name, name_size, attributes);
+ new_var->data = g_malloc(data_size);
+ new_var->data_size = data_size;
+ memcpy(new_var->data, data, data_size);
+ uv->used_storage += variable_size(new_var);
+}
+
+void uefi_vars_clear_volatile(uefi_vars_state *uv)
+{
+ uefi_variable *var, *n;
+
+ QTAILQ_FOREACH_SAFE(var, &uv->variables, next, n) {
+ if (var->attributes & EFI_VARIABLE_NON_VOLATILE) {
+ continue;
+ }
+ uv->used_storage -= variable_size(var);
+ del_variable(uv, var);
+ }
+}
+
+void uefi_vars_clear_all(uefi_vars_state *uv)
+{
+ uefi_variable *var, *n;
+
+ QTAILQ_FOREACH_SAFE(var, &uv->variables, next, n) {
+ del_variable(uv, var);
+ }
+ uv->used_storage = 0;
+}
+
+void uefi_vars_update_storage(uefi_vars_state *uv)
+{
+ uefi_variable *var;
+
+ uv->used_storage = 0;
+ QTAILQ_FOREACH(var, &uv->variables, next) {
+ uv->used_storage += variable_size(var);
+ }
+}
+
+static gboolean check_access(uefi_vars_state *uv, uefi_variable *var)
+{
+ if (!uv->exit_boot_service) {
+ if (!(var->attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
+ return false;
+ }
+ } else {
+ if (!(var->attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static efi_status check_update(uefi_vars_state *uv, uefi_variable *old_var,
+ uefi_variable *new_var)
+{
+ efi_status status;
+
+ if (old_var) {
+ if (!check_access(uv, old_var)) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ if (new_var) {
+ if (new_var->attributes & ~EFI_VARIABLE_ATTRIBUTE_SUPPORTED) {
+ return EFI_UNSUPPORTED;
+ }
+ if (!check_access(uv, new_var)) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ if (old_var && new_var) {
+ if (old_var->attributes != new_var->attributes) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (new_var) {
+ /* create + update */
+ status = uefi_vars_policy_check(uv, new_var, old_var == NULL);
+ } else {
+ /* delete */
+ g_assert(old_var);
+ status = uefi_vars_policy_check(uv, old_var, false);
+ }
+ if (status != EFI_SUCCESS) {
+ return status;
+ }
+
+ status = uefi_vars_check_secure_boot(uv, new_var ?: old_var);
+ if (status != EFI_SUCCESS) {
+ return status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+static void append_write(uefi_variable *old_var,
+ uefi_variable *new_var)
+{
+ uefi_vars_siglist siglist;
+ uint64_t size;
+ void *data;
+
+ uefi_vars_siglist_init(&siglist);
+ uefi_vars_siglist_parse(&siglist, old_var->data, old_var->data_size);
+ uefi_vars_siglist_parse(&siglist, new_var->data, new_var->data_size);
+
+ size = uefi_vars_siglist_blob_size(&siglist);
+ data = g_malloc(size);
+ uefi_vars_siglist_blob_generate(&siglist, data, size);
+
+ g_free(new_var->data);
+ new_var->data = data;
+ new_var->data_size = size;
+
+ uefi_vars_siglist_free(&siglist);
+}
+
+static size_t uefi_vars_mm_error(mm_header *mhdr, mm_variable *mvar,
+ uint64_t status)
+{
+ mvar->status = status;
+ return sizeof(*mvar);
+}
+
+static size_t uefi_vars_mm_get_variable(uefi_vars_state *uv, mm_header *mhdr,
+ mm_variable *mvar, void *func)
+{
+ mm_variable_access *va = func;
+ uint16_t *name;
+ void *data;
+ uefi_variable *var;
+ uint64_t length;
+
+ length = sizeof(*mvar) + sizeof(*va);
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ if (va->name_size > uv->max_storage ||
+ va->data_size > uv->max_storage) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
+ }
+
+ name = func + sizeof(*va);
+ if (uadd64_overflow(length, va->name_size, &length)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ if (!uefi_str_is_valid(name, va->name_size, true)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
+ }
+
+ uefi_trace_variable(__func__, va->guid, name, va->name_size);
+
+ var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
+ if (!var) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND);
+ }
+
+ /* check permissions etc. */
+ if (!check_access(uv, var)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_ACCESS_DENIED);
+ }
+
+ data = func + sizeof(*va) + va->name_size;
+ if (uadd64_overflow(length, va->data_size, &length)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+ if (uv->buf_size < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ va->attributes = var->attributes;
+ if (va->data_size < var->data_size) {
+ va->data_size = var->data_size;
+ length -= va->data_size;
+ mvar->status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ va->data_size = var->data_size;
+ memcpy(data, var->data, var->data_size);
+ mvar->status = EFI_SUCCESS;
+ }
+ return length;
+}
+
+static size_t
+uefi_vars_mm_get_next_variable(uefi_vars_state *uv, mm_header *mhdr,
+ mm_variable *mvar, void *func)
+{
+ mm_next_variable *nv = func;
+ uefi_variable *var;
+ uint16_t *name;
+ uint64_t length;
+
+ length = sizeof(*mvar) + sizeof(*nv);
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ if (nv->name_size > uv->max_storage) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
+ }
+
+ name = func + sizeof(*nv);
+ if (uadd64_overflow(length, nv->name_size, &length)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ if (!uefi_str_is_valid(name, nv->name_size, true)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
+ }
+
+ if (uefi_strlen(name, nv->name_size) == 0) {
+ /* empty string -> first */
+ var = QTAILQ_FIRST(&uv->variables);
+ if (!var) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND);
+ }
+ } else {
+ var = uefi_vars_find_variable(uv, nv->guid, name, nv->name_size);
+ if (!var) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
+ }
+ do {
+ var = QTAILQ_NEXT(var, next);
+ } while (var && !check_access(uv, var));
+ if (!var) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND);
+ }
+ }
+
+ length = sizeof(*mvar) + sizeof(*nv) + var->name_size;
+ if (uv->buf_size < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ nv->guid = var->guid;
+ nv->name_size = var->name_size;
+ memcpy(name, var->name, var->name_size);
+ mvar->status = EFI_SUCCESS;
+ return length;
+}
+
+static bool uefi_vars_mm_digest_compare(uefi_variable *old_var,
+ uefi_variable *new_var)
+{
+ if (!old_var->digest ||
+ !new_var->digest ||
+ !old_var->digest_size ||
+ !new_var->digest_size) {
+ /* should not happen */
+ trace_uefi_vars_security_violation("inconsistent authvar digest state");
+ return false;
+ }
+ if (old_var->digest_size != new_var->digest_size) {
+ trace_uefi_vars_security_violation("authvar digest size mismatch");
+ return false;
+ }
+ if (memcmp(old_var->digest, new_var->digest,
+ old_var->digest_size) != 0) {
+ trace_uefi_vars_security_violation("authvar digest data mismatch");
+ return false;
+ }
+ return true;
+}
+
+static size_t uefi_vars_mm_set_variable(uefi_vars_state *uv, mm_header *mhdr,
+ mm_variable *mvar, void *func)
+{
+ mm_variable_access *va = func;
+ uint32_t attributes = 0;
+ uint16_t *name;
+ void *data;
+ uefi_variable *old_var, *new_var;
+ uint64_t length;
+ size_t new_storage;
+ efi_status status;
+
+ length = sizeof(*mvar) + sizeof(*va);
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ if (va->name_size > uv->max_storage ||
+ va->data_size > uv->max_storage) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
+ }
+
+ name = func + sizeof(*va);
+ if (uadd64_overflow(length, va->name_size, &length)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ data = func + sizeof(*va) + va->name_size;
+ if (uadd64_overflow(length, va->data_size, &length)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ g_assert(va->name_size < G_MAXUINT32);
+ g_assert(va->data_size < G_MAXUINT32);
+
+ if (!uefi_str_is_valid(name, va->name_size, true)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
+ }
+
+ uefi_trace_variable(__func__, va->guid, name, va->name_size);
+
+ old_var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
+ if (va->data_size) {
+ new_var = add_variable(uv, va->guid, name, va->name_size,
+ va->attributes);
+ if (va->attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
+ /* not implemented (deprecated in uefi spec) */
+ warn_report("%s: AUTHENTICATED_WRITE_ACCESS", __func__);
+ mvar->status = EFI_UNSUPPORTED;
+ goto rollback;
+ } else if (va->attributes &
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+ status = uefi_vars_check_auth_2(uv, new_var, va, data);
+ if (status != EFI_SUCCESS) {
+ mvar->status = status;
+ goto rollback;
+ }
+ if (old_var && new_var) {
+ if (uefi_time_compare(&old_var->time, &new_var->time) > 0) {
+ trace_uefi_vars_security_violation("time check failed");
+ mvar->status = EFI_SECURITY_VIOLATION;
+ goto rollback;
+ }
+ if (old_var->digest_size || new_var->digest_size) {
+ if (!uefi_vars_mm_digest_compare(old_var, new_var)) {
+ mvar->status = EFI_SECURITY_VIOLATION;
+ goto rollback;
+ }
+ }
+ }
+ } else {
+ new_var->data = g_malloc(va->data_size);
+ memcpy(new_var->data, data, va->data_size);
+ new_var->data_size = va->data_size;
+ }
+ if (!new_var->data) {
+ /* we land here when deleting authenticated variables */
+ del_variable(uv, new_var);
+ new_var = NULL;
+ }
+ } else {
+ new_var = NULL;
+ }
+
+ if (!old_var && !new_var) {
+ /* delete non-existing variable -> nothing to do */
+ mvar->status = EFI_SUCCESS;
+ return sizeof(*mvar);
+ }
+
+ /* check permissions etc. */
+ status = check_update(uv, old_var, new_var);
+ if (status != EFI_SUCCESS) {
+ mvar->status = status;
+ goto rollback;
+ }
+
+ if (va->attributes & EFI_VARIABLE_APPEND_WRITE && old_var && new_var) {
+ /* merge signature databases */
+ if (!uefi_vars_is_sb_any(new_var)) {
+ mvar->status = EFI_UNSUPPORTED;
+ goto rollback;
+ }
+ append_write(old_var, new_var);
+ }
+
+ /* check storage space */
+ new_storage = uv->used_storage;
+ if (old_var) {
+ new_storage -= variable_size(old_var);
+ }
+ if (new_var) {
+ new_storage += variable_size(new_var);
+ }
+ if (new_storage > uv->max_storage) {
+ mvar->status = EFI_OUT_OF_RESOURCES;
+ goto rollback;
+ }
+
+ attributes = new_var
+ ? new_var->attributes
+ : old_var->attributes;
+
+ /* all good, commit */
+ del_variable(uv, old_var);
+ uv->used_storage = new_storage;
+
+ if (attributes & EFI_VARIABLE_NON_VOLATILE) {
+ uefi_vars_json_save(uv);
+ }
+
+ if (new_var && uefi_vars_is_sb_pk(new_var)) {
+ uefi_vars_auth_init(uv);
+ }
+
+ mvar->status = EFI_SUCCESS;
+ return sizeof(*mvar);
+
+rollback:
+ del_variable(uv, new_var);
+ return sizeof(*mvar);
+}
+
+static size_t uefi_vars_mm_variable_info(uefi_vars_state *uv, mm_header *mhdr,
+ mm_variable *mvar, void *func)
+{
+ mm_variable_info *vi = func;
+ uint64_t length;
+
+ length = sizeof(*mvar) + sizeof(*vi);
+ if (uv->buf_size < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ vi->max_storage_size = uv->max_storage;
+ vi->free_storage_size = uv->max_storage - uv->used_storage;
+ vi->max_variable_size = uv->max_storage >> 2;
+ vi->attributes = 0;
+
+ mvar->status = EFI_SUCCESS;
+ return length;
+}
+
+static size_t
+uefi_vars_mm_get_payload_size(uefi_vars_state *uv, mm_header *mhdr,
+ mm_variable *mvar, void *func)
+{
+ mm_get_payload_size *ps = func;
+ uint64_t length;
+
+ length = sizeof(*mvar) + sizeof(*ps);
+ if (uv->buf_size < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ ps->payload_size = uv->buf_size;
+ mvar->status = EFI_SUCCESS;
+ return length;
+}
+
+static size_t
+uefi_vars_mm_lock_variable(uefi_vars_state *uv, mm_header *mhdr,
+ mm_variable *mvar, void *func)
+{
+ mm_lock_variable *lv = func;
+ variable_policy_entry *pe;
+ uint16_t *name, *dest;
+ uint64_t length;
+
+ length = sizeof(*mvar) + sizeof(*lv);
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ name = func + sizeof(*lv);
+ if (uadd64_overflow(length, lv->name_size, &length)) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+ if (mhdr->length < length) {
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
+ }
+
+ uefi_trace_variable(__func__, lv->guid, name, lv->name_size);
+
+ pe = g_malloc0(sizeof(*pe) + lv->name_size);
+ pe->version = VARIABLE_POLICY_ENTRY_REVISION;
+ pe->size = sizeof(*pe) + lv->name_size;
+ pe->offset_to_name = sizeof(*pe);
+ pe->namespace = lv->guid;
+ pe->min_size = 0;
+ pe->max_size = UINT32_MAX;
+ pe->attributes_must_have = 0;
+ pe->attributes_cant_have = 0;
+ pe->lock_policy_type = VARIABLE_POLICY_TYPE_LOCK_NOW;
+
+ dest = (void *)pe + pe->offset_to_name;
+ memcpy(dest, name, lv->name_size);
+
+ uefi_vars_add_policy(uv, pe);
+ g_free(pe);
+
+ mvar->status = EFI_SUCCESS;
+ return length;
+}
+
+uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv)
+{
+ static const char *fnames[] = {
+ "zero",
+ "get-variable",
+ "get-next-variable-name",
+ "set-variable",
+ "query-variable-info",
+ "ready-to-boot",
+ "exit-boot-service",
+ "get-statistics",
+ "lock-variable",
+ "var-check-prop-set",
+ "var-check-prop-get",
+ "get-payload-size",
+ "init-runtime-cache-contect",
+ "sync-runtime-cache",
+ "get-runtime-cache-info",
+ };
+ const char *fname;
+ uint64_t length;
+
+ mm_header *mhdr = (mm_header *) uv->buffer;
+ mm_variable *mvar = (mm_variable *) (uv->buffer + sizeof(*mhdr));
+ void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mvar));
+
+ if (mhdr->length < sizeof(*mvar)) {
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
+ }
+
+ fname = mvar->function < ARRAY_SIZE(fnames)
+ ? fnames[mvar->function]
+ : "unknown";
+ trace_uefi_vars_proto_cmd(fname);
+
+ switch (mvar->function) {
+ case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
+ length = uefi_vars_mm_get_variable(uv, mhdr, mvar, func);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
+ length = uefi_vars_mm_get_next_variable(uv, mhdr, mvar, func);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
+ length = uefi_vars_mm_set_variable(uv, mhdr, mvar, func);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
+ length = uefi_vars_mm_variable_info(uv, mhdr, mvar, func);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
+ length = uefi_vars_mm_lock_variable(uv, mhdr, mvar, func);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE:
+ length = uefi_vars_mm_get_payload_size(uv, mhdr, mvar, func);
+ break;
+
+ case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
+ trace_uefi_event("ready-to-boot");
+ uv->ready_to_boot = true;
+ length = 0;
+ break;
+
+ case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
+ trace_uefi_event("exit-boot-service");
+ uv->exit_boot_service = true;
+ length = 0;
+ break;
+
+ default:
+ length = uefi_vars_mm_error(mhdr, mvar, EFI_UNSUPPORTED);
+ break;
+ }
+
+ if (mhdr->length < length) {
+ mvar->status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ uefi_trace_status(__func__, mvar->status);
+ return UEFI_VARS_STS_SUCCESS;
+}
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index 81bfff9..2d8ffd7 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -14,7 +14,7 @@
#include "qemu/memalign.h"
#include "hw/scsi/scsi.h"
#include "scsi/constants.h"
-#include "sysemu/block-backend.h"
+#include "system/block-backend.h"
#include "qemu/cutils.h"
#include "trace.h"
#include "ufs.h"
@@ -194,7 +194,7 @@ static int ufs_emulate_wlun_inquiry(UfsRequest *req, uint8_t *outbuf,
static UfsReqResult ufs_emulate_scsi_cmd(UfsLu *lu, UfsRequest *req)
{
uint8_t lun = lu->lun;
- uint8_t outbuf[4096];
+ QEMU_UNINITIALIZED uint8_t outbuf[4096];
uint8_t sense_buf[UFS_SENSE_SIZE];
uint8_t scsi_status;
int len = 0;
@@ -274,10 +274,9 @@ static UfsReqResult ufs_process_scsi_cmd(UfsLu *lu, UfsRequest *req)
return UFS_REQUEST_NO_COMPLETE;
}
-static Property ufs_lu_props[] = {
+static const Property ufs_lu_props[] = {
DEFINE_PROP_DRIVE("drive", UfsLu, conf.blk),
DEFINE_PROP_UINT8("lun", UfsLu, lun, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static bool ufs_add_lu(UfsHc *u, UfsLu *lu, Error **errp)
@@ -420,7 +419,7 @@ static void ufs_lu_unrealize(DeviceState *dev)
}
}
-static void ufs_lu_class_init(ObjectClass *oc, void *data)
+static void ufs_lu_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 945a0ea..0577747 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -25,6 +25,7 @@
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "scsi/constants.h"
+#include "hw/irq.h"
#include "trace.h"
#include "ufs.h"
@@ -34,6 +35,11 @@
#define UFS_MAX_NUTMRS 8
#define UFS_MCQ_QCFGPTR 2
+/* Each value represents the temperature in celsius as (value - 80) */
+#define UFS_TEMPERATURE 120
+#define UFS_TOO_HIGH_TEMP_BOUNDARY 160
+#define UFS_TOO_LOW_TEMP_BOUNDARY 60
+
static void ufs_exec_req(UfsRequest *req);
static void ufs_clear_req(UfsRequest *req);
@@ -838,6 +844,42 @@ static const MemoryRegionOps ufs_mmio_ops = {
},
};
+static void ufs_update_ee_status(UfsHc *u)
+{
+ uint16_t ee_status = be16_to_cpu(u->attributes.exception_event_status);
+ uint8_t high_temp_thresh = u->attributes.device_too_high_temp_boundary;
+ uint8_t low_temp_thresh = u->attributes.device_too_low_temp_boundary;
+
+ if (u->temperature >= high_temp_thresh) {
+ ee_status |= MASK_EE_TOO_HIGH_TEMP;
+ } else {
+ ee_status &= ~MASK_EE_TOO_HIGH_TEMP;
+ }
+
+ if (u->temperature <= low_temp_thresh) {
+ ee_status |= MASK_EE_TOO_LOW_TEMP;
+ } else {
+ ee_status &= ~MASK_EE_TOO_LOW_TEMP;
+ }
+
+ u->attributes.exception_event_status = cpu_to_be16(ee_status);
+}
+
+static bool ufs_check_exception_event_alert(UfsHc *u, uint8_t trans_type)
+{
+ uint16_t ee_control = be16_to_cpu(u->attributes.exception_event_control);
+ uint16_t ee_status;
+
+ if (trans_type != UFS_UPIU_TRANSACTION_RESPONSE) {
+ return false;
+ }
+
+ ufs_update_ee_status(u);
+
+ ee_status = be16_to_cpu(u->attributes.exception_event_status);
+
+ return ee_control & ee_status;
+}
void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags,
uint8_t response, uint8_t scsi_status,
@@ -848,9 +890,19 @@ void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags,
req->rsp_upiu.header.flags = flags;
req->rsp_upiu.header.response = response;
req->rsp_upiu.header.scsi_status = scsi_status;
+ req->rsp_upiu.header.device_inf =
+ ufs_check_exception_event_alert(req->hc, trans_type);
req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
}
+void ufs_build_query_response(UfsRequest *req)
+{
+ req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode;
+ req->rsp_upiu.qr.idn = req->req_upiu.qr.idn;
+ req->rsp_upiu.qr.index = req->req_upiu.qr.index;
+ req->rsp_upiu.qr.selector = req->req_upiu.qr.selector;
+}
+
static UfsReqResult ufs_exec_scsi_cmd(UfsRequest *req)
{
UfsHc *u = req->hc;
@@ -1034,6 +1086,25 @@ static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op)
return UFS_QUERY_RESULT_SUCCESS;
}
+static inline uint8_t ufs_read_device_temp(UfsHc *u)
+{
+ uint8_t feat_sup = u->device_desc.ufs_features_support;
+ bool high_temp_sup, low_temp_sup, high_temp_en, low_temp_en;
+ uint16_t ee_control = be16_to_cpu(u->attributes.exception_event_control);
+
+ high_temp_sup = feat_sup & UFS_DEV_HIGH_TEMP_NOTIF;
+ low_temp_sup = feat_sup & UFS_DEV_LOW_TEMP_NOTIF;
+ high_temp_en = ee_control & MASK_EE_TOO_HIGH_TEMP;
+ low_temp_en = ee_control & MASK_EE_TOO_LOW_TEMP;
+
+ if ((high_temp_sup && high_temp_en) ||
+ (low_temp_sup && low_temp_en)) {
+ return u->temperature;
+ }
+
+ return 0;
+}
+
static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
{
switch (idn) {
@@ -1064,6 +1135,7 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
case UFS_QUERY_ATTR_IDN_EE_CONTROL:
return be16_to_cpu(u->attributes.exception_event_control);
case UFS_QUERY_ATTR_IDN_EE_STATUS:
+ ufs_update_ee_status(u);
return be16_to_cpu(u->attributes.exception_event_status);
case UFS_QUERY_ATTR_IDN_SECONDS_PASSED:
return be32_to_cpu(u->attributes.seconds_passed);
@@ -1078,7 +1150,8 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
case UFS_QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME:
return u->attributes.ref_clk_gating_wait_time;
case UFS_QUERY_ATTR_IDN_CASE_ROUGH_TEMP:
- return u->attributes.device_case_rough_temperaure;
+ u->attributes.device_case_rough_temperature = ufs_read_device_temp(u);
+ return u->attributes.device_case_rough_temperature;
case UFS_QUERY_ATTR_IDN_HIGH_TEMP_BOUND:
return u->attributes.device_too_high_temp_boundary;
case UFS_QUERY_ATTR_IDN_LOW_TEMP_BOUND:
@@ -1103,10 +1176,13 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
return 0;
}
-static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
+static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
{
switch (idn) {
case UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
+ if (value > UFS_QUERY_ATTR_ACTIVE_ICC_MAXVALUE) {
+ return UFS_QUERY_RESULT_INVALID_VALUE;
+ }
u->attributes.active_icc_level = value;
break;
case UFS_QUERY_ATTR_IDN_MAX_DATA_IN:
@@ -1134,6 +1210,7 @@ static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
u->attributes.psa_data_size = cpu_to_be32(value);
break;
}
+ return UFS_QUERY_RESULT_SUCCESS;
}
static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
@@ -1150,13 +1227,13 @@ static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
if (op == UFS_QUERY_ATTR_READ) {
value = ufs_read_attr_value(u, idn);
+ ret = UFS_QUERY_RESULT_SUCCESS;
} else {
value = be32_to_cpu(req->req_upiu.qr.value);
- ufs_write_attr_value(u, idn, value);
+ ret = ufs_write_attr_value(u, idn, value);
}
-
req->rsp_upiu.qr.value = cpu_to_be32(value);
- return UFS_QUERY_RESULT_SUCCESS;
+ return ret;
}
static const RpmbUnitDescriptor rpmb_unit_desc = {
@@ -1279,9 +1356,12 @@ static QueryRespCode ufs_read_desc(UfsRequest *req)
UfsHc *u = req->hc;
QueryRespCode status;
uint8_t idn = req->req_upiu.qr.idn;
+ uint8_t selector = req->req_upiu.qr.selector;
uint16_t length = be16_to_cpu(req->req_upiu.qr.length);
InterconnectDescriptor desc;
-
+ if (selector != 0) {
+ return UFS_QUERY_RESULT_INVALID_SELECTOR;
+ }
switch (idn) {
case UFS_QUERY_DESC_IDN_DEVICE:
memcpy(&req->rsp_upiu.qr.data, &u->device_desc, sizeof(u->device_desc));
@@ -1327,10 +1407,6 @@ static QueryRespCode ufs_read_desc(UfsRequest *req)
if (length > req->rsp_upiu.qr.data[0]) {
length = req->rsp_upiu.qr.data[0];
}
- req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode;
- req->rsp_upiu.qr.idn = req->req_upiu.qr.idn;
- req->rsp_upiu.qr.index = req->req_upiu.qr.index;
- req->rsp_upiu.qr.selector = req->req_upiu.qr.selector;
req->rsp_upiu.qr.length = cpu_to_be16(length);
return status;
@@ -1411,6 +1487,7 @@ static UfsReqResult ufs_exec_query_cmd(UfsRequest *req)
data_segment_length = be16_to_cpu(req->rsp_upiu.qr.length);
ufs_build_upiu_header(req, UFS_UPIU_TRANSACTION_QUERY_RSP, 0, status, 0,
data_segment_length);
+ ufs_build_query_response(req);
if (status != UFS_QUERY_RESULT_SUCCESS) {
return UFS_REQUEST_FAIL;
@@ -1623,7 +1700,7 @@ static void ufs_init_hc(UfsHc *u)
cap = FIELD_DP32(cap, CAP, OODDS, 0);
cap = FIELD_DP32(cap, CAP, UICDMETMS, 0);
cap = FIELD_DP32(cap, CAP, CS, 0);
- cap = FIELD_DP32(cap, CAP, LSDBS, 1);
+ cap = FIELD_DP32(cap, CAP, LSDBS, 0);
cap = FIELD_DP32(cap, CAP, MCQS, u->params.mcq);
u->reg.cap = cap;
@@ -1665,15 +1742,19 @@ static void ufs_init_hc(UfsHc *u)
u->device_desc.ud_0_base_offset = 0x16;
u->device_desc.ud_config_p_length = 0x1A;
u->device_desc.device_rtt_cap = 0x02;
+ u->device_desc.ufs_features_support = UFS_DEV_HIGH_TEMP_NOTIF |
+ UFS_DEV_LOW_TEMP_NOTIF;
u->device_desc.queue_depth = u->params.nutrs;
u->device_desc.product_revision_level = 0x04;
+ u->device_desc.extended_ufs_features_support =
+ cpu_to_be32(UFS_DEV_HIGH_TEMP_NOTIF | UFS_DEV_LOW_TEMP_NOTIF);
memset(&u->geometry_desc, 0, sizeof(GeometryDescriptor));
u->geometry_desc.length = sizeof(GeometryDescriptor);
u->geometry_desc.descriptor_idn = UFS_QUERY_DESC_IDN_GEOMETRY;
u->geometry_desc.max_number_lu = (UFS_MAX_LUS == 32) ? 0x1 : 0x0;
- u->geometry_desc.segment_size = cpu_to_be32(0x2000); /* 4KB */
- u->geometry_desc.allocation_unit_size = 0x1; /* 4KB */
+ u->geometry_desc.segment_size = cpu_to_be32(0x2000); /* 4MB: 8192 * 512B */
+ u->geometry_desc.allocation_unit_size = 0x1; /* 4MB: 1 segment */
u->geometry_desc.min_addr_block_size = 0x8; /* 4KB */
u->geometry_desc.max_in_buffer_size = 0x8;
u->geometry_desc.max_out_buffer_size = 0x8;
@@ -1690,9 +1771,17 @@ static void ufs_init_hc(UfsHc *u)
/* configure descriptor is not supported */
u->attributes.config_descr_lock = 0x01;
u->attributes.max_num_of_rtt = 0x02;
+ u->attributes.device_too_high_temp_boundary = UFS_TOO_HIGH_TEMP_BOUNDARY;
+ u->attributes.device_too_low_temp_boundary = UFS_TOO_LOW_TEMP_BOUNDARY;
memset(&u->flags, 0, sizeof(u->flags));
u->flags.permanently_disable_fw_update = 1;
+
+ /*
+ * The temperature value is fixed to UFS_TEMPERATURE and does not change
+ * dynamically
+ */
+ u->temperature = UFS_TEMPERATURE;
}
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
@@ -1720,6 +1809,8 @@ static void ufs_exit(PCIDevice *pci_dev)
{
UfsHc *u = UFS(pci_dev);
+ qemu_free_irq(u->irq);
+
qemu_bh_delete(u->doorbell_bh);
qemu_bh_delete(u->complete_bh);
@@ -1740,13 +1831,12 @@ static void ufs_exit(PCIDevice *pci_dev)
}
}
-static Property ufs_props[] = {
+static const Property ufs_props[] = {
DEFINE_PROP_STRING("serial", UfsHc, params.serial),
DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8),
DEFINE_PROP_BOOL("mcq", UfsHc, params.mcq, false),
DEFINE_PROP_UINT8("mcq-maxq", UfsHc, params.mcq_maxq, 2),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription ufs_vmstate = {
@@ -1754,7 +1844,7 @@ static const VMStateDescription ufs_vmstate = {
.unmigratable = 1,
};
-static void ufs_class_init(ObjectClass *oc, void *data)
+static void ufs_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
@@ -1790,7 +1880,7 @@ static char *ufs_bus_get_dev_path(DeviceState *dev)
return qdev_get_dev_path(bus->parent);
}
-static void ufs_bus_class_init(ObjectClass *class, void *data)
+static void ufs_bus_class_init(ObjectClass *class, const void *data)
{
BusClass *bc = BUS_CLASS(class);
bc->get_dev_path = ufs_bus_get_dev_path;
@@ -1802,7 +1892,7 @@ static const TypeInfo ufs_info = {
.parent = TYPE_PCI_DEVICE,
.class_init = ufs_class_init,
.instance_size = sizeof(UfsHc),
- .interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
+ .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
};
static const TypeInfo ufs_bus_info = {
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
index 6c9382c..3799d97 100644
--- a/hw/ufs/ufs.h
+++ b/hw/ufs/ufs.h
@@ -146,6 +146,8 @@ typedef struct UfsHc {
/* MCQ properties */
UfsSq *sq[UFS_MAX_MCQ_QNUM];
UfsCq *cq[UFS_MAX_MCQ_QNUM];
+
+ uint8_t temperature;
} UfsHc;
static inline uint32_t ufs_mcq_sq_tail(UfsHc *u, uint32_t qid)
@@ -228,6 +230,7 @@ static inline bool is_wlun(uint8_t lun)
void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags,
uint8_t response, uint8_t scsi_status,
uint16_t data_segment_length);
+void ufs_build_query_response(UfsRequest *req);
void ufs_complete_req(UfsRequest *req, UfsReqResult req_result);
void ufs_init_wlu(UfsLu *wlu, uint8_t wlun);
#endif /* HW_UFS_UFS_H */
diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
index 84bc7fb..69c663be 100644
--- a/hw/usb/Kconfig
+++ b/hw/usb/Kconfig
@@ -53,18 +53,10 @@ config USB_XHCI_SYSBUS
bool
select USB_XHCI
-config USB_MUSB
- bool
- select USB
-
config USB_DWC2
bool
select USB
-config TUSB6010
- bool
- select USB_MUSB
-
config USB_HUB
bool
default y
@@ -151,3 +143,7 @@ config USB_DWC3
config XLNX_USB_SUBSYS
bool
select USB_DWC3
+
+config USB_CHIPIDEA
+ bool
+ select USB_EHCI_SYSBUS
diff --git a/hw/usb/bus-stub.c b/hw/usb/bus-stub.c
index fcabe84..cd0c317 100644
--- a/hw/usb/bus-stub.c
+++ b/hw/usb/bus-stub.c
@@ -10,7 +10,7 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-machine.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "monitor/monitor.h"
#include "hw/usb.h"
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index bfab280..8dd2ce4 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -6,7 +6,7 @@
#include "qapi/type-helpers.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "migration/vmstate.h"
#include "monitor/monitor.h"
#include "trace.h"
@@ -18,16 +18,15 @@ static char *usb_get_dev_path(DeviceState *dev);
static char *usb_get_fw_dev_path(DeviceState *qdev);
static void usb_qdev_unrealize(DeviceState *qdev);
-static Property usb_props[] = {
+static const Property usb_props[] = {
DEFINE_PROP_STRING("port", USBDevice, port_path),
DEFINE_PROP_STRING("serial", USBDevice, serial),
DEFINE_PROP_BIT("msos-desc", USBDevice, flags,
USB_DEV_FLAG_MSOS_DESC_ENABLE, true),
DEFINE_PROP_STRING("pcap", USBDevice, pcap_filename),
- DEFINE_PROP_END_OF_LIST()
};
-static void usb_bus_class_init(ObjectClass *klass, void *data)
+static void usb_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
@@ -43,7 +42,7 @@ static const TypeInfo usb_bus_info = {
.parent = TYPE_BUS,
.instance_size = sizeof(USBBus),
.class_init = usb_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
@@ -412,7 +411,7 @@ void usb_claim_port(USBDevice *dev, Error **errp)
} else {
if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
/* Create a new hub and chain it on */
- hub = usb_try_new("usb-hub");
+ hub = USB_DEVICE(qdev_try_new("usb-hub"));
if (hub) {
usb_realize_and_unref(hub, bus, NULL);
}
@@ -663,7 +662,8 @@ USBDevice *usbdevice_create(const char *driver)
return NULL;
}
- dev = f->usbdevice_init ? f->usbdevice_init() : usb_new(f->name);
+ dev = f->usbdevice_init ? f->usbdevice_init()
+ : USB_DEVICE(qdev_new(f->name));
if (!dev) {
error_report("Failed to create USB device '%s'", f->name);
return NULL;
@@ -713,7 +713,7 @@ static void usb_device_instance_init(Object *obj)
}
}
-static void usb_device_class_init(ObjectClass *klass, void *data)
+static void usb_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->bus_type = TYPE_USB_BUS;
diff --git a/hw/usb/canokey.c b/hw/usb/canokey.c
index b306eeb..cbefbb5 100644
--- a/hw/usb/canokey.c
+++ b/hw/usb/canokey.c
@@ -197,8 +197,8 @@ static void canokey_handle_data(USBDevice *dev, USBPacket *p)
switch (p->pid) {
case USB_TOKEN_OUT:
trace_canokey_handle_data_out(ep_out, p->iov.size);
- usb_packet_copy(p, key->ep_out_buffer[ep_out], p->iov.size);
out_pos = 0;
+ /* segment packet into (possibly multiple) ep_out */
while (out_pos != p->iov.size) {
/*
* key->ep_out[ep_out] set by prepare_receive
@@ -207,8 +207,8 @@ static void canokey_handle_data(USBDevice *dev, USBPacket *p)
* to be the buffer length
*/
out_len = MIN(p->iov.size - out_pos, key->ep_out_size[ep_out]);
- memcpy(key->ep_out[ep_out],
- key->ep_out_buffer[ep_out] + out_pos, out_len);
+ /* usb_packet_copy would update the pos offset internally */
+ usb_packet_copy(p, key->ep_out[ep_out], out_len);
out_pos += out_len;
/* update ep_out_size to actual len */
key->ep_out_size[ep_out] = out_len;
@@ -296,12 +296,11 @@ static void canokey_unrealize(USBDevice *base)
trace_canokey_unrealize();
}
-static Property canokey_properties[] = {
+static const Property canokey_properties[] = {
DEFINE_PROP_STRING("file", CanoKeyState, file),
- DEFINE_PROP_END_OF_LIST(),
};
-static void canokey_class_init(ObjectClass *klass, void *data)
+static void canokey_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/canokey.h b/hw/usb/canokey.h
index e528889..1b60d73 100644
--- a/hw/usb/canokey.h
+++ b/hw/usb/canokey.h
@@ -24,8 +24,6 @@
#define CANOKEY_EP_NUM 3
/* BULK/INTR IN can be up to 1352 bytes, e.g. get key info */
#define CANOKEY_EP_IN_BUFFER_SIZE 2048
-/* BULK OUT can be up to 270 bytes, e.g. PIV import cert */
-#define CANOKEY_EP_OUT_BUFFER_SIZE 512
typedef enum {
CANOKEY_EP_IN_WAIT,
@@ -59,8 +57,6 @@ typedef struct CanoKeyState {
/* OUT pointer to canokey recv buffer */
uint8_t *ep_out[CANOKEY_EP_NUM];
uint32_t ep_out_size[CANOKEY_EP_NUM];
- /* For large BULK OUT, multiple write to ep_out is needed */
- uint8_t ep_out_buffer[CANOKEY_EP_NUM][CANOKEY_EP_OUT_BUFFER_SIZE];
/* Properties */
char *file; /* canokey-file */
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index 3ee9c73..c21cefd 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -582,17 +582,16 @@ static void emulated_unrealize(CCIDCardState *base)
qemu_mutex_destroy(&card->event_list_mutex);
}
-static Property emulated_card_properties[] = {
+static const Property emulated_card_properties[] = {
DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
DEFINE_PROP_STRING("db", EmulatedState, db),
DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void emulated_class_initfn(ObjectClass *klass, void *data)
+static void emulated_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
CCIDCardClass *cc = CCID_CARD_CLASS(klass);
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index a515703..1eea21a 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -388,13 +388,12 @@ static const VMStateDescription passthru_vmstate = {
}
};
-static Property passthru_card_properties[] = {
+static const Property passthru_card_properties[] = {
DEFINE_PROP_CHR("chardev", PassthruState, cs),
DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void passthru_class_initfn(ObjectClass *klass, void *data)
+static void passthru_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
CCIDCardClass *cc = CCID_CARD_CLASS(klass);
diff --git a/hw/usb/chipidea.c b/hw/usb/chipidea.c
index b1c8540..250c2b3 100644
--- a/hw/usb/chipidea.c
+++ b/hw/usb/chipidea.c
@@ -144,7 +144,7 @@ static void chipidea_init(Object *obj)
}
}
-static void chipidea_class_init(ObjectClass *klass, void *data)
+static void chipidea_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index 1897fff..26af709 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -990,15 +990,14 @@ static const VMStateDescription vmstate_usb_audio = {
.unmigratable = 1,
};
-static Property usb_audio_properties[] = {
+static const Property usb_audio_properties[] = {
DEFINE_AUDIO_PROPERTIES(USBAudioState, card),
DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
DEFINE_PROP_UINT32("buffer", USBAudioState, buffer_user, 0),
DEFINE_PROP_BOOL("multi", USBAudioState, multi, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_audio_class_init(ObjectClass *klass, void *data)
+static void usb_audio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *k = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 9e358c9..54d064e 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -774,7 +774,7 @@ static const VMStateDescription vmstate_usb_kbd = {
}
};
-static void usb_hid_class_initfn(ObjectClass *klass, void *data)
+static void usb_hid_class_initfn(ObjectClass *klass, const void *data)
{
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
@@ -793,14 +793,13 @@ static const TypeInfo usb_hid_type_info = {
.class_init = usb_hid_class_initfn,
};
-static Property usb_tablet_properties[] = {
+static const Property usb_tablet_properties[] = {
DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
DEFINE_PROP_STRING("display", USBHIDState, display),
DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
+static void usb_tablet_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
@@ -818,12 +817,11 @@ static const TypeInfo usb_tablet_info = {
.class_init = usb_tablet_class_initfn,
};
-static Property usb_mouse_properties[] = {
+static const Property usb_mouse_properties[] = {
DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
+static void usb_mouse_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
@@ -841,13 +839,12 @@ static const TypeInfo usb_mouse_info = {
.class_init = usb_mouse_class_initfn,
};
-static Property usb_keyboard_properties[] = {
+static const Property usb_keyboard_properties[] = {
DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
DEFINE_PROP_STRING("display", USBHIDState, display),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
+static void usb_keyboard_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 06e9537..a19350d 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -479,6 +479,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
usb_hub_port_clear(port, PORT_STAT_SUSPEND);
port->wPortChange = 0;
}
+ break;
default:
goto fail;
}
@@ -664,13 +665,12 @@ static const VMStateDescription vmstate_usb_hub = {
}
};
-static Property usb_hub_properties[] = {
+static const Property usb_hub_properties[] = {
DEFINE_PROP_UINT32("ports", USBHubState, num_ports, 8),
DEFINE_PROP_BOOL("port-power", USBHubState, port_power, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_hub_class_initfn(ObjectClass *klass, void *data)
+static void usb_hub_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 554b397..ce45c9c 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -1234,8 +1234,6 @@ static void usb_mtp_object_delete(MTPState *s, uint32_t handle,
default:
g_assert_not_reached();
}
-
- return;
}
static void usb_mtp_command(MTPState *s, MTPControl *c)
@@ -2078,14 +2076,13 @@ static const VMStateDescription vmstate_usb_mtp = {
}
};
-static Property mtp_properties[] = {
+static const Property mtp_properties[] = {
DEFINE_PROP_STRING("rootdir", MTPState, root),
DEFINE_PROP_STRING("desc", MTPState, desc),
DEFINE_PROP_BOOL("readonly", MTPState, readonly, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_mtp_class_initfn(ObjectClass *klass, void *data)
+static void usb_mtp_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index d00d68b2..81cc09d 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -33,7 +33,7 @@
#include "qemu/error-report.h"
#include "qemu/queue.h"
#include "qemu/config-file.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/iov.h"
#include "qemu/module.h"
#include "qemu/cutils.h"
@@ -1407,12 +1407,11 @@ static const VMStateDescription vmstate_usb_net = {
.unmigratable = 1,
};
-static Property net_properties[] = {
+static const Property net_properties[] = {
DEFINE_NIC_PROPERTIES(USBNetState, conf),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_net_class_initfn(ObjectClass *klass, void *data)
+static void usb_net_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 63047d7..1c116d8 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -472,8 +472,6 @@ static void usb_serial_token_in(USBSerialState *s, USBPacket *p)
s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
packet_len -= len + 2;
}
-
- return;
}
static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
@@ -624,7 +622,7 @@ static USBDevice *usb_braille_init(void)
return NULL;
}
- dev = usb_new("usb-braille");
+ dev = USB_DEVICE(qdev_new("usb-braille"));
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
return dev;
}
@@ -634,13 +632,12 @@ static const VMStateDescription vmstate_usb_serial = {
.unmigratable = 1,
};
-static Property serial_properties[] = {
+static const Property serial_properties[] = {
DEFINE_PROP_CHR("chardev", USBSerialState, cs),
DEFINE_PROP_BOOL("always-plugged", USBSerialState, always_plugged, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_serial_dev_class_init(ObjectClass *klass, void *data)
+static void usb_serial_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
@@ -661,7 +658,7 @@ static const TypeInfo usb_serial_dev_type_info = {
.class_init = usb_serial_dev_class_init,
};
-static void usb_serial_class_initfn(ObjectClass *klass, void *data)
+static void usb_serial_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
@@ -677,12 +674,11 @@ static const TypeInfo serial_info = {
.class_init = usb_serial_class_initfn,
};
-static Property braille_properties[] = {
+static const Property braille_properties[] = {
DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_braille_class_initfn(ObjectClass *klass, void *data)
+static void usb_braille_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index c0d63e0..6ce7154 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1069,7 +1069,6 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
err:
p->status = USB_RET_STALL;
s->bulk_out_pos = 0;
- return;
}
static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p,
@@ -1171,9 +1170,8 @@ static Answer *ccid_peek_next_answer(USBCCIDState *s)
: &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
}
-static Property ccid_props[] = {
+static const Property ccid_props[] = {
DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const TypeInfo ccid_bus_info = {
@@ -1431,12 +1429,11 @@ static const VMStateDescription ccid_vmstate = {
}
};
-static Property ccid_properties[] = {
+static const Property ccid_properties[] = {
DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ccid_class_initfn(ObjectClass *klass, void *data)
+static void ccid_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
@@ -1461,13 +1458,13 @@ static const TypeInfo ccid_info = {
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBCCIDState),
.class_init = ccid_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
-static void ccid_card_class_init(ObjectClass *klass, void *data)
+static void ccid_card_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->bus_type = TYPE_CCID_BUS;
diff --git a/hw/usb/dev-storage-bot.c b/hw/usb/dev-storage-bot.c
index 1e5c5c7..df6ab7f 100644
--- a/hw/usb/dev-storage-bot.c
+++ b/hw/usb/dev-storage-bot.c
@@ -40,7 +40,7 @@ static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
usb_msd_handle_reset(dev);
}
-static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
+static void usb_msd_class_bot_initfn(ObjectClass *klass, const void *data)
{
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-storage-classic.c b/hw/usb/dev-storage-classic.c
index 6147387..dabe156 100644
--- a/hw/usb/dev-storage-classic.c
+++ b/hw/usb/dev-storage-classic.c
@@ -13,8 +13,8 @@
#include "hw/usb.h"
#include "hw/usb/desc.h"
#include "hw/usb/msd.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
+#include "system/system.h"
+#include "system/block-backend.h"
static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
.tcq = false,
@@ -67,15 +67,14 @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
s->scsi_dev = scsi_dev;
}
-static Property msd_properties[] = {
+static const Property msd_properties[] = {
DEFINE_BLOCK_PROPERTIES(MSDState, conf),
DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
DEFINE_PROP_BOOL("removable", MSDState, removable, false),
DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
+static void usb_msd_class_storage_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 341e505..b13fe34 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -177,7 +177,7 @@ static const USBDesc desc = {
.str = desc_strings,
};
-static void usb_msd_packet_complete(MSDState *s)
+static void usb_msd_packet_complete(MSDState *s, int status)
{
USBPacket *p = s->packet;
@@ -187,6 +187,7 @@ static void usb_msd_packet_complete(MSDState *s)
* usb_packet_complete returns.
*/
trace_usb_msd_packet_complete();
+ p->status = status;
s->packet = NULL;
usb_packet_complete(&s->dev, p);
}
@@ -196,8 +197,7 @@ static void usb_msd_fatal_error(MSDState *s)
trace_usb_msd_fatal_error();
if (s->packet) {
- s->packet->status = USB_RET_STALL;
- usb_msd_packet_complete(s);
+ usb_msd_packet_complete(s, USB_RET_STALL);
}
/*
@@ -255,8 +255,8 @@ void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
usb_msd_copy_data(s, p);
p = s->packet;
if (p && p->actual_length == p->iov.size) {
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_msd_packet_complete(s);
+ /* USB_RET_SUCCESS status clears previous ASYNC status */
+ usb_msd_packet_complete(s, USB_RET_SUCCESS);
}
}
}
@@ -295,8 +295,8 @@ void usb_msd_command_complete(SCSIRequest *req, size_t resid)
s->mode = USB_MSDM_CSW;
}
}
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_msd_packet_complete(s);
+ /* USB_RET_SUCCESS status clears previous ASYNC status */
+ usb_msd_packet_complete(s, USB_RET_SUCCESS);
} else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
@@ -332,8 +332,7 @@ void usb_msd_handle_reset(USBDevice *dev)
assert(s->req == NULL);
if (s->packet) {
- s->packet->status = USB_RET_STALL;
- usb_msd_packet_complete(s);
+ usb_msd_packet_complete(s, USB_RET_STALL);
}
memset(&s->csw, 0, sizeof(s->csw));
@@ -586,7 +585,7 @@ static const VMStateDescription vmstate_usb_msd = {
}
};
-static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
+static void usb_msd_class_initfn_common(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index 1804cb6..21cc283 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -914,7 +914,6 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
err_stream:
error_report("%s: invalid stream %d", __func__, p->stream);
p->status = USB_RET_STALL;
- return;
}
static void usb_uas_unrealize(USBDevice *dev)
@@ -953,12 +952,11 @@ static const VMStateDescription vmstate_usb_uas = {
}
};
-static Property uas_properties[] = {
+static const Property uas_properties[] = {
DEFINE_PROP_UINT32("log-scsi-req", UASDevice, requestlog, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_uas_class_initfn(ObjectClass *klass, void *data)
+static void usb_uas_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index 7177c17..f4b71a2 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -420,7 +420,7 @@ static const VMStateDescription vmstate_usb_wacom = {
.unmigratable = 1,
};
-static void usb_wacom_class_init(ObjectClass *klass, void *data)
+static void usb_wacom_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c
index b4f0652..8386450 100644
--- a/hw/usb/hcd-dwc2.c
+++ b/hw/usb/hcd-dwc2.c
@@ -1448,12 +1448,11 @@ const VMStateDescription vmstate_dwc2_state = {
}
};
-static Property dwc2_usb_properties[] = {
+static const Property dwc2_usb_properties[] = {
DEFINE_PROP_UINT32("usb_version", DWC2State, usb_version, 2),
- DEFINE_PROP_END_OF_LIST(),
};
-static void dwc2_class_init(ObjectClass *klass, void *data)
+static void dwc2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
DWC2Class *c = DWC2_USB_CLASS(klass);
diff --git a/hw/usb/hcd-dwc2.h b/hw/usb/hcd-dwc2.h
index 9c3d88e..2d5a569 100644
--- a/hw/usb/hcd-dwc2.h
+++ b/hw/usb/hcd-dwc2.h
@@ -23,7 +23,7 @@
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/usb.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qom/object.h"
#define DWC2_MMIO_SIZE 0x11000
diff --git a/hw/usb/hcd-dwc3.c b/hw/usb/hcd-dwc3.c
index 09d8e25..98a342b 100644
--- a/hw/usb/hcd-dwc3.c
+++ b/hw/usb/hcd-dwc3.c
@@ -343,6 +343,8 @@ REG32(GFLADJ, 0x530)
FIELD(GFLADJ, GFLADJ_REFCLK_FLADJ, 8, 14)
FIELD(GFLADJ, GFLADJ_30MHZ_SDBND_SEL, 7, 1)
FIELD(GFLADJ, GFLADJ_30MHZ, 0, 6)
+REG32(GUSB2RHBCTL, 0x540)
+ FIELD(GUSB2RHBCTL, OVRD_L1TIMEOUT, 0, 4)
#define DWC3_GLOBAL_OFFSET 0xC100
static void reset_csr(USBDWC3 * s)
@@ -560,6 +562,9 @@ static const RegisterAccessInfo usb_dwc3_regs_info[] = {
.rsvd = 0x40,
.ro = 0x400040,
.unimp = 0xffffffff,
+ },{ .name = "GUSB2RHBCTL", .addr = A_GUSB2RHBCTL,
+ .rsvd = 0xfffffff0,
+ .unimp = 0xffffffff,
}
};
@@ -656,17 +661,16 @@ static const VMStateDescription vmstate_usb_dwc3 = {
}
};
-static Property usb_dwc3_properties[] = {
+static const Property usb_dwc3_properties[] = {
DEFINE_PROP_UINT32("DWC_USB3_USERID", USBDWC3, cfg.dwc_usb3_user,
0x12345678),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_dwc3_class_init(ObjectClass *klass, void *data)
+static void usb_dwc3_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = usb_dwc3_reset;
+ device_class_set_legacy_reset(dc, usb_dwc3_reset);
dc->realize = usb_dwc3_realize;
dc->vmsd = &vmstate_usb_dwc3;
device_class_set_props(dc, usb_dwc3_properties);
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 3ff54ed..38ad340 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -135,9 +135,8 @@ static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
i->ehci.as = busmaster ? pci_get_address_space(dev) : &address_space_memory;
}
-static Property ehci_pci_properties[] = {
+static const Property ehci_pci_properties[] = {
DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_ehci_pci = {
@@ -151,7 +150,7 @@ static const VMStateDescription vmstate_ehci_pci = {
}
};
-static void ehci_class_init(ObjectClass *klass, void *data)
+static void ehci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -162,7 +161,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
k->config_write = usb_ehci_pci_write_config;
dc->vmsd = &vmstate_ehci_pci;
device_class_set_props(dc, ehci_pci_properties);
- dc->reset = usb_ehci_pci_reset;
+ device_class_set_legacy_reset(dc, usb_ehci_pci_reset);
}
static const TypeInfo ehci_pci_type_info = {
@@ -173,17 +172,17 @@ static const TypeInfo ehci_pci_type_info = {
.instance_finalize = usb_ehci_pci_finalize,
.abstract = true,
.class_init = ehci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-static void ehci_data_class_init(ObjectClass *klass, void *data)
+static void ehci_data_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- EHCIPCIInfo *i = data;
+ const EHCIPCIInfo *i = data;
k->vendor_id = i->vendor_id;
k->device_id = i->device_id;
@@ -228,7 +227,7 @@ static void ehci_pci_register_types(void)
for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) {
ehci_type_info.name = ehci_pci_info[i].name;
ehci_type_info.class_data = ehci_pci_info + i;
- type_register(&ehci_type_info);
+ type_register_static(&ehci_type_info);
}
}
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index fe1dabd..0449f5f 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -19,7 +19,6 @@
#include "hw/qdev-properties.h"
#include "hw/usb/hcd-ehci.h"
#include "migration/vmstate.h"
-#include "qemu/module.h"
static const VMStateDescription vmstate_ehci_sysbus = {
.name = "ehci-sysbus",
@@ -31,11 +30,10 @@ static const VMStateDescription vmstate_ehci_sysbus = {
}
};
-static Property ehci_sysbus_properties[] = {
+static const Property ehci_sysbus_properties[] = {
DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
DEFINE_PROP_BOOL("companion-enable", EHCISysBusState, ehci.companion_enable,
false),
- DEFINE_PROP_END_OF_LIST(),
};
static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
@@ -82,7 +80,7 @@ static void ehci_sysbus_finalize(Object *obj)
usb_ehci_finalize(s);
}
-static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
+static void ehci_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
@@ -93,22 +91,11 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
dc->realize = usb_ehci_sysbus_realize;
dc->vmsd = &vmstate_ehci_sysbus;
device_class_set_props(dc, ehci_sysbus_properties);
- dc->reset = usb_ehci_sysbus_reset;
+ device_class_set_legacy_reset(dc, usb_ehci_sysbus_reset);
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_type_info = {
- .name = TYPE_SYS_BUS_EHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(EHCISysBusState),
- .instance_init = ehci_sysbus_init,
- .instance_finalize = ehci_sysbus_finalize,
- .abstract = true,
- .class_init = ehci_sysbus_class_init,
- .class_size = sizeof(SysBusEHCIClass),
-};
-
-static void ehci_platform_class_init(ObjectClass *oc, void *data)
+static void ehci_platform_class_init(ObjectClass *oc, const void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -118,13 +105,7 @@ static void ehci_platform_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_platform_type_info = {
- .name = TYPE_PLATFORM_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_platform_class_init,
-};
-
-static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
+static void ehci_exynos4210_class_init(ObjectClass *oc, const void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -134,13 +115,7 @@ static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_exynos4210_type_info = {
- .name = TYPE_EXYNOS4210_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_exynos4210_class_init,
-};
-
-static void ehci_aw_h3_class_init(ObjectClass *oc, void *data)
+static void ehci_aw_h3_class_init(ObjectClass *oc, const void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -150,13 +125,7 @@ static void ehci_aw_h3_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_aw_h3_type_info = {
- .name = TYPE_AW_H3_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_aw_h3_class_init,
-};
-
-static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data)
+static void ehci_npcm7xx_class_init(ObjectClass *oc, const void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -168,13 +137,7 @@ static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_npcm7xx_type_info = {
- .name = TYPE_NPCM7XX_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_npcm7xx_class_init,
-};
-
-static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
+static void ehci_tegra2_class_init(ObjectClass *oc, const void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -184,12 +147,6 @@ static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_tegra2_type_info = {
- .name = TYPE_TEGRA2_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_tegra2_class_init,
-};
-
static void ehci_ppc4xx_init(Object *o)
{
EHCISysBusState *s = SYS_BUS_EHCI(o);
@@ -197,7 +154,7 @@ static void ehci_ppc4xx_init(Object *o)
s->ehci.companion_enable = true;
}
-static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data)
+static void ehci_ppc4xx_class_init(ObjectClass *oc, const void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -207,13 +164,6 @@ static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_ppc4xx_type_info = {
- .name = TYPE_PPC4xx_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_ppc4xx_class_init,
- .instance_init = ehci_ppc4xx_init,
-};
-
/*
* Faraday FUSBH200 USB 2.0 EHCI
*/
@@ -270,7 +220,7 @@ static void fusbh200_ehci_init(Object *obj)
&f->mem_vendor);
}
-static void fusbh200_ehci_class_init(ObjectClass *oc, void *data)
+static void fusbh200_ehci_class_init(ObjectClass *oc, const void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -282,24 +232,55 @@ static void fusbh200_ehci_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
-static const TypeInfo ehci_fusbh200_type_info = {
- .name = TYPE_FUSBH200_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .instance_size = sizeof(FUSBH200EHCIState),
- .instance_init = fusbh200_ehci_init,
- .class_init = fusbh200_ehci_class_init,
+static const TypeInfo ehci_sysbus_types[] = {
+ {
+ .name = TYPE_SYS_BUS_EHCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(EHCISysBusState),
+ .instance_init = ehci_sysbus_init,
+ .instance_finalize = ehci_sysbus_finalize,
+ .abstract = true,
+ .class_init = ehci_sysbus_class_init,
+ .class_size = sizeof(SysBusEHCIClass),
+ },
+ {
+ .name = TYPE_PLATFORM_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = ehci_platform_class_init,
+ },
+ {
+ .name = TYPE_EXYNOS4210_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = ehci_exynos4210_class_init,
+ },
+ {
+ .name = TYPE_AW_H3_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = ehci_aw_h3_class_init,
+ },
+ {
+ .name = TYPE_NPCM7XX_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = ehci_npcm7xx_class_init,
+ },
+ {
+ .name = TYPE_TEGRA2_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = ehci_tegra2_class_init,
+ },
+ {
+ .name = TYPE_PPC4xx_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = ehci_ppc4xx_class_init,
+ .instance_init = ehci_ppc4xx_init,
+ },
+ {
+ .name = TYPE_FUSBH200_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .instance_size = sizeof(FUSBH200EHCIState),
+ .instance_init = fusbh200_ehci_init,
+ .class_init = fusbh200_ehci_class_init,
+ },
};
-static void ehci_sysbus_register_types(void)
-{
- type_register_static(&ehci_type_info);
- type_register_static(&ehci_platform_type_info);
- type_register_static(&ehci_exynos4210_type_info);
- type_register_static(&ehci_aw_h3_type_info);
- type_register_static(&ehci_npcm7xx_type_info);
- type_register_static(&ehci_tegra2_type_info);
- type_register_static(&ehci_ppc4xx_type_info);
- type_register_static(&ehci_fusbh200_type_info);
-}
-
-type_init(ehci_sysbus_register_types)
+DEFINE_TYPES(ehci_sysbus_types)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 01864d4..b090f25 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -35,7 +35,7 @@
#include "trace.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#define FRAME_TIMER_FREQ 1000
#define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ)
@@ -2287,7 +2287,8 @@ static void ehci_work_bh(void *opaque)
ehci_update_frindex(ehci, skipped_uframes);
ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes;
uframes -= skipped_uframes;
- DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes);
+ DPRINTF("WARNING - EHCI skipped %"PRIu64" uframes\n",
+ skipped_uframes);
}
for (i = 0; i < uframes; i++) {
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 56a1c09..ffd6c51 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -20,7 +20,7 @@
#include "qemu/timer.h"
#include "hw/usb.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/pci/pci_device.h"
#include "hw/sysbus.h"
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
deleted file mode 100644
index 6dca373..0000000
--- a/hw/usb/hcd-musb.c
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
- * USB2.0 OTG compliant core used in various chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Only host-mode and non-DMA accesses are currently supported.
- */
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/usb/hcd-musb.h"
-#include "hw/irq.h"
-#include "hw/hw.h"
-
-/* Common USB registers */
-#define MUSB_HDRC_FADDR 0x00 /* 8-bit */
-#define MUSB_HDRC_POWER 0x01 /* 8-bit */
-
-#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */
-#define MUSB_HDRC_INTRRX 0x04
-#define MUSB_HDRC_INTRTXE 0x06
-#define MUSB_HDRC_INTRRXE 0x08
-#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */
-#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */
-#define MUSB_HDRC_FRAME 0x0c /* 16-bit */
-#define MUSB_HDRC_INDEX 0x0e /* 8 bit */
-#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */
-
-/* Per-EP registers in indexed mode */
-#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */
-
-/* EP FIFOs */
-#define MUSB_HDRC_FIFO 0x20
-
-/* Additional Control Registers */
-#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */
-
-/* These are indexed */
-#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */
-#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */
-#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */
-#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */
-
-/* Some more registers */
-#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */
-#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */
-
-/* Added in HDRC 1.9(?) & MHDRC 1.4 */
-/* ULPI pass-through */
-#define MUSB_HDRC_ULPI_VBUSCTL 0x70
-#define MUSB_HDRC_ULPI_REGDATA 0x74
-#define MUSB_HDRC_ULPI_REGADDR 0x75
-#define MUSB_HDRC_ULPI_REGCTL 0x76
-
-/* Extended config & PHY control */
-#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */
-#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */
-#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */
-#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */
-#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */
-#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */
-#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */
-
-/* Per-EP BUSCTL registers */
-#define MUSB_HDRC_BUSCTL 0x80
-
-/* Per-EP registers in flat mode */
-#define MUSB_HDRC_EP 0x100
-
-/* offsets to registers in flat model */
-#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */
-#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */
-#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */
-#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */
-#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */
-#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */
-#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */
-#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */
-#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */
-#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */
-#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */
-#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */
-#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */
-#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */
-#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */
-
-/* "Bus control" registers */
-#define MUSB_HDRC_TXFUNCADDR 0x00
-#define MUSB_HDRC_TXHUBADDR 0x02
-#define MUSB_HDRC_TXHUBPORT 0x03
-
-#define MUSB_HDRC_RXFUNCADDR 0x04
-#define MUSB_HDRC_RXHUBADDR 0x06
-#define MUSB_HDRC_RXHUBPORT 0x07
-
-/*
- * MUSBHDRC Register bit masks
- */
-
-/* POWER */
-#define MGC_M_POWER_ISOUPDATE 0x80
-#define MGC_M_POWER_SOFTCONN 0x40
-#define MGC_M_POWER_HSENAB 0x20
-#define MGC_M_POWER_HSMODE 0x10
-#define MGC_M_POWER_RESET 0x08
-#define MGC_M_POWER_RESUME 0x04
-#define MGC_M_POWER_SUSPENDM 0x02
-#define MGC_M_POWER_ENSUSPEND 0x01
-
-/* INTRUSB */
-#define MGC_M_INTR_SUSPEND 0x01
-#define MGC_M_INTR_RESUME 0x02
-#define MGC_M_INTR_RESET 0x04
-#define MGC_M_INTR_BABBLE 0x04
-#define MGC_M_INTR_SOF 0x08
-#define MGC_M_INTR_CONNECT 0x10
-#define MGC_M_INTR_DISCONNECT 0x20
-#define MGC_M_INTR_SESSREQ 0x40
-#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */
-#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */
-
-/* DEVCTL */
-#define MGC_M_DEVCTL_BDEVICE 0x80
-#define MGC_M_DEVCTL_FSDEV 0x40
-#define MGC_M_DEVCTL_LSDEV 0x20
-#define MGC_M_DEVCTL_VBUS 0x18
-#define MGC_S_DEVCTL_VBUS 3
-#define MGC_M_DEVCTL_HM 0x04
-#define MGC_M_DEVCTL_HR 0x02
-#define MGC_M_DEVCTL_SESSION 0x01
-
-/* TESTMODE */
-#define MGC_M_TEST_FORCE_HOST 0x80
-#define MGC_M_TEST_FIFO_ACCESS 0x40
-#define MGC_M_TEST_FORCE_FS 0x20
-#define MGC_M_TEST_FORCE_HS 0x10
-#define MGC_M_TEST_PACKET 0x08
-#define MGC_M_TEST_K 0x04
-#define MGC_M_TEST_J 0x02
-#define MGC_M_TEST_SE0_NAK 0x01
-
-/* CSR0 */
-#define MGC_M_CSR0_FLUSHFIFO 0x0100
-#define MGC_M_CSR0_TXPKTRDY 0x0002
-#define MGC_M_CSR0_RXPKTRDY 0x0001
-
-/* CSR0 in Peripheral mode */
-#define MGC_M_CSR0_P_SVDSETUPEND 0x0080
-#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040
-#define MGC_M_CSR0_P_SENDSTALL 0x0020
-#define MGC_M_CSR0_P_SETUPEND 0x0010
-#define MGC_M_CSR0_P_DATAEND 0x0008
-#define MGC_M_CSR0_P_SENTSTALL 0x0004
-
-/* CSR0 in Host mode */
-#define MGC_M_CSR0_H_NO_PING 0x0800
-#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */
-#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */
-#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080
-#define MGC_M_CSR0_H_STATUSPKT 0x0040
-#define MGC_M_CSR0_H_REQPKT 0x0020
-#define MGC_M_CSR0_H_ERROR 0x0010
-#define MGC_M_CSR0_H_SETUPPKT 0x0008
-#define MGC_M_CSR0_H_RXSTALL 0x0004
-
-/* CONFIGDATA */
-#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */
-#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */
-#define MGC_M_CONFIGDATA_BIGENDIAN 0x20
-#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
-#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
-#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */
-#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
-#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */
-
-/* TXCSR in Peripheral and Host mode */
-#define MGC_M_TXCSR_AUTOSET 0x8000
-#define MGC_M_TXCSR_ISO 0x4000
-#define MGC_M_TXCSR_MODE 0x2000
-#define MGC_M_TXCSR_DMAENAB 0x1000
-#define MGC_M_TXCSR_FRCDATATOG 0x0800
-#define MGC_M_TXCSR_DMAMODE 0x0400
-#define MGC_M_TXCSR_CLRDATATOG 0x0040
-#define MGC_M_TXCSR_FLUSHFIFO 0x0008
-#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002
-#define MGC_M_TXCSR_TXPKTRDY 0x0001
-
-/* TXCSR in Peripheral mode */
-#define MGC_M_TXCSR_P_INCOMPTX 0x0080
-#define MGC_M_TXCSR_P_SENTSTALL 0x0020
-#define MGC_M_TXCSR_P_SENDSTALL 0x0010
-#define MGC_M_TXCSR_P_UNDERRUN 0x0004
-
-/* TXCSR in Host mode */
-#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200
-#define MGC_M_TXCSR_H_DATATOGGLE 0x0100
-#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080
-#define MGC_M_TXCSR_H_RXSTALL 0x0020
-#define MGC_M_TXCSR_H_ERROR 0x0004
-
-/* RXCSR in Peripheral and Host mode */
-#define MGC_M_RXCSR_AUTOCLEAR 0x8000
-#define MGC_M_RXCSR_DMAENAB 0x2000
-#define MGC_M_RXCSR_DISNYET 0x1000
-#define MGC_M_RXCSR_DMAMODE 0x0800
-#define MGC_M_RXCSR_INCOMPRX 0x0100
-#define MGC_M_RXCSR_CLRDATATOG 0x0080
-#define MGC_M_RXCSR_FLUSHFIFO 0x0010
-#define MGC_M_RXCSR_DATAERROR 0x0008
-#define MGC_M_RXCSR_FIFOFULL 0x0002
-#define MGC_M_RXCSR_RXPKTRDY 0x0001
-
-/* RXCSR in Peripheral mode */
-#define MGC_M_RXCSR_P_ISO 0x4000
-#define MGC_M_RXCSR_P_SENTSTALL 0x0040
-#define MGC_M_RXCSR_P_SENDSTALL 0x0020
-#define MGC_M_RXCSR_P_OVERRUN 0x0004
-
-/* RXCSR in Host mode */
-#define MGC_M_RXCSR_H_AUTOREQ 0x4000
-#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400
-#define MGC_M_RXCSR_H_DATATOGGLE 0x0200
-#define MGC_M_RXCSR_H_RXSTALL 0x0040
-#define MGC_M_RXCSR_H_REQPKT 0x0020
-#define MGC_M_RXCSR_H_ERROR 0x0004
-
-/* HUBADDR */
-#define MGC_M_HUBADDR_MULTI_TT 0x80
-
-/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */
-#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02
-#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01
-#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08
-#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04
-#define MGC_M_ULPI_REGCTL_COMPLETE 0x02
-#define MGC_M_ULPI_REGCTL_REG 0x01
-
-/* #define MUSB_DEBUG */
-
-#ifdef MUSB_DEBUG
-#define TRACE(fmt, ...) fprintf(stderr, "%s@%d: " fmt "\n", __func__, \
- __LINE__, ##__VA_ARGS__)
-#else
-#define TRACE(...)
-#endif
-
-
-static void musb_attach(USBPort *port);
-static void musb_detach(USBPort *port);
-static void musb_child_detach(USBPort *port, USBDevice *child);
-static void musb_schedule_cb(USBPort *port, USBPacket *p);
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
-
-static USBPortOps musb_port_ops = {
- .attach = musb_attach,
- .detach = musb_detach,
- .child_detach = musb_child_detach,
- .complete = musb_schedule_cb,
-};
-
-static USBBusOps musb_bus_ops = {
-};
-
-typedef struct MUSBPacket MUSBPacket;
-typedef struct MUSBEndPoint MUSBEndPoint;
-
-struct MUSBPacket {
- USBPacket p;
- MUSBEndPoint *ep;
- int dir;
-};
-
-struct MUSBEndPoint {
- uint16_t faddr[2];
- uint8_t haddr[2];
- uint8_t hport[2];
- uint16_t csr[2];
- uint16_t maxp[2];
- uint16_t rxcount;
- uint8_t type[2];
- uint8_t interval[2];
- uint8_t config;
- uint8_t fifosize;
- int timeout[2]; /* Always in microframes */
-
- uint8_t *buf[2];
- int fifolen[2];
- int fifostart[2];
- int fifoaddr[2];
- MUSBPacket packey[2];
- int status[2];
- int ext_size[2];
-
- /* For callbacks' use */
- int epnum;
- int interrupt[2];
- MUSBState *musb;
- USBCallback *delayed_cb[2];
- QEMUTimer *intv_timer[2];
-};
-
-struct MUSBState {
- qemu_irq irqs[musb_irq_max];
- USBBus bus;
- USBPort port;
-
- int idx;
- uint8_t devctl;
- uint8_t power;
- uint8_t faddr;
-
- uint8_t intr;
- uint8_t mask;
- uint16_t tx_intr;
- uint16_t tx_mask;
- uint16_t rx_intr;
- uint16_t rx_mask;
-
- int setup_len;
- int session;
-
- uint8_t buf[0x8000];
-
- /* Duplicating the world since 2008!... probably we should have 32
- * logical, single endpoints instead. */
- MUSBEndPoint ep[16];
-};
-
-void musb_reset(MUSBState *s)
-{
- int i;
-
- s->faddr = 0x00;
- s->devctl = 0;
- s->power = MGC_M_POWER_HSENAB;
- s->tx_intr = 0x0000;
- s->rx_intr = 0x0000;
- s->tx_mask = 0xffff;
- s->rx_mask = 0xffff;
- s->intr = 0x00;
- s->mask = 0x06;
- s->idx = 0;
-
- s->setup_len = 0;
- s->session = 0;
- memset(s->buf, 0, sizeof(s->buf));
-
- /* TODO: _DW */
- s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
- for (i = 0; i < 16; i ++) {
- s->ep[i].fifosize = 64;
- s->ep[i].maxp[0] = 0x40;
- s->ep[i].maxp[1] = 0x40;
- s->ep[i].musb = s;
- s->ep[i].epnum = i;
- usb_packet_init(&s->ep[i].packey[0].p);
- usb_packet_init(&s->ep[i].packey[1].p);
- }
-}
-
-struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
-{
- MUSBState *s = g_malloc0(sizeof(*s));
- int i;
-
- for (i = 0; i < musb_irq_max; i++) {
- s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
- }
-
- musb_reset(s);
-
- usb_bus_new(&s->bus, sizeof(s->bus), &musb_bus_ops, parent_device);
- usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-
- return s;
-}
-
-static void musb_vbus_set(MUSBState *s, int level)
-{
- if (level)
- s->devctl |= 3 << MGC_S_DEVCTL_VBUS;
- else
- s->devctl &= ~MGC_M_DEVCTL_VBUS;
-
- qemu_set_irq(s->irqs[musb_set_vbus], level);
-}
-
-static void musb_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->intr &= ~(1 << line);
- qemu_irq_lower(s->irqs[line]);
- } else if (s->mask & (1 << line)) {
- s->intr |= 1 << line;
- qemu_irq_raise(s->irqs[line]);
- }
-}
-
-static void musb_tx_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->tx_intr &= ~(1 << line);
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- } else if (s->tx_mask & (1 << line)) {
- s->tx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_tx]);
- }
-}
-
-static void musb_rx_intr_set(MUSBState *s, int line, int level)
-{
- if (line) {
- if (!level) {
- s->rx_intr &= ~(1 << line);
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- } else if (s->rx_mask & (1 << line)) {
- s->rx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_rx]);
- }
- } else
- musb_tx_intr_set(s, line, level);
-}
-
-uint32_t musb_core_intr_get(MUSBState *s)
-{
- return (s->rx_intr << 15) | s->tx_intr;
-}
-
-void musb_core_intr_clear(MUSBState *s, uint32_t mask)
-{
- if (s->rx_intr) {
- s->rx_intr &= mask >> 15;
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- }
-
- if (s->tx_intr) {
- s->tx_intr &= mask & 0xffff;
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- }
-}
-
-void musb_set_size(MUSBState *s, int epnum, int size, int is_tx)
-{
- s->ep[epnum].ext_size[!is_tx] = size;
- s->ep[epnum].fifostart[0] = 0;
- s->ep[epnum].fifostart[1] = 0;
- s->ep[epnum].fifolen[0] = 0;
- s->ep[epnum].fifolen[1] = 0;
-}
-
-static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
-{
- int detect_prev = prev_dev && prev_sess;
- int detect = !!s->port.dev && s->session;
-
- if (detect && !detect_prev) {
- /* Let's skip the ID pin sense and VBUS sense formalities and
- * and signal a successful SRP directly. This should work at least
- * for the Linux driver stack. */
- musb_intr_set(s, musb_irq_connect, 1);
-
- if (s->port.dev->speed == USB_SPEED_LOW) {
- s->devctl &= ~MGC_M_DEVCTL_FSDEV;
- s->devctl |= MGC_M_DEVCTL_LSDEV;
- } else {
- s->devctl |= MGC_M_DEVCTL_FSDEV;
- s->devctl &= ~MGC_M_DEVCTL_LSDEV;
- }
-
- /* A-mode? */
- s->devctl &= ~MGC_M_DEVCTL_BDEVICE;
-
- /* Host-mode bit? */
- s->devctl |= MGC_M_DEVCTL_HM;
-#if 1
- musb_vbus_set(s, 1);
-#endif
- } else if (!detect && detect_prev) {
-#if 1
- musb_vbus_set(s, 0);
-#endif
- }
-}
-
-/* Attach or detach a device on our only port. */
-static void musb_attach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_intr_set(s, musb_irq_vbus_request, 1);
- musb_session_update(s, 0, s->session);
-}
-
-static void musb_detach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, port->dev);
-
- musb_intr_set(s, musb_irq_disconnect, 1);
- musb_session_update(s, 1, s->session);
-}
-
-static void musb_child_detach(USBPort *port, USBDevice *child)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, child);
-}
-
-static void musb_cb_tick0(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[0](&ep->packey[0].p, opaque);
-}
-
-static void musb_cb_tick1(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[1](&ep->packey[1].p, opaque);
-}
-
-#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
-
-static void musb_schedule_cb(USBPort *port, USBPacket *packey)
-{
- MUSBPacket *p = container_of(packey, MUSBPacket, p);
- MUSBEndPoint *ep = p->ep;
- int dir = p->dir;
- int timeout = 0;
-
- if (ep->status[dir] == USB_RET_NAK)
- timeout = ep->timeout[dir];
- else if (ep->interrupt[dir])
- timeout = 8;
- else {
- musb_cb_tick(ep);
- return;
- }
-
- if (!ep->intv_timer[dir])
- ep->intv_timer[dir] = timer_new_ns(QEMU_CLOCK_VIRTUAL, musb_cb_tick, ep);
-
- timer_mod(ep->intv_timer[dir], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(timeout, NANOSECONDS_PER_SECOND, 8000));
-}
-
-static int musb_timeout(int ttype, int speed, int val)
-{
-#if 1
- return val << 3;
-#endif
-
- switch (ttype) {
- case USB_ENDPOINT_XFER_CONTROL:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
-
- case USB_ENDPOINT_XFER_INT:
- if (speed == USB_SPEED_HIGH)
- if (val < 2)
- return 0;
- else
- return 1 << (val - 1);
- else
- return val << 3;
-
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_ISOC:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
- /* TODO: what with low-speed Bulk and Isochronous? */
- }
-
- hw_error("bad interval\n");
-}
-
-static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
- int epnum, int pid, int len, USBCallback cb, int dir)
-{
- USBDevice *dev;
- USBEndpoint *uep;
- int idx = epnum && dir;
- int id;
- int ttype;
-
- /* ep->type[0,1] contains:
- * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)
- * in bits 5:4 the transfer type (BULK / INT)
- * in bits 3:0 the EP num
- */
- ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;
-
- ep->timeout[dir] = musb_timeout(ttype,
- ep->type[idx] >> 6, ep->interval[idx]);
- ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
- ep->delayed_cb[dir] = cb;
-
- /* A wild guess on the FADDR semantics... */
- dev = usb_find_device(&s->port, ep->faddr[idx]);
- if (dev == NULL) {
- return;
- }
- uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
- id = pid | (dev->addr << 16) | (uep->nr << 8);
- usb_packet_setup(&ep->packey[dir].p, pid, uep, 0, id, false, true);
- usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
- ep->packey[dir].ep = ep;
- ep->packey[dir].dir = dir;
-
- usb_handle_packet(dev, &ep->packey[dir].p);
-
- if (ep->packey[dir].p.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, uep);
- ep->status[dir] = len;
- return;
- }
-
- if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
- ep->status[dir] = ep->packey[dir].p.actual_length;
- } else {
- ep->status[dir] = ep->packey[dir].p.status;
- }
- musb_schedule_cb(&s->port, &ep->packey[dir].p);
-}
-
-static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[0] = 0;
- ep->fifolen[0] = 0;
-#ifdef CLEAR_NAK
- if (ep->status[0] != USB_RET_NAK) {
-#endif
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the error bits first */
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |
- MGC_M_TXCSR_H_NAKTIMEOUT);
- else
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[0] == USB_RET_STALL) {
- /* Command not supported by target! */
- ep->status[0] = 0;
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;
- else
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[0] == USB_RET_NAK) {
- ep->status[0] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[0]) {
- return;
- }
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;
- else
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[0] < 0) {
- if (ep->status[0] == USB_RET_BABBLE)
- musb_intr_set(s, musb_irq_rst_babble, 1);
-
- /* Pretend we've tried three times already and failed (in
- * case of USB_TOKEN_SETUP). */
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_ERROR;
- else
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_tx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
-
-#ifdef SETUPLEN_HACK
- if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)
- s->setup_len = ep->packey[0].data[6];
-#endif
-
- /* In DMA mode: if no error, assert DMA request for this EP,
- * and skip the interrupt. */
- musb_tx_intr_set(s, epnum, 1);
-}
-
-static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[1] = 0;
- ep->fifolen[1] = 0;
-
-#ifdef CLEAR_NAK
- if (ep->status[1] != USB_RET_NAK) {
-#endif
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the imaginable error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[1] == USB_RET_STALL) {
- ep->status[1] = 0;
-
- ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[1] == USB_RET_NAK) {
- ep->status[1] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[1]) {
- musb_packet(s, ep, epnum, USB_TOKEN_IN,
- packey->iov.size, musb_rx_packet_complete, 1);
- return;
- }
-
- ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[1] < 0) {
- if (ep->status[1] == USB_RET_BABBLE) {
- musb_intr_set(s, musb_irq_rst_babble, 1);
- return;
- }
-
- /* Pretend we've tried three times already and failed (in
- * case of a control transfer). */
- ep->csr[1] |= MGC_M_RXCSR_H_ERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
- /* TODO: perhaps make use of e->ext_size[1] here. */
-
- if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
-
- ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
- /* In DMA mode: assert DMA request for this EP */
- }
-
- /* Only if DMA has not been asserted */
- musb_rx_intr_set(s, epnum, 1);
-}
-
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
-{
- int ep, dir;
-
- for (ep = 0; ep < 16; ep++) {
- for (dir = 0; dir < 2; dir++) {
- if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
- s->ep[ep].packey[dir].p.ep->dev != dev) {
- continue;
- }
- usb_cancel_packet(&s->ep[ep].packey[dir].p);
- /* status updates needed here? */
- }
- }
-}
-
-static void musb_tx_rdy(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int pid;
- int total, valid = 0;
- TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] );
- ep->fifostart[0] += ep->fifolen[0];
- ep->fifolen[0] = 0;
-
- /* XXX: how's the total size of the packet retrieved exactly in
- * the generic case? */
- total = ep->maxp[0] & 0x3ff;
-
- if (ep->ext_size[0]) {
- total = ep->ext_size[0];
- ep->ext_size[0] = 0;
- valid = 1;
- }
-
- /* If the packet is not fully ready yet, wait for a next segment. */
- if (epnum && (ep->fifostart[0]) < total)
- return;
-
- if (!valid)
- total = ep->fifostart[0];
-
- pid = USB_TOKEN_OUT;
- if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
- pid = USB_TOKEN_SETUP;
- if (total != 8) {
- TRACE("illegal SETUPPKT length of %i bytes", total);
- }
- /* Controller should retry SETUP packets three times on errors
- * but it doesn't make sense for us to do that. */
- }
-
- musb_packet(s, ep, epnum, pid, total, musb_tx_packet_complete, 0);
-}
-
-static void musb_rx_req(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int total;
-
- /* If we already have a packet, which didn't fit into the
- * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
- if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
- (ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].p.iov.size) {
- TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
- ep->fifostart[1] += ep->rxcount;
- ep->fifolen[1] = 0;
-
- ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
- ep->maxp[1]);
-
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-
- /* Clear all of the error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
-
- /* The driver sets maxp[1] to 64 or less because it knows the hardware
- * FIFO is this deep. Bigger packets get split in
- * usb_generic_handle_packet but we can also do the splitting locally
- * for performance. It turns out we can also have a bigger FIFO and
- * ignore the limit set in ep->maxp[1]. The Linux MUSB driver deals
- * OK with single packets of even 32KB and we avoid splitting, however
- * usb_msd.c sometimes sends a packet bigger than what Linux expects
- * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN. Splitting
- * hides this overrun from Linux. Up to 4096 everything is fine
- * though. Currently this is disabled.
- *
- * XXX: mind ep->fifosize. */
- total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));
-
-#ifdef SETUPLEN_HACK
- /* Why should *we* do that instead of Linux? */
- if (!epnum) {
- if (ep->packey[0].p.devaddr == 2) {
- total = MIN(s->setup_len, 8);
- } else {
- total = MIN(s->setup_len, 64);
- }
- s->setup_len -= total;
- }
-#endif
-
- musb_packet(s, ep, epnum, USB_TOKEN_IN, total, musb_rx_packet_complete, 1);
-}
-
-static uint8_t musb_read_fifo(MUSBEndPoint *ep)
-{
- uint8_t value;
- if (ep->fifolen[1] >= 64) {
- /* We have a FIFO underrun */
- TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
- return 0x00000000;
- }
- /* In DMA mode clear RXPKTRDY and set REQPKT automatically
- * (if AUTOREQ is set) */
-
- ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
- value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
- TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
- return value;
-}
-
-static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
-{
- TRACE("EP%d = %02x", ep->epnum, value);
- if (ep->fifolen[0] >= 64) {
- /* We have a FIFO overrun */
- TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
- return;
- }
-
- ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
- ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
-}
-
-static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
-{
- if (ep->intv_timer[dir])
- timer_del(ep->intv_timer[dir]);
-}
-
-/* Bus control */
-static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- /* For USB2.0 HS hubs only */
- case MUSB_HDRC_TXHUBADDR:
- return s->ep[ep].haddr[0];
- case MUSB_HDRC_TXHUBPORT:
- return s->ep[ep].hport[0];
- case MUSB_HDRC_RXHUBADDR:
- return s->ep[ep].haddr[1];
- case MUSB_HDRC_RXHUBPORT:
- return s->ep[ep].hport[1];
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
- case MUSB_HDRC_TXHUBADDR:
- s->ep[ep].haddr[0] = value;
- break;
- case MUSB_HDRC_TXHUBPORT:
- s->ep[ep].hport[0] = value;
- break;
- case MUSB_HDRC_RXHUBADDR:
- s->ep[ep].haddr[1] = value;
- break;
- case MUSB_HDRC_RXHUBPORT:
- s->ep[ep].hport[1] = value;
- break;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- return s->ep[ep].faddr[0];
- case MUSB_HDRC_RXFUNCADDR:
- return s->ep[ep].faddr[1];
-
- default:
- return musb_busctl_readb(s, ep, addr) |
- (musb_busctl_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
-
- default:
- musb_busctl_writeb(s, ep, addr, value & 0xff);
- musb_busctl_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Endpoint control */
-static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- return s->ep[ep].type[0];
- case MUSB_HDRC_TXINTERVAL:
- return s->ep[ep].interval[0];
- case MUSB_HDRC_RXTYPE:
- return s->ep[ep].type[1];
- case MUSB_HDRC_RXINTERVAL:
- return s->ep[ep].interval[1];
- case (MUSB_HDRC_FIFOSIZE & ~1):
- return 0x00;
- case MUSB_HDRC_FIFOSIZE:
- return ep ? s->ep[ep].fifosize : s->ep[ep].config;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- s->ep[ep].type[0] = value;
- break;
- case MUSB_HDRC_TXINTERVAL:
- s->ep[ep].interval[0] = value;
- musb_ep_frame_cancel(&s->ep[ep], 0);
- break;
- case MUSB_HDRC_RXTYPE:
- s->ep[ep].type[1] = value;
- break;
- case MUSB_HDRC_RXINTERVAL:
- s->ep[ep].interval[1] = value;
- musb_ep_frame_cancel(&s->ep[ep], 1);
- break;
- case (MUSB_HDRC_FIFOSIZE & ~1):
- break;
- case MUSB_HDRC_FIFOSIZE:
- TRACE("somebody messes with fifosize (now %i bytes)", value);
- s->ep[ep].fifosize = value;
- break;
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- return s->ep[ep].maxp[0];
- case MUSB_HDRC_TXCSR:
- return s->ep[ep].csr[0];
- case MUSB_HDRC_RXMAXP:
- return s->ep[ep].maxp[1];
- case MUSB_HDRC_RXCSR:
- ret = s->ep[ep].csr[1];
-
- /* TODO: This and other bits probably depend on
- * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */
- if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR)
- s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY;
-
- return ret;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- return musb_ep_readb(s, ep, addr) |
- (musb_ep_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- s->ep[ep].maxp[0] = value;
- break;
- case MUSB_HDRC_TXCSR:
- if (ep) {
- s->ep[ep].csr[0] &= value & 0xa6;
- s->ep[ep].csr[0] |= value & 0xff59;
- } else {
- s->ep[ep].csr[0] &= value & 0x85;
- s->ep[ep].csr[0] |= value & 0xf7a;
- }
-
- musb_ep_frame_cancel(&s->ep[ep], 0);
-
- if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) ||
- (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) {
- s->ep[ep].fifolen[0] = 0;
- s->ep[ep].fifostart[0] = 0;
- if (ep)
- s->ep[ep].csr[0] &=
- ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- s->ep[ep].csr[0] &=
- ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY);
- }
- if (
- (ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_TXCSR_TXPKTRDY) &&
- !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||
-#else
- (value & MGC_M_TXCSR_TXPKTRDY)) ||
-#endif
- (!ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_CSR0_TXPKTRDY) &&
- !(value & MGC_M_CSR0_H_NAKTIMEOUT)))
-#else
- (value & MGC_M_CSR0_TXPKTRDY)))
-#endif
- musb_tx_rdy(s, ep);
- if (!ep &&
- (value & MGC_M_CSR0_H_REQPKT) &&
-#ifdef CLEAR_NAK
- !(value & (MGC_M_CSR0_H_NAKTIMEOUT |
- MGC_M_CSR0_RXPKTRDY)))
-#else
- !(value & MGC_M_CSR0_RXPKTRDY))
-#endif
- musb_rx_req(s, ep);
- break;
-
- case MUSB_HDRC_RXMAXP:
- s->ep[ep].maxp[1] = value;
- break;
- case MUSB_HDRC_RXCSR:
- /* (DMA mode only) */
- if (
- (value & MGC_M_RXCSR_H_AUTOREQ) &&
- !(value & MGC_M_RXCSR_RXPKTRDY) &&
- (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY))
- value |= MGC_M_RXCSR_H_REQPKT;
-
- s->ep[ep].csr[1] &= 0x102 | (value & 0x4d);
- s->ep[ep].csr[1] |= value & 0xfeb0;
-
- musb_ep_frame_cancel(&s->ep[ep], 1);
-
- if (value & MGC_M_RXCSR_FLUSHFIFO) {
- s->ep[ep].fifolen[1] = 0;
- s->ep[ep].fifostart[1] = 0;
- s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY);
- /* If double buffering and we have two packets ready, flush
- * only the first one and set up the fifo at the second packet. */
- }
-#ifdef CLEAR_NAK
- if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))
-#else
- if (value & MGC_M_RXCSR_H_REQPKT)
-#endif
- musb_rx_req(s, ep);
- break;
- case MUSB_HDRC_RXCOUNT:
- s->ep[ep].rxcount = value;
- break;
-
- default:
- musb_ep_writeb(s, ep, addr, value & 0xff);
- musb_ep_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Generic control */
-static uint32_t musb_readb(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint8_t ret;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- return s->faddr;
- case MUSB_HDRC_POWER:
- return s->power;
- case MUSB_HDRC_INTRUSB:
- ret = s->intr;
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRUSBE:
- return s->mask;
- case MUSB_HDRC_INDEX:
- return s->idx;
- case MUSB_HDRC_TESTMODE:
- return 0x00;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readb(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_DEVCTL:
- return s->devctl;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- return 0x00;
-
- case MUSB_HDRC_HWVERS:
- return (1 << 10) | 400;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_HWVERS | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- return 0x00;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readb(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readb(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return musb_read_fifo(s->ep + ep);
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00;
- };
-}
-
-static void musb_writeb(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- s->faddr = value & 0x7f;
- break;
- case MUSB_HDRC_POWER:
- s->power = (value & 0xef) | (s->power & 0x10);
- /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
- if ((value & MGC_M_POWER_RESET) && s->port.dev) {
- usb_device_reset(s->port.dev);
- /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */
- if ((value & MGC_M_POWER_HSENAB) &&
- s->port.dev->speed == USB_SPEED_HIGH)
- s->power |= MGC_M_POWER_HSMODE; /* Success */
- /* Restart frame counting. */
- }
- if (value & MGC_M_POWER_SUSPENDM) {
- /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND
- * is set, also go into low power mode. Frame counting stops. */
- /* XXX: Cleared when the interrupt register is read */
- }
- if (value & MGC_M_POWER_RESUME) {
- /* Wait 20ms and signal resuming on the bus. Frame counting
- * restarts. */
- }
- break;
- case MUSB_HDRC_INTRUSB:
- break;
- case MUSB_HDRC_INTRUSBE:
- s->mask = value & 0xff;
- break;
- case MUSB_HDRC_INDEX:
- s->idx = value & 0xf;
- break;
- case MUSB_HDRC_TESTMODE:
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeb(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_DEVCTL:
- s->session = !!(value & MGC_M_DEVCTL_SESSION);
- musb_session_update(s,
- !!s->port.dev,
- !!(s->devctl & MGC_M_DEVCTL_SESSION));
-
- /* It seems this is the only R/W bit in this register? */
- s->devctl &= ~MGC_M_DEVCTL_SESSION;
- s->devctl |= value & MGC_M_DEVCTL_SESSION;
- break;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- break;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeb(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeb(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- break;
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-static uint32_t musb_readh(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_INTRTX:
- ret = s->tx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_tx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRRX:
- ret = s->rx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_rx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRTXE:
- return s->tx_mask;
- case MUSB_HDRC_INTRRXE:
- return s->rx_mask;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- return 0x0000;
- case MUSB_HDRC_TXFIFOADDR:
- return s->ep[s->idx].fifoaddr[0];
- case MUSB_HDRC_RXFIFOADDR:
- return s->ep[s->idx].fifoaddr[1];
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readh(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readh(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readh(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
-
- default:
- return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
- };
-}
-
-static void musb_writeh(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_INTRTXE:
- s->tx_mask = value;
- /* XXX: the masks seem to apply on the raising edge like with
- * edge-triggered interrupts, thus no need to update. I may be
- * wrong though. */
- break;
- case MUSB_HDRC_INTRRXE:
- s->rx_mask = value;
- break;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- break;
- case MUSB_HDRC_TXFIFOADDR:
- s->ep[s->idx].fifoaddr[0] = value;
- s->ep[s->idx].buf[0] =
- s->buf + ((value << 3) & 0x7ff );
- break;
- case MUSB_HDRC_RXFIFOADDR:
- s->ep[s->idx].fifoaddr[1] = value;
- s->ep[s->idx].buf[1] =
- s->buf + ((value << 3) & 0x7ff);
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeh(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeh(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeh(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
- break;
-
- default:
- musb_writeb(s, addr, value & 0xff);
- musb_writeb(s, addr | 1, value >> 8);
- };
-}
-
-static uint32_t musb_readw(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return ( musb_read_fifo(s->ep + ep) |
- musb_read_fifo(s->ep + ep) << 8 |
- musb_read_fifo(s->ep + ep) << 16 |
- musb_read_fifo(s->ep + ep) << 24 );
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00000000;
- };
-}
-
-static void musb_writew(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
- break;
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-MUSBReadFunc * const musb_read[] = {
- musb_readb,
- musb_readh,
- musb_readw,
-};
-
-MUSBWriteFunc * const musb_write[] = {
- musb_writeb,
- musb_writeh,
- musb_writew,
-};
diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c
index 33ed9b6..94d1077 100644
--- a/hw/usb/hcd-ohci-pci.c
+++ b/hw/usb/hcd-ohci-pci.c
@@ -109,11 +109,10 @@ static void usb_ohci_reset_pci(DeviceState *d)
ohci_hard_reset(s);
}
-static Property ohci_pci_properties[] = {
+static const Property ohci_pci_properties[] = {
DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_ohci = {
@@ -127,7 +126,7 @@ static const VMStateDescription vmstate_ohci = {
}
};
-static void ohci_pci_class_init(ObjectClass *klass, void *data)
+static void ohci_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -142,7 +141,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, ohci_pci_properties);
dc->hotpluggable = false;
dc->vmsd = &vmstate_ohci;
- dc->reset = usb_ohci_reset_pci;
+ device_class_set_legacy_reset(dc, usb_ohci_reset_pci);
}
static const TypeInfo ohci_pci_info = {
@@ -150,7 +149,7 @@ static const TypeInfo ohci_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(OHCIPCIState),
.class_init = ohci_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/usb/hcd-ohci-sysbus.c b/hw/usb/hcd-ohci-sysbus.c
index 6fba7f5..3fc6cce 100644
--- a/hw/usb/hcd-ohci-sysbus.c
+++ b/hw/usb/hcd-ohci-sysbus.c
@@ -57,15 +57,14 @@ static void ohci_sysbus_reset(DeviceState *dev)
ohci_hard_reset(ohci);
}
-static Property ohci_sysbus_properties[] = {
+static const Property ohci_sysbus_properties[] = {
DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus),
DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0),
DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
+static void ohci_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -73,7 +72,7 @@ static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
dc->desc = "OHCI USB Controller";
device_class_set_props(dc, ohci_sysbus_properties);
- dc->reset = ohci_sysbus_reset;
+ device_class_set_legacy_reset(dc, ohci_sysbus_reset);
}
static const TypeInfo ohci_sysbus_types[] = {
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 71b5491..72a9f9f 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -577,7 +577,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed)
USBDevice *dev;
USBEndpoint *ep;
USBPacket *pkt;
- uint8_t buf[8192];
+ QEMU_UNINITIALIZED uint8_t buf[8192];
bool int_req;
struct ohci_iso_td iso_td;
uint32_t addr;
diff --git a/hw/usb/hcd-ohci.h b/hw/usb/hcd-ohci.h
index e182722..3cc35a5 100644
--- a/hw/usb/hcd-ohci.h
+++ b/hw/usb/hcd-ohci.h
@@ -22,7 +22,7 @@
#define HCD_OHCI_H
#include "hw/sysbus.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/usb.h"
#include "qom/object.h"
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index a03cf22..4822c70 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -36,7 +36,7 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "qemu/iov.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "trace.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
@@ -67,7 +67,7 @@ struct UHCIPCIDeviceClass {
UHCIInfo info;
};
-/*
+/*
* Pending async transaction.
* 'packet' must be the first field because completion
* handler does "(UHCIAsync *) pkt" cast.
@@ -220,8 +220,9 @@ static void uhci_async_cancel(UHCIAsync *async)
uhci_async_unlink(async);
trace_usb_uhci_packet_cancel(async->queue->token, async->td_addr,
async->done);
- if (!async->done)
+ if (!async->done) {
usb_cancel_packet(&async->packet);
+ }
uhci_async_free(async);
}
@@ -322,7 +323,7 @@ static void uhci_reset(DeviceState *dev)
s->fl_base_addr = 0;
s->sof_timing = 64;
- for(i = 0; i < UHCI_PORTS; i++) {
+ for (i = 0; i < UHCI_PORTS; i++) {
port = &s->ports[i];
port->ctrl = 0x0080;
if (port->port.dev && port->port.dev->attached) {
@@ -387,8 +388,8 @@ static void uhci_port_write(void *opaque, hwaddr addr,
trace_usb_uhci_mmio_writew(addr, val);
- switch(addr) {
- case 0x00:
+ switch (addr) {
+ case UHCI_USBCMD:
if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
/* start frame processing */
trace_usb_uhci_schedule_start();
@@ -404,7 +405,7 @@ static void uhci_port_write(void *opaque, hwaddr addr,
int i;
/* send reset on the USB bus */
- for(i = 0; i < UHCI_PORTS; i++) {
+ for (i = 0; i < UHCI_PORTS; i++) {
port = &s->ports[i];
usb_device_reset(port->port.dev);
}
@@ -423,34 +424,38 @@ static void uhci_port_write(void *opaque, hwaddr addr,
}
}
break;
- case 0x02:
+ case UHCI_USBSTS:
s->status &= ~val;
- /* XXX: the chip spec is not coherent, so we add a hidden
- register to distinguish between IOC and SPD */
- if (val & UHCI_STS_USBINT)
+ /*
+ * XXX: the chip spec is not coherent, so we add a hidden
+ * register to distinguish between IOC and SPD
+ */
+ if (val & UHCI_STS_USBINT) {
s->status2 = 0;
+ }
uhci_update_irq(s);
break;
- case 0x04:
+ case UHCI_USBINTR:
s->intr = val;
uhci_update_irq(s);
break;
- case 0x06:
- if (s->status & UHCI_STS_HCHALTED)
+ case UHCI_USBFRNUM:
+ if (s->status & UHCI_STS_HCHALTED) {
s->frnum = val & 0x7ff;
+ }
break;
- case 0x08:
+ case UHCI_USBFLBASEADD:
s->fl_base_addr &= 0xffff0000;
s->fl_base_addr |= val & ~0xfff;
break;
- case 0x0a:
+ case UHCI_USBFLBASEADD + 2:
s->fl_base_addr &= 0x0000ffff;
s->fl_base_addr |= (val << 16);
break;
- case 0x0c:
+ case UHCI_USBSOF:
s->sof_timing = val & 0xff;
break;
- case 0x10 ... 0x1f:
+ case UHCI_USBPORTSC1 ... UHCI_USBPORTSC4:
{
UHCIPort *port;
USBDevice *dev;
@@ -464,8 +469,8 @@ static void uhci_port_write(void *opaque, hwaddr addr,
dev = port->port.dev;
if (dev && dev->attached) {
/* port reset */
- if ( (val & UHCI_PORT_RESET) &&
- !(port->ctrl & UHCI_PORT_RESET) ) {
+ if ((val & UHCI_PORT_RESET) &&
+ !(port->ctrl & UHCI_PORT_RESET)) {
usb_device_reset(dev);
}
}
@@ -487,29 +492,29 @@ static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size)
UHCIState *s = opaque;
uint32_t val;
- switch(addr) {
- case 0x00:
+ switch (addr) {
+ case UHCI_USBCMD:
val = s->cmd;
break;
- case 0x02:
+ case UHCI_USBSTS:
val = s->status;
break;
- case 0x04:
+ case UHCI_USBINTR:
val = s->intr;
break;
- case 0x06:
+ case UHCI_USBFRNUM:
val = s->frnum;
break;
- case 0x08:
+ case UHCI_USBFLBASEADD:
val = s->fl_base_addr & 0xffff;
break;
- case 0x0a:
+ case UHCI_USBFLBASEADD + 2:
val = (s->fl_base_addr >> 16) & 0xffff;
break;
- case 0x0c:
+ case UHCI_USBSOF:
val = s->sof_timing;
break;
- case 0x10 ... 0x1f:
+ case UHCI_USBPORTSC1 ... UHCI_USBPORTSC4:
{
UHCIPort *port;
int n;
@@ -533,12 +538,13 @@ static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size)
}
/* signal resume if controller suspended */
-static void uhci_resume (void *opaque)
+static void uhci_resume(void *opaque)
{
UHCIState *s = (UHCIState *)opaque;
- if (!s)
+ if (!s) {
return;
+ }
if (s->cmd & UHCI_CMD_EGSM) {
s->cmd |= UHCI_CMD_FGR;
@@ -674,7 +680,8 @@ static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr,
return ret;
}
-static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
+static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async,
+ uint32_t *int_mask)
{
int len = 0, max_len;
uint8_t pid;
@@ -682,8 +689,9 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
- if (td->ctrl & TD_CTRL_IOS)
+ if (td->ctrl & TD_CTRL_IOS) {
td->ctrl &= ~TD_CTRL_ACTIVE;
+ }
if (async->packet.status != USB_RET_SUCCESS) {
return uhci_handle_td_error(s, td, async->td_addr,
@@ -693,12 +701,15 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
len = async->packet.actual_length;
td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
- /* The NAK bit may have been set by a previous frame, so clear it
- here. The docs are somewhat unclear, but win2k relies on this
- behavior. */
+ /*
+ * The NAK bit may have been set by a previous frame, so clear it
+ * here. The docs are somewhat unclear, but win2k relies on this
+ * behavior.
+ */
td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
- if (td->ctrl & TD_CTRL_IOC)
+ if (td->ctrl & TD_CTRL_IOC) {
*int_mask |= 0x01;
+ }
if (pid == USB_TOKEN_IN) {
pci_dma_write(&s->dev, td->buffer, async->buf, len);
@@ -780,9 +791,11 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
if (async) {
if (queuing) {
- /* we are busy filling the queue, we are not prepared
- to consume completed packages then, just leave them
- in async state */
+ /*
+ * we are busy filling the queue, we are not prepared
+ * to consume completed packages then, just leave them
+ * in async state
+ */
return TD_RESULT_ASYNC_CONT;
}
if (!async->done) {
@@ -832,7 +845,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
}
usb_packet_addbuf(&async->packet, async->buf, max_len);
- switch(pid) {
+ switch (pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
pci_dma_read(&s->dev, td->buffer, async->buf, max_len);
@@ -911,12 +924,15 @@ static void qhdb_reset(QhDb *db)
static int qhdb_insert(QhDb *db, uint32_t addr)
{
int i;
- for (i = 0; i < db->count; i++)
- if (db->addr[i] == addr)
+ for (i = 0; i < db->count; i++) {
+ if (db->addr[i] == addr) {
return 1;
+ }
+ }
- if (db->count >= UHCI_MAX_QUEUES)
+ if (db->count >= UHCI_MAX_QUEUES) {
return 1;
+ }
db->addr[db->count++] = addr;
return 0;
@@ -970,8 +986,10 @@ static void uhci_process_frame(UHCIState *s)
for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
if (!s->completions_only && s->frame_bytes >= s->frame_bandwidth) {
- /* We've reached the usb 1.1 bandwidth, which is
- 1280 bytes/frame, stop processing */
+ /*
+ * We've reached the usb 1.1 bandwidth, which is
+ * 1280 bytes/frame, stop processing
+ */
trace_usb_uhci_frame_stop_bandwidth();
break;
}
@@ -1120,8 +1138,10 @@ static void uhci_frame_timer(void *opaque)
uhci_async_validate_begin(s);
uhci_process_frame(s);
uhci_async_validate_end(s);
- /* The spec says frnum is the frame currently being processed, and
- * the guest must look at frnum - 1 on interrupt, so inc frnum now */
+ /*
+ * The spec says frnum is the frame currently being processed, and
+ * the guest must look at frnum - 1 on interrupt, so inc frnum now
+ */
s->frnum = (s->frnum + 1) & 0x7ff;
s->expire_time += frame_t;
}
@@ -1174,7 +1194,7 @@ void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
if (s->masterbus) {
USBPort *ports[UHCI_PORTS];
- for(i = 0; i < UHCI_PORTS; i++) {
+ for (i = 0; i < UHCI_PORTS; i++) {
ports[i] = &s->ports[i].port;
}
usb_register_companion(s->masterbus, ports, UHCI_PORTS,
@@ -1200,8 +1220,10 @@ void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
memory_region_init_io(&s->io_bar, OBJECT(s), &uhci_ioport_ops, s,
"uhci", 0x20);
- /* Use region 4 for consistency with real hardware. BSD guests seem
- to rely on this. */
+ /*
+ * Use region 4 for consistency with real hardware. BSD guests seem
+ * to rely on this.
+ */
pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
}
@@ -1227,27 +1249,25 @@ static void usb_uhci_exit(PCIDevice *dev)
}
}
-static Property uhci_properties_companion[] = {
+static const Property uhci_properties_companion[] = {
DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
};
-static Property uhci_properties_standalone[] = {
+static const Property uhci_properties_standalone[] = {
DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
};
-static void uhci_class_init(ObjectClass *klass, void *data)
+static void uhci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->class_id = PCI_CLASS_SERIAL_USB;
dc->vmsd = &vmstate_uhci;
- dc->reset = uhci_reset;
+ device_class_set_legacy_reset(dc, uhci_reset);
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
@@ -1258,18 +1278,18 @@ static const TypeInfo uhci_pci_type_info = {
.class_size = sizeof(UHCIPCIDeviceClass),
.abstract = true,
.class_init = uhci_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
-void uhci_data_class_init(ObjectClass *klass, void *data)
+void uhci_data_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
UHCIPCIDeviceClass *u = UHCI_CLASS(klass);
- UHCIInfo *info = data;
+ const UHCIInfo *info = data;
k->realize = info->realize ? info->realize : usb_uhci_common_realize;
k->exit = info->unplug ? usb_uhci_exit : NULL;
@@ -1362,7 +1382,7 @@ static void uhci_register_types(void)
for (i = 0; i < ARRAY_SIZE(uhci_info); i++) {
uhci_type_info.name = uhci_info[i].name;
uhci_type_info.class_data = uhci_info + i;
- type_register(&uhci_type_info);
+ type_register_static(&uhci_type_info);
}
}
diff --git a/hw/usb/hcd-uhci.h b/hw/usb/hcd-uhci.h
index 6d26b94..e0a6525 100644
--- a/hw/usb/hcd-uhci.h
+++ b/hw/usb/hcd-uhci.h
@@ -28,7 +28,7 @@
#ifndef HW_USB_HCD_UHCI_H
#define HW_USB_HCD_UHCI_H
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qemu/timer.h"
#include "hw/pci/pci_device.h"
#include "hw/usb.h"
@@ -88,7 +88,7 @@ typedef struct UHCIInfo {
bool notuser; /* disallow user_creatable */
} UHCIInfo;
-void uhci_data_class_init(ObjectClass *klass, void *data);
+void uhci_data_class_init(ObjectClass *klass, const void *data);
void usb_uhci_common_realize(PCIDevice *dev, Error **errp);
#define TYPE_PIIX3_USB_UHCI "piix3-usb-uhci"
diff --git a/hw/usb/hcd-xhci-nec.c b/hw/usb/hcd-xhci-nec.c
index 0c063b3..9e0fea2 100644
--- a/hw/usb/hcd-xhci-nec.c
+++ b/hw/usb/hcd-xhci-nec.c
@@ -30,20 +30,15 @@
OBJECT_DECLARE_SIMPLE_TYPE(XHCINecState, NEC_XHCI)
struct XHCINecState {
- /*< private >*/
XHCIPciState parent_obj;
- /*< public >*/
- uint32_t flags;
+
uint32_t intrs;
uint32_t slots;
};
-static Property nec_xhci_properties[] = {
- DEFINE_PROP_ON_OFF_AUTO("msi", XHCIPciState, msi, ON_OFF_AUTO_AUTO),
- DEFINE_PROP_ON_OFF_AUTO("msix", XHCIPciState, msix, ON_OFF_AUTO_AUTO),
+static const Property nec_xhci_properties[] = {
DEFINE_PROP_UINT32("intrs", XHCINecState, intrs, XHCI_MAXINTRS),
DEFINE_PROP_UINT32("slots", XHCINecState, slots, XHCI_MAXSLOTS),
- DEFINE_PROP_END_OF_LIST(),
};
static void nec_xhci_instance_init(Object *obj)
@@ -51,12 +46,11 @@ static void nec_xhci_instance_init(Object *obj)
XHCIPciState *pci = XHCI_PCI(obj);
XHCINecState *nec = NEC_XHCI(obj);
- pci->xhci.flags = nec->flags;
pci->xhci.numintrs = nec->intrs;
pci->xhci.numslots = nec->slots;
}
-static void nec_xhci_class_init(ObjectClass *klass, void *data)
+static void nec_xhci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c
index 264d7eb..b93c80b 100644
--- a/hw/usb/hcd-xhci-pci.c
+++ b/hw/usb/hcd-xhci-pci.c
@@ -74,6 +74,7 @@ static bool xhci_pci_intr_raise(XHCIState *xhci, int n, bool level)
}
if (msi_enabled(pci_dev) && level) {
+ n %= msi_nr_vectors_allocated(pci_dev);
msi_notify(pci_dev, n);
return true;
}
@@ -81,6 +82,21 @@ static bool xhci_pci_intr_raise(XHCIState *xhci, int n, bool level)
return false;
}
+static bool xhci_pci_intr_mapping_conditional(XHCIState *xhci)
+{
+ XHCIPciState *s = container_of(xhci, XHCIPciState, xhci);
+ PCIDevice *pci_dev = PCI_DEVICE(s);
+
+ /*
+ * Implementation of the "conditional-intr-mapping" property, which only
+ * enables interrupter mapping if MSI or MSI-X is available and active.
+ * Forces all events onto interrupter/event ring 0 in pin-based IRQ mode.
+ * Provides compatibility with macOS guests on machine types where MSI(-X)
+ * is not available.
+ */
+ return msix_enabled(pci_dev) || msi_enabled(pci_dev);
+}
+
static void xhci_pci_reset(DeviceState *dev)
{
XHCIPciState *s = XHCI_PCI(dev);
@@ -94,7 +110,7 @@ static int xhci_pci_vmstate_post_load(void *opaque, int version_id)
PCIDevice *pci_dev = PCI_DEVICE(s);
int intr;
- for (intr = 0; intr < s->xhci.numintrs; intr++) {
+ for (intr = 0; intr < s->xhci.numintrs; intr++) {
if (s->xhci.intr[intr].msix_used) {
msix_vector_use(pci_dev, intr);
} else {
@@ -118,6 +134,9 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp)
object_property_set_link(OBJECT(&s->xhci), "host", OBJECT(s), NULL);
s->xhci.intr_update = xhci_pci_intr_update;
s->xhci.intr_raise = xhci_pci_intr_raise;
+ if (s->conditional_intr_mapping) {
+ s->xhci.intr_mapping_supported = xhci_pci_intr_mapping_conditional;
+ }
if (!qdev_realize(DEVICE(&s->xhci), NULL, errp)) {
return;
}
@@ -197,17 +216,29 @@ static void xhci_instance_init(Object *obj)
qdev_alias_all_properties(DEVICE(&s->xhci), obj);
}
-static void xhci_class_init(ObjectClass *klass, void *data)
+static const Property xhci_pci_properties[] = {
+ DEFINE_PROP_ON_OFF_AUTO("msi", XHCIPciState, msi, ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO("msix", XHCIPciState, msix, ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_BOOL("conditional-intr-mapping", XHCIPciState,
+ conditional_intr_mapping, false),
+};
+
+static void xhci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xhci_pci_reset;
+ device_class_set_legacy_reset(dc, xhci_pci_reset);
dc->vmsd = &vmstate_xhci_pci;
set_bit(DEVICE_CATEGORY_USB, dc->categories);
k->realize = usb_xhci_pci_realize;
k->exit = usb_xhci_pci_exit;
k->class_id = PCI_CLASS_SERIAL_USB;
+ device_class_set_props(dc, xhci_pci_properties);
+ object_class_property_set_description(klass, "conditional-intr-mapping",
+ "When true, disables interrupter mapping for pin-based IRQ mode. "
+ "Intended to be used with guest drivers with questionable behaviour, "
+ "such as macOS's.");
}
static const TypeInfo xhci_pci_info = {
@@ -217,14 +248,14 @@ static const TypeInfo xhci_pci_info = {
.class_init = xhci_class_init,
.instance_init = xhci_instance_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
-static void qemu_xhci_class_init(ObjectClass *klass, void *data)
+static void qemu_xhci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/usb/hcd-xhci-pci.h b/hw/usb/hcd-xhci-pci.h
index 08f70ce..5b61ae8 100644
--- a/hw/usb/hcd-xhci-pci.h
+++ b/hw/usb/hcd-xhci-pci.h
@@ -40,6 +40,7 @@ typedef struct XHCIPciState {
XHCIState xhci;
OnOffAuto msi;
OnOffAuto msix;
+ bool conditional_intr_mapping;
} XHCIPciState;
#endif
diff --git a/hw/usb/hcd-xhci-sysbus.c b/hw/usb/hcd-xhci-sysbus.c
index d93bae3..244698e 100644
--- a/hw/usb/hcd-xhci-sysbus.c
+++ b/hw/usb/hcd-xhci-sysbus.c
@@ -82,10 +82,9 @@ void xhci_sysbus_build_aml(Aml *scope, uint32_t mmio, unsigned int irq)
aml_append(scope, dev);
}
-static Property xhci_sysbus_props[] = {
+static const Property xhci_sysbus_props[] = {
DEFINE_PROP_UINT32("intrs", XHCISysbusState, xhci.numintrs, XHCI_MAXINTRS),
DEFINE_PROP_UINT32("slots", XHCISysbusState, xhci.numslots, XHCI_MAXSLOTS),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_xhci_sysbus = {
@@ -97,11 +96,11 @@ static const VMStateDescription vmstate_xhci_sysbus = {
}
};
-static void xhci_sysbus_class_init(ObjectClass *klass, void *data)
+static void xhci_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xhci_sysbus_reset;
+ device_class_set_legacy_reset(dc, xhci_sysbus_reset);
dc->realize = xhci_sysbus_realize;
dc->vmsd = &vmstate_xhci_sysbus;
device_class_set_props(dc, xhci_sysbus_props);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index b6411f0..292c378 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -644,6 +644,11 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
dma_addr_t erdp;
unsigned int dp_idx;
+ if (xhci->numintrs == 1 ||
+ (xhci->intr_mapping_supported && !xhci->intr_mapping_supported(xhci))) {
+ v = 0;
+ }
+
if (v >= xhci->numintrs) {
DPRINTF("intr nr out of range (%d >= %d)\n", v, xhci->numintrs);
return;
@@ -1182,6 +1187,12 @@ static void xhci_ep_free_xfer(XHCITransfer *xfer)
g_free(xfer);
}
+static void xhci_xfer_unmap(XHCITransfer *xfer)
+{
+ usb_packet_unmap(&xfer->packet, &xfer->sgl);
+ qemu_sglist_destroy(&xfer->sgl);
+}
+
static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report)
{
int killed = 0;
@@ -1193,6 +1204,7 @@ static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report)
if (t->running_async) {
usb_cancel_packet(&t->packet);
+ xhci_xfer_unmap(t);
t->running_async = 0;
killed = 1;
}
@@ -1475,12 +1487,6 @@ err:
return -1;
}
-static void xhci_xfer_unmap(XHCITransfer *xfer)
-{
- usb_packet_unmap(&xfer->packet, &xfer->sgl);
- qemu_sglist_destroy(&xfer->sgl);
-}
-
static void xhci_xfer_report(XHCITransfer *xfer)
{
uint32_t edtla = 0;
@@ -2810,9 +2816,15 @@ static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size)
case 0x08: /* PORTLI */
ret = 0;
break;
- case 0x0c: /* reserved */
+ case 0x0c: /* PORTHLPMC */
+ ret = 0;
+ qemu_log_mask(LOG_UNIMP, "%s: read from port register PORTHLPMC",
+ __func__);
+ break;
default:
- trace_usb_xhci_unimplemented("port read", reg);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: read from port offset 0x%" HWADDR_PRIx,
+ __func__, reg);
ret = 0;
}
@@ -2881,9 +2893,22 @@ static void xhci_port_write(void *ptr, hwaddr reg,
}
break;
case 0x04: /* PORTPMSC */
+ case 0x0c: /* PORTHLPMC */
+ qemu_log_mask(LOG_UNIMP,
+ "%s: write 0x%" PRIx64
+ " (%u bytes) to port register at offset 0x%" HWADDR_PRIx,
+ __func__, val, size, reg);
+ break;
case 0x08: /* PORTLI */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Write to read-only PORTLI register",
+ __func__);
+ break;
default:
- trace_usb_xhci_unimplemented("port write", reg);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write 0x%" PRIx64 " (%u bytes) to unknown port "
+ "register at offset 0x%" HWADDR_PRIx,
+ __func__, val, size, reg);
+ break;
}
}
@@ -3605,23 +3630,22 @@ const VMStateDescription vmstate_xhci = {
}
};
-static Property xhci_properties[] = {
+static const Property xhci_properties[] = {
DEFINE_PROP_BIT("streams", XHCIState, flags,
XHCI_FLAG_ENABLE_STREAMS, true),
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
DEFINE_PROP_LINK("host", XHCIState, hostOpaque, TYPE_DEVICE,
DeviceState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xhci_class_init(ObjectClass *klass, void *data)
+static void xhci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = usb_xhci_realize;
dc->unrealize = usb_xhci_unrealize;
- dc->reset = xhci_reset;
+ device_class_set_legacy_reset(dc, xhci_reset);
device_class_set_props(dc, xhci_properties);
dc->user_creatable = false;
}
diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h
index fe16d7a..9c3974f 100644
--- a/hw/usb/hcd-xhci.h
+++ b/hw/usb/hcd-xhci.h
@@ -25,7 +25,7 @@
#include "hw/usb.h"
#include "hw/usb/xhci.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
OBJECT_DECLARE_SIMPLE_TYPE(XHCIState, XHCI)
@@ -193,6 +193,11 @@ typedef struct XHCIState {
uint32_t max_pstreams_mask;
void (*intr_update)(XHCIState *s, int n, bool enable);
bool (*intr_raise)(XHCIState *s, int n, bool level);
+ /*
+ * Callback for special-casing interrupter mapping support. NULL for most
+ * implementations, for defaulting to enabled mapping unless numintrs == 1.
+ */
+ bool (*intr_mapping_supported)(XHCIState *s);
DeviceState *hostOpaque;
/* Operational Registers */
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 691bc88..b74670a 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -51,8 +51,8 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "trace.h"
#include "hw/qdev-properties.h"
@@ -1758,7 +1758,7 @@ static const VMStateDescription vmstate_usb_host = {
}
};
-static Property usb_host_dev_properties[] = {
+static const Property usb_host_dev_properties[] = {
DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
@@ -1779,10 +1779,9 @@ static Property usb_host_dev_properties[] = {
USB_HOST_OPT_PIPELINE, true),
DEFINE_PROP_BOOL("suppress-remote-wake", USBHostDevice,
suppress_remote_wake, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usb_host_class_initfn(ObjectClass *klass, void *data)
+static void usb_host_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/imx-usb-phy.c b/hw/usb/imx-usb-phy.c
index 18917d7..c25566d 100644
--- a/hw/usb/imx-usb-phy.c
+++ b/hw/usb/imx-usb-phy.c
@@ -214,11 +214,11 @@ static void imx_usbphy_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
-static void imx_usbphy_class_init(ObjectClass *klass, void *data)
+static void imx_usbphy_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx_usbphy_reset;
+ device_class_set_legacy_reset(dc, imx_usbphy_reset);
dc->vmsd = &vmstate_imx_usbphy;
dc->desc = "i.MX USB PHY Module";
dc->realize = imx_usbphy_realize;
diff --git a/hw/usb/libhw.c b/hw/usb/libhw.c
index f350eae..4f03ef4 100644
--- a/hw/usb/libhw.c
+++ b/hw/usb/libhw.c
@@ -21,7 +21,7 @@
*/
#include "qemu/osdep.h"
#include "hw/usb.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
{
diff --git a/hw/usb/meson.build b/hw/usb/meson.build
index d7de100..17360a5 100644
--- a/hw/usb/meson.build
+++ b/hw/usb/meson.build
@@ -23,12 +23,10 @@ system_ss.add(when: 'CONFIG_USB_XHCI', if_true: files('hcd-xhci.c'))
system_ss.add(when: 'CONFIG_USB_XHCI_PCI', if_true: files('hcd-xhci-pci.c'))
system_ss.add(when: 'CONFIG_USB_XHCI_SYSBUS', if_true: files('hcd-xhci-sysbus.c'))
system_ss.add(when: 'CONFIG_USB_XHCI_NEC', if_true: files('hcd-xhci-nec.c'))
-system_ss.add(when: 'CONFIG_USB_MUSB', if_true: files('hcd-musb.c'))
system_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('hcd-dwc2.c'))
system_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c'))
+system_ss.add(when: 'CONFIG_USB_CHIPIDEA', if_true: files('chipidea.c'))
-system_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c'))
-system_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c'))
system_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c'))
system_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686-uhci-pci.c'))
system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2-ctrl-regs.c'))
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 0f2dd2e..f516ff4 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -30,8 +30,8 @@
#include "qemu/units.h"
#include "qapi/error.h"
#include "qemu/timer.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "qemu/iov.h"
@@ -2573,17 +2573,16 @@ static const VMStateDescription usbredir_vmstate = {
}
};
-static Property usbredir_properties[] = {
+static const Property usbredir_properties[] = {
DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning),
DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
DEFINE_PROP_BOOL("streams", USBRedirDevice, enable_streams, true),
DEFINE_PROP_BOOL("suppress-remote-wake", USBRedirDevice,
suppress_remote_wake, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void usbredir_class_initfn(ObjectClass *klass, void *data)
+static void usbredir_class_initfn(ObjectClass *klass, const void *data)
{
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/usb/tusb6010.c b/hw/usb/tusb6010.c
deleted file mode 100644
index 1dd4071..0000000
--- a/hw/usb/tusb6010.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * Texas Instruments TUSB6010 emulation.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/module.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/usb/hcd-musb.h"
-#include "hw/arm/omap.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "qom/object.h"
-
-#define TYPE_TUSB6010 "tusb6010"
-OBJECT_DECLARE_SIMPLE_TYPE(TUSBState, TUSB6010)
-
-struct TUSBState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem[2];
- qemu_irq irq;
- MUSBState *musb;
- QEMUTimer *otg_timer;
- QEMUTimer *pwr_timer;
-
- int power;
- uint32_t scratch;
- uint16_t test_reset;
- uint32_t prcm_config;
- uint32_t prcm_mngmt;
- uint16_t otg_status;
- uint32_t dev_config;
- int host_mode;
- uint32_t intr;
- uint32_t intr_ok;
- uint32_t mask;
- uint32_t usbip_intr;
- uint32_t usbip_mask;
- uint32_t gpio_intr;
- uint32_t gpio_mask;
- uint32_t gpio_config;
- uint32_t dma_intr;
- uint32_t dma_mask;
- uint32_t dma_map;
- uint32_t dma_config;
- uint32_t ep0_config;
- uint32_t rx_config[15];
- uint32_t tx_config[15];
- uint32_t wkup_mask;
- uint32_t pullup[2];
- uint32_t control_config;
- uint32_t otg_timer_val;
-};
-
-#define TUSB_DEVCLOCK 60000000 /* 60 MHz */
-
-#define TUSB_VLYNQ_CTRL 0x004
-
-/* Mentor Graphics OTG core registers. */
-#define TUSB_BASE_OFFSET 0x400
-
-/* FIFO registers, 32-bit. */
-#define TUSB_FIFO_BASE 0x600
-
-/* Device System & Control registers, 32-bit. */
-#define TUSB_SYS_REG_BASE 0x800
-
-#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000)
-#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16)
-#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15)
-#define TUSB_DEV_CONF_SOFT_ID (1 << 1)
-#define TUSB_DEV_CONF_ID_SEL (1 << 0)
-
-#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004)
-#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008)
-#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24)
-#define TUSB_PHY_OTG_CTRL_O_ID_PULLUP (1 << 23)
-#define TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
-#define TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
-#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17)
-#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16)
-#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15)
-#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14)
-#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13)
-#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12)
-#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11)
-#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10)
-#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9)
-#define TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
-#define TUSB_PHY_OTG_CTRL_PD (1 << 6)
-#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5)
-#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4)
-#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3)
-#define TUSB_PHY_OTG_CTRL_RESET (1 << 2)
-#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1)
-#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0)
-
-/* OTG status register */
-#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c)
-#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8)
-#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7)
-#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6)
-#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5)
-#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4)
-#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3)
-#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2)
-#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0)
-#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1)
-#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0)
-
-#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010)
-#define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31)
-#define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff)
-#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014)
-
-/* PRCM configuration register */
-#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018)
-#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24)
-#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16)
-
-/* PRCM management register */
-#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c)
-#define TUSB_PRCM_MNGMT_SRP_FIX_TMR(v) (((v) & 0xf) << 25)
-#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
-#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18)
-#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17)
-#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
-#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
-#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8)
-#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4)
-#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3)
-#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2)
-#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
-#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
-
-/* Wake-up source clear and mask registers */
-#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
-#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028)
-#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c)
-#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13)
-#define TUSB_PRCM_WGPIO_7 (1 << 12)
-#define TUSB_PRCM_WGPIO_6 (1 << 11)
-#define TUSB_PRCM_WGPIO_5 (1 << 10)
-#define TUSB_PRCM_WGPIO_4 (1 << 9)
-#define TUSB_PRCM_WGPIO_3 (1 << 8)
-#define TUSB_PRCM_WGPIO_2 (1 << 7)
-#define TUSB_PRCM_WGPIO_1 (1 << 6)
-#define TUSB_PRCM_WGPIO_0 (1 << 5)
-#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */
-#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */
-#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */
-#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */
-#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */
-
-#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030)
-#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034)
-#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038)
-#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c)
-#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040)
-#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044)
-#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048)
-#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c)
-#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050)
-#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054)
-#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058)
-#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c)
-#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060)
-#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064)
-#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068)
-#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c)
-
-/* NOR flash interrupt source registers */
-#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070)
-#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074)
-#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078)
-#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c)
-#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24)
-#define TUSB_INT_SRC_USB_IP_CORE (1 << 17)
-#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16)
-#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15)
-#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14)
-#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13)
-#define TUSB_INT_SRC_DEV_READY (1 << 12)
-#define TUSB_INT_SRC_USB_IP_TX (1 << 9)
-#define TUSB_INT_SRC_USB_IP_RX (1 << 8)
-#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7)
-#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6)
-#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5)
-#define TUSB_INT_SRC_USB_IP_CONN (1 << 4)
-#define TUSB_INT_SRC_USB_IP_SOF (1 << 3)
-#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2)
-#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1)
-#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0)
-
-#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080)
-#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084)
-#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100)
-#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104)
-#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108)
-#define TUSB_EP_IN_SIZE (TUSB_SYS_REG_BASE + 0x10c)
-#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148)
-#define TUSB_EP_OUT_SIZE (TUSB_SYS_REG_BASE + 0x14c)
-#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
-#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4)
-#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8)
-#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8)
-
-#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8)
-#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc)
-
-/* Device System & Control register bitfields */
-#define TUSB_INT_CTRL_CONF_INT_RLCYC(v) (((v) & 0x7) << 18)
-#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17)
-#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16)
-#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24)
-#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v) (((v) & 0xf) << 16)
-#define TUSB_EP0_CONFIG_SW_EN (1 << 8)
-#define TUSB_EP0_CONFIG_DIR_TX (1 << 7)
-#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f)
-#define TUSB_EP_CONFIG_SW_EN (1 << 31)
-#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff)
-#define TUSB_PROD_TEST_RESET_VAL 0xa596
-
-static void tusb_intr_update(TUSBState *s)
-{
- if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
- qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
- else
- qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
-}
-
-static void tusb_usbip_intr_update(TUSBState *s)
-{
- /* TX interrupt in the MUSB */
- if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_TX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
-
- /* RX interrupt in the MUSB */
- if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_RX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
-
- /* XXX: What about TUSB_INT_SRC_USB_IP_CORE? */
-
- tusb_intr_update(s);
-}
-
-static void tusb_dma_intr_update(TUSBState *s)
-{
- if (s->dma_intr & ~s->dma_mask)
- s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
- else
- s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
-
- tusb_intr_update(s);
-}
-
-static void tusb_gpio_intr_update(TUSBState *s)
-{
- /* TODO: How is this signalled? */
-}
-
-static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[0](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[1](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
- uint32_t ret;
-
- switch (offset) {
- case TUSB_DEV_CONF:
- return s->dev_config;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[2](s->musb, offset & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return 0x00; /* TODO */
-
- case TUSB_DEV_OTG_STAT:
- ret = s->otg_status;
-#if 0
- if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
- ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-#endif
- return ret;
- case TUSB_DEV_OTG_TIMER:
- return s->otg_timer_val;
-
- case TUSB_PRCM_REV:
- return 0x20;
- case TUSB_PRCM_CONF:
- return s->prcm_config;
- case TUSB_PRCM_MNGMT:
- return s->prcm_mngmt;
- case TUSB_PRCM_WAKEUP_SOURCE:
- case TUSB_PRCM_WAKEUP_CLEAR: /* TODO: What does this one return? */
- return 0x00000000;
- case TUSB_PRCM_WAKEUP_MASK:
- return s->wkup_mask;
-
- case TUSB_PULLUP_1_CTRL:
- return s->pullup[0];
- case TUSB_PULLUP_2_CTRL:
- return s->pullup[1];
-
- case TUSB_INT_CTRL_REV:
- return 0x20;
- case TUSB_INT_CTRL_CONF:
- return s->control_config;
-
- case TUSB_USBIP_INT_SRC:
- case TUSB_USBIP_INT_SET: /* TODO: What do these two return? */
- case TUSB_USBIP_INT_CLEAR:
- return s->usbip_intr;
- case TUSB_USBIP_INT_MASK:
- return s->usbip_mask;
-
- case TUSB_DMA_INT_SRC:
- case TUSB_DMA_INT_SET: /* TODO: What do these two return? */
- case TUSB_DMA_INT_CLEAR:
- return s->dma_intr;
- case TUSB_DMA_INT_MASK:
- return s->dma_mask;
-
- case TUSB_GPIO_INT_SRC: /* TODO: What do these two return? */
- case TUSB_GPIO_INT_SET:
- case TUSB_GPIO_INT_CLEAR:
- return s->gpio_intr;
- case TUSB_GPIO_INT_MASK:
- return s->gpio_mask;
-
- case TUSB_INT_SRC:
- case TUSB_INT_SRC_SET: /* TODO: What do these two return? */
- case TUSB_INT_SRC_CLEAR:
- return s->intr;
- case TUSB_INT_MASK:
- return s->mask;
-
- case TUSB_GPIO_REV:
- return 0x30;
- case TUSB_GPIO_CONF:
- return s->gpio_config;
-
- case TUSB_DMA_CTRL_REV:
- return 0x30;
- case TUSB_DMA_REQ_CONF:
- return s->dma_config;
- case TUSB_EP0_CONF:
- return s->ep0_config;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- return s->tx_config[epnum];
- case TUSB_DMA_EP_MAP:
- return s->dma_map;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- return s->rx_config[epnum];
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return 0x00000000; /* TODO */
- case TUSB_WAIT_COUNT:
- return 0x00; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- return s->scratch;
-
- case TUSB_PROD_TEST_RESET:
- return s->test_reset;
-
- /* DIE IDs */
- case TUSB_DIDR1_LO:
- return 0xa9453c59;
- case TUSB_DIDR1_HI:
- return 0x54059adf;
- }
-
- printf("%s: unknown register at %03x\n", __func__, offset);
- return 0;
-}
-
-static void tusb_async_writeb(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[0](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writeh(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[1](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writew(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
-
- switch (offset) {
- case TUSB_VLYNQ_CTRL:
- break;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[2](s->musb, offset & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- case TUSB_DEV_CONF:
- s->dev_config = value;
- s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
- if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
- hw_error("%s: Product Test mode not allowed\n", __func__);
- break;
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return; /* TODO */
- case TUSB_DEV_OTG_TIMER:
- s->otg_timer_val = value;
- if (value & TUSB_DEV_OTG_TIMER_ENABLE)
- timer_mod(s->otg_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
- NANOSECONDS_PER_SECOND, TUSB_DEVCLOCK));
- else
- timer_del(s->otg_timer);
- break;
-
- case TUSB_PRCM_CONF:
- s->prcm_config = value;
- break;
- case TUSB_PRCM_MNGMT:
- s->prcm_mngmt = value;
- break;
- case TUSB_PRCM_WAKEUP_CLEAR:
- break;
- case TUSB_PRCM_WAKEUP_MASK:
- s->wkup_mask = value;
- break;
-
- case TUSB_PULLUP_1_CTRL:
- s->pullup[0] = value;
- break;
- case TUSB_PULLUP_2_CTRL:
- s->pullup[1] = value;
- break;
- case TUSB_INT_CTRL_CONF:
- s->control_config = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_USBIP_INT_SET:
- s->usbip_intr |= value;
- tusb_usbip_intr_update(s);
- break;
- case TUSB_USBIP_INT_CLEAR:
- s->usbip_intr &= ~value;
- tusb_usbip_intr_update(s);
- musb_core_intr_clear(s->musb, ~value);
- break;
- case TUSB_USBIP_INT_MASK:
- s->usbip_mask = value;
- tusb_usbip_intr_update(s);
- break;
-
- case TUSB_DMA_INT_SET:
- s->dma_intr |= value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_CLEAR:
- s->dma_intr &= ~value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_MASK:
- s->dma_mask = value;
- tusb_dma_intr_update(s);
- break;
-
- case TUSB_GPIO_INT_SET:
- s->gpio_intr |= value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_CLEAR:
- s->gpio_intr &= ~value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_MASK:
- s->gpio_mask = value;
- tusb_gpio_intr_update(s);
- break;
-
- case TUSB_INT_SRC_SET:
- s->intr |= value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_SRC_CLEAR:
- s->intr &= ~value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_MASK:
- s->mask = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_GPIO_CONF:
- s->gpio_config = value;
- break;
- case TUSB_DMA_REQ_CONF:
- s->dma_config = value;
- break;
- case TUSB_EP0_CONF:
- s->ep0_config = value & 0x1ff;
- musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
- value & TUSB_EP0_CONFIG_DIR_TX);
- break;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- s->tx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
- break;
- case TUSB_DMA_EP_MAP:
- s->dma_map = value;
- break;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- s->rx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
- break;
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return; /* TODO */
- case TUSB_WAIT_COUNT:
- return; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- s->scratch = value;
- break;
-
- case TUSB_PROD_TEST_RESET:
- s->test_reset = value;
- break;
-
- default:
- printf("%s: unknown register at %03x\n", __func__, offset);
- return;
- }
-}
-
-static uint64_t tusb_async_readfn(void *opaque, hwaddr addr, unsigned size)
-{
- switch (size) {
- case 1:
- return tusb_async_readb(opaque, addr);
- case 2:
- return tusb_async_readh(opaque, addr);
- case 4:
- return tusb_async_readw(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void tusb_async_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 1:
- tusb_async_writeb(opaque, addr, value);
- break;
- case 2:
- tusb_async_writeh(opaque, addr, value);
- break;
- case 4:
- tusb_async_writew(opaque, addr, value);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static const MemoryRegionOps tusb_async_ops = {
- .read = tusb_async_readfn,
- .write = tusb_async_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void tusb_otg_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- s->otg_timer_val = 0;
- s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
- tusb_intr_update(s);
-}
-
-static void tusb_power_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- if (s->power) {
- s->intr_ok = ~0;
- tusb_intr_update(s);
- }
-}
-
-static void tusb_musb_core_intr(void *opaque, int source, int level)
-{
- TUSBState *s = (TUSBState *) opaque;
- uint16_t otg_status = s->otg_status;
-
- switch (source) {
- case musb_set_vbus:
- if (level)
- otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
- else
- otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set? */
- if (s->otg_status != otg_status) {
- s->otg_status = otg_status;
- s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
- tusb_intr_update(s);
- }
- break;
-
- case musb_set_session:
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set? */
- if (level) {
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
- } else {
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
- }
-
- /* XXX: some IRQ or anything? */
- break;
-
- case musb_irq_tx:
- case musb_irq_rx:
- s->usbip_intr = musb_core_intr_get(s->musb);
- /* Fall through. */
- default:
- if (level)
- s->intr |= 1 << source;
- else
- s->intr &= ~(1 << source);
- tusb_intr_update(s);
- break;
- }
-}
-
-static void tusb6010_power(TUSBState *s, int on)
-{
- if (!on) {
- s->power = 0;
- } else if (!s->power && on) {
- s->power = 1;
- /* Pull the interrupt down after TUSB6010 comes up. */
- s->intr_ok = 0;
- tusb_intr_update(s);
- timer_mod(s->pwr_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 2);
- }
-}
-
-static void tusb6010_irq(void *opaque, int source, int level)
-{
- if (source) {
- tusb_musb_core_intr(opaque, source - 1, level);
- } else {
- tusb6010_power(opaque, level);
- }
-}
-
-static void tusb6010_reset(DeviceState *dev)
-{
- TUSBState *s = TUSB6010(dev);
- int i;
-
- s->test_reset = TUSB_PROD_TEST_RESET_VAL;
- s->host_mode = 0;
- s->dev_config = 0;
- s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
- s->power = 0;
- s->mask = 0xffffffff;
- s->intr = 0x00000000;
- s->otg_timer_val = 0;
- s->scratch = 0;
- s->prcm_config = 0;
- s->prcm_mngmt = 0;
- s->intr_ok = 0;
- s->usbip_intr = 0;
- s->usbip_mask = 0;
- s->gpio_intr = 0;
- s->gpio_mask = 0;
- s->gpio_config = 0;
- s->dma_intr = 0;
- s->dma_mask = 0;
- s->dma_map = 0;
- s->dma_config = 0;
- s->ep0_config = 0;
- s->wkup_mask = 0;
- s->pullup[0] = s->pullup[1] = 0;
- s->control_config = 0;
- for (i = 0; i < 15; i++) {
- s->rx_config[i] = s->tx_config[i] = 0;
- }
- musb_reset(s->musb);
-}
-
-static void tusb6010_realize(DeviceState *dev, Error **errp)
-{
- TUSBState *s = TUSB6010(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- s->otg_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_otg_tick, s);
- s->pwr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_power_tick, s);
- memory_region_init_io(&s->iomem[1], OBJECT(s), &tusb_async_ops, s,
- "tusb-async", UINT32_MAX);
- sysbus_init_mmio(sbd, &s->iomem[0]);
- sysbus_init_mmio(sbd, &s->iomem[1]);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, tusb6010_irq, musb_irq_max + 1);
- s->musb = musb_init(dev, 1);
-}
-
-static void tusb6010_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = tusb6010_realize;
- dc->reset = tusb6010_reset;
-}
-
-static const TypeInfo tusb6010_info = {
- .name = TYPE_TUSB6010,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TUSBState),
- .class_init = tusb6010_class_init,
-};
-
-static void tusb6010_register_types(void)
-{
- type_register_static(&tusb6010_info);
-}
-
-type_init(tusb6010_register_types)
diff --git a/hw/usb/u2f-emulated.c b/hw/usb/u2f-emulated.c
index 63cceaa..ace5ece 100644
--- a/hw/usb/u2f-emulated.c
+++ b/hw/usb/u2f-emulated.c
@@ -369,16 +369,15 @@ static void u2f_emulated_unrealize(U2FKeyState *base)
}
}
-static Property u2f_emulated_properties[] = {
+static const Property u2f_emulated_properties[] = {
DEFINE_PROP_STRING("dir", U2FEmulatedState, dir),
DEFINE_PROP_STRING("cert", U2FEmulatedState, cert),
DEFINE_PROP_STRING("privkey", U2FEmulatedState, privkey),
DEFINE_PROP_STRING("entropy", U2FEmulatedState, entropy),
DEFINE_PROP_STRING("counter", U2FEmulatedState, counter),
- DEFINE_PROP_END_OF_LIST(),
};
-static void u2f_emulated_class_init(ObjectClass *klass, void *data)
+static void u2f_emulated_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
U2FKeyClass *kc = U2F_KEY_CLASS(klass);
diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c
index c4a783d..fa8d9cd 100644
--- a/hw/usb/u2f-passthru.c
+++ b/hw/usb/u2f-passthru.c
@@ -516,12 +516,11 @@ static const VMStateDescription u2f_passthru_vmstate = {
}
};
-static Property u2f_passthru_properties[] = {
+static const Property u2f_passthru_properties[] = {
DEFINE_PROP_STRING("hidraw", U2FPassthruState, hidraw),
- DEFINE_PROP_END_OF_LIST(),
};
-static void u2f_passthru_class_init(ObjectClass *klass, void *data)
+static void u2f_passthru_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
U2FKeyClass *kc = U2F_KEY_CLASS(klass);
diff --git a/hw/usb/u2f.c b/hw/usb/u2f.c
index 1fb59cf..b051a99 100644
--- a/hw/usb/u2f.c
+++ b/hw/usb/u2f.c
@@ -317,7 +317,7 @@ const VMStateDescription vmstate_u2f_key = {
}
};
-static void u2f_key_class_init(ObjectClass *klass, void *data)
+static void u2f_key_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
index 1390162..fa46a7d 100644
--- a/hw/usb/xen-usb.c
+++ b/hw/usb/xen-usb.c
@@ -30,8 +30,8 @@
#include "hw/xen/xen-legacy-backend.h"
#include "monitor/qdev.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qstring.h"
+#include "qobject/qdict.h"
+#include "qobject/qstring.h"
#include "hw/xen/interface/io/usbif.h"
@@ -755,10 +755,10 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port,
qdict = qdict_new();
qdict_put_str(qdict, "driver", "usb-host");
- tmp = g_strdup_printf("%s.0", usbif->xendev.qdev.id);
+ tmp = g_strdup_printf("%s.0", DEVICE(&usbif->xendev)->id);
qdict_put_str(qdict, "bus", tmp);
g_free(tmp);
- tmp = g_strdup_printf("%s-%u", usbif->xendev.qdev.id, port);
+ tmp = g_strdup_printf("%s-%u", DEVICE(&usbif->xendev)->id, port);
qdict_put_str(qdict, "id", tmp);
g_free(tmp);
qdict_put_int(qdict, "port", port);
@@ -1022,7 +1022,7 @@ static void usbback_alloc(struct XenLegacyDevice *xendev)
usbif = container_of(xendev, struct usbback_info, xendev);
usb_bus_new(&usbif->bus, sizeof(usbif->bus), &xen_usb_bus_ops,
- DEVICE(&xendev->qdev));
+ DEVICE(xendev));
for (i = 0; i < USBBACK_MAXPORTS; i++) {
p = &(usbif->ports[i].port);
usb_register_port(&usbif->bus, p, usbif, i, &xen_usb_port_ops,
diff --git a/hw/usb/xlnx-usb-subsystem.c b/hw/usb/xlnx-usb-subsystem.c
index d8deeb6..98967ef 100644
--- a/hw/usb/xlnx-usb-subsystem.c
+++ b/hw/usb/xlnx-usb-subsystem.c
@@ -69,7 +69,7 @@ static void versal_usb2_init(Object *obj)
object_property_add_alias(obj, "dma", OBJECT(&s->dwc3.sysbus_xhci), "dma");
}
-static void versal_usb2_class_init(ObjectClass *klass, void *data)
+static void versal_usb2_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/usb/xlnx-versal-usb2-ctrl-regs.c b/hw/usb/xlnx-versal-usb2-ctrl-regs.c
index 66c793a..4114672 100644
--- a/hw/usb/xlnx-versal-usb2-ctrl-regs.c
+++ b/hw/usb/xlnx-versal-usb2-ctrl-regs.c
@@ -202,7 +202,7 @@ static const VMStateDescription vmstate_usb2_ctrl_regs = {
}
};
-static void usb2_ctrl_regs_class_init(ObjectClass *klass, void *data)
+static void usb2_ctrl_regs_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/vfio-user/Kconfig b/hw/vfio-user/Kconfig
new file mode 100644
index 0000000..24bdf7a
--- /dev/null
+++ b/hw/vfio-user/Kconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config VFIO_USER
+ bool
+ default y
+ depends on VFIO_PCI
+
diff --git a/hw/vfio-user/container.c b/hw/vfio-user/container.c
new file mode 100644
index 0000000..3133fef
--- /dev/null
+++ b/hw/vfio-user/container.c
@@ -0,0 +1,370 @@
+/*
+ * Container for vfio-user IOMMU type: rather than communicating with the kernel
+ * vfio driver, we communicate over a socket to a server using the vfio-user
+ * protocol.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/ioctl.h>
+#include <linux/vfio.h>
+#include "qemu/osdep.h"
+
+#include "hw/vfio-user/container.h"
+#include "hw/vfio-user/device.h"
+#include "hw/vfio-user/trace.h"
+#include "hw/vfio/vfio-cpr.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio/vfio-listener.h"
+#include "qapi/error.h"
+
+/*
+ * When DMA space is the physical address space, the region add/del listeners
+ * will fire during memory update transactions. These depend on BQL being held,
+ * so do any resulting map/demap ops async while keeping BQL.
+ */
+static void vfio_user_listener_begin(VFIOContainerBase *bcontainer)
+{
+ VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer,
+ bcontainer);
+
+ container->proxy->async_ops = true;
+}
+
+static void vfio_user_listener_commit(VFIOContainerBase *bcontainer)
+{
+ VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer,
+ bcontainer);
+
+ /* wait here for any async requests sent during the transaction */
+ container->proxy->async_ops = false;
+ vfio_user_wait_reqs(container->proxy);
+}
+
+static int vfio_user_dma_unmap(const VFIOContainerBase *bcontainer,
+ hwaddr iova, ram_addr_t size,
+ IOMMUTLBEntry *iotlb, bool unmap_all)
+{
+ VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer,
+ bcontainer);
+ Error *local_err = NULL;
+ int ret = 0;
+
+ VFIOUserDMAUnmap *msgp = g_malloc(sizeof(*msgp));
+
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_DMA_UNMAP, sizeof(*msgp), 0);
+ msgp->argsz = sizeof(struct vfio_iommu_type1_dma_unmap);
+ msgp->flags = unmap_all ? VFIO_DMA_UNMAP_FLAG_ALL : 0;
+ msgp->iova = iova;
+ msgp->size = size;
+ trace_vfio_user_dma_unmap(msgp->iova, msgp->size, msgp->flags,
+ container->proxy->async_ops);
+
+ if (container->proxy->async_ops) {
+ if (!vfio_user_send_nowait(container->proxy, &msgp->hdr, NULL,
+ 0, &local_err)) {
+ error_report_err(local_err);
+ ret = -EFAULT;
+ } else {
+ ret = 0;
+ }
+ } else {
+ if (!vfio_user_send_wait(container->proxy, &msgp->hdr, NULL,
+ 0, &local_err)) {
+ error_report_err(local_err);
+ ret = -EFAULT;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ ret = -msgp->hdr.error_reply;
+ }
+
+ g_free(msgp);
+ }
+
+ return ret;
+}
+
+static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
+ ram_addr_t size, void *vaddr, bool readonly,
+ MemoryRegion *mrp)
+{
+ VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer,
+ bcontainer);
+ int fd = memory_region_get_fd(mrp);
+ Error *local_err = NULL;
+ int ret;
+
+ VFIOUserFDs *fds = NULL;
+ VFIOUserDMAMap *msgp = g_malloc0(sizeof(*msgp));
+
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_DMA_MAP, sizeof(*msgp), 0);
+ msgp->argsz = sizeof(struct vfio_iommu_type1_dma_map);
+ msgp->flags = VFIO_DMA_MAP_FLAG_READ;
+ msgp->offset = 0;
+ msgp->iova = iova;
+ msgp->size = size;
+
+ /*
+ * vaddr enters as a QEMU process address; make it either a file offset
+ * for mapped areas or leave as 0.
+ */
+ if (fd != -1) {
+ msgp->offset = qemu_ram_block_host_offset(mrp->ram_block, vaddr);
+ }
+
+ if (!readonly) {
+ msgp->flags |= VFIO_DMA_MAP_FLAG_WRITE;
+ }
+
+ trace_vfio_user_dma_map(msgp->iova, msgp->size, msgp->offset, msgp->flags,
+ container->proxy->async_ops);
+
+ /*
+ * The async_ops case sends without blocking. They're later waited for in
+ * vfio_send_wait_reqs.
+ */
+ if (container->proxy->async_ops) {
+ /* can't use auto variable since we don't block */
+ if (fd != -1) {
+ fds = vfio_user_getfds(1);
+ fds->send_fds = 1;
+ fds->fds[0] = fd;
+ }
+
+ if (!vfio_user_send_nowait(container->proxy, &msgp->hdr, fds,
+ 0, &local_err)) {
+ error_report_err(local_err);
+ ret = -EFAULT;
+ } else {
+ ret = 0;
+ }
+ } else {
+ VFIOUserFDs local_fds = { 1, 0, &fd };
+
+ fds = fd != -1 ? &local_fds : NULL;
+
+ if (!vfio_user_send_wait(container->proxy, &msgp->hdr, fds,
+ 0, &local_err)) {
+ error_report_err(local_err);
+ ret = -EFAULT;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ ret = -msgp->hdr.error_reply;
+ }
+
+ g_free(msgp);
+ }
+
+ return ret;
+}
+
+static int
+vfio_user_set_dirty_page_tracking(const VFIOContainerBase *bcontainer,
+ bool start, Error **errp)
+{
+ error_setg_errno(errp, ENOTSUP, "Not supported");
+ return -ENOTSUP;
+}
+
+static int vfio_user_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
+ VFIOBitmap *vbmap, hwaddr iova,
+ hwaddr size, Error **errp)
+{
+ error_setg_errno(errp, ENOTSUP, "Not supported");
+ return -ENOTSUP;
+}
+
+static bool vfio_user_setup(VFIOContainerBase *bcontainer, Error **errp)
+{
+ VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer,
+ bcontainer);
+
+ assert(container->proxy->dma_pgsizes != 0);
+ bcontainer->pgsizes = container->proxy->dma_pgsizes;
+ bcontainer->dma_max_mappings = container->proxy->max_dma;
+
+ /* No live migration support yet. */
+ bcontainer->dirty_pages_supported = false;
+ bcontainer->max_dirty_bitmap_size = container->proxy->max_bitmap;
+ bcontainer->dirty_pgsizes = container->proxy->migr_pgsize;
+
+ return true;
+}
+
+static VFIOUserContainer *vfio_user_create_container(VFIODevice *vbasedev,
+ Error **errp)
+{
+ VFIOUserContainer *container;
+
+ container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER));
+ container->proxy = vbasedev->proxy;
+ return container;
+}
+
+/*
+ * Try to mirror vfio_container_connect() as much as possible.
+ */
+static VFIOUserContainer *
+vfio_user_container_connect(AddressSpace *as, VFIODevice *vbasedev,
+ Error **errp)
+{
+ VFIOContainerBase *bcontainer;
+ VFIOUserContainer *container;
+ VFIOAddressSpace *space;
+ VFIOIOMMUClass *vioc;
+ int ret;
+
+ space = vfio_address_space_get(as);
+
+ container = vfio_user_create_container(vbasedev, errp);
+ if (!container) {
+ goto put_space_exit;
+ }
+
+ bcontainer = &container->bcontainer;
+
+ if (!vfio_cpr_register_container(bcontainer, errp)) {
+ goto free_container_exit;
+ }
+
+ ret = ram_block_uncoordinated_discard_disable(true);
+ if (ret) {
+ error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
+ goto unregister_container_exit;
+ }
+
+ vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+ assert(vioc->setup);
+
+ if (!vioc->setup(bcontainer, errp)) {
+ goto enable_discards_exit;
+ }
+
+ vfio_address_space_insert(space, bcontainer);
+
+ if (!vfio_listener_register(bcontainer, errp)) {
+ goto listener_release_exit;
+ }
+
+ bcontainer->initialized = true;
+
+ return container;
+
+listener_release_exit:
+ vfio_listener_unregister(bcontainer);
+ if (vioc->release) {
+ vioc->release(bcontainer);
+ }
+
+enable_discards_exit:
+ ram_block_uncoordinated_discard_disable(false);
+
+unregister_container_exit:
+ vfio_cpr_unregister_container(bcontainer);
+
+free_container_exit:
+ object_unref(container);
+
+put_space_exit:
+ vfio_address_space_put(space);
+
+ return NULL;
+}
+
+static void vfio_user_container_disconnect(VFIOUserContainer *container)
+{
+ VFIOContainerBase *bcontainer = &container->bcontainer;
+ VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+ VFIOAddressSpace *space = bcontainer->space;
+
+ ram_block_uncoordinated_discard_disable(false);
+
+ vfio_listener_unregister(bcontainer);
+ if (vioc->release) {
+ vioc->release(bcontainer);
+ }
+
+ vfio_cpr_unregister_container(bcontainer);
+ object_unref(container);
+
+ vfio_address_space_put(space);
+}
+
+static bool vfio_user_device_get(VFIOUserContainer *container,
+ VFIODevice *vbasedev, Error **errp)
+{
+ struct vfio_device_info info = { .argsz = sizeof(info) };
+
+
+ if (!vfio_user_get_device_info(vbasedev->proxy, &info, errp)) {
+ return false;
+ }
+
+ vbasedev->fd = -1;
+
+ vfio_device_prepare(vbasedev, &container->bcontainer, &info);
+
+ return true;
+}
+
+/*
+ * vfio_user_device_attach: attach a device to a new container.
+ */
+static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev,
+ AddressSpace *as, Error **errp)
+{
+ VFIOUserContainer *container;
+
+ container = vfio_user_container_connect(as, vbasedev, errp);
+ if (container == NULL) {
+ error_prepend(errp, "failed to connect proxy");
+ return false;
+ }
+
+ return vfio_user_device_get(container, vbasedev, errp);
+}
+
+static void vfio_user_device_detach(VFIODevice *vbasedev)
+{
+ VFIOUserContainer *container = container_of(vbasedev->bcontainer,
+ VFIOUserContainer, bcontainer);
+
+ vfio_device_unprepare(vbasedev);
+
+ vfio_user_container_disconnect(container);
+}
+
+static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single)
+{
+ /* ->needs_reset is always false for vfio-user. */
+ return 0;
+}
+
+static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data)
+{
+ VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
+
+ vioc->setup = vfio_user_setup;
+ vioc->listener_begin = vfio_user_listener_begin,
+ vioc->listener_commit = vfio_user_listener_commit,
+ vioc->dma_map = vfio_user_dma_map;
+ vioc->dma_unmap = vfio_user_dma_unmap;
+ vioc->attach_device = vfio_user_device_attach;
+ vioc->detach_device = vfio_user_device_detach;
+ vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking;
+ vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap;
+ vioc->pci_hot_reset = vfio_user_pci_hot_reset;
+};
+
+static const TypeInfo types[] = {
+ {
+ .name = TYPE_VFIO_IOMMU_USER,
+ .parent = TYPE_VFIO_IOMMU,
+ .instance_size = sizeof(VFIOUserContainer),
+ .class_init = vfio_iommu_user_class_init,
+ },
+};
+
+DEFINE_TYPES(types)
diff --git a/hw/vfio-user/container.h b/hw/vfio-user/container.h
new file mode 100644
index 0000000..2bb1fa1
--- /dev/null
+++ b/hw/vfio-user/container.h
@@ -0,0 +1,23 @@
+/*
+ * vfio-user specific definitions.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VFIO_USER_CONTAINER_H
+#define HW_VFIO_USER_CONTAINER_H
+
+#include "qemu/osdep.h"
+
+#include "hw/vfio/vfio-container-base.h"
+#include "hw/vfio-user/proxy.h"
+
+/* MMU container sub-class for vfio-user. */
+typedef struct VFIOUserContainer {
+ VFIOContainerBase bcontainer;
+ VFIOUserProxy *proxy;
+} VFIOUserContainer;
+
+OBJECT_DECLARE_SIMPLE_TYPE(VFIOUserContainer, VFIO_IOMMU_USER);
+
+#endif /* HW_VFIO_USER_CONTAINER_H */
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
new file mode 100644
index 0000000..0609a7d
--- /dev/null
+++ b/hw/vfio-user/device.c
@@ -0,0 +1,441 @@
+/*
+ * vfio protocol over a UNIX socket device handling.
+ *
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/lockable.h"
+#include "qemu/thread.h"
+
+#include "hw/vfio-user/device.h"
+#include "hw/vfio-user/trace.h"
+
+/*
+ * These are to defend against a malign server trying
+ * to force us to run out of memory.
+ */
+#define VFIO_USER_MAX_REGIONS 100
+#define VFIO_USER_MAX_IRQS 50
+
+bool vfio_user_get_device_info(VFIOUserProxy *proxy,
+ struct vfio_device_info *info, Error **errp)
+{
+ VFIOUserDeviceInfo msg;
+ uint32_t argsz = sizeof(msg) - sizeof(msg.hdr);
+
+ memset(&msg, 0, sizeof(msg));
+ vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_INFO, sizeof(msg), 0);
+ msg.argsz = argsz;
+
+ if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, errp)) {
+ return false;
+ }
+
+ if (msg.hdr.flags & VFIO_USER_ERROR) {
+ error_setg_errno(errp, -msg.hdr.error_reply,
+ "VFIO_USER_DEVICE_GET_INFO failed");
+ return false;
+ }
+
+ trace_vfio_user_get_info(msg.num_regions, msg.num_irqs);
+
+ memcpy(info, &msg.argsz, argsz);
+
+ /* defend against a malicious server */
+ if (info->num_regions > VFIO_USER_MAX_REGIONS ||
+ info->num_irqs > VFIO_USER_MAX_IRQS) {
+ error_setg_errno(errp, EINVAL, "invalid reply");
+ return false;
+ }
+
+ return true;
+}
+
+void vfio_user_device_reset(VFIOUserProxy *proxy)
+{
+ Error *local_err = NULL;
+ VFIOUserHdr hdr;
+
+ vfio_user_request_msg(&hdr, VFIO_USER_DEVICE_RESET, sizeof(hdr), 0);
+
+ if (!vfio_user_send_wait(proxy, &hdr, NULL, 0, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ return;
+ }
+
+ if (hdr.flags & VFIO_USER_ERROR) {
+ error_printf("reset reply error %d\n", hdr.error_reply);
+ }
+}
+
+static int vfio_user_get_region_info(VFIOUserProxy *proxy,
+ struct vfio_region_info *info,
+ VFIOUserFDs *fds)
+{
+ g_autofree VFIOUserRegionInfo *msgp = NULL;
+ Error *local_err = NULL;
+ uint32_t size;
+
+ /* data returned can be larger than vfio_region_info */
+ if (info->argsz < sizeof(*info)) {
+ error_printf("vfio_user_get_region_info argsz too small\n");
+ return -E2BIG;
+ }
+ if (fds != NULL && fds->send_fds != 0) {
+ error_printf("vfio_user_get_region_info can't send FDs\n");
+ return -EINVAL;
+ }
+
+ size = info->argsz + sizeof(VFIOUserHdr);
+ msgp = g_malloc0(size);
+
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_GET_REGION_INFO,
+ sizeof(*msgp), 0);
+ msgp->argsz = info->argsz;
+ msgp->index = info->index;
+
+ if (!vfio_user_send_wait(proxy, &msgp->hdr, fds, size, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ return -EFAULT;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ return -msgp->hdr.error_reply;
+ }
+ trace_vfio_user_get_region_info(msgp->index, msgp->flags, msgp->size);
+
+ memcpy(info, &msgp->argsz, info->argsz);
+
+ /*
+ * If at least one region is directly mapped into the VM, then we can no
+ * longer rely on the sequential nature of vfio-user request handling to
+ * ensure that posted writes are completed before a subsequent read. In this
+ * case, disable posted write support. This is a per-device property, not
+ * per-region.
+ */
+ if (info->flags & VFIO_REGION_INFO_FLAG_MMAP) {
+ vfio_user_disable_posted_writes(proxy);
+ }
+
+ return 0;
+}
+
+static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev,
+ struct vfio_region_info *info,
+ int *fd)
+{
+ VFIOUserFDs fds = { 0, 1, fd};
+ int ret;
+
+ if (info->index > vbasedev->num_regions) {
+ return -EINVAL;
+ }
+
+ ret = vfio_user_get_region_info(vbasedev->proxy, info, &fds);
+ if (ret) {
+ return ret;
+ }
+
+ /* cap_offset in valid area */
+ if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) &&
+ (info->cap_offset < sizeof(*info) || info->cap_offset > info->argsz)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vfio_user_device_io_get_irq_info(VFIODevice *vbasedev,
+ struct vfio_irq_info *info)
+{
+ VFIOUserProxy *proxy = vbasedev->proxy;
+ Error *local_err = NULL;
+ VFIOUserIRQInfo msg;
+
+ memset(&msg, 0, sizeof(msg));
+ vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_IRQ_INFO,
+ sizeof(msg), 0);
+ msg.argsz = info->argsz;
+ msg.index = info->index;
+
+ if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ return -EFAULT;
+ }
+
+ if (msg.hdr.flags & VFIO_USER_ERROR) {
+ return -msg.hdr.error_reply;
+ }
+ trace_vfio_user_get_irq_info(msg.index, msg.flags, msg.count);
+
+ memcpy(info, &msg.argsz, sizeof(*info));
+ return 0;
+}
+
+static int irq_howmany(int *fdp, uint32_t cur, uint32_t max)
+{
+ int n = 0;
+
+ if (fdp[cur] != -1) {
+ do {
+ n++;
+ } while (n < max && fdp[cur + n] != -1);
+ } else {
+ do {
+ n++;
+ } while (n < max && fdp[cur + n] == -1);
+ }
+
+ return n;
+}
+
+static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev,
+ struct vfio_irq_set *irq)
+{
+ VFIOUserProxy *proxy = vbasedev->proxy;
+ g_autofree VFIOUserIRQSet *msgp = NULL;
+ uint32_t size, nfds, send_fds, sent_fds, max;
+ Error *local_err = NULL;
+
+ if (irq->argsz < sizeof(*irq)) {
+ error_printf("vfio_user_set_irqs argsz too small\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Handle simple case
+ */
+ if ((irq->flags & VFIO_IRQ_SET_DATA_EVENTFD) == 0) {
+ size = sizeof(VFIOUserHdr) + irq->argsz;
+ msgp = g_malloc0(size);
+
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0);
+ msgp->argsz = irq->argsz;
+ msgp->flags = irq->flags;
+ msgp->index = irq->index;
+ msgp->start = irq->start;
+ msgp->count = irq->count;
+ trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
+ msgp->flags);
+
+ if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ return -EFAULT;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ return -msgp->hdr.error_reply;
+ }
+
+ return 0;
+ }
+
+ /*
+ * Calculate the number of FDs to send
+ * and adjust argsz
+ */
+ nfds = (irq->argsz - sizeof(*irq)) / sizeof(int);
+ irq->argsz = sizeof(*irq);
+ msgp = g_malloc0(sizeof(*msgp));
+ /*
+ * Send in chunks if over max_send_fds
+ */
+ for (sent_fds = 0; nfds > sent_fds; sent_fds += send_fds) {
+ VFIOUserFDs *arg_fds, loop_fds;
+
+ /* must send all valid FDs or all invalid FDs in single msg */
+ max = nfds - sent_fds;
+ if (max > proxy->max_send_fds) {
+ max = proxy->max_send_fds;
+ }
+ send_fds = irq_howmany((int *)irq->data, sent_fds, max);
+
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS,
+ sizeof(*msgp), 0);
+ msgp->argsz = irq->argsz;
+ msgp->flags = irq->flags;
+ msgp->index = irq->index;
+ msgp->start = irq->start + sent_fds;
+ msgp->count = send_fds;
+ trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
+ msgp->flags);
+
+ loop_fds.send_fds = send_fds;
+ loop_fds.recv_fds = 0;
+ loop_fds.fds = (int *)irq->data + sent_fds;
+ arg_fds = loop_fds.fds[0] != -1 ? &loop_fds : NULL;
+
+ if (!vfio_user_send_wait(proxy, &msgp->hdr, arg_fds, 0, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ return -EFAULT;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ return -msgp->hdr.error_reply;
+ }
+ }
+
+ return 0;
+}
+
+static int vfio_user_device_io_region_read(VFIODevice *vbasedev, uint8_t index,
+ off_t off, uint32_t count,
+ void *data)
+{
+ g_autofree VFIOUserRegionRW *msgp = NULL;
+ VFIOUserProxy *proxy = vbasedev->proxy;
+ int size = sizeof(*msgp) + count;
+ Error *local_err = NULL;
+
+ if (count > proxy->max_xfer_size) {
+ return -EINVAL;
+ }
+
+ msgp = g_malloc0(size);
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_READ, sizeof(*msgp), 0);
+ msgp->offset = off;
+ msgp->region = index;
+ msgp->count = count;
+ trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
+
+ if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, size, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ return -EFAULT;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ return -msgp->hdr.error_reply;
+ } else if (msgp->count > count) {
+ return -E2BIG;
+ } else {
+ memcpy(data, &msgp->data, msgp->count);
+ }
+
+ return msgp->count;
+}
+
+/*
+ * If this is a posted write, and VFIO_PROXY_NO_POST is not set, then we are OK
+ * to send the write to the socket without waiting for the server's reply:
+ * a subsequent read (of any region) will not pass the posted write, as all
+ * messages are handled sequentially.
+ */
+static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index,
+ off_t off, unsigned count,
+ void *data, bool post)
+{
+ VFIOUserRegionRW *msgp = NULL;
+ VFIOUserProxy *proxy = vbasedev->proxy;
+ int size = sizeof(*msgp) + count;
+ Error *local_err = NULL;
+ bool can_multi;
+ int flags = 0;
+ int ret;
+
+ if (count > proxy->max_xfer_size) {
+ return -EINVAL;
+ }
+
+ if (proxy->flags & VFIO_PROXY_NO_POST) {
+ post = false;
+ }
+
+ if (post) {
+ flags |= VFIO_USER_NO_REPLY;
+ }
+
+ /* write eligible to be in a WRITE_MULTI msg ? */
+ can_multi = (proxy->flags & VFIO_PROXY_USE_MULTI) && post &&
+ count <= VFIO_USER_MULTI_DATA;
+
+ /*
+ * This should be a rare case, so first check without the lock,
+ * if we're wrong, vfio_send_queued() will flush any posted writes
+ * we missed here
+ */
+ if (proxy->wr_multi != NULL ||
+ (proxy->num_outgoing > VFIO_USER_OUT_HIGH && can_multi)) {
+
+ /*
+ * re-check with lock
+ *
+ * if already building a WRITE_MULTI msg,
+ * add this one if possible else flush pending before
+ * sending the current one
+ *
+ * else if outgoing queue is over the highwater,
+ * start a new WRITE_MULTI message
+ */
+ WITH_QEMU_LOCK_GUARD(&proxy->lock) {
+ if (proxy->wr_multi != NULL) {
+ if (can_multi) {
+ vfio_user_add_multi(proxy, index, off, count, data);
+ return count;
+ }
+ vfio_user_flush_multi(proxy);
+ } else if (proxy->num_outgoing > VFIO_USER_OUT_HIGH && can_multi) {
+ vfio_user_create_multi(proxy);
+ vfio_user_add_multi(proxy, index, off, count, data);
+ return count;
+ }
+ }
+ }
+
+ msgp = g_malloc0(size);
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, flags);
+ msgp->offset = off;
+ msgp->region = index;
+ msgp->count = count;
+ memcpy(&msgp->data, data, count);
+ trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
+
+ /* async send will free msg after it's sent */
+ if (post) {
+ if (!vfio_user_send_async(proxy, &msgp->hdr, NULL, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ return -EFAULT;
+ }
+
+ return count;
+ }
+
+ if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
+ error_prepend(&local_err, "%s: ", __func__);
+ error_report_err(local_err);
+ g_free(msgp);
+ return -EFAULT;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ ret = -msgp->hdr.error_reply;
+ } else {
+ ret = count;
+ }
+
+ g_free(msgp);
+ return ret;
+}
+
+/*
+ * Socket-based io_ops
+ */
+VFIODeviceIOOps vfio_user_device_io_ops_sock = {
+ .get_region_info = vfio_user_device_io_get_region_info,
+ .get_irq_info = vfio_user_device_io_get_irq_info,
+ .set_irqs = vfio_user_device_io_set_irqs,
+ .region_read = vfio_user_device_io_region_read,
+ .region_write = vfio_user_device_io_region_write,
+
+};
diff --git a/hw/vfio-user/device.h b/hw/vfio-user/device.h
new file mode 100644
index 0000000..d183a39
--- /dev/null
+++ b/hw/vfio-user/device.h
@@ -0,0 +1,24 @@
+#ifndef VFIO_USER_DEVICE_H
+#define VFIO_USER_DEVICE_H
+
+/*
+ * vfio protocol over a UNIX socket device handling.
+ *
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "linux/vfio.h"
+
+#include "hw/vfio-user/proxy.h"
+
+bool vfio_user_get_device_info(VFIOUserProxy *proxy,
+ struct vfio_device_info *info, Error **errp);
+
+void vfio_user_device_reset(VFIOUserProxy *proxy);
+
+extern VFIODeviceIOOps vfio_user_device_io_ops_sock;
+
+#endif /* VFIO_USER_DEVICE_H */
diff --git a/hw/vfio-user/meson.build b/hw/vfio-user/meson.build
new file mode 100644
index 0000000..2ed0ae5
--- /dev/null
+++ b/hw/vfio-user/meson.build
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+vfio_user_ss = ss.source_set()
+vfio_user_ss.add(files(
+ 'container.c',
+ 'device.c',
+ 'pci.c',
+ 'proxy.c',
+))
+
+system_ss.add_all(when: 'CONFIG_VFIO_USER', if_true: vfio_user_ss)
diff --git a/hw/vfio-user/pci.c b/hw/vfio-user/pci.c
new file mode 100644
index 0000000..be71c77
--- /dev/null
+++ b/hw/vfio-user/pci.c
@@ -0,0 +1,475 @@
+/*
+ * vfio PCI device over a UNIX socket.
+ *
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/ioctl.h>
+#include "qemu/osdep.h"
+#include "qapi-visit-sockets.h"
+#include "qemu/error-report.h"
+
+#include "hw/qdev-properties.h"
+#include "hw/vfio/pci.h"
+#include "hw/vfio-user/device.h"
+#include "hw/vfio-user/proxy.h"
+
+#define TYPE_VFIO_USER_PCI "vfio-user-pci"
+OBJECT_DECLARE_SIMPLE_TYPE(VFIOUserPCIDevice, VFIO_USER_PCI)
+
+struct VFIOUserPCIDevice {
+ VFIOPCIDevice device;
+ SocketAddress *socket;
+ bool send_queued; /* all sends are queued */
+ uint32_t wait_time; /* timeout for message replies */
+ bool no_post; /* all region writes are sync */
+};
+
+/*
+ * The server maintains the device's pending interrupts,
+ * via its MSIX table and PBA, so we treat these accesses
+ * like PCI config space and forward them.
+ */
+static uint64_t vfio_user_pba_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ VFIOPCIDevice *vdev = opaque;
+ VFIORegion *region = &vdev->bars[vdev->msix->pba_bar].region;
+ uint64_t data;
+
+ /* server copy is what matters */
+ data = vfio_region_read(region, addr + vdev->msix->pba_offset, size);
+ return data;
+}
+
+static void vfio_user_pba_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ /* dropped */
+}
+
+static const MemoryRegionOps vfio_user_pba_ops = {
+ .read = vfio_user_pba_read,
+ .write = vfio_user_pba_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_user_msix_setup(VFIOPCIDevice *vdev)
+{
+ MemoryRegion *vfio_reg, *msix_reg, *pba_reg;
+
+ pba_reg = g_new0(MemoryRegion, 1);
+ vdev->msix->pba_region = pba_reg;
+
+ vfio_reg = vdev->bars[vdev->msix->pba_bar].mr;
+ msix_reg = &vdev->pdev.msix_pba_mmio;
+ memory_region_init_io(pba_reg, OBJECT(vdev), &vfio_user_pba_ops, vdev,
+ "VFIO MSIX PBA", int128_get64(msix_reg->size));
+ memory_region_add_subregion_overlap(vfio_reg, vdev->msix->pba_offset,
+ pba_reg, 1);
+}
+
+static void vfio_user_msix_teardown(VFIOPCIDevice *vdev)
+{
+ MemoryRegion *mr, *sub;
+
+ mr = vdev->bars[vdev->msix->pba_bar].mr;
+ sub = vdev->msix->pba_region;
+ memory_region_del_subregion(mr, sub);
+
+ g_free(vdev->msix->pba_region);
+ vdev->msix->pba_region = NULL;
+}
+
+static void vfio_user_dma_read(VFIOPCIDevice *vdev, VFIOUserDMARW *msg)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ VFIOUserProxy *proxy = vdev->vbasedev.proxy;
+ VFIOUserDMARW *res;
+ MemTxResult r;
+ size_t size;
+
+ if (msg->hdr.size < sizeof(*msg)) {
+ vfio_user_send_error(proxy, &msg->hdr, EINVAL);
+ return;
+ }
+ if (msg->count > proxy->max_xfer_size) {
+ vfio_user_send_error(proxy, &msg->hdr, E2BIG);
+ return;
+ }
+
+ /* switch to our own message buffer */
+ size = msg->count + sizeof(VFIOUserDMARW);
+ res = g_malloc0(size);
+ memcpy(res, msg, sizeof(*res));
+ g_free(msg);
+
+ r = pci_dma_read(pdev, res->offset, &res->data, res->count);
+
+ switch (r) {
+ case MEMTX_OK:
+ if (res->hdr.flags & VFIO_USER_NO_REPLY) {
+ g_free(res);
+ return;
+ }
+ vfio_user_send_reply(proxy, &res->hdr, size);
+ break;
+ case MEMTX_ERROR:
+ vfio_user_send_error(proxy, &res->hdr, EFAULT);
+ break;
+ case MEMTX_DECODE_ERROR:
+ vfio_user_send_error(proxy, &res->hdr, ENODEV);
+ break;
+ case MEMTX_ACCESS_ERROR:
+ vfio_user_send_error(proxy, &res->hdr, EPERM);
+ break;
+ default:
+ error_printf("vfio_user_dma_read unknown error %d\n", r);
+ vfio_user_send_error(vdev->vbasedev.proxy, &res->hdr, EINVAL);
+ }
+}
+
+static void vfio_user_dma_write(VFIOPCIDevice *vdev, VFIOUserDMARW *msg)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ VFIOUserProxy *proxy = vdev->vbasedev.proxy;
+ MemTxResult r;
+
+ if (msg->hdr.size < sizeof(*msg)) {
+ vfio_user_send_error(proxy, &msg->hdr, EINVAL);
+ return;
+ }
+ /* make sure transfer count isn't larger than the message data */
+ if (msg->count > msg->hdr.size - sizeof(*msg)) {
+ vfio_user_send_error(proxy, &msg->hdr, E2BIG);
+ return;
+ }
+
+ r = pci_dma_write(pdev, msg->offset, &msg->data, msg->count);
+
+ switch (r) {
+ case MEMTX_OK:
+ if ((msg->hdr.flags & VFIO_USER_NO_REPLY) == 0) {
+ vfio_user_send_reply(proxy, &msg->hdr, sizeof(msg->hdr));
+ } else {
+ g_free(msg);
+ }
+ break;
+ case MEMTX_ERROR:
+ vfio_user_send_error(proxy, &msg->hdr, EFAULT);
+ break;
+ case MEMTX_DECODE_ERROR:
+ vfio_user_send_error(proxy, &msg->hdr, ENODEV);
+ break;
+ case MEMTX_ACCESS_ERROR:
+ vfio_user_send_error(proxy, &msg->hdr, EPERM);
+ break;
+ default:
+ error_printf("vfio_user_dma_write unknown error %d\n", r);
+ vfio_user_send_error(vdev->vbasedev.proxy, &msg->hdr, EINVAL);
+ }
+}
+
+/*
+ * Incoming request message callback.
+ *
+ * Runs off main loop, so BQL held.
+ */
+static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg)
+{
+ VFIOPCIDevice *vdev = opaque;
+ VFIOUserHdr *hdr = msg->hdr;
+
+ /* no incoming PCI requests pass FDs */
+ if (msg->fds != NULL) {
+ vfio_user_send_error(vdev->vbasedev.proxy, hdr, EINVAL);
+ vfio_user_putfds(msg);
+ return;
+ }
+
+ switch (hdr->command) {
+ case VFIO_USER_DMA_READ:
+ vfio_user_dma_read(vdev, (VFIOUserDMARW *)hdr);
+ break;
+ case VFIO_USER_DMA_WRITE:
+ vfio_user_dma_write(vdev, (VFIOUserDMARW *)hdr);
+ break;
+ default:
+ error_printf("vfio_user_pci_process_req unknown cmd %d\n",
+ hdr->command);
+ vfio_user_send_error(vdev->vbasedev.proxy, hdr, ENOSYS);
+ }
+}
+
+/*
+ * Emulated devices don't use host hot reset
+ */
+static void vfio_user_compute_needs_reset(VFIODevice *vbasedev)
+{
+ vbasedev->needs_reset = false;
+}
+
+static Object *vfio_user_pci_get_object(VFIODevice *vbasedev)
+{
+ VFIOUserPCIDevice *vdev = container_of(vbasedev, VFIOUserPCIDevice,
+ device.vbasedev);
+
+ return OBJECT(vdev);
+}
+
+static VFIODeviceOps vfio_user_pci_ops = {
+ .vfio_compute_needs_reset = vfio_user_compute_needs_reset,
+ .vfio_eoi = vfio_pci_intx_eoi,
+ .vfio_get_object = vfio_user_pci_get_object,
+ /* No live migration support yet. */
+ .vfio_save_config = NULL,
+ .vfio_load_config = NULL,
+};
+
+static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp)
+{
+ ERRP_GUARD();
+ VFIOUserPCIDevice *udev = VFIO_USER_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
+ const char *sock_name;
+ AddressSpace *as;
+ SocketAddress addr;
+ VFIOUserProxy *proxy;
+
+ if (!udev->socket) {
+ error_setg(errp, "No socket specified");
+ error_append_hint(errp, "e.g. -device '{"
+ "\"driver\":\"vfio-user-pci\", "
+ "\"socket\": {\"path\": \"/tmp/vfio-user.sock\", "
+ "\"type\": \"unix\"}'"
+ "}'\n");
+ return;
+ }
+
+ sock_name = udev->socket->u.q_unix.path;
+
+ vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.type = SOCKET_ADDRESS_TYPE_UNIX;
+ addr.u.q_unix.path = (char *)sock_name;
+ proxy = vfio_user_connect_dev(&addr, errp);
+ if (!proxy) {
+ return;
+ }
+ vbasedev->proxy = proxy;
+ vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev);
+
+ vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name);
+
+ if (udev->send_queued) {
+ proxy->flags |= VFIO_PROXY_FORCE_QUEUED;
+ }
+
+ if (udev->no_post) {
+ proxy->flags |= VFIO_PROXY_NO_POST;
+ }
+
+ /* user specified or 5 sec default */
+ proxy->wait_time = udev->wait_time;
+
+ if (!vfio_user_validate_version(proxy, errp)) {
+ goto error;
+ }
+
+ /*
+ * Use socket-based device I/O instead of vfio kernel driver.
+ */
+ vbasedev->io_ops = &vfio_user_device_io_ops_sock;
+
+ /*
+ * vfio-user devices are effectively mdevs (don't use a host iommu).
+ */
+ vbasedev->mdev = true;
+
+ /*
+ * Enable per-region fds.
+ */
+ vbasedev->use_region_fds = true;
+
+ as = pci_device_iommu_address_space(pdev);
+ if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER,
+ vbasedev->name, vbasedev,
+ as, errp)) {
+ goto error;
+ }
+
+ if (!vfio_pci_populate_device(vdev, errp)) {
+ goto error;
+ }
+
+ if (!vfio_pci_config_setup(vdev, errp)) {
+ goto error;
+ }
+
+ /*
+ * vfio_pci_config_setup will have registered the device's BARs
+ * and setup any MSIX BARs, so errors after it succeeds must
+ * use out_teardown
+ */
+
+ if (!vfio_pci_add_capabilities(vdev, errp)) {
+ goto out_teardown;
+ }
+
+ if (vdev->msix != NULL) {
+ vfio_user_msix_setup(vdev);
+ }
+
+ if (!vfio_pci_interrupt_setup(vdev, errp)) {
+ goto out_teardown;
+ }
+
+ vfio_pci_register_err_notifier(vdev);
+ vfio_pci_register_req_notifier(vdev);
+
+ return;
+
+out_teardown:
+ vfio_pci_teardown_msi(vdev);
+ vfio_pci_bars_exit(vdev);
+error:
+ error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
+ vfio_pci_put_device(vdev);
+}
+
+static void vfio_user_instance_init(Object *obj)
+{
+ PCIDevice *pci_dev = PCI_DEVICE(obj);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
+ VFIODevice *vbasedev = &vdev->vbasedev;
+
+ device_add_bootindex_property(obj, &vdev->bootindex,
+ "bootindex", NULL,
+ &pci_dev->qdev);
+ vdev->host.domain = ~0U;
+ vdev->host.bus = ~0U;
+ vdev->host.slot = ~0U;
+ vdev->host.function = ~0U;
+
+ vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_PCI, &vfio_user_pci_ops,
+ DEVICE(vdev), false);
+
+ vdev->nv_gpudirect_clique = 0xFF;
+
+ /*
+ * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command
+ * line, therefore, no need to wait to realize like other devices.
+ */
+ pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
+}
+
+static void vfio_user_instance_finalize(Object *obj)
+{
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
+ VFIODevice *vbasedev = &vdev->vbasedev;
+
+ if (vdev->msix != NULL) {
+ vfio_user_msix_teardown(vdev);
+ }
+
+ vfio_pci_put_device(vdev);
+
+ if (vbasedev->proxy != NULL) {
+ vfio_user_disconnect(vbasedev->proxy);
+ }
+}
+
+static void vfio_user_pci_reset(DeviceState *dev)
+{
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(dev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
+
+ vfio_pci_pre_reset(vdev);
+
+ if (vbasedev->reset_works) {
+ vfio_user_device_reset(vbasedev->proxy);
+ }
+
+ vfio_pci_post_reset(vdev);
+}
+
+static const Property vfio_user_pci_dev_properties[] = {
+ DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice,
+ vendor_id, PCI_ANY_ID),
+ DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice,
+ device_id, PCI_ANY_ID),
+ DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice,
+ sub_vendor_id, PCI_ANY_ID),
+ DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
+ sub_device_id, PCI_ANY_ID),
+ DEFINE_PROP_BOOL("x-send-queued", VFIOUserPCIDevice, send_queued, false),
+ DEFINE_PROP_UINT32("x-msg-timeout", VFIOUserPCIDevice, wait_time, 5000),
+ DEFINE_PROP_BOOL("x-no-posted-writes", VFIOUserPCIDevice, no_post, false),
+};
+
+static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ VFIOUserPCIDevice *udev = VFIO_USER_PCI(obj);
+ bool success;
+
+ if (udev->device.vbasedev.proxy) {
+ error_setg(errp, "Proxy is connected");
+ return;
+ }
+
+ qapi_free_SocketAddress(udev->socket);
+
+ udev->socket = NULL;
+
+ success = visit_type_SocketAddress(v, name, &udev->socket, errp);
+
+ if (!success) {
+ return;
+ }
+
+ if (udev->socket->type != SOCKET_ADDRESS_TYPE_UNIX) {
+ error_setg(errp, "Unsupported socket type %s",
+ SocketAddressType_str(udev->socket->type));
+ qapi_free_SocketAddress(udev->socket);
+ udev->socket = NULL;
+ return;
+ }
+}
+
+static void vfio_user_pci_dev_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
+
+ device_class_set_legacy_reset(dc, vfio_user_pci_reset);
+ device_class_set_props(dc, vfio_user_pci_dev_properties);
+
+ object_class_property_add(klass, "socket", "SocketAddress", NULL,
+ vfio_user_pci_set_socket, NULL, NULL);
+ object_class_property_set_description(klass, "socket",
+ "SocketAddress (UNIX sockets only)");
+
+ dc->desc = "VFIO over socket PCI device assignment";
+ pdc->realize = vfio_user_pci_realize;
+}
+
+static const TypeInfo vfio_user_pci_dev_info = {
+ .name = TYPE_VFIO_USER_PCI,
+ .parent = TYPE_VFIO_PCI_BASE,
+ .instance_size = sizeof(VFIOUserPCIDevice),
+ .class_init = vfio_user_pci_dev_class_init,
+ .instance_init = vfio_user_instance_init,
+ .instance_finalize = vfio_user_instance_finalize,
+};
+
+static void register_vfio_user_dev_type(void)
+{
+ type_register_static(&vfio_user_pci_dev_info);
+}
+
+ type_init(register_vfio_user_dev_type)
diff --git a/hw/vfio-user/protocol.h b/hw/vfio-user/protocol.h
new file mode 100644
index 0000000..3249a4a
--- /dev/null
+++ b/hw/vfio-user/protocol.h
@@ -0,0 +1,242 @@
+#ifndef VFIO_USER_PROTOCOL_H
+#define VFIO_USER_PROTOCOL_H
+
+/*
+ * vfio protocol over a UNIX socket.
+ *
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
+ *
+ * Each message has a standard header that describes the command
+ * being sent, which is almost always a VFIO ioctl().
+ *
+ * The header may be followed by command-specific data, such as the
+ * region and offset info for read and write commands.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+typedef struct {
+ uint16_t id;
+ uint16_t command;
+ uint32_t size;
+ uint32_t flags;
+ uint32_t error_reply;
+} VFIOUserHdr;
+
+/* VFIOUserHdr commands */
+enum vfio_user_command {
+ VFIO_USER_VERSION = 1,
+ VFIO_USER_DMA_MAP = 2,
+ VFIO_USER_DMA_UNMAP = 3,
+ VFIO_USER_DEVICE_GET_INFO = 4,
+ VFIO_USER_DEVICE_GET_REGION_INFO = 5,
+ VFIO_USER_DEVICE_GET_REGION_IO_FDS = 6,
+ VFIO_USER_DEVICE_GET_IRQ_INFO = 7,
+ VFIO_USER_DEVICE_SET_IRQS = 8,
+ VFIO_USER_REGION_READ = 9,
+ VFIO_USER_REGION_WRITE = 10,
+ VFIO_USER_DMA_READ = 11,
+ VFIO_USER_DMA_WRITE = 12,
+ VFIO_USER_DEVICE_RESET = 13,
+ VFIO_USER_DIRTY_PAGES = 14,
+ VFIO_USER_REGION_WRITE_MULTI = 15,
+ VFIO_USER_MAX,
+};
+
+/* VFIOUserHdr flags */
+#define VFIO_USER_REQUEST 0x0
+#define VFIO_USER_REPLY 0x1
+#define VFIO_USER_TYPE 0xF
+
+#define VFIO_USER_NO_REPLY 0x10
+#define VFIO_USER_ERROR 0x20
+
+
+/*
+ * VFIO_USER_VERSION
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint16_t major;
+ uint16_t minor;
+ char capabilities[];
+} VFIOUserVersion;
+
+#define VFIO_USER_MAJOR_VER 0
+#define VFIO_USER_MINOR_VER 0
+
+#define VFIO_USER_CAP "capabilities"
+
+/* "capabilities" members */
+#define VFIO_USER_CAP_MAX_FDS "max_msg_fds"
+#define VFIO_USER_CAP_MAX_XFER "max_data_xfer_size"
+#define VFIO_USER_CAP_PGSIZES "pgsizes"
+#define VFIO_USER_CAP_MAP_MAX "max_dma_maps"
+#define VFIO_USER_CAP_MIGR "migration"
+#define VFIO_USER_CAP_MULTI "write_multiple"
+
+/* "migration" members */
+#define VFIO_USER_CAP_PGSIZE "pgsize"
+#define VFIO_USER_CAP_MAX_BITMAP "max_bitmap_size"
+
+/*
+ * Max FDs mainly comes into play when a device supports multiple interrupts
+ * where each ones uses an eventfd to inject it into the guest.
+ * It is clamped by the the number of FDs the qio channel supports in a
+ * single message.
+ */
+#define VFIO_USER_DEF_MAX_FDS 8
+#define VFIO_USER_MAX_MAX_FDS 16
+
+/*
+ * Max transfer limits the amount of data in region and DMA messages.
+ * Region R/W will be very small (limited by how much a single instruction
+ * can process) so just use a reasonable limit here.
+ */
+#define VFIO_USER_DEF_MAX_XFER (1024 * 1024)
+#define VFIO_USER_MAX_MAX_XFER (64 * 1024 * 1024)
+
+/*
+ * Default pagesizes supported is 4k.
+ */
+#define VFIO_USER_DEF_PGSIZE 4096
+
+/*
+ * Default max number of DMA mappings is stolen from the
+ * linux kernel "dma_entry_limit"
+ */
+#define VFIO_USER_DEF_MAP_MAX 65535
+
+/*
+ * Default max bitmap size is also take from the linux kernel,
+ * where usage of signed ints limits the VA range to 2^31 bytes.
+ * Dividing that by the number of bits per byte yields 256MB
+ */
+#define VFIO_USER_DEF_MAX_BITMAP (256 * 1024 * 1024)
+
+/*
+ * VFIO_USER_DMA_MAP
+ * imported from struct vfio_iommu_type1_dma_map
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint32_t argsz;
+ uint32_t flags;
+ uint64_t offset; /* FD offset */
+ uint64_t iova;
+ uint64_t size;
+} VFIOUserDMAMap;
+
+/*
+ * VFIO_USER_DMA_UNMAP
+ * imported from struct vfio_iommu_type1_dma_unmap
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint32_t argsz;
+ uint32_t flags;
+ uint64_t iova;
+ uint64_t size;
+} VFIOUserDMAUnmap;
+
+/*
+ * VFIO_USER_DEVICE_GET_INFO
+ * imported from struct vfio_device_info
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint32_t argsz;
+ uint32_t flags;
+ uint32_t num_regions;
+ uint32_t num_irqs;
+} VFIOUserDeviceInfo;
+
+/*
+ * VFIO_USER_DEVICE_GET_REGION_INFO
+ * imported from struct vfio_region_info
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint32_t argsz;
+ uint32_t flags;
+ uint32_t index;
+ uint32_t cap_offset;
+ uint64_t size;
+ uint64_t offset;
+} VFIOUserRegionInfo;
+
+/*
+ * VFIO_USER_DEVICE_GET_IRQ_INFO
+ * imported from struct vfio_irq_info
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint32_t argsz;
+ uint32_t flags;
+ uint32_t index;
+ uint32_t count;
+} VFIOUserIRQInfo;
+
+/*
+ * VFIO_USER_DEVICE_SET_IRQS
+ * imported from struct vfio_irq_set
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint32_t argsz;
+ uint32_t flags;
+ uint32_t index;
+ uint32_t start;
+ uint32_t count;
+} VFIOUserIRQSet;
+
+/*
+ * VFIO_USER_REGION_READ
+ * VFIO_USER_REGION_WRITE
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint64_t offset;
+ uint32_t region;
+ uint32_t count;
+ char data[];
+} VFIOUserRegionRW;
+
+/*
+ * VFIO_USER_DMA_READ
+ * VFIO_USER_DMA_WRITE
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint64_t offset;
+ uint32_t count;
+ char data[];
+} VFIOUserDMARW;
+
+/* imported from struct vfio_bitmap */
+typedef struct {
+ uint64_t pgsize;
+ uint64_t size;
+ char data[];
+} VFIOUserBitmap;
+
+/*
+ * VFIO_USER_REGION_WRITE_MULTI
+ */
+#define VFIO_USER_MULTI_DATA 8
+#define VFIO_USER_MULTI_MAX 200
+
+typedef struct {
+ uint64_t offset;
+ uint32_t region;
+ uint32_t count;
+ char data[VFIO_USER_MULTI_DATA];
+} VFIOUserWROne;
+
+typedef struct {
+ VFIOUserHdr hdr;
+ uint64_t wr_cnt;
+ VFIOUserWROne wrs[VFIO_USER_MULTI_MAX];
+} VFIOUserWRMulti;
+
+#endif /* VFIO_USER_PROTOCOL_H */
diff --git a/hw/vfio-user/proxy.c b/hw/vfio-user/proxy.c
new file mode 100644
index 0000000..c418954
--- /dev/null
+++ b/hw/vfio-user/proxy.c
@@ -0,0 +1,1356 @@
+/*
+ * vfio protocol over a UNIX socket.
+ *
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio-user/proxy.h"
+#include "hw/vfio-user/trace.h"
+#include "qapi/error.h"
+#include "qobject/qbool.h"
+#include "qobject/qdict.h"
+#include "qobject/qjson.h"
+#include "qobject/qnum.h"
+#include "qemu/error-report.h"
+#include "qemu/lockable.h"
+#include "qemu/main-loop.h"
+#include "qemu/thread.h"
+#include "system/iothread.h"
+
+static IOThread *vfio_user_iothread;
+
+static void vfio_user_shutdown(VFIOUserProxy *proxy);
+static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds);
+static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg);
+
+static void vfio_user_recv(void *opaque);
+static void vfio_user_send(void *opaque);
+static void vfio_user_cb(void *opaque);
+
+static void vfio_user_request(void *opaque);
+
+static inline void vfio_user_set_error(VFIOUserHdr *hdr, uint32_t err)
+{
+ hdr->flags |= VFIO_USER_ERROR;
+ hdr->error_reply = err;
+}
+
+/*
+ * Functions called by main, CPU, or iothread threads
+ */
+
+static void vfio_user_shutdown(VFIOUserProxy *proxy)
+{
+ qio_channel_shutdown(proxy->ioc, QIO_CHANNEL_SHUTDOWN_READ, NULL);
+ qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, NULL,
+ proxy->ctx, NULL, NULL);
+}
+
+/*
+ * Same return values as qio_channel_writev_full():
+ *
+ * QIO_CHANNEL_ERR_BLOCK: *errp not set
+ * -1: *errp will be populated
+ * otherwise: bytes written
+ */
+static ssize_t vfio_user_send_qio(VFIOUserProxy *proxy, VFIOUserMsg *msg,
+ Error **errp)
+{
+ VFIOUserFDs *fds = msg->fds;
+ struct iovec iov = {
+ .iov_base = msg->hdr,
+ .iov_len = msg->hdr->size,
+ };
+ size_t numfds = 0;
+ int *fdp = NULL;
+ ssize_t ret;
+
+ if (fds != NULL && fds->send_fds != 0) {
+ numfds = fds->send_fds;
+ fdp = fds->fds;
+ }
+
+ ret = qio_channel_writev_full(proxy->ioc, &iov, 1, fdp, numfds, 0, errp);
+
+ if (ret == -1) {
+ vfio_user_set_error(msg->hdr, EIO);
+ vfio_user_shutdown(proxy);
+ }
+ trace_vfio_user_send_write(msg->hdr->id, ret);
+
+ return ret;
+}
+
+static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds)
+{
+ VFIOUserMsg *msg;
+
+ msg = QTAILQ_FIRST(&proxy->free);
+ if (msg != NULL) {
+ QTAILQ_REMOVE(&proxy->free, msg, next);
+ } else {
+ msg = g_malloc0(sizeof(*msg));
+ qemu_cond_init(&msg->cv);
+ }
+
+ msg->hdr = hdr;
+ msg->fds = fds;
+ return msg;
+}
+
+/*
+ * Recycle a message list entry to the free list.
+ */
+static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg)
+{
+ if (msg->type == VFIO_MSG_NONE) {
+ error_printf("vfio_user_recycle - freeing free msg\n");
+ return;
+ }
+
+ /* free msg buffer if no one is waiting to consume the reply */
+ if (msg->type == VFIO_MSG_NOWAIT || msg->type == VFIO_MSG_ASYNC) {
+ g_free(msg->hdr);
+ if (msg->fds != NULL) {
+ g_free(msg->fds);
+ }
+ }
+
+ msg->type = VFIO_MSG_NONE;
+ msg->hdr = NULL;
+ msg->fds = NULL;
+ msg->complete = false;
+ msg->pending = false;
+ QTAILQ_INSERT_HEAD(&proxy->free, msg, next);
+}
+
+VFIOUserFDs *vfio_user_getfds(int numfds)
+{
+ VFIOUserFDs *fds = g_malloc0(sizeof(*fds) + (numfds * sizeof(int)));
+
+ fds->fds = (int *)((char *)fds + sizeof(*fds));
+
+ return fds;
+}
+
+/*
+ * Functions only called by iothread
+ */
+
+/*
+ * Process a received message.
+ */
+static void vfio_user_process(VFIOUserProxy *proxy, VFIOUserMsg *msg,
+ bool isreply)
+{
+
+ /*
+ * Replies signal a waiter, if none just check for errors
+ * and free the message buffer.
+ *
+ * Requests get queued for the BH.
+ */
+ if (isreply) {
+ msg->complete = true;
+ if (msg->type == VFIO_MSG_WAIT) {
+ qemu_cond_signal(&msg->cv);
+ } else {
+ if (msg->hdr->flags & VFIO_USER_ERROR) {
+ error_printf("vfio_user_process: error reply on async ");
+ error_printf("request command %x error %s\n",
+ msg->hdr->command,
+ strerror(msg->hdr->error_reply));
+ }
+ /* youngest nowait msg has been ack'd */
+ if (proxy->last_nowait == msg) {
+ proxy->last_nowait = NULL;
+ }
+ vfio_user_recycle(proxy, msg);
+ }
+ } else {
+ QTAILQ_INSERT_TAIL(&proxy->incoming, msg, next);
+ qemu_bh_schedule(proxy->req_bh);
+ }
+}
+
+/*
+ * Complete a partial message read
+ */
+static int vfio_user_complete(VFIOUserProxy *proxy, Error **errp)
+{
+ VFIOUserMsg *msg = proxy->part_recv;
+ size_t msgleft = proxy->recv_left;
+ bool isreply;
+ char *data;
+ int ret;
+
+ data = (char *)msg->hdr + (msg->hdr->size - msgleft);
+ while (msgleft > 0) {
+ ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
+
+ /* error or would block */
+ if (ret <= 0) {
+ /* try for rest on next iternation */
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ proxy->recv_left = msgleft;
+ }
+ return ret;
+ }
+ trace_vfio_user_recv_read(msg->hdr->id, ret);
+
+ msgleft -= ret;
+ data += ret;
+ }
+
+ /*
+ * Read complete message, process it.
+ */
+ proxy->part_recv = NULL;
+ proxy->recv_left = 0;
+ isreply = (msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REPLY;
+ vfio_user_process(proxy, msg, isreply);
+
+ /* return positive value */
+ return 1;
+}
+
+/*
+ * Receive and process one incoming message.
+ *
+ * For replies, find matching outgoing request and wake any waiters.
+ * For requests, queue in incoming list and run request BH.
+ */
+static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
+{
+ VFIOUserMsg *msg = NULL;
+ g_autofree int *fdp = NULL;
+ VFIOUserFDs *reqfds;
+ VFIOUserHdr hdr;
+ struct iovec iov = {
+ .iov_base = &hdr,
+ .iov_len = sizeof(hdr),
+ };
+ bool isreply = false;
+ int i, ret;
+ size_t msgleft, numfds = 0;
+ char *data = NULL;
+ char *buf = NULL;
+
+ /*
+ * Complete any partial reads
+ */
+ if (proxy->part_recv != NULL) {
+ ret = vfio_user_complete(proxy, errp);
+
+ /* still not complete, try later */
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ return ret;
+ }
+
+ if (ret <= 0) {
+ goto fatal;
+ }
+ /* else fall into reading another msg */
+ }
+
+ /*
+ * Read header
+ */
+ ret = qio_channel_readv_full(proxy->ioc, &iov, 1, &fdp, &numfds, 0,
+ errp);
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ return ret;
+ }
+
+ /* read error or other side closed connection */
+ if (ret <= 0) {
+ goto fatal;
+ }
+
+ if (ret < sizeof(hdr)) {
+ error_setg(errp, "short read of header");
+ goto fatal;
+ }
+
+ /*
+ * Validate header
+ */
+ if (hdr.size < sizeof(VFIOUserHdr)) {
+ error_setg(errp, "bad header size");
+ goto fatal;
+ }
+ switch (hdr.flags & VFIO_USER_TYPE) {
+ case VFIO_USER_REQUEST:
+ isreply = false;
+ break;
+ case VFIO_USER_REPLY:
+ isreply = true;
+ break;
+ default:
+ error_setg(errp, "unknown message type");
+ goto fatal;
+ }
+ trace_vfio_user_recv_hdr(proxy->sockname, hdr.id, hdr.command, hdr.size,
+ hdr.flags);
+
+ /*
+ * For replies, find the matching pending request.
+ * For requests, reap incoming FDs.
+ */
+ if (isreply) {
+ QTAILQ_FOREACH(msg, &proxy->pending, next) {
+ if (hdr.id == msg->id) {
+ break;
+ }
+ }
+ if (msg == NULL) {
+ error_setg(errp, "unexpected reply");
+ goto err;
+ }
+ QTAILQ_REMOVE(&proxy->pending, msg, next);
+
+ /*
+ * Process any received FDs
+ */
+ if (numfds != 0) {
+ if (msg->fds == NULL || msg->fds->recv_fds < numfds) {
+ error_setg(errp, "unexpected FDs");
+ goto err;
+ }
+ msg->fds->recv_fds = numfds;
+ memcpy(msg->fds->fds, fdp, numfds * sizeof(int));
+ }
+ } else {
+ if (numfds != 0) {
+ reqfds = vfio_user_getfds(numfds);
+ memcpy(reqfds->fds, fdp, numfds * sizeof(int));
+ } else {
+ reqfds = NULL;
+ }
+ }
+
+ /*
+ * Put the whole message into a single buffer.
+ */
+ if (isreply) {
+ if (hdr.size > msg->rsize) {
+ error_setg(errp, "reply larger than recv buffer");
+ goto err;
+ }
+ *msg->hdr = hdr;
+ data = (char *)msg->hdr + sizeof(hdr);
+ } else {
+ if (hdr.size > proxy->max_xfer_size + sizeof(VFIOUserDMARW)) {
+ error_setg(errp, "vfio_user_recv request larger than max");
+ goto err;
+ }
+ buf = g_malloc0(hdr.size);
+ memcpy(buf, &hdr, sizeof(hdr));
+ data = buf + sizeof(hdr);
+ msg = vfio_user_getmsg(proxy, (VFIOUserHdr *)buf, reqfds);
+ msg->type = VFIO_MSG_REQ;
+ }
+
+ /*
+ * Read rest of message.
+ */
+ msgleft = hdr.size - sizeof(hdr);
+ while (msgleft > 0) {
+ ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
+
+ /* prepare to complete read on next iternation */
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ proxy->part_recv = msg;
+ proxy->recv_left = msgleft;
+ return ret;
+ }
+
+ if (ret <= 0) {
+ goto fatal;
+ }
+ trace_vfio_user_recv_read(hdr.id, ret);
+
+ msgleft -= ret;
+ data += ret;
+ }
+
+ vfio_user_process(proxy, msg, isreply);
+ return 0;
+
+ /*
+ * fatal means the other side closed or we don't trust the stream
+ * err means this message is corrupt
+ */
+fatal:
+ vfio_user_shutdown(proxy);
+ proxy->state = VFIO_PROXY_ERROR;
+
+ /* set error if server side closed */
+ if (ret == 0) {
+ error_setg(errp, "server closed socket");
+ }
+
+err:
+ for (i = 0; i < numfds; i++) {
+ close(fdp[i]);
+ }
+ if (isreply && msg != NULL) {
+ /* force an error to keep sending thread from hanging */
+ vfio_user_set_error(msg->hdr, EINVAL);
+ msg->complete = true;
+ qemu_cond_signal(&msg->cv);
+ }
+ return -1;
+}
+
+static void vfio_user_recv(void *opaque)
+{
+ VFIOUserProxy *proxy = opaque;
+
+ QEMU_LOCK_GUARD(&proxy->lock);
+
+ if (proxy->state == VFIO_PROXY_CONNECTED) {
+ Error *local_err = NULL;
+
+ while (vfio_user_recv_one(proxy, &local_err) == 0) {
+ ;
+ }
+
+ if (local_err != NULL) {
+ error_report_err(local_err);
+ }
+ }
+}
+
+/*
+ * Send a single message, same return semantics as vfio_user_send_qio().
+ *
+ * Sent async messages are freed, others are moved to pending queue.
+ */
+static ssize_t vfio_user_send_one(VFIOUserProxy *proxy, Error **errp)
+{
+ VFIOUserMsg *msg;
+ ssize_t ret;
+
+ msg = QTAILQ_FIRST(&proxy->outgoing);
+ ret = vfio_user_send_qio(proxy, msg, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ QTAILQ_REMOVE(&proxy->outgoing, msg, next);
+ proxy->num_outgoing--;
+ if (msg->type == VFIO_MSG_ASYNC) {
+ vfio_user_recycle(proxy, msg);
+ } else {
+ QTAILQ_INSERT_TAIL(&proxy->pending, msg, next);
+ msg->pending = true;
+ }
+
+ return ret;
+}
+
+/*
+ * Send messages from outgoing queue when the socket buffer has space.
+ * If we deplete 'outgoing', remove ourselves from the poll list.
+ */
+static void vfio_user_send(void *opaque)
+{
+ VFIOUserProxy *proxy = opaque;
+
+ QEMU_LOCK_GUARD(&proxy->lock);
+
+ if (proxy->state == VFIO_PROXY_CONNECTED) {
+ while (!QTAILQ_EMPTY(&proxy->outgoing)) {
+ Error *local_err = NULL;
+ int ret;
+
+ ret = vfio_user_send_one(proxy, &local_err);
+
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ return;
+ } else if (ret == -1) {
+ error_report_err(local_err);
+ return;
+ }
+ }
+ qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
+ vfio_user_recv, NULL, NULL, proxy);
+
+ /* queue empty - send any pending multi write msgs */
+ if (proxy->wr_multi != NULL) {
+ vfio_user_flush_multi(proxy);
+ }
+ }
+}
+
+static void vfio_user_cb(void *opaque)
+{
+ VFIOUserProxy *proxy = opaque;
+
+ QEMU_LOCK_GUARD(&proxy->lock);
+
+ proxy->state = VFIO_PROXY_CLOSED;
+ qemu_cond_signal(&proxy->close_cv);
+}
+
+
+/*
+ * Functions called by main or CPU threads
+ */
+
+/*
+ * Process incoming requests.
+ *
+ * The bus-specific callback has the form:
+ * request(opaque, msg)
+ * where 'opaque' was specified in vfio_user_set_handler
+ * and 'msg' is the inbound message.
+ *
+ * The callback is responsible for disposing of the message buffer,
+ * usually by re-using it when calling vfio_send_reply or vfio_send_error,
+ * both of which free their message buffer when the reply is sent.
+ *
+ * If the callback uses a new buffer, it needs to free the old one.
+ */
+static void vfio_user_request(void *opaque)
+{
+ VFIOUserProxy *proxy = opaque;
+ VFIOUserMsgQ new, free;
+ VFIOUserMsg *msg, *m1;
+
+ /* reap all incoming */
+ QTAILQ_INIT(&new);
+ WITH_QEMU_LOCK_GUARD(&proxy->lock) {
+ QTAILQ_FOREACH_SAFE(msg, &proxy->incoming, next, m1) {
+ QTAILQ_REMOVE(&proxy->incoming, msg, next);
+ QTAILQ_INSERT_TAIL(&new, msg, next);
+ }
+ }
+
+ /* process list */
+ QTAILQ_INIT(&free);
+ QTAILQ_FOREACH_SAFE(msg, &new, next, m1) {
+ QTAILQ_REMOVE(&new, msg, next);
+ trace_vfio_user_recv_request(msg->hdr->command);
+ proxy->request(proxy->req_arg, msg);
+ QTAILQ_INSERT_HEAD(&free, msg, next);
+ }
+
+ /* free list */
+ WITH_QEMU_LOCK_GUARD(&proxy->lock) {
+ QTAILQ_FOREACH_SAFE(msg, &free, next, m1) {
+ vfio_user_recycle(proxy, msg);
+ }
+ }
+}
+
+/*
+ * Messages are queued onto the proxy's outgoing list.
+ *
+ * It handles 3 types of messages:
+ *
+ * async messages - replies and posted writes
+ *
+ * There will be no reply from the server, so message
+ * buffers are freed after they're sent.
+ *
+ * nowait messages - map/unmap during address space transactions
+ *
+ * These are also sent async, but a reply is expected so that
+ * vfio_wait_reqs() can wait for the youngest nowait request.
+ * They transition from the outgoing list to the pending list
+ * when sent, and are freed when the reply is received.
+ *
+ * wait messages - all other requests
+ *
+ * The reply to these messages is waited for by their caller.
+ * They also transition from outgoing to pending when sent, but
+ * the message buffer is returned to the caller with the reply
+ * contents. The caller is responsible for freeing these messages.
+ *
+ * As an optimization, if the outgoing list and the socket send
+ * buffer are empty, the message is sent inline instead of being
+ * added to the outgoing list. The rest of the transitions are
+ * unchanged.
+ */
+static bool vfio_user_send_queued(VFIOUserProxy *proxy, VFIOUserMsg *msg,
+ Error **errp)
+{
+ int ret;
+
+ /* older coalesced writes go first */
+ if (proxy->wr_multi != NULL &&
+ ((msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REQUEST)) {
+ vfio_user_flush_multi(proxy);
+ }
+
+ /*
+ * Unsent outgoing msgs - add to tail
+ */
+ if (!QTAILQ_EMPTY(&proxy->outgoing)) {
+ QTAILQ_INSERT_TAIL(&proxy->outgoing, msg, next);
+ proxy->num_outgoing++;
+ return true;
+ }
+
+ /*
+ * Try inline - if blocked, queue it and kick send poller
+ */
+ if (proxy->flags & VFIO_PROXY_FORCE_QUEUED) {
+ ret = QIO_CHANNEL_ERR_BLOCK;
+ } else {
+ ret = vfio_user_send_qio(proxy, msg, errp);
+ }
+
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ QTAILQ_INSERT_HEAD(&proxy->outgoing, msg, next);
+ proxy->num_outgoing = 1;
+ qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
+ vfio_user_recv, proxy->ctx,
+ vfio_user_send, proxy);
+ return true;
+ }
+ if (ret == -1) {
+ return false;
+ }
+
+ /*
+ * Sent - free async, add others to pending
+ */
+ if (msg->type == VFIO_MSG_ASYNC) {
+ vfio_user_recycle(proxy, msg);
+ } else {
+ QTAILQ_INSERT_TAIL(&proxy->pending, msg, next);
+ msg->pending = true;
+ }
+
+ return true;
+}
+
+/*
+ * nowait send - vfio_wait_reqs() can wait for it later
+ *
+ * Returns false if we did not successfully receive a reply message, in which
+ * case @errp will be populated.
+ *
+ * In either case, ownership of @hdr and @fds is taken, and the caller must
+ * *not* free them itself.
+ */
+bool vfio_user_send_nowait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds, int rsize, Error **errp)
+{
+ VFIOUserMsg *msg;
+
+ QEMU_LOCK_GUARD(&proxy->lock);
+
+ msg = vfio_user_getmsg(proxy, hdr, fds);
+ msg->id = hdr->id;
+ msg->rsize = rsize ? rsize : hdr->size;
+ msg->type = VFIO_MSG_NOWAIT;
+
+ if (hdr->flags & VFIO_USER_NO_REPLY) {
+ error_setg_errno(errp, EINVAL, "%s on NO_REPLY message", __func__);
+ vfio_user_recycle(proxy, msg);
+ return false;
+ }
+
+ if (!vfio_user_send_queued(proxy, msg, errp)) {
+ vfio_user_recycle(proxy, msg);
+ return false;
+ }
+
+ proxy->last_nowait = msg;
+
+ return true;
+}
+
+/*
+ * Returns false if we did not successfully receive a reply message, in which
+ * case @errp will be populated.
+ *
+ * In either case, the caller must free @hdr and @fds if needed.
+ */
+bool vfio_user_send_wait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds, int rsize, Error **errp)
+{
+ VFIOUserMsg *msg;
+ bool ok = false;
+
+ if (hdr->flags & VFIO_USER_NO_REPLY) {
+ error_setg_errno(errp, EINVAL, "%s on NO_REPLY message", __func__);
+ return false;
+ }
+
+ qemu_mutex_lock(&proxy->lock);
+
+ msg = vfio_user_getmsg(proxy, hdr, fds);
+ msg->id = hdr->id;
+ msg->rsize = rsize ? rsize : hdr->size;
+ msg->type = VFIO_MSG_WAIT;
+
+ ok = vfio_user_send_queued(proxy, msg, errp);
+
+ if (ok) {
+ while (!msg->complete) {
+ if (!qemu_cond_timedwait(&msg->cv, &proxy->lock,
+ proxy->wait_time)) {
+ VFIOUserMsgQ *list;
+
+ list = msg->pending ? &proxy->pending : &proxy->outgoing;
+ QTAILQ_REMOVE(list, msg, next);
+ error_setg_errno(errp, ETIMEDOUT,
+ "timed out waiting for reply");
+ ok = false;
+ break;
+ }
+ }
+ }
+
+ vfio_user_recycle(proxy, msg);
+
+ qemu_mutex_unlock(&proxy->lock);
+
+ return ok;
+}
+
+/*
+ * async send - msg can be queued, but will be freed when sent
+ *
+ * Returns false on failure, in which case @errp will be populated.
+ *
+ * In either case, ownership of @hdr and @fds is taken, and the caller must
+ * *not* free them itself.
+ */
+bool vfio_user_send_async(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds, Error **errp)
+{
+ VFIOUserMsg *msg;
+
+ QEMU_LOCK_GUARD(&proxy->lock);
+
+ msg = vfio_user_getmsg(proxy, hdr, fds);
+ msg->id = hdr->id;
+ msg->rsize = 0;
+ msg->type = VFIO_MSG_ASYNC;
+
+ if (!(hdr->flags & (VFIO_USER_NO_REPLY | VFIO_USER_REPLY))) {
+ error_setg_errno(errp, EINVAL, "%s on sync message", __func__);
+ vfio_user_recycle(proxy, msg);
+ return false;
+ }
+
+ if (!vfio_user_send_queued(proxy, msg, errp)) {
+ vfio_user_recycle(proxy, msg);
+ return false;
+ }
+
+ return true;
+}
+
+void vfio_user_wait_reqs(VFIOUserProxy *proxy)
+{
+ VFIOUserMsg *msg;
+
+ /*
+ * Any DMA map/unmap requests sent in the middle
+ * of a memory region transaction were sent nowait.
+ * Wait for them here.
+ */
+ qemu_mutex_lock(&proxy->lock);
+ if (proxy->last_nowait != NULL) {
+ /*
+ * Change type to WAIT to wait for reply
+ */
+ msg = proxy->last_nowait;
+ msg->type = VFIO_MSG_WAIT;
+ proxy->last_nowait = NULL;
+ while (!msg->complete) {
+ if (!qemu_cond_timedwait(&msg->cv, &proxy->lock,
+ proxy->wait_time)) {
+ VFIOUserMsgQ *list;
+
+ list = msg->pending ? &proxy->pending : &proxy->outgoing;
+ QTAILQ_REMOVE(list, msg, next);
+ error_printf("vfio_wait_reqs - timed out\n");
+ break;
+ }
+ }
+
+ if (msg->hdr->flags & VFIO_USER_ERROR) {
+ error_printf("vfio_user_wait_reqs - error reply on async ");
+ error_printf("request: command %x error %s\n", msg->hdr->command,
+ strerror(msg->hdr->error_reply));
+ }
+
+ /*
+ * Change type back to NOWAIT to free
+ */
+ msg->type = VFIO_MSG_NOWAIT;
+ vfio_user_recycle(proxy, msg);
+ }
+
+ qemu_mutex_unlock(&proxy->lock);
+}
+
+/*
+ * Reply to an incoming request.
+ */
+void vfio_user_send_reply(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int size)
+{
+ Error *local_err = NULL;
+
+ if (size < sizeof(VFIOUserHdr)) {
+ error_printf("%s: size too small", __func__);
+ g_free(hdr);
+ return;
+ }
+
+ /*
+ * convert header to associated reply
+ */
+ hdr->flags = VFIO_USER_REPLY;
+ hdr->size = size;
+
+ if (!vfio_user_send_async(proxy, hdr, NULL, &local_err)) {
+ error_report_err(local_err);
+ }
+}
+
+/*
+ * Send an error reply to an incoming request.
+ */
+void vfio_user_send_error(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int error)
+{
+ Error *local_err = NULL;
+
+ /*
+ * convert header to associated reply
+ */
+ hdr->flags = VFIO_USER_REPLY;
+ hdr->flags |= VFIO_USER_ERROR;
+ hdr->error_reply = error;
+ hdr->size = sizeof(*hdr);
+
+ if (!vfio_user_send_async(proxy, hdr, NULL, &local_err)) {
+ error_report_err(local_err);
+ }
+}
+
+/*
+ * Close FDs erroneously received in an incoming request.
+ */
+void vfio_user_putfds(VFIOUserMsg *msg)
+{
+ VFIOUserFDs *fds = msg->fds;
+ int i;
+
+ for (i = 0; i < fds->recv_fds; i++) {
+ close(fds->fds[i]);
+ }
+ g_free(fds);
+ msg->fds = NULL;
+}
+
+void
+vfio_user_disable_posted_writes(VFIOUserProxy *proxy)
+{
+ WITH_QEMU_LOCK_GUARD(&proxy->lock) {
+ proxy->flags |= VFIO_PROXY_NO_POST;
+ }
+}
+
+static QLIST_HEAD(, VFIOUserProxy) vfio_user_sockets =
+ QLIST_HEAD_INITIALIZER(vfio_user_sockets);
+
+VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
+{
+ VFIOUserProxy *proxy;
+ QIOChannelSocket *sioc;
+ QIOChannel *ioc;
+ char *sockname;
+
+ if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
+ error_setg(errp, "vfio_user_connect - bad address family");
+ return NULL;
+ }
+ sockname = addr->u.q_unix.path;
+
+ sioc = qio_channel_socket_new();
+ ioc = QIO_CHANNEL(sioc);
+ if (qio_channel_socket_connect_sync(sioc, addr, errp)) {
+ object_unref(OBJECT(ioc));
+ return NULL;
+ }
+ qio_channel_set_blocking(ioc, false, NULL);
+
+ proxy = g_malloc0(sizeof(VFIOUserProxy));
+ proxy->sockname = g_strdup_printf("unix:%s", sockname);
+ proxy->ioc = ioc;
+
+ /* init defaults */
+ proxy->max_xfer_size = VFIO_USER_DEF_MAX_XFER;
+ proxy->max_send_fds = VFIO_USER_DEF_MAX_FDS;
+ proxy->max_dma = VFIO_USER_DEF_MAP_MAX;
+ proxy->dma_pgsizes = VFIO_USER_DEF_PGSIZE;
+ proxy->max_bitmap = VFIO_USER_DEF_MAX_BITMAP;
+ proxy->migr_pgsize = VFIO_USER_DEF_PGSIZE;
+
+ proxy->flags = VFIO_PROXY_CLIENT;
+ proxy->state = VFIO_PROXY_CONNECTED;
+
+ qemu_mutex_init(&proxy->lock);
+ qemu_cond_init(&proxy->close_cv);
+
+ if (vfio_user_iothread == NULL) {
+ vfio_user_iothread = iothread_create("VFIO user", errp);
+ }
+
+ proxy->ctx = iothread_get_aio_context(vfio_user_iothread);
+ proxy->req_bh = qemu_bh_new(vfio_user_request, proxy);
+
+ QTAILQ_INIT(&proxy->outgoing);
+ QTAILQ_INIT(&proxy->incoming);
+ QTAILQ_INIT(&proxy->free);
+ QTAILQ_INIT(&proxy->pending);
+ QLIST_INSERT_HEAD(&vfio_user_sockets, proxy, next);
+
+ return proxy;
+}
+
+void vfio_user_set_handler(VFIODevice *vbasedev,
+ void (*handler)(void *opaque, VFIOUserMsg *msg),
+ void *req_arg)
+{
+ VFIOUserProxy *proxy = vbasedev->proxy;
+
+ proxy->request = handler;
+ proxy->req_arg = req_arg;
+ qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
+ vfio_user_recv, NULL, NULL, proxy);
+}
+
+void vfio_user_disconnect(VFIOUserProxy *proxy)
+{
+ VFIOUserMsg *r1, *r2;
+
+ qemu_mutex_lock(&proxy->lock);
+
+ /* our side is quitting */
+ if (proxy->state == VFIO_PROXY_CONNECTED) {
+ vfio_user_shutdown(proxy);
+ if (!QTAILQ_EMPTY(&proxy->pending)) {
+ error_printf("vfio_user_disconnect: outstanding requests\n");
+ }
+ }
+ object_unref(OBJECT(proxy->ioc));
+ proxy->ioc = NULL;
+ qemu_bh_delete(proxy->req_bh);
+ proxy->req_bh = NULL;
+
+ proxy->state = VFIO_PROXY_CLOSING;
+ QTAILQ_FOREACH_SAFE(r1, &proxy->outgoing, next, r2) {
+ qemu_cond_destroy(&r1->cv);
+ QTAILQ_REMOVE(&proxy->outgoing, r1, next);
+ g_free(r1);
+ }
+ QTAILQ_FOREACH_SAFE(r1, &proxy->incoming, next, r2) {
+ qemu_cond_destroy(&r1->cv);
+ QTAILQ_REMOVE(&proxy->incoming, r1, next);
+ g_free(r1);
+ }
+ QTAILQ_FOREACH_SAFE(r1, &proxy->pending, next, r2) {
+ qemu_cond_destroy(&r1->cv);
+ QTAILQ_REMOVE(&proxy->pending, r1, next);
+ g_free(r1);
+ }
+ QTAILQ_FOREACH_SAFE(r1, &proxy->free, next, r2) {
+ qemu_cond_destroy(&r1->cv);
+ QTAILQ_REMOVE(&proxy->free, r1, next);
+ g_free(r1);
+ }
+
+ /*
+ * Make sure the iothread isn't blocking anywhere
+ * with a ref to this proxy by waiting for a BH
+ * handler to run after the proxy fd handlers were
+ * deleted above.
+ */
+ aio_bh_schedule_oneshot(proxy->ctx, vfio_user_cb, proxy);
+ qemu_cond_wait(&proxy->close_cv, &proxy->lock);
+
+ /* we now hold the only ref to proxy */
+ qemu_mutex_unlock(&proxy->lock);
+ qemu_cond_destroy(&proxy->close_cv);
+ qemu_mutex_destroy(&proxy->lock);
+
+ QLIST_REMOVE(proxy, next);
+ if (QLIST_EMPTY(&vfio_user_sockets)) {
+ iothread_destroy(vfio_user_iothread);
+ vfio_user_iothread = NULL;
+ }
+
+ g_free(proxy->sockname);
+ g_free(proxy);
+}
+
+void vfio_user_request_msg(VFIOUserHdr *hdr, uint16_t cmd,
+ uint32_t size, uint32_t flags)
+{
+ static uint16_t next_id;
+
+ hdr->id = qatomic_fetch_inc(&next_id);
+ hdr->command = cmd;
+ hdr->size = size;
+ hdr->flags = (flags & ~VFIO_USER_TYPE) | VFIO_USER_REQUEST;
+ hdr->error_reply = 0;
+}
+
+struct cap_entry {
+ const char *name;
+ bool (*check)(VFIOUserProxy *proxy, QObject *qobj, Error **errp);
+};
+
+static bool caps_parse(VFIOUserProxy *proxy, QDict *qdict,
+ struct cap_entry caps[], Error **errp)
+{
+ QObject *qobj;
+ struct cap_entry *p;
+
+ for (p = caps; p->name != NULL; p++) {
+ qobj = qdict_get(qdict, p->name);
+ if (qobj != NULL) {
+ if (!p->check(proxy, qobj, errp)) {
+ return false;
+ }
+ qdict_del(qdict, p->name);
+ }
+ }
+
+ /* warning, for now */
+ if (qdict_size(qdict) != 0) {
+ warn_report("spurious capabilities");
+ }
+ return true;
+}
+
+static bool check_migr_pgsize(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QNum *qn = qobject_to(QNum, qobj);
+ uint64_t pgsize;
+
+ if (qn == NULL || !qnum_get_try_uint(qn, &pgsize)) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_PGSIZE);
+ return false;
+ }
+
+ /* must be larger than default */
+ if (pgsize & (VFIO_USER_DEF_PGSIZE - 1)) {
+ error_setg(errp, "pgsize 0x%"PRIx64" too small", pgsize);
+ return false;
+ }
+
+ proxy->migr_pgsize = pgsize;
+ return true;
+}
+
+static bool check_bitmap(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QNum *qn = qobject_to(QNum, qobj);
+ uint64_t bitmap_size;
+
+ if (qn == NULL || !qnum_get_try_uint(qn, &bitmap_size)) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_BITMAP);
+ return false;
+ }
+
+ /* can only lower it */
+ if (bitmap_size > VFIO_USER_DEF_MAX_BITMAP) {
+ error_setg(errp, "%s too large", VFIO_USER_CAP_MAX_BITMAP);
+ return false;
+ }
+
+ proxy->max_bitmap = bitmap_size;
+ return true;
+}
+
+static struct cap_entry caps_migr[] = {
+ { VFIO_USER_CAP_PGSIZE, check_migr_pgsize },
+ { VFIO_USER_CAP_MAX_BITMAP, check_bitmap },
+ { NULL }
+};
+
+static bool check_max_fds(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QNum *qn = qobject_to(QNum, qobj);
+ uint64_t max_send_fds;
+
+ if (qn == NULL || !qnum_get_try_uint(qn, &max_send_fds) ||
+ max_send_fds > VFIO_USER_MAX_MAX_FDS) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_FDS);
+ return false;
+ }
+ proxy->max_send_fds = max_send_fds;
+ return true;
+}
+
+static bool check_max_xfer(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QNum *qn = qobject_to(QNum, qobj);
+ uint64_t max_xfer_size;
+
+ if (qn == NULL || !qnum_get_try_uint(qn, &max_xfer_size) ||
+ max_xfer_size > VFIO_USER_MAX_MAX_XFER) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_XFER);
+ return false;
+ }
+ proxy->max_xfer_size = max_xfer_size;
+ return true;
+}
+
+static bool check_pgsizes(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QNum *qn = qobject_to(QNum, qobj);
+ uint64_t pgsizes;
+
+ if (qn == NULL || !qnum_get_try_uint(qn, &pgsizes)) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_PGSIZES);
+ return false;
+ }
+
+ /* must be larger than default */
+ if (pgsizes & (VFIO_USER_DEF_PGSIZE - 1)) {
+ error_setg(errp, "pgsize 0x%"PRIx64" too small", pgsizes);
+ return false;
+ }
+
+ proxy->dma_pgsizes = pgsizes;
+ return true;
+}
+
+static bool check_max_dma(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QNum *qn = qobject_to(QNum, qobj);
+ uint64_t max_dma;
+
+ if (qn == NULL || !qnum_get_try_uint(qn, &max_dma)) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_MAP_MAX);
+ return false;
+ }
+
+ /* can only lower it */
+ if (max_dma > VFIO_USER_DEF_MAP_MAX) {
+ error_setg(errp, "%s too large", VFIO_USER_CAP_MAP_MAX);
+ return false;
+ }
+
+ proxy->max_dma = max_dma;
+ return true;
+}
+
+static bool check_migr(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QDict *qdict = qobject_to(QDict, qobj);
+
+ if (qdict == NULL) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_FDS);
+ return true;
+ }
+ return caps_parse(proxy, qdict, caps_migr, errp);
+}
+
+static bool check_multi(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QBool *qb = qobject_to(QBool, qobj);
+
+ if (qb == NULL) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP_MULTI);
+ return false;
+ }
+ if (qbool_get_bool(qb)) {
+ proxy->flags |= VFIO_PROXY_USE_MULTI;
+ }
+ return true;
+}
+
+static struct cap_entry caps_cap[] = {
+ { VFIO_USER_CAP_MAX_FDS, check_max_fds },
+ { VFIO_USER_CAP_MAX_XFER, check_max_xfer },
+ { VFIO_USER_CAP_PGSIZES, check_pgsizes },
+ { VFIO_USER_CAP_MAP_MAX, check_max_dma },
+ { VFIO_USER_CAP_MIGR, check_migr },
+ { VFIO_USER_CAP_MULTI, check_multi },
+ { NULL }
+};
+
+static bool check_cap(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
+{
+ QDict *qdict = qobject_to(QDict, qobj);
+
+ if (qdict == NULL) {
+ error_setg(errp, "malformed %s", VFIO_USER_CAP);
+ return false;
+ }
+ return caps_parse(proxy, qdict, caps_cap, errp);
+}
+
+static struct cap_entry ver_0_0[] = {
+ { VFIO_USER_CAP, check_cap },
+ { NULL }
+};
+
+static bool caps_check(VFIOUserProxy *proxy, int minor, const char *caps,
+ Error **errp)
+{
+ QObject *qobj;
+ QDict *qdict;
+ bool ret;
+
+ qobj = qobject_from_json(caps, NULL);
+ if (qobj == NULL) {
+ error_setg(errp, "malformed capabilities %s", caps);
+ return false;
+ }
+ qdict = qobject_to(QDict, qobj);
+ if (qdict == NULL) {
+ error_setg(errp, "capabilities %s not an object", caps);
+ qobject_unref(qobj);
+ return false;
+ }
+ ret = caps_parse(proxy, qdict, ver_0_0, errp);
+
+ qobject_unref(qobj);
+ return ret;
+}
+
+static GString *caps_json(void)
+{
+ QDict *dict = qdict_new();
+ QDict *capdict = qdict_new();
+ QDict *migdict = qdict_new();
+ GString *str;
+
+ qdict_put_int(migdict, VFIO_USER_CAP_PGSIZE, VFIO_USER_DEF_PGSIZE);
+ qdict_put_int(migdict, VFIO_USER_CAP_MAX_BITMAP, VFIO_USER_DEF_MAX_BITMAP);
+ qdict_put_obj(capdict, VFIO_USER_CAP_MIGR, QOBJECT(migdict));
+
+ qdict_put_int(capdict, VFIO_USER_CAP_MAX_FDS, VFIO_USER_MAX_MAX_FDS);
+ qdict_put_int(capdict, VFIO_USER_CAP_MAX_XFER, VFIO_USER_DEF_MAX_XFER);
+ qdict_put_int(capdict, VFIO_USER_CAP_PGSIZES, VFIO_USER_DEF_PGSIZE);
+ qdict_put_int(capdict, VFIO_USER_CAP_MAP_MAX, VFIO_USER_DEF_MAP_MAX);
+ qdict_put_bool(capdict, VFIO_USER_CAP_MULTI, true);
+
+ qdict_put_obj(dict, VFIO_USER_CAP, QOBJECT(capdict));
+
+ str = qobject_to_json(QOBJECT(dict));
+ qobject_unref(dict);
+ return str;
+}
+
+bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp)
+{
+ g_autofree VFIOUserVersion *msgp = NULL;
+ GString *caps;
+ char *reply;
+ int size, caplen;
+
+ caps = caps_json();
+ caplen = caps->len + 1;
+ size = sizeof(*msgp) + caplen;
+ msgp = g_malloc0(size);
+
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_VERSION, size, 0);
+ msgp->major = VFIO_USER_MAJOR_VER;
+ msgp->minor = VFIO_USER_MINOR_VER;
+ memcpy(&msgp->capabilities, caps->str, caplen);
+ g_string_free(caps, true);
+ trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
+
+ if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, errp)) {
+ return false;
+ }
+
+ if (msgp->hdr.flags & VFIO_USER_ERROR) {
+ error_setg_errno(errp, msgp->hdr.error_reply, "version reply");
+ return false;
+ }
+
+ if (msgp->major != VFIO_USER_MAJOR_VER ||
+ msgp->minor > VFIO_USER_MINOR_VER) {
+ error_setg(errp, "incompatible server version");
+ return false;
+ }
+
+ reply = msgp->capabilities;
+ if (reply[msgp->hdr.size - sizeof(*msgp) - 1] != '\0') {
+ error_setg(errp, "corrupt version reply");
+ return false;
+ }
+
+ if (!caps_check(proxy, msgp->minor, reply, errp)) {
+ return false;
+ }
+
+ trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
+ return true;
+}
+
+void vfio_user_flush_multi(VFIOUserProxy *proxy)
+{
+ VFIOUserMsg *msg;
+ VFIOUserWRMulti *wm = proxy->wr_multi;
+ Error *local_err = NULL;
+
+ proxy->wr_multi = NULL;
+
+ /* adjust size for actual # of writes */
+ wm->hdr.size -= (VFIO_USER_MULTI_MAX - wm->wr_cnt) * sizeof(VFIOUserWROne);
+
+ msg = vfio_user_getmsg(proxy, &wm->hdr, NULL);
+ msg->id = wm->hdr.id;
+ msg->rsize = 0;
+ msg->type = VFIO_MSG_ASYNC;
+ trace_vfio_user_wrmulti("flush", wm->wr_cnt);
+
+ if (!vfio_user_send_queued(proxy, msg, &local_err)) {
+ error_report_err(local_err);
+ vfio_user_recycle(proxy, msg);
+ }
+}
+
+void vfio_user_create_multi(VFIOUserProxy *proxy)
+{
+ VFIOUserWRMulti *wm;
+
+ wm = g_malloc0(sizeof(*wm));
+ vfio_user_request_msg(&wm->hdr, VFIO_USER_REGION_WRITE_MULTI,
+ sizeof(*wm), VFIO_USER_NO_REPLY);
+ proxy->wr_multi = wm;
+}
+
+void vfio_user_add_multi(VFIOUserProxy *proxy, uint8_t index,
+ off_t offset, uint32_t count, void *data)
+{
+ VFIOUserWRMulti *wm = proxy->wr_multi;
+ VFIOUserWROne *w1 = &wm->wrs[wm->wr_cnt];
+
+ w1->offset = offset;
+ w1->region = index;
+ w1->count = count;
+ memcpy(&w1->data, data, count);
+
+ wm->wr_cnt++;
+ trace_vfio_user_wrmulti("add", wm->wr_cnt);
+ if (wm->wr_cnt == VFIO_USER_MULTI_MAX ||
+ proxy->num_outgoing < VFIO_USER_OUT_LOW) {
+ vfio_user_flush_multi(proxy);
+ }
+}
diff --git a/hw/vfio-user/proxy.h b/hw/vfio-user/proxy.h
new file mode 100644
index 0000000..61e64a0
--- /dev/null
+++ b/hw/vfio-user/proxy.h
@@ -0,0 +1,135 @@
+#ifndef VFIO_USER_PROXY_H
+#define VFIO_USER_PROXY_H
+
+/*
+ * vfio protocol over a UNIX socket.
+ *
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "io/channel.h"
+#include "io/channel-socket.h"
+
+#include "qemu/queue.h"
+#include "qemu/sockets.h"
+#include "qemu/thread.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio-user/protocol.h"
+
+typedef struct {
+ int send_fds;
+ int recv_fds;
+ int *fds;
+} VFIOUserFDs;
+
+enum msg_type {
+ VFIO_MSG_NONE,
+ VFIO_MSG_ASYNC,
+ VFIO_MSG_WAIT,
+ VFIO_MSG_NOWAIT,
+ VFIO_MSG_REQ,
+};
+
+typedef struct VFIOUserMsg {
+ QTAILQ_ENTRY(VFIOUserMsg) next;
+ VFIOUserHdr *hdr;
+ VFIOUserFDs *fds;
+ uint32_t rsize;
+ uint32_t id;
+ QemuCond cv;
+ bool complete;
+ bool pending;
+ enum msg_type type;
+} VFIOUserMsg;
+
+
+enum proxy_state {
+ VFIO_PROXY_CONNECTED = 1,
+ VFIO_PROXY_ERROR = 2,
+ VFIO_PROXY_CLOSING = 3,
+ VFIO_PROXY_CLOSED = 4,
+};
+
+typedef QTAILQ_HEAD(VFIOUserMsgQ, VFIOUserMsg) VFIOUserMsgQ;
+
+typedef struct VFIOUserProxy {
+ QLIST_ENTRY(VFIOUserProxy) next;
+ char *sockname;
+ struct QIOChannel *ioc;
+ void (*request)(void *opaque, VFIOUserMsg *msg);
+ void *req_arg;
+ uint64_t max_xfer_size;
+ uint64_t max_send_fds;
+ uint64_t max_dma;
+ uint64_t dma_pgsizes;
+ uint64_t max_bitmap;
+ uint64_t migr_pgsize;
+ int flags;
+ uint32_t wait_time;
+ QemuCond close_cv;
+ AioContext *ctx;
+ QEMUBH *req_bh;
+ bool async_ops;
+
+ /*
+ * above only changed when BQL is held
+ * below are protected by per-proxy lock
+ */
+ QemuMutex lock;
+ VFIOUserMsgQ free;
+ VFIOUserMsgQ pending;
+ VFIOUserMsgQ incoming;
+ VFIOUserMsgQ outgoing;
+ VFIOUserMsg *last_nowait;
+ VFIOUserMsg *part_recv;
+ size_t recv_left;
+ VFIOUserWRMulti *wr_multi;
+ int num_outgoing;
+ enum proxy_state state;
+} VFIOUserProxy;
+
+/* VFIOProxy flags */
+#define VFIO_PROXY_CLIENT 0x1
+#define VFIO_PROXY_FORCE_QUEUED 0x4
+#define VFIO_PROXY_NO_POST 0x8
+#define VFIO_PROXY_USE_MULTI 0x16
+
+/* coalescing high and low water marks for VFIOProxy num_outgoing */
+#define VFIO_USER_OUT_HIGH 1024
+#define VFIO_USER_OUT_LOW 128
+
+typedef struct VFIODevice VFIODevice;
+
+VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp);
+void vfio_user_disconnect(VFIOUserProxy *proxy);
+void vfio_user_set_handler(VFIODevice *vbasedev,
+ void (*handler)(void *opaque, VFIOUserMsg *msg),
+ void *reqarg);
+bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp);
+
+VFIOUserFDs *vfio_user_getfds(int numfds);
+void vfio_user_putfds(VFIOUserMsg *msg);
+
+void vfio_user_disable_posted_writes(VFIOUserProxy *proxy);
+
+void vfio_user_request_msg(VFIOUserHdr *hdr, uint16_t cmd,
+ uint32_t size, uint32_t flags);
+void vfio_user_wait_reqs(VFIOUserProxy *proxy);
+bool vfio_user_send_wait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds, int rsize, Error **errp);
+bool vfio_user_send_nowait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds, int rsize, Error **errp);
+bool vfio_user_send_async(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds, Error **errp);
+
+void vfio_user_send_reply(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int size);
+void vfio_user_send_error(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int error);
+
+void vfio_user_flush_multi(VFIOUserProxy *proxy);
+void vfio_user_create_multi(VFIOUserProxy *proxy);
+void vfio_user_add_multi(VFIOUserProxy *proxy, uint8_t index,
+ off_t offset, uint32_t count, void *data);
+
+#endif /* VFIO_USER_PROXY_H */
diff --git a/hw/vfio-user/trace-events b/hw/vfio-user/trace-events
new file mode 100644
index 0000000..abb67f4
--- /dev/null
+++ b/hw/vfio-user/trace-events
@@ -0,0 +1,20 @@
+# See docs/devel/tracing.rst for syntax documentation.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# common.c
+vfio_user_recv_hdr(const char *name, uint16_t id, uint16_t cmd, uint32_t size, uint32_t flags) " (%s) id 0x%x cmd 0x%x size 0x%x flags 0x%x"
+vfio_user_recv_read(uint16_t id, int read) " id 0x%x read 0x%x"
+vfio_user_recv_request(uint16_t cmd) " command 0x%x"
+vfio_user_send_write(uint16_t id, int wrote) " id 0x%x wrote 0x%x"
+vfio_user_version(uint16_t major, uint16_t minor, const char *caps) " major %d minor %d caps: %s"
+vfio_user_get_info(uint32_t nregions, uint32_t nirqs) " #regions %d #irqs %d"
+vfio_user_get_region_info(uint32_t index, uint32_t flags, uint64_t size) " index %d flags 0x%x size 0x%"PRIx64
+vfio_user_region_rw(uint32_t region, uint64_t off, uint32_t count) " region %d offset 0x%"PRIx64" count %d"
+vfio_user_get_irq_info(uint32_t index, uint32_t flags, uint32_t count) " index %d flags 0x%x count %d"
+vfio_user_set_irqs(uint32_t index, uint32_t start, uint32_t count, uint32_t flags) " index %d start %d count %d flags 0x%x"
+vfio_user_wrmulti(const char *s, uint64_t wr_cnt) " %s count 0x%"PRIx64
+
+# container.c
+vfio_user_dma_map(uint64_t iova, uint64_t size, uint64_t off, uint32_t flags, bool async_ops) " iova 0x%"PRIx64" size 0x%"PRIx64" off 0x%"PRIx64" flags 0x%x async_ops %d"
+vfio_user_dma_unmap(uint64_t iova, uint64_t size, uint32_t flags, bool async_ops) " iova 0x%"PRIx64" size 0x%"PRIx64" flags 0x%x async_ops %d"
diff --git a/hw/vfio-user/trace.h b/hw/vfio-user/trace.h
new file mode 100644
index 0000000..9cf02d9
--- /dev/null
+++ b/hw/vfio-user/trace.h
@@ -0,0 +1,4 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "trace/trace-hw_vfio_user.h"
diff --git a/hw/vfio/Kconfig b/hw/vfio/Kconfig
index 7cdba05..91d9023 100644
--- a/hw/vfio/Kconfig
+++ b/hw/vfio/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
config VFIO
bool
depends on LINUX
diff --git a/hw/vfio/amd-xgbe.c b/hw/vfio/amd-xgbe.c
index 96bd608..58f590e 100644
--- a/hw/vfio/amd-xgbe.c
+++ b/hw/vfio/amd-xgbe.c
@@ -15,12 +15,14 @@
#include "hw/vfio/vfio-amd-xgbe.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
static void amd_xgbe_realize(DeviceState *dev, Error **errp)
{
VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
VFIOAmdXgbeDeviceClass *k = VFIO_AMD_XGBE_DEVICE_GET_CLASS(dev);
+ warn_report("-device vfio-amd-xgbe is deprecated");
vdev->compat = g_strdup("amd,xgbe-seattle-v1a");
vdev->num_compat = 1;
@@ -32,7 +34,7 @@ static const VMStateDescription vfio_platform_amd_xgbe_vmstate = {
.unmigratable = 1,
};
-static void vfio_amd_xgbe_class_init(ObjectClass *klass, void *data)
+static void vfio_amd_xgbe_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VFIOAmdXgbeDeviceClass *vcxc =
@@ -41,8 +43,6 @@ static void vfio_amd_xgbe_class_init(ObjectClass *klass, void *data)
&vcxc->parent_realize);
dc->desc = "VFIO AMD XGBE";
dc->vmsd = &vfio_platform_amd_xgbe_vmstate;
- /* Supported by TYPE_VIRT_MACHINE */
- dc->user_creatable = true;
}
static const TypeInfo vfio_amd_xgbe_dev_info = {
diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c
index 71bf32b..1df4438 100644
--- a/hw/vfio/ap.c
+++ b/hw/vfio/ap.c
@@ -10,16 +10,19 @@
* directory.
*/
+#include <stdbool.h>
#include "qemu/osdep.h"
#include CONFIG_DEVICES /* CONFIG_IOMMUFD */
#include <linux/vfio.h>
#include <sys/ioctl.h>
#include "qapi/error.h"
-#include "hw/vfio/vfio-common.h"
-#include "sysemu/iommufd.h"
+#include "hw/vfio/vfio-device.h"
+#include "system/iommufd.h"
#include "hw/s390x/ap-device.h"
+#include "hw/s390x/css.h"
#include "qemu/error-report.h"
#include "qemu/event_notifier.h"
+#include "qemu/lockable.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/option.h"
@@ -28,7 +31,7 @@
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/ap-bridge.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qom/object.h"
#define TYPE_VFIO_AP_DEVICE "vfio-ap"
@@ -37,8 +40,23 @@ struct VFIOAPDevice {
APDevice apdev;
VFIODevice vdev;
EventNotifier req_notifier;
+ EventNotifier cfg_notifier;
};
+typedef struct APConfigChgEvent {
+ QTAILQ_ENTRY(APConfigChgEvent) next;
+} APConfigChgEvent;
+
+static QTAILQ_HEAD(, APConfigChgEvent) cfg_chg_events =
+ QTAILQ_HEAD_INITIALIZER(cfg_chg_events);
+
+static QemuMutex cfg_chg_events_lock;
+
+static void __attribute__((constructor)) vfio_ap_global_init(void)
+{
+ qemu_mutex_init(&cfg_chg_events_lock);
+}
+
OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE)
static void vfio_ap_compute_needs_reset(VFIODevice *vdev)
@@ -70,14 +88,65 @@ static void vfio_ap_req_notifier_handler(void *opaque)
}
}
+static void vfio_ap_cfg_chg_notifier_handler(void *opaque)
+{
+ APConfigChgEvent *cfg_chg_event;
+ VFIOAPDevice *vapdev = opaque;
+
+ if (!event_notifier_test_and_clear(&vapdev->cfg_notifier)) {
+ return;
+ }
+
+ cfg_chg_event = g_new0(APConfigChgEvent, 1);
+
+ WITH_QEMU_LOCK_GUARD(&cfg_chg_events_lock) {
+ QTAILQ_INSERT_TAIL(&cfg_chg_events, cfg_chg_event, next);
+ }
+
+ css_generate_css_crws(0);
+
+}
+
+int ap_chsc_sei_nt0_get_event(void *res)
+{
+ ChscSeiNt0Res *nt0_res = (ChscSeiNt0Res *)res;
+ APConfigChgEvent *cfg_chg_event;
+
+ WITH_QEMU_LOCK_GUARD(&cfg_chg_events_lock) {
+ if (QTAILQ_EMPTY(&cfg_chg_events)) {
+ return EVENT_INFORMATION_NOT_STORED;
+ }
+
+ cfg_chg_event = QTAILQ_FIRST(&cfg_chg_events);
+ QTAILQ_REMOVE(&cfg_chg_events, cfg_chg_event, next);
+ }
+
+ memset(nt0_res, 0, sizeof(*nt0_res));
+ g_free(cfg_chg_event);
+ nt0_res->flags |= PENDING_EVENT_INFO_BITMASK;
+ nt0_res->length = sizeof(ChscSeiNt0Res);
+ nt0_res->code = NT0_RES_RESPONSE_CODE;
+ nt0_res->nt = NT0_RES_NT_DEFAULT;
+ nt0_res->rs = NT0_RES_RS_AP_CHANGE;
+ nt0_res->cc = NT0_RES_CC_AP_CHANGE;
+
+ return EVENT_INFORMATION_STORED;
+}
+
+bool ap_chsc_sei_nt0_have_event(void)
+{
+ QEMU_LOCK_GUARD(&cfg_chg_events_lock);
+ return !QTAILQ_EMPTY(&cfg_chg_events);
+}
+
static bool vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev,
unsigned int irq, Error **errp)
{
int fd;
- size_t argsz;
+ int ret;
IOHandler *fd_read;
EventNotifier *notifier;
- g_autofree struct vfio_irq_info *irq_info = NULL;
+ struct vfio_irq_info irq_info;
VFIODevice *vdev = &vapdev->vdev;
switch (irq) {
@@ -85,6 +154,10 @@ static bool vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev,
notifier = &vapdev->req_notifier;
fd_read = vfio_ap_req_notifier_handler;
break;
+ case VFIO_AP_CFG_CHG_IRQ_INDEX:
+ notifier = &vapdev->cfg_notifier;
+ fd_read = vfio_ap_cfg_chg_notifier_handler;
+ break;
default:
error_setg(errp, "vfio: Unsupported device irq(%d)", irq);
return false;
@@ -96,14 +169,15 @@ static bool vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev,
return false;
}
- argsz = sizeof(*irq_info);
- irq_info = g_malloc0(argsz);
- irq_info->index = irq;
- irq_info->argsz = argsz;
+ ret = vfio_device_get_irq_info(vdev, irq, &irq_info);
+
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "vfio: Error getting irq info");
+ return false;
+ }
- if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO,
- irq_info) < 0 || irq_info->count < 1) {
- error_setg_errno(errp, errno, "vfio: Error getting irq info");
+ if (irq_info.count < 1) {
+ error_setg(errp, "vfio: Error getting irq info, count=0");
return false;
}
@@ -117,8 +191,8 @@ static bool vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev,
fd = event_notifier_get_fd(notifier);
qemu_set_fd_handler(fd, fd_read, NULL, vapdev);
- if (!vfio_set_irq_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd,
- errp)) {
+ if (!vfio_device_irq_set_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd,
+ errp)) {
qemu_set_fd_handler(fd, NULL, NULL, vapdev);
event_notifier_cleanup(notifier);
}
@@ -136,13 +210,16 @@ static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev,
case VFIO_AP_REQ_IRQ_INDEX:
notifier = &vapdev->req_notifier;
break;
+ case VFIO_AP_CFG_CHG_IRQ_INDEX:
+ notifier = &vapdev->cfg_notifier;
+ break;
default:
error_report("vfio: Unsupported device irq(%d)", irq);
return;
}
- if (!vfio_set_irq_signaling(&vapdev->vdev, irq, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
+ if (!vfio_device_irq_set_signaling(&vapdev->vdev, irq, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name);
}
@@ -162,7 +239,7 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp)
return;
}
- if (!vfio_attach_device(vbasedev->name, vbasedev,
+ if (!vfio_device_attach(vbasedev->name, vbasedev,
&address_space_memory, errp)) {
goto error;
}
@@ -175,6 +252,15 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp)
warn_report_err(err);
}
+ if (!vfio_ap_register_irq_notifier(vapdev, VFIO_AP_CFG_CHG_IRQ_INDEX, &err))
+ {
+ /*
+ * Report this error, but do not make it a failing condition.
+ * Lack of this IRQ in the host does not prevent normal operation.
+ */
+ warn_report_err(err);
+ }
+
return;
error:
@@ -187,17 +273,17 @@ static void vfio_ap_unrealize(DeviceState *dev)
VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX);
- vfio_detach_device(&vapdev->vdev);
+ vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_CFG_CHG_IRQ_INDEX);
+ vfio_device_detach(&vapdev->vdev);
g_free(vapdev->vdev.name);
}
-static Property vfio_ap_properties[] = {
+static const Property vfio_ap_properties[] = {
DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev),
#ifdef CONFIG_IOMMUFD
DEFINE_PROP_LINK("iommufd", VFIOAPDevice, vdev.iommufd,
TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *),
#endif
- DEFINE_PROP_END_OF_LIST(),
};
static void vfio_ap_reset(DeviceState *dev)
@@ -242,7 +328,7 @@ static void vfio_ap_set_fd(Object *obj, const char *str, Error **errp)
}
#endif
-static void vfio_ap_class_init(ObjectClass *klass, void *data)
+static void vfio_ap_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -256,8 +342,17 @@ static void vfio_ap_class_init(ObjectClass *klass, void *data)
dc->realize = vfio_ap_realize;
dc->unrealize = vfio_ap_unrealize;
dc->hotpluggable = true;
- dc->reset = vfio_ap_reset;
+ device_class_set_legacy_reset(dc, vfio_ap_reset);
dc->bus_type = TYPE_AP_BUS;
+
+ object_class_property_set_description(klass, /* 3.1 */
+ "sysfsdev",
+ "Host sysfs path of assigned device");
+#ifdef CONFIG_IOMMUFD
+ object_class_property_set_description(klass, /* 9.0 */
+ "iommufd",
+ "Set host IOMMUFD backend device");
+#endif
}
static const TypeInfo vfio_ap_info = {
diff --git a/hw/vfio/calxeda-xgmac.c b/hw/vfio/calxeda-xgmac.c
index 87c382e..03f2ff5 100644
--- a/hw/vfio/calxeda-xgmac.c
+++ b/hw/vfio/calxeda-xgmac.c
@@ -15,12 +15,14 @@
#include "hw/vfio/vfio-calxeda-xgmac.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
static void calxeda_xgmac_realize(DeviceState *dev, Error **errp)
{
VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
VFIOCalxedaXgmacDeviceClass *k = VFIO_CALXEDA_XGMAC_DEVICE_GET_CLASS(dev);
+ warn_report("-device vfio-calxeda-xgmac is deprecated");
vdev->compat = g_strdup("calxeda,hb-xgmac");
vdev->num_compat = 1;
@@ -32,7 +34,7 @@ static const VMStateDescription vfio_platform_calxeda_xgmac_vmstate = {
.unmigratable = 1,
};
-static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, void *data)
+static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VFIOCalxedaXgmacDeviceClass *vcxc =
@@ -41,8 +43,6 @@ static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, void *data)
&vcxc->parent_realize);
dc->desc = "VFIO Calxeda XGMAC";
dc->vmsd = &vfio_platform_calxeda_xgmac_vmstate;
- /* Supported by TYPE_VIRT_MACHINE */
- dc->user_creatable = true;
}
static const TypeInfo vfio_calxeda_xgmac_dev_info = {
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 115862f..cea9d6e 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -21,13 +21,13 @@
#include <sys/ioctl.h>
#include "qapi/error.h"
-#include "hw/vfio/vfio-common.h"
-#include "sysemu/iommufd.h"
+#include "hw/vfio/vfio-device.h"
+#include "system/iommufd.h"
#include "hw/s390x/s390-ccw.h"
#include "hw/s390x/vfio-ccw.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/ccw-device.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
@@ -51,17 +51,8 @@ struct VFIOCCWDevice {
EventNotifier crw_notifier;
EventNotifier req_notifier;
bool force_orb_pfch;
- bool warned_orb_pfch;
};
-static inline void warn_once_pfch(VFIOCCWDevice *vcdev, SubchDev *sch,
- const char *msg)
-{
- warn_report_once_cond(&vcdev->warned_orb_pfch,
- "vfio-ccw (devno %x.%x.%04x): %s",
- sch->cssid, sch->ssid, sch->devno, msg);
-}
-
static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
{
vdev->needs_reset = false;
@@ -83,7 +74,8 @@ static IOInstEnding vfio_ccw_handle_request(SubchDev *sch)
if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH) && vcdev->force_orb_pfch) {
sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH;
- warn_once_pfch(vcdev, sch, "PFCH flag forced");
+ warn_report_once("vfio-ccw (devno %x.%x.%04x): PFCH flag forced",
+ sch->cssid, sch->ssid, sch->devno);
}
QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB));
@@ -384,8 +376,8 @@ static bool vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev,
Error **errp)
{
VFIODevice *vdev = &vcdev->vdev;
- g_autofree struct vfio_irq_info *irq_info = NULL;
- size_t argsz;
+ struct vfio_irq_info irq_info;
+ int ret;
int fd;
EventNotifier *notifier;
IOHandler *fd_read;
@@ -414,13 +406,15 @@ static bool vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev,
return false;
}
- argsz = sizeof(*irq_info);
- irq_info = g_malloc0(argsz);
- irq_info->index = irq;
- irq_info->argsz = argsz;
- if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO,
- irq_info) < 0 || irq_info->count < 1) {
- error_setg_errno(errp, errno, "vfio: Error getting irq info");
+ ret = vfio_device_get_irq_info(vdev, irq, &irq_info);
+
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "vfio: Error getting irq info");
+ return false;
+ }
+
+ if (irq_info.count < 1) {
+ error_setg(errp, "vfio: Error getting irq info, count=0");
return false;
}
@@ -434,8 +428,8 @@ static bool vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev,
fd = event_notifier_get_fd(notifier);
qemu_set_fd_handler(fd, fd_read, NULL, vcdev);
- if (!vfio_set_irq_signaling(vdev, irq, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) {
+ if (!vfio_device_irq_set_signaling(vdev, irq, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) {
qemu_set_fd_handler(fd, NULL, NULL, vcdev);
event_notifier_cleanup(notifier);
}
@@ -464,8 +458,8 @@ static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev,
return;
}
- if (!vfio_set_irq_signaling(&vcdev->vdev, irq, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
+ if (!vfio_device_irq_set_signaling(&vcdev->vdev, irq, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name);
}
@@ -496,7 +490,7 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
return false;
}
- ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info);
+ ret = vfio_device_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info);
if (ret) {
error_setg_errno(errp, -ret, "vfio: Error getting config info");
return false;
@@ -510,11 +504,10 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
vcdev->io_region_offset = info->offset;
vcdev->io_region = g_malloc0(info->size);
- g_free(info);
/* check for the optional async command region */
- ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
- VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD, &info);
+ ret = vfio_device_get_region_info_type(vdev, VFIO_REGION_TYPE_CCW,
+ VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD, &info);
if (!ret) {
vcdev->async_cmd_region_size = info->size;
if (sizeof(*vcdev->async_cmd_region) != vcdev->async_cmd_region_size) {
@@ -523,11 +516,10 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
}
vcdev->async_cmd_region_offset = info->offset;
vcdev->async_cmd_region = g_malloc0(info->size);
- g_free(info);
}
- ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
- VFIO_REGION_SUBTYPE_CCW_SCHIB, &info);
+ ret = vfio_device_get_region_info_type(vdev, VFIO_REGION_TYPE_CCW,
+ VFIO_REGION_SUBTYPE_CCW_SCHIB, &info);
if (!ret) {
vcdev->schib_region_size = info->size;
if (sizeof(*vcdev->schib_region) != vcdev->schib_region_size) {
@@ -536,11 +528,10 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
}
vcdev->schib_region_offset = info->offset;
vcdev->schib_region = g_malloc(info->size);
- g_free(info);
}
- ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
- VFIO_REGION_SUBTYPE_CCW_CRW, &info);
+ ret = vfio_device_get_region_info_type(vdev, VFIO_REGION_TYPE_CCW,
+ VFIO_REGION_SUBTYPE_CCW_CRW, &info);
if (!ret) {
vcdev->crw_region_size = info->size;
@@ -550,7 +541,6 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
}
vcdev->crw_region_offset = info->offset;
vcdev->crw_region = g_malloc(info->size);
- g_free(info);
}
return true;
@@ -560,7 +550,6 @@ out_err:
g_free(vcdev->schib_region);
g_free(vcdev->async_cmd_region);
g_free(vcdev->io_region);
- g_free(info);
return false;
}
@@ -591,7 +580,7 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
goto out_unrealize;
}
- if (!vfio_attach_device(cdev->mdevid, vbasedev,
+ if (!vfio_device_attach(cdev->mdevid, vbasedev,
&address_space_memory, errp)) {
goto out_attach_dev_err;
}
@@ -628,7 +617,7 @@ out_irq_notifier_err:
out_io_notifier_err:
vfio_ccw_put_region(vcdev);
out_region_err:
- vfio_detach_device(vbasedev);
+ vfio_device_detach(vbasedev);
out_attach_dev_err:
g_free(vbasedev->name);
out_unrealize:
@@ -647,7 +636,7 @@ static void vfio_ccw_unrealize(DeviceState *dev)
vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX);
vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX);
vfio_ccw_put_region(vcdev);
- vfio_detach_device(&vcdev->vdev);
+ vfio_device_detach(&vcdev->vdev);
g_free(vcdev->vdev.name);
if (cdc->unrealize) {
@@ -655,14 +644,14 @@ static void vfio_ccw_unrealize(DeviceState *dev)
}
}
-static Property vfio_ccw_properties[] = {
+static const Property vfio_ccw_properties[] = {
DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev),
DEFINE_PROP_BOOL("force-orb-pfch", VFIOCCWDevice, force_orb_pfch, false),
#ifdef CONFIG_IOMMUFD
DEFINE_PROP_LINK("iommufd", VFIOCCWDevice, vdev.iommufd,
TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *),
#endif
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm),
};
static const VMStateDescription vfio_ccw_vmstate = {
@@ -697,7 +686,7 @@ static void vfio_ccw_set_fd(Object *obj, const char *str, Error **errp)
}
#endif
-static void vfio_ccw_class_init(ObjectClass *klass, void *data)
+static void vfio_ccw_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass);
@@ -711,12 +700,27 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->realize = vfio_ccw_realize;
dc->unrealize = vfio_ccw_unrealize;
- dc->reset = vfio_ccw_reset;
+ device_class_set_legacy_reset(dc, vfio_ccw_reset);
cdc->handle_request = vfio_ccw_handle_request;
cdc->handle_halt = vfio_ccw_handle_halt;
cdc->handle_clear = vfio_ccw_handle_clear;
cdc->handle_store = vfio_ccw_handle_store;
+
+ object_class_property_set_description(klass, /* 2.10 */
+ "sysfsdev",
+ "Host sysfs path of assigned device");
+ object_class_property_set_description(klass, /* 3.0 */
+ "force-orb-pfch",
+ "Force unlimited prefetch");
+#ifdef CONFIG_IOMMUFD
+ object_class_property_set_description(klass, /* 9.0 */
+ "iommufd",
+ "Set host IOMMUFD backend device");
+#endif
+ object_class_property_set_description(klass, /* 9.2 */
+ "loadparm",
+ "Define which devices that can be used for booting");
}
static const TypeInfo vfio_ccw_info = {
diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c
index 809b157..d834bd4 100644
--- a/hw/vfio/container-base.c
+++ b/hw/vfio/container-base.c
@@ -10,29 +10,87 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
+#include <sys/ioctl.h>
+#include <linux/vfio.h>
+
#include "qemu/osdep.h"
+#include "system/tcg.h"
+#include "system/ram_addr.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/vfio/vfio-container-base.h"
+#include "hw/vfio/vfio-device.h" /* vfio_device_reset_handler */
+#include "system/reset.h"
+#include "vfio-helpers.h"
+
+#include "trace.h"
+
+static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
+ QLIST_HEAD_INITIALIZER(vfio_address_spaces);
+
+VFIOAddressSpace *vfio_address_space_get(AddressSpace *as)
+{
+ VFIOAddressSpace *space;
+
+ QLIST_FOREACH(space, &vfio_address_spaces, list) {
+ if (space->as == as) {
+ return space;
+ }
+ }
+
+ /* No suitable VFIOAddressSpace, create a new one */
+ space = g_malloc0(sizeof(*space));
+ space->as = as;
+ QLIST_INIT(&space->containers);
+
+ if (QLIST_EMPTY(&vfio_address_spaces)) {
+ qemu_register_reset(vfio_device_reset_handler, NULL);
+ }
+
+ QLIST_INSERT_HEAD(&vfio_address_spaces, space, list);
+
+ return space;
+}
+
+void vfio_address_space_put(VFIOAddressSpace *space)
+{
+ if (!QLIST_EMPTY(&space->containers)) {
+ return;
+ }
+
+ QLIST_REMOVE(space, list);
+ g_free(space);
+
+ if (QLIST_EMPTY(&vfio_address_spaces)) {
+ qemu_unregister_reset(vfio_device_reset_handler, NULL);
+ }
+}
+
+void vfio_address_space_insert(VFIOAddressSpace *space,
+ VFIOContainerBase *bcontainer)
+{
+ QLIST_INSERT_HEAD(&space->containers, bcontainer, next);
+ bcontainer->space = space;
+}
int vfio_container_dma_map(VFIOContainerBase *bcontainer,
hwaddr iova, ram_addr_t size,
- void *vaddr, bool readonly)
+ void *vaddr, bool readonly, MemoryRegion *mr)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
g_assert(vioc->dma_map);
- return vioc->dma_map(bcontainer, iova, size, vaddr, readonly);
+ return vioc->dma_map(bcontainer, iova, size, vaddr, readonly, mr);
}
int vfio_container_dma_unmap(VFIOContainerBase *bcontainer,
hwaddr iova, ram_addr_t size,
- IOMMUTLBEntry *iotlb)
+ IOMMUTLBEntry *iotlb, bool unmap_all)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
g_assert(vioc->dma_unmap);
- return vioc->dma_unmap(bcontainer, iova, size, iotlb);
+ return vioc->dma_unmap(bcontainer, iova, size, iotlb, unmap_all);
}
bool vfio_container_add_section_window(VFIOContainerBase *bcontainer,
@@ -64,16 +122,86 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer,
bool start, Error **errp)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+ int ret;
if (!bcontainer->dirty_pages_supported) {
return 0;
}
g_assert(vioc->set_dirty_page_tracking);
- return vioc->set_dirty_page_tracking(bcontainer, start, errp);
+ if (bcontainer->dirty_pages_started == start) {
+ return 0;
+ }
+
+ ret = vioc->set_dirty_page_tracking(bcontainer, start, errp);
+ if (!ret) {
+ bcontainer->dirty_pages_started = start;
+ }
+
+ return ret;
+}
+
+static bool vfio_container_devices_dirty_tracking_is_started(
+ const VFIOContainerBase *bcontainer)
+{
+ VFIODevice *vbasedev;
+
+ QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
+ if (!vbasedev->dirty_tracking) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool vfio_container_dirty_tracking_is_started(
+ const VFIOContainerBase *bcontainer)
+{
+ return vfio_container_devices_dirty_tracking_is_started(bcontainer) ||
+ bcontainer->dirty_pages_started;
+}
+
+bool vfio_container_devices_dirty_tracking_is_supported(
+ const VFIOContainerBase *bcontainer)
+{
+ VFIODevice *vbasedev;
+
+ QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
+ if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) {
+ return false;
+ }
+ if (!vbasedev->dirty_pages_supported) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova,
+ hwaddr size, void *bitmap)
+{
+ uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) +
+ sizeof(struct vfio_device_feature_dma_logging_report),
+ sizeof(uint64_t))] = {};
+ struct vfio_device_feature *feature = (struct vfio_device_feature *)buf;
+ struct vfio_device_feature_dma_logging_report *report =
+ (struct vfio_device_feature_dma_logging_report *)feature->data;
+
+ report->iova = iova;
+ report->length = size;
+ report->page_size = qemu_real_host_page_size();
+ report->bitmap = (uintptr_t)bitmap;
+
+ feature->argsz = sizeof(buf);
+ feature->flags = VFIO_DEVICE_FEATURE_GET |
+ VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT;
+
+ return vbasedev->io_ops->device_feature(vbasedev, feature);
}
-int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
+static int vfio_container_iommu_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
@@ -83,6 +211,74 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
errp);
}
+static int vfio_container_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
+ VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp)
+{
+ VFIODevice *vbasedev;
+ int ret;
+
+ QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
+ ret = vfio_device_dma_logging_report(vbasedev, iova, size,
+ vbmap->bitmap);
+ if (ret) {
+ error_setg_errno(errp, -ret,
+ "%s: Failed to get DMA logging report, iova: "
+ "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx,
+ vbasedev->name, iova, size);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova,
+ uint64_t size, ram_addr_t ram_addr, Error **errp)
+{
+ bool all_device_dirty_tracking =
+ vfio_container_devices_dirty_tracking_is_supported(bcontainer);
+ uint64_t dirty_pages;
+ VFIOBitmap vbmap;
+ int ret;
+
+ if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) {
+ cpu_physical_memory_set_dirty_range(ram_addr, size,
+ tcg_enabled() ? DIRTY_CLIENTS_ALL :
+ DIRTY_CLIENTS_NOCODE);
+ return 0;
+ }
+
+ ret = vfio_bitmap_alloc(&vbmap, size);
+ if (ret) {
+ error_setg_errno(errp, -ret,
+ "Failed to allocate dirty tracking bitmap");
+ return ret;
+ }
+
+ if (all_device_dirty_tracking) {
+ ret = vfio_container_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
+ errp);
+ } else {
+ ret = vfio_container_iommu_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
+ errp);
+ }
+
+ if (ret) {
+ goto out;
+ }
+
+ dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr,
+ vbmap.pages);
+
+ trace_vfio_container_query_dirty_bitmap(iova, size, vbmap.size, ram_addr,
+ dirty_pages);
+out:
+ g_free(vbmap.bitmap);
+
+ return ret;
+}
+
static gpointer copy_iova_range(gconstpointer src, gpointer data)
{
Range *source = (Range *)src;
@@ -103,7 +299,7 @@ static void vfio_container_instance_finalize(Object *obj)
VFIOContainerBase *bcontainer = VFIO_IOMMU(obj);
VFIOGuestIOMMU *giommu, *tmp;
- QLIST_REMOVE(bcontainer, next);
+ QLIST_SAFE_REMOVE(bcontainer, next);
QLIST_FOREACH_SAFE(giommu, &bcontainer->giommu_list, giommu_next, tmp) {
memory_region_unregister_iommu_notifier(
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 9ccdb63..3e13fea 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -22,18 +22,26 @@
#include <sys/ioctl.h>
#include <linux/vfio.h>
-#include "hw/vfio/vfio-common.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-#include "exec/ram_addr.h"
+#include "hw/vfio/vfio-device.h"
+#include "system/address-spaces.h"
+#include "system/memory.h"
+#include "system/ram_addr.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "trace.h"
#include "qapi/error.h"
+#include "migration/cpr.h"
+#include "migration/blocker.h"
#include "pci.h"
+#include "hw/vfio/vfio-container.h"
+#include "vfio-helpers.h"
+#include "vfio-listener.h"
-VFIOGroupList vfio_group_list =
+#define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE "-legacy-vfio"
+
+typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList;
+static VFIOGroupList vfio_group_list =
QLIST_HEAD_INITIALIZER(vfio_group_list);
static int vfio_ram_block_discard_disable(VFIOContainer *container, bool state)
@@ -112,12 +120,9 @@ unmap_exit:
return ret;
}
-/*
- * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86
- */
-static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer,
- hwaddr iova, ram_addr_t size,
- IOMMUTLBEntry *iotlb)
+static int vfio_legacy_dma_unmap_one(const VFIOContainerBase *bcontainer,
+ hwaddr iova, ram_addr_t size,
+ IOMMUTLBEntry *iotlb)
{
const VFIOContainer *container = container_of(bcontainer, VFIOContainer,
bcontainer);
@@ -131,8 +136,10 @@ static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer,
int ret;
Error *local_err = NULL;
- if (iotlb && vfio_devices_all_running_and_mig_active(bcontainer)) {
- if (!vfio_devices_all_device_dirty_tracking(bcontainer) &&
+ g_assert(!cpr_is_incoming());
+
+ if (iotlb && vfio_container_dirty_tracking_is_started(bcontainer)) {
+ if (!vfio_container_devices_dirty_tracking_is_supported(bcontainer) &&
bcontainer->dirty_pages_supported) {
return vfio_dma_unmap_bitmap(container, iova, size, iotlb);
}
@@ -159,12 +166,11 @@ static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer,
unmap.size -= 1ULL << ctz64(bcontainer->pgsizes);
continue;
}
- error_report("VFIO_UNMAP_DMA failed: %s", strerror(errno));
return -errno;
}
if (need_dirty_sync) {
- ret = vfio_get_dirty_bitmap(bcontainer, iova, size,
+ ret = vfio_container_query_dirty_bitmap(bcontainer, iova, size,
iotlb->translated_addr, &local_err);
if (ret) {
error_report_err(local_err);
@@ -175,8 +181,37 @@ static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer,
return 0;
}
+/*
+ * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86
+ */
+static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer,
+ hwaddr iova, ram_addr_t size,
+ IOMMUTLBEntry *iotlb, bool unmap_all)
+{
+ int ret;
+
+ if (unmap_all) {
+ /* The unmap ioctl doesn't accept a full 64-bit span. */
+ Int128 llsize = int128_rshift(int128_2_64(), 1);
+
+ ret = vfio_legacy_dma_unmap_one(bcontainer, 0, int128_get64(llsize),
+ iotlb);
+
+ if (ret == 0) {
+ ret = vfio_legacy_dma_unmap_one(bcontainer, int128_get64(llsize),
+ int128_get64(llsize), iotlb);
+ }
+
+ } else {
+ ret = vfio_legacy_dma_unmap_one(bcontainer, iova, size, iotlb);
+ }
+
+ return ret;
+}
+
static int vfio_legacy_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
- ram_addr_t size, void *vaddr, bool readonly)
+ ram_addr_t size, void *vaddr, bool readonly,
+ MemoryRegion *mr)
{
const VFIOContainer *container = container_of(bcontainer, VFIOContainer,
bcontainer);
@@ -199,12 +234,11 @@ static int vfio_legacy_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
*/
if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 ||
(errno == EBUSY &&
- vfio_legacy_dma_unmap(bcontainer, iova, size, NULL) == 0 &&
+ vfio_legacy_dma_unmap(bcontainer, iova, size, NULL, false) == 0 &&
ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) {
return 0;
}
- error_report("VFIO_MAP_DMA failed: %s", strerror(errno));
return -errno;
}
@@ -275,37 +309,6 @@ static int vfio_legacy_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
return ret;
}
-static struct vfio_info_cap_header *
-vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id)
-{
- if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) {
- return NULL;
- }
-
- return vfio_get_cap((void *)info, info->cap_offset, id);
-}
-
-bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
- unsigned int *avail)
-{
- struct vfio_info_cap_header *hdr;
- struct vfio_iommu_type1_info_dma_avail *cap;
-
- /* If the capability cannot be found, assume no DMA limiting */
- hdr = vfio_get_iommu_type1_info_cap(info,
- VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL);
- if (!hdr) {
- return false;
- }
-
- if (avail != NULL) {
- cap = (void *) hdr;
- *avail = cap->avail;
- }
-
- return true;
-}
-
static bool vfio_get_info_iova_range(struct vfio_iommu_type1_info *info,
VFIOContainerBase *bcontainer)
{
@@ -332,7 +335,7 @@ static bool vfio_get_info_iova_range(struct vfio_iommu_type1_info *info,
return true;
}
-static void vfio_kvm_device_add_group(VFIOGroup *group)
+static void vfio_group_add_kvm_device(VFIOGroup *group)
{
Error *err = NULL;
@@ -341,7 +344,7 @@ static void vfio_kvm_device_add_group(VFIOGroup *group)
}
}
-static void vfio_kvm_device_del_group(VFIOGroup *group)
+static void vfio_group_del_kvm_device(VFIOGroup *group)
{
Error *err = NULL;
@@ -426,7 +429,12 @@ static VFIOContainer *vfio_create_container(int fd, VFIOGroup *group,
return NULL;
}
- if (!vfio_set_iommu(fd, group->fd, &iommu_type, errp)) {
+ /*
+ * During CPR, just set the container type and skip the ioctls, as the
+ * container and group are already configured in the kernel.
+ */
+ if (!cpr_is_incoming() &&
+ !vfio_set_iommu(fd, group->fd, &iommu_type, errp)) {
return NULL;
}
@@ -537,16 +545,10 @@ static bool vfio_legacy_setup(VFIOContainerBase *bcontainer, Error **errp)
return true;
}
-static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as,
- Error **errp)
+static bool vfio_container_attach_discard_disable(VFIOContainer *container,
+ VFIOGroup *group, Error **errp)
{
- VFIOContainer *container;
- VFIOContainerBase *bcontainer;
- int ret, fd;
- VFIOAddressSpace *space;
- VFIOIOMMUClass *vioc;
-
- space = vfio_get_address_space(as);
+ int ret;
/*
* VFIO is currently incompatible with discarding of RAM insofar as the
@@ -579,108 +581,158 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as,
* details once we know which type of IOMMU we are using.
*/
- QLIST_FOREACH(bcontainer, &space->containers, next) {
- container = container_of(bcontainer, VFIOContainer, bcontainer);
- if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
- ret = vfio_ram_block_discard_disable(container, true);
- if (ret) {
- error_setg_errno(errp, -ret,
- "Cannot set discarding of RAM broken");
- if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER,
- &container->fd)) {
- error_report("vfio: error disconnecting group %d from"
- " container", group->groupid);
- }
- return false;
- }
- group->container = container;
- QLIST_INSERT_HEAD(&container->group_list, group, container_next);
- vfio_kvm_device_add_group(group);
- return true;
+ ret = vfio_ram_block_discard_disable(container, true);
+ if (ret) {
+ error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
+ if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) {
+ error_report("vfio: error disconnecting group %d from"
+ " container", group->groupid);
}
}
+ return !ret;
+}
- fd = qemu_open("/dev/vfio/vfio", O_RDWR, errp);
- if (fd < 0) {
- goto put_space_exit;
+static bool vfio_container_group_add(VFIOContainer *container, VFIOGroup *group,
+ Error **errp)
+{
+ if (!vfio_container_attach_discard_disable(container, group, errp)) {
+ return false;
+ }
+ group->container = container;
+ QLIST_INSERT_HEAD(&container->group_list, group, container_next);
+ vfio_group_add_kvm_device(group);
+ /*
+ * Remember the container fd for each group, so we can attach to the same
+ * container after CPR.
+ */
+ cpr_resave_fd("vfio_container_for_group", group->groupid, container->fd);
+ return true;
+}
+
+static void vfio_container_group_del(VFIOContainer *container, VFIOGroup *group)
+{
+ QLIST_REMOVE(group, container_next);
+ group->container = NULL;
+ vfio_group_del_kvm_device(group);
+ vfio_ram_block_discard_disable(container, false);
+ cpr_delete_fd("vfio_container_for_group", group->groupid);
+}
+
+static bool vfio_container_connect(VFIOGroup *group, AddressSpace *as,
+ Error **errp)
+{
+ VFIOContainer *container;
+ VFIOContainerBase *bcontainer;
+ int ret, fd = -1;
+ VFIOAddressSpace *space;
+ VFIOIOMMUClass *vioc = NULL;
+ bool new_container = false;
+ bool group_was_added = false;
+
+ space = vfio_address_space_get(as);
+ fd = cpr_find_fd("vfio_container_for_group", group->groupid);
+
+ if (!cpr_is_incoming()) {
+ QLIST_FOREACH(bcontainer, &space->containers, next) {
+ container = container_of(bcontainer, VFIOContainer, bcontainer);
+ if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
+ return vfio_container_group_add(container, group, errp);
+ }
+ }
+
+ fd = qemu_open("/dev/vfio/vfio", O_RDWR, errp);
+ if (fd < 0) {
+ goto fail;
+ }
+ } else {
+ /*
+ * For incoming CPR, the group is already attached in the kernel.
+ * If a container with matching fd is found, then update the
+ * userland group list and return. If not, then after the loop,
+ * create the container struct and group list.
+ */
+ QLIST_FOREACH(bcontainer, &space->containers, next) {
+ container = container_of(bcontainer, VFIOContainer, bcontainer);
+
+ if (vfio_cpr_container_match(container, group, fd)) {
+ return vfio_container_group_add(container, group, errp);
+ }
+ }
}
ret = ioctl(fd, VFIO_GET_API_VERSION);
if (ret != VFIO_API_VERSION) {
error_setg(errp, "supported vfio version: %d, "
"reported version: %d", VFIO_API_VERSION, ret);
- goto close_fd_exit;
+ goto fail;
}
container = vfio_create_container(fd, group, errp);
if (!container) {
- goto close_fd_exit;
+ goto fail;
}
+ new_container = true;
bcontainer = &container->bcontainer;
- if (!vfio_cpr_register_container(bcontainer, errp)) {
- goto free_container_exit;
- }
-
- ret = vfio_ram_block_discard_disable(container, true);
- if (ret) {
- error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
- goto unregister_container_exit;
+ if (!vfio_legacy_cpr_register_container(container, errp)) {
+ goto fail;
}
vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
assert(vioc->setup);
if (!vioc->setup(bcontainer, errp)) {
- goto enable_discards_exit;
+ goto fail;
}
- vfio_kvm_device_add_group(group);
-
vfio_address_space_insert(space, bcontainer);
- group->container = container;
- QLIST_INSERT_HEAD(&container->group_list, group, container_next);
-
- bcontainer->listener = vfio_memory_listener;
- memory_listener_register(&bcontainer->listener, bcontainer->space->as);
+ if (!vfio_container_group_add(container, group, errp)) {
+ goto fail;
+ }
+ group_was_added = true;
- if (bcontainer->error) {
- error_propagate_prepend(errp, bcontainer->error,
- "memory listener initialization failed: ");
- goto listener_release_exit;
+ /*
+ * If CPR, register the listener later, after all state that may
+ * affect regions and mapping boundaries has been cpr load'ed. Later,
+ * the listener will invoke its callback on each flat section and call
+ * dma_map to supply the new vaddr, and the calls will match the mappings
+ * remembered by the kernel.
+ */
+ if (!cpr_is_incoming()) {
+ if (!vfio_listener_register(bcontainer, errp)) {
+ goto fail;
+ }
}
bcontainer->initialized = true;
return true;
-listener_release_exit:
- QLIST_REMOVE(group, container_next);
- vfio_kvm_device_del_group(group);
- memory_listener_unregister(&bcontainer->listener);
- if (vioc->release) {
- vioc->release(bcontainer);
- }
-
-enable_discards_exit:
- vfio_ram_block_discard_disable(container, false);
-
-unregister_container_exit:
- vfio_cpr_unregister_container(bcontainer);
-
-free_container_exit:
- object_unref(container);
-close_fd_exit:
- close(fd);
+fail:
+ if (new_container) {
+ vfio_listener_unregister(bcontainer);
+ }
-put_space_exit:
- vfio_put_address_space(space);
+ if (group_was_added) {
+ vfio_container_group_del(container, group);
+ }
+ if (vioc && vioc->release) {
+ vioc->release(bcontainer);
+ }
+ if (new_container) {
+ vfio_legacy_cpr_unregister_container(container);
+ object_unref(container);
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+ vfio_address_space_put(space);
return false;
}
-static void vfio_disconnect_container(VFIOGroup *group)
+static void vfio_container_disconnect(VFIOGroup *group)
{
VFIOContainer *container = group->container;
VFIOContainerBase *bcontainer = &container->bcontainer;
@@ -688,6 +740,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
QLIST_REMOVE(group, container_next);
group->container = NULL;
+ cpr_delete_fd("vfio_container_for_group", group->groupid);
/*
* Explicitly release the listener first before unset container,
@@ -695,7 +748,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
* group.
*/
if (QLIST_EMPTY(&container->group_list)) {
- memory_listener_unregister(&bcontainer->listener);
+ vfio_listener_unregister(bcontainer);
if (vioc->release) {
vioc->release(bcontainer);
}
@@ -709,16 +762,16 @@ static void vfio_disconnect_container(VFIOGroup *group)
if (QLIST_EMPTY(&container->group_list)) {
VFIOAddressSpace *space = bcontainer->space;
- trace_vfio_disconnect_container(container->fd);
- vfio_cpr_unregister_container(bcontainer);
+ trace_vfio_container_disconnect(container->fd);
+ vfio_legacy_cpr_unregister_container(container);
close(container->fd);
object_unref(container);
- vfio_put_address_space(space);
+ vfio_address_space_put(space);
}
}
-static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp)
+static VFIOGroup *vfio_group_get(int groupid, AddressSpace *as, Error **errp)
{
ERRP_GUARD();
VFIOGroup *group;
@@ -741,7 +794,7 @@ static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp)
group = g_malloc0(sizeof(*group));
snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
- group->fd = qemu_open(path, O_RDWR, errp);
+ group->fd = cpr_open_fd(path, O_RDWR, "vfio_group", groupid, errp);
if (group->fd < 0) {
goto free_group_exit;
}
@@ -762,7 +815,7 @@ static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp)
group->groupid = groupid;
QLIST_INIT(&group->device_list);
- if (!vfio_connect_container(group, as, errp)) {
+ if (!vfio_container_connect(group, as, errp)) {
error_prepend(errp, "failed to setup container for group %d: ",
groupid);
goto close_fd_exit;
@@ -773,6 +826,7 @@ static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp)
return group;
close_fd_exit:
+ cpr_delete_fd("vfio_group", groupid);
close(group->fd);
free_group_exit:
@@ -781,7 +835,7 @@ free_group_exit:
return NULL;
}
-static void vfio_put_group(VFIOGroup *group)
+static void vfio_group_put(VFIOGroup *group)
{
if (!group || !QLIST_EMPTY(&group->device_list)) {
return;
@@ -790,21 +844,22 @@ static void vfio_put_group(VFIOGroup *group)
if (!group->ram_block_discard_allowed) {
vfio_ram_block_discard_disable(group->container, false);
}
- vfio_kvm_device_del_group(group);
- vfio_disconnect_container(group);
+ vfio_group_del_kvm_device(group);
+ vfio_container_disconnect(group);
QLIST_REMOVE(group, next);
- trace_vfio_put_group(group->fd);
+ trace_vfio_group_put(group->fd);
+ cpr_delete_fd("vfio_group", group->groupid);
close(group->fd);
g_free(group);
}
-static bool vfio_get_device(VFIOGroup *group, const char *name,
+static bool vfio_device_get(VFIOGroup *group, const char *name,
VFIODevice *vbasedev, Error **errp)
{
g_autofree struct vfio_device_info *info = NULL;
int fd;
- fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
+ fd = vfio_cpr_group_get_device_fd(group->fd, name);
if (fd < 0) {
error_setg_errno(errp, errno, "error getting device from group %d",
group->groupid);
@@ -817,8 +872,7 @@ static bool vfio_get_device(VFIOGroup *group, const char *name,
info = vfio_get_device_info(fd);
if (!info) {
error_setg_errno(errp, errno, "error getting device info");
- close(fd);
- return false;
+ goto fail;
}
/*
@@ -832,8 +886,7 @@ static bool vfio_get_device(VFIOGroup *group, const char *name,
if (!QLIST_EMPTY(&group->device_list)) {
error_setg(errp, "Inconsistent setting of support for discarding "
"RAM (e.g., balloon) within group");
- close(fd);
- return false;
+ goto fail;
}
if (!group->ram_block_discard_allowed) {
@@ -842,33 +895,35 @@ static bool vfio_get_device(VFIOGroup *group, const char *name,
}
}
+ vfio_device_prepare(vbasedev, &group->container->bcontainer, info);
+
vbasedev->fd = fd;
vbasedev->group = group;
QLIST_INSERT_HEAD(&group->device_list, vbasedev, next);
- vbasedev->num_irqs = info->num_irqs;
- vbasedev->num_regions = info->num_regions;
- vbasedev->flags = info->flags;
-
- trace_vfio_get_device(name, info->flags, info->num_regions, info->num_irqs);
-
- vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET);
+ trace_vfio_device_get(name, info->flags, info->num_regions, info->num_irqs);
return true;
+
+fail:
+ close(fd);
+ cpr_delete_fd(name, 0);
+ return false;
}
-static void vfio_put_base_device(VFIODevice *vbasedev)
+static void vfio_device_put(VFIODevice *vbasedev)
{
if (!vbasedev->group) {
return;
}
QLIST_REMOVE(vbasedev, next);
vbasedev->group = NULL;
- trace_vfio_put_base_device(vbasedev->fd);
+ trace_vfio_device_put(vbasedev->fd);
+ cpr_delete_fd(vbasedev->name, 0);
close(vbasedev->fd);
}
-static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp)
+static int vfio_device_get_groupid(VFIODevice *vbasedev, Error **errp)
{
char *tmp, group_path[PATH_MAX];
g_autofree char *group_name = NULL;
@@ -896,29 +951,24 @@ static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp)
}
/*
- * vfio_attach_device: attach a device to a security context
+ * vfio_device_attach: attach a device to a security context
* @name and @vbasedev->name are likely to be different depending
* on the type of the device, hence the need for passing @name
*/
static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev,
AddressSpace *as, Error **errp)
{
- int groupid = vfio_device_groupid(vbasedev, errp);
+ int groupid = vfio_device_get_groupid(vbasedev, errp);
VFIODevice *vbasedev_iter;
VFIOGroup *group;
- VFIOContainerBase *bcontainer;
if (groupid < 0) {
return false;
}
- trace_vfio_attach_device(vbasedev->name, groupid);
+ trace_vfio_device_attach(vbasedev->name, groupid);
- if (!vfio_device_hiod_realize(vbasedev, errp)) {
- return false;
- }
-
- group = vfio_get_group(groupid, as, errp);
+ group = vfio_group_get(groupid, as, errp);
if (!group) {
return false;
}
@@ -926,33 +976,51 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev,
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) {
error_setg(errp, "device is already attached");
- vfio_put_group(group);
- return false;
+ goto group_put_exit;
}
}
- if (!vfio_get_device(group, name, vbasedev, errp)) {
- vfio_put_group(group);
- return false;
+ if (!vfio_device_get(group, name, vbasedev, errp)) {
+ goto group_put_exit;
}
- bcontainer = &group->container->bcontainer;
- vbasedev->bcontainer = bcontainer;
- QLIST_INSERT_HEAD(&bcontainer->device_list, vbasedev, container_next);
- QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next);
+ if (!vfio_device_hiod_create_and_realize(vbasedev,
+ TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO,
+ errp)) {
+ goto device_put_exit;
+ }
+
+ if (vbasedev->mdev) {
+ error_setg(&vbasedev->cpr.mdev_blocker,
+ "CPR does not support vfio mdev %s", vbasedev->name);
+ if (migrate_add_blocker_modes(&vbasedev->cpr.mdev_blocker, errp,
+ MIG_MODE_CPR_TRANSFER, -1) < 0) {
+ goto hiod_unref_exit;
+ }
+ }
return true;
+
+hiod_unref_exit:
+ object_unref(vbasedev->hiod);
+device_put_exit:
+ vfio_device_put(vbasedev);
+group_put_exit:
+ vfio_group_put(group);
+ return false;
}
static void vfio_legacy_detach_device(VFIODevice *vbasedev)
{
VFIOGroup *group = vbasedev->group;
- QLIST_REMOVE(vbasedev, global_next);
- QLIST_REMOVE(vbasedev, container_next);
- vbasedev->bcontainer = NULL;
- trace_vfio_detach_device(vbasedev->name, group->groupid);
- vfio_put_base_device(vbasedev);
- vfio_put_group(group);
+ trace_vfio_device_detach(vbasedev->name, group->groupid);
+
+ vfio_device_unprepare(vbasedev);
+
+ migrate_del_blocker(&vbasedev->cpr.mdev_blocker);
+ object_unref(vbasedev->hiod);
+ vfio_device_put(vbasedev);
+ vfio_group_put(group);
}
static int vfio_legacy_pci_hot_reset(VFIODevice *vbasedev, bool single)
@@ -1123,12 +1191,10 @@ out_single:
return ret;
}
-static void vfio_iommu_legacy_class_init(ObjectClass *klass, void *data)
+static void vfio_iommu_legacy_class_init(ObjectClass *klass, const void *data)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
- vioc->hiod_typename = TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO;
-
vioc->setup = vfio_legacy_setup;
vioc->dma_map = vfio_legacy_dma_map;
vioc->dma_unmap = vfio_legacy_dma_unmap;
@@ -1187,7 +1253,7 @@ static void vfio_iommu_legacy_instance_init(Object *obj)
QLIST_INIT(&container->group_list);
}
-static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data)
+static void hiod_legacy_vfio_class_init(ObjectClass *oc, const void *data)
{
HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc);
diff --git a/hw/vfio/cpr-legacy.c b/hw/vfio/cpr-legacy.c
new file mode 100644
index 0000000..a84c324
--- /dev/null
+++ b/hw/vfio/cpr-legacy.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2021-2025 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/ioctl.h>
+#include <linux/vfio.h>
+#include "qemu/osdep.h"
+#include "hw/vfio/vfio-container.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio/vfio-listener.h"
+#include "migration/blocker.h"
+#include "migration/cpr.h"
+#include "migration/migration.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+
+static bool vfio_dma_unmap_vaddr_all(VFIOContainer *container, Error **errp)
+{
+ struct vfio_iommu_type1_dma_unmap unmap = {
+ .argsz = sizeof(unmap),
+ .flags = VFIO_DMA_UNMAP_FLAG_VADDR | VFIO_DMA_UNMAP_FLAG_ALL,
+ .iova = 0,
+ .size = 0,
+ };
+ if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
+ error_setg_errno(errp, errno, "vfio_dma_unmap_vaddr_all");
+ return false;
+ }
+ container->cpr.vaddr_unmapped = true;
+ return true;
+}
+
+/*
+ * Set the new @vaddr for any mappings registered during cpr load.
+ * The incoming state is cleared thereafter.
+ */
+static int vfio_legacy_cpr_dma_map(const VFIOContainerBase *bcontainer,
+ hwaddr iova, ram_addr_t size, void *vaddr,
+ bool readonly, MemoryRegion *mr)
+{
+ const VFIOContainer *container = container_of(bcontainer, VFIOContainer,
+ bcontainer);
+ struct vfio_iommu_type1_dma_map map = {
+ .argsz = sizeof(map),
+ .flags = VFIO_DMA_MAP_FLAG_VADDR,
+ .vaddr = (__u64)(uintptr_t)vaddr,
+ .iova = iova,
+ .size = size,
+ };
+
+ g_assert(cpr_is_incoming());
+
+ if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map)) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+static void vfio_region_remap(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ VFIOContainer *container = container_of(listener, VFIOContainer,
+ cpr.remap_listener);
+ vfio_container_region_add(&container->bcontainer, section, true);
+}
+
+static bool vfio_cpr_supported(VFIOContainer *container, Error **errp)
+{
+ if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR)) {
+ error_setg(errp, "VFIO container does not support VFIO_UPDATE_VADDR");
+ return false;
+
+ } else if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UNMAP_ALL)) {
+ error_setg(errp, "VFIO container does not support VFIO_UNMAP_ALL");
+ return false;
+
+ } else {
+ return true;
+ }
+}
+
+static int vfio_container_pre_save(void *opaque)
+{
+ VFIOContainer *container = opaque;
+ Error *local_err = NULL;
+
+ if (!vfio_dma_unmap_vaddr_all(container, &local_err)) {
+ error_report_err(local_err);
+ return -1;
+ }
+ return 0;
+}
+
+static int vfio_container_post_load(void *opaque, int version_id)
+{
+ VFIOContainer *container = opaque;
+ VFIOContainerBase *bcontainer = &container->bcontainer;
+ VFIOGroup *group;
+ Error *local_err = NULL;
+
+ if (!vfio_listener_register(bcontainer, &local_err)) {
+ error_report_err(local_err);
+ return -1;
+ }
+
+ QLIST_FOREACH(group, &container->group_list, container_next) {
+ VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+
+ /* Restore original dma_map function */
+ vioc->dma_map = container->cpr.saved_dma_map;
+ }
+ return 0;
+}
+
+static const VMStateDescription vfio_container_vmstate = {
+ .name = "vfio-container",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .priority = MIG_PRI_LOW, /* Must happen after devices and groups */
+ .pre_save = vfio_container_pre_save,
+ .post_load = vfio_container_post_load,
+ .needed = cpr_incoming_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int vfio_cpr_fail_notifier(NotifierWithReturn *notifier,
+ MigrationEvent *e, Error **errp)
+{
+ VFIOContainer *container =
+ container_of(notifier, VFIOContainer, cpr.transfer_notifier);
+ VFIOContainerBase *bcontainer = &container->bcontainer;
+
+ if (e->type != MIG_EVENT_PRECOPY_FAILED) {
+ return 0;
+ }
+
+ if (container->cpr.vaddr_unmapped) {
+ /*
+ * Force a call to vfio_region_remap for each mapped section by
+ * temporarily registering a listener, and temporarily diverting
+ * dma_map to vfio_legacy_cpr_dma_map. The latter restores vaddr.
+ */
+
+ VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+ vioc->dma_map = vfio_legacy_cpr_dma_map;
+
+ container->cpr.remap_listener = (MemoryListener) {
+ .name = "vfio cpr recover",
+ .region_add = vfio_region_remap
+ };
+ memory_listener_register(&container->cpr.remap_listener,
+ bcontainer->space->as);
+ memory_listener_unregister(&container->cpr.remap_listener);
+ container->cpr.vaddr_unmapped = false;
+ vioc->dma_map = container->cpr.saved_dma_map;
+ }
+ return 0;
+}
+
+bool vfio_legacy_cpr_register_container(VFIOContainer *container, Error **errp)
+{
+ VFIOContainerBase *bcontainer = &container->bcontainer;
+ Error **cpr_blocker = &container->cpr.blocker;
+
+ migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier,
+ vfio_cpr_reboot_notifier,
+ MIG_MODE_CPR_REBOOT);
+
+ if (!vfio_cpr_supported(container, cpr_blocker)) {
+ return migrate_add_blocker_modes(cpr_blocker, errp,
+ MIG_MODE_CPR_TRANSFER, -1) == 0;
+ }
+
+ vmstate_register(NULL, -1, &vfio_container_vmstate, container);
+
+ /* During incoming CPR, divert calls to dma_map. */
+ if (cpr_is_incoming()) {
+ VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
+ container->cpr.saved_dma_map = vioc->dma_map;
+ vioc->dma_map = vfio_legacy_cpr_dma_map;
+ }
+
+ migration_add_notifier_mode(&container->cpr.transfer_notifier,
+ vfio_cpr_fail_notifier,
+ MIG_MODE_CPR_TRANSFER);
+ return true;
+}
+
+void vfio_legacy_cpr_unregister_container(VFIOContainer *container)
+{
+ VFIOContainerBase *bcontainer = &container->bcontainer;
+
+ migration_remove_notifier(&bcontainer->cpr_reboot_notifier);
+ migrate_del_blocker(&container->cpr.blocker);
+ vmstate_unregister(NULL, &vfio_container_vmstate, container);
+ migration_remove_notifier(&container->cpr.transfer_notifier);
+}
+
+/*
+ * In old QEMU, VFIO_DMA_UNMAP_FLAG_VADDR may fail on some mapping after
+ * succeeding for others, so the latter have lost their vaddr. Call this
+ * to restore vaddr for a section with a giommu.
+ *
+ * The giommu already exists. Find it and replay it, which calls
+ * vfio_legacy_cpr_dma_map further down the stack.
+ */
+void vfio_cpr_giommu_remap(VFIOContainerBase *bcontainer,
+ MemoryRegionSection *section)
+{
+ VFIOGuestIOMMU *giommu = NULL;
+ hwaddr as_offset = section->offset_within_address_space;
+ hwaddr iommu_offset = as_offset - section->offset_within_region;
+
+ QLIST_FOREACH(giommu, &bcontainer->giommu_list, giommu_next) {
+ if (giommu->iommu_mr == IOMMU_MEMORY_REGION(section->mr) &&
+ giommu->iommu_offset == iommu_offset) {
+ break;
+ }
+ }
+ g_assert(giommu);
+ memory_region_iommu_replay(giommu->iommu_mr, &giommu->n);
+}
+
+/*
+ * In old QEMU, VFIO_DMA_UNMAP_FLAG_VADDR may fail on some mapping after
+ * succeeding for others, so the latter have lost their vaddr. Call this
+ * to restore vaddr for a section with a RamDiscardManager.
+ *
+ * The ram discard listener already exists. Call its populate function
+ * directly, which calls vfio_legacy_cpr_dma_map.
+ */
+bool vfio_cpr_ram_discard_register_listener(VFIOContainerBase *bcontainer,
+ MemoryRegionSection *section)
+{
+ VFIORamDiscardListener *vrdl =
+ vfio_find_ram_discard_listener(bcontainer, section);
+
+ g_assert(vrdl);
+ return vrdl->listener.notify_populate(&vrdl->listener, section) == 0;
+}
+
+int vfio_cpr_group_get_device_fd(int d, const char *name)
+{
+ const int id = 0;
+ int fd = cpr_find_fd(name, id);
+
+ if (fd < 0) {
+ fd = ioctl(d, VFIO_GROUP_GET_DEVICE_FD, name);
+ if (fd >= 0) {
+ cpr_save_fd(name, id, fd);
+ }
+ }
+ return fd;
+}
+
+static bool same_device(int fd1, int fd2)
+{
+ struct stat st1, st2;
+
+ return !fstat(fd1, &st1) && !fstat(fd2, &st2) && st1.st_dev == st2.st_dev;
+}
+
+bool vfio_cpr_container_match(VFIOContainer *container, VFIOGroup *group,
+ int fd)
+{
+ if (container->fd == fd) {
+ return true;
+ }
+ if (!same_device(container->fd, fd)) {
+ return false;
+ }
+ /*
+ * Same device, different fd. This occurs when the container fd is
+ * cpr_save'd multiple times, once for each groupid, so SCM_RIGHTS
+ * produces duplicates. De-dup it.
+ */
+ cpr_delete_fd("vfio_container_for_group", group->groupid);
+ close(fd);
+ cpr_save_fd("vfio_container_for_group", group->groupid, container->fd);
+ return true;
+}
diff --git a/hw/vfio/cpr.c b/hw/vfio/cpr.c
index 87e51fc..fdbb58e 100644
--- a/hw/vfio/cpr.c
+++ b/hw/vfio/cpr.c
@@ -6,13 +6,15 @@
*/
#include "qemu/osdep.h"
-#include "hw/vfio/vfio-common.h"
-#include "migration/misc.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio/vfio-cpr.h"
+#include "hw/vfio/pci.h"
+#include "migration/cpr.h"
#include "qapi/error.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
-static int vfio_cpr_reboot_notifier(NotifierWithReturn *notifier,
- MigrationEvent *e, Error **errp)
+int vfio_cpr_reboot_notifier(NotifierWithReturn *notifier,
+ MigrationEvent *e, Error **errp)
{
if (e->type == MIG_EVENT_PRECOPY_SETUP &&
!runstate_check(RUN_STATE_SUSPENDED) && !vm_get_suspended()) {
@@ -37,3 +39,32 @@ void vfio_cpr_unregister_container(VFIOContainerBase *bcontainer)
{
migration_remove_notifier(&bcontainer->cpr_reboot_notifier);
}
+
+/*
+ * The kernel may change non-emulated config bits. Exclude them from the
+ * changed-bits check in get_pci_config_device.
+ */
+static int vfio_cpr_pci_pre_load(void *opaque)
+{
+ VFIOPCIDevice *vdev = opaque;
+ PCIDevice *pdev = &vdev->pdev;
+ int size = MIN(pci_config_size(pdev), vdev->config_size);
+ int i;
+
+ for (i = 0; i < size; i++) {
+ pdev->cmask[i] &= vdev->emulated_config_bits[i];
+ }
+
+ return 0;
+}
+
+const VMStateDescription vfio_cpr_pci_vmstate = {
+ .name = "vfio-cpr-pci",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .pre_load = vfio_cpr_pci_pre_load,
+ .needed = cpr_incoming_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ }
+};
diff --git a/hw/vfio/device.c b/hw/vfio/device.c
new file mode 100644
index 0000000..d91c695
--- /dev/null
+++ b/hw/vfio/device.c
@@ -0,0 +1,576 @@
+/*
+ * VFIO device
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Based on qemu-kvm device-assignment:
+ * Adapted for KVM by Qumranet.
+ * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
+ */
+
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio/pci.h"
+#include "hw/hw.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "monitor/monitor.h"
+#include "vfio-helpers.h"
+
+VFIODeviceList vfio_device_list =
+ QLIST_HEAD_INITIALIZER(vfio_device_list);
+
+/*
+ * We want to differentiate hot reset of multiple in-use devices vs
+ * hot reset of a single in-use device. VFIO_DEVICE_RESET will already
+ * handle the case of doing hot resets when there is only a single
+ * device per bus. The in-use here refers to how many VFIODevices are
+ * affected. A hot reset that affects multiple devices, but only a
+ * single in-use device, means that we can call it from our bus
+ * ->reset() callback since the extent is effectively a single
+ * device. This allows us to make use of it in the hotplug path. When
+ * there are multiple in-use devices, we can only trigger the hot
+ * reset during a system reset and thus from our reset handler. We
+ * separate _one vs _multi here so that we don't overlap and do a
+ * double reset on the system reset path where both our reset handler
+ * and ->reset() callback are used. Calling _one() will only do a hot
+ * reset for the one in-use devices case, calling _multi() will do
+ * nothing if a _one() would have been sufficient.
+ */
+void vfio_device_reset_handler(void *opaque)
+{
+ VFIODevice *vbasedev;
+
+ trace_vfio_device_reset_handler();
+ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
+ if (vbasedev->dev->realized) {
+ vbasedev->ops->vfio_compute_needs_reset(vbasedev);
+ }
+ }
+
+ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
+ if (vbasedev->dev->realized && vbasedev->needs_reset) {
+ vbasedev->ops->vfio_hot_reset_multi(vbasedev);
+ }
+ }
+}
+
+/*
+ * Common VFIO interrupt disable
+ */
+void vfio_device_irq_disable(VFIODevice *vbasedev, int index)
+{
+ struct vfio_irq_set irq_set = {
+ .argsz = sizeof(irq_set),
+ .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
+ .index = index,
+ .start = 0,
+ .count = 0,
+ };
+
+ vbasedev->io_ops->set_irqs(vbasedev, &irq_set);
+}
+
+void vfio_device_irq_unmask(VFIODevice *vbasedev, int index)
+{
+ struct vfio_irq_set irq_set = {
+ .argsz = sizeof(irq_set),
+ .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
+ .index = index,
+ .start = 0,
+ .count = 1,
+ };
+
+ vbasedev->io_ops->set_irqs(vbasedev, &irq_set);
+}
+
+void vfio_device_irq_mask(VFIODevice *vbasedev, int index)
+{
+ struct vfio_irq_set irq_set = {
+ .argsz = sizeof(irq_set),
+ .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
+ .index = index,
+ .start = 0,
+ .count = 1,
+ };
+
+ vbasedev->io_ops->set_irqs(vbasedev, &irq_set);
+}
+
+static inline const char *action_to_str(int action)
+{
+ switch (action) {
+ case VFIO_IRQ_SET_ACTION_MASK:
+ return "MASK";
+ case VFIO_IRQ_SET_ACTION_UNMASK:
+ return "UNMASK";
+ case VFIO_IRQ_SET_ACTION_TRIGGER:
+ return "TRIGGER";
+ default:
+ return "UNKNOWN ACTION";
+ }
+}
+
+static const char *index_to_str(VFIODevice *vbasedev, int index)
+{
+ if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) {
+ return NULL;
+ }
+
+ switch (index) {
+ case VFIO_PCI_INTX_IRQ_INDEX:
+ return "INTX";
+ case VFIO_PCI_MSI_IRQ_INDEX:
+ return "MSI";
+ case VFIO_PCI_MSIX_IRQ_INDEX:
+ return "MSIX";
+ case VFIO_PCI_ERR_IRQ_INDEX:
+ return "ERR";
+ case VFIO_PCI_REQ_IRQ_INDEX:
+ return "REQ";
+ default:
+ return NULL;
+ }
+}
+
+bool vfio_device_irq_set_signaling(VFIODevice *vbasedev, int index, int subindex,
+ int action, int fd, Error **errp)
+{
+ ERRP_GUARD();
+ g_autofree struct vfio_irq_set *irq_set = NULL;
+ int argsz;
+ const char *name;
+ int32_t *pfd;
+
+ argsz = sizeof(*irq_set) + sizeof(*pfd);
+
+ irq_set = g_malloc0(argsz);
+ irq_set->argsz = argsz;
+ irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action;
+ irq_set->index = index;
+ irq_set->start = subindex;
+ irq_set->count = 1;
+ pfd = (int32_t *)&irq_set->data;
+ *pfd = fd;
+
+ if (!vbasedev->io_ops->set_irqs(vbasedev, irq_set)) {
+ return true;
+ }
+
+ error_setg_errno(errp, errno, "VFIO_DEVICE_SET_IRQS failure");
+
+ name = index_to_str(vbasedev, index);
+ if (name) {
+ error_prepend(errp, "%s-%d: ", name, subindex);
+ } else {
+ error_prepend(errp, "index %d-%d: ", index, subindex);
+ }
+ error_prepend(errp,
+ "Failed to %s %s eventfd signaling for interrupt ",
+ fd < 0 ? "tear down" : "set up", action_to_str(action));
+ return false;
+}
+
+int vfio_device_get_irq_info(VFIODevice *vbasedev, int index,
+ struct vfio_irq_info *info)
+{
+ memset(info, 0, sizeof(*info));
+
+ info->argsz = sizeof(*info);
+ info->index = index;
+
+ return vbasedev->io_ops->get_irq_info(vbasedev, info);
+}
+
+int vfio_device_get_region_info(VFIODevice *vbasedev, int index,
+ struct vfio_region_info **info)
+{
+ size_t argsz = sizeof(struct vfio_region_info);
+ int fd = -1;
+ int ret;
+
+ /* check cache */
+ if (vbasedev->reginfo[index] != NULL) {
+ *info = vbasedev->reginfo[index];
+ return 0;
+ }
+
+ *info = g_malloc0(argsz);
+
+ (*info)->index = index;
+retry:
+ (*info)->argsz = argsz;
+
+ ret = vbasedev->io_ops->get_region_info(vbasedev, *info, &fd);
+ if (ret != 0) {
+ g_free(*info);
+ *info = NULL;
+ return ret;
+ }
+
+ if ((*info)->argsz > argsz) {
+ argsz = (*info)->argsz;
+ *info = g_realloc(*info, argsz);
+
+ if (fd != -1) {
+ close(fd);
+ fd = -1;
+ }
+
+ goto retry;
+ }
+
+ /* fill cache */
+ vbasedev->reginfo[index] = *info;
+ if (vbasedev->region_fds != NULL) {
+ vbasedev->region_fds[index] = fd;
+ }
+
+ return 0;
+}
+
+int vfio_device_get_region_fd(VFIODevice *vbasedev, int index)
+{
+ return vbasedev->region_fds ?
+ vbasedev->region_fds[index] :
+ vbasedev->fd;
+}
+
+int vfio_device_get_region_info_type(VFIODevice *vbasedev, uint32_t type,
+ uint32_t subtype, struct vfio_region_info **info)
+{
+ int i;
+
+ for (i = 0; i < vbasedev->num_regions; i++) {
+ struct vfio_info_cap_header *hdr;
+ struct vfio_region_info_cap_type *cap_type;
+
+ if (vfio_device_get_region_info(vbasedev, i, info)) {
+ continue;
+ }
+
+ hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE);
+ if (!hdr) {
+ continue;
+ }
+
+ cap_type = container_of(hdr, struct vfio_region_info_cap_type, header);
+
+ trace_vfio_device_get_region_info_type(vbasedev->name, i,
+ cap_type->type, cap_type->subtype);
+
+ if (cap_type->type == type && cap_type->subtype == subtype) {
+ return 0;
+ }
+ }
+
+ *info = NULL;
+ return -ENODEV;
+}
+
+bool vfio_device_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type)
+{
+ struct vfio_region_info *info = NULL;
+ bool ret = false;
+
+ if (!vfio_device_get_region_info(vbasedev, region, &info)) {
+ if (vfio_get_region_info_cap(info, cap_type)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp)
+{
+ ERRP_GUARD();
+ struct stat st;
+
+ if (vbasedev->fd < 0) {
+ if (stat(vbasedev->sysfsdev, &st) < 0) {
+ error_setg_errno(errp, errno, "no such host device");
+ error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev);
+ return false;
+ }
+ /* User may specify a name, e.g: VFIO platform device */
+ if (!vbasedev->name) {
+ vbasedev->name = g_path_get_basename(vbasedev->sysfsdev);
+ }
+ } else {
+ if (!vbasedev->iommufd) {
+ error_setg(errp, "Use FD passing only with iommufd backend");
+ return false;
+ }
+ /*
+ * Give a name with fd so any function printing out vbasedev->name
+ * will not break.
+ */
+ if (!vbasedev->name) {
+ vbasedev->name = g_strdup_printf("VFIO_FD%d", vbasedev->fd);
+ }
+ }
+
+ return true;
+}
+
+void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp)
+{
+ ERRP_GUARD();
+ int fd = monitor_fd_param(monitor_cur(), str, errp);
+
+ if (fd < 0) {
+ error_prepend(errp, "Could not parse remote object fd %s:", str);
+ return;
+ }
+ vbasedev->fd = fd;
+}
+
+static VFIODeviceIOOps vfio_device_io_ops_ioctl;
+
+void vfio_device_init(VFIODevice *vbasedev, int type, VFIODeviceOps *ops,
+ DeviceState *dev, bool ram_discard)
+{
+ vbasedev->type = type;
+ vbasedev->ops = ops;
+ vbasedev->io_ops = &vfio_device_io_ops_ioctl;
+ vbasedev->dev = dev;
+ vbasedev->fd = -1;
+ vbasedev->use_region_fds = false;
+
+ vbasedev->ram_block_discard_allowed = ram_discard;
+}
+
+int vfio_device_get_aw_bits(VFIODevice *vdev)
+{
+ /*
+ * iova_ranges is a sorted list. For old kernels that support
+ * VFIO but not support query of iova ranges, iova_ranges is NULL,
+ * in this case HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX(64) is returned.
+ */
+ GList *l = g_list_last(vdev->bcontainer->iova_ranges);
+
+ if (l) {
+ Range *range = l->data;
+ return range_get_last_bit(range) + 1;
+ }
+
+ return HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX;
+}
+
+bool vfio_device_is_mdev(VFIODevice *vbasedev)
+{
+ g_autofree char *subsys = NULL;
+ g_autofree char *tmp = NULL;
+
+ if (!vbasedev->sysfsdev) {
+ return false;
+ }
+
+ tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev);
+ subsys = realpath(tmp, NULL);
+ return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0);
+}
+
+bool vfio_device_hiod_create_and_realize(VFIODevice *vbasedev,
+ const char *typename, Error **errp)
+{
+ HostIOMMUDevice *hiod;
+
+ if (vbasedev->mdev) {
+ return true;
+ }
+
+ hiod = HOST_IOMMU_DEVICE(object_new(typename));
+
+ if (!HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp)) {
+ object_unref(hiod);
+ return false;
+ }
+
+ vbasedev->hiod = hiod;
+ return true;
+}
+
+VFIODevice *vfio_get_vfio_device(Object *obj)
+{
+ if (object_dynamic_cast(obj, TYPE_VFIO_PCI)) {
+ return &VFIO_PCI_BASE(obj)->vbasedev;
+ } else {
+ return NULL;
+ }
+}
+
+bool vfio_device_attach_by_iommu_type(const char *iommu_type, char *name,
+ VFIODevice *vbasedev, AddressSpace *as,
+ Error **errp)
+{
+ const VFIOIOMMUClass *ops =
+ VFIO_IOMMU_CLASS(object_class_by_name(iommu_type));
+
+ assert(ops);
+
+ return ops->attach_device(name, vbasedev, as, errp);
+}
+
+bool vfio_device_attach(char *name, VFIODevice *vbasedev,
+ AddressSpace *as, Error **errp)
+{
+ const char *iommu_type = vbasedev->iommufd ?
+ TYPE_VFIO_IOMMU_IOMMUFD :
+ TYPE_VFIO_IOMMU_LEGACY;
+
+ return vfio_device_attach_by_iommu_type(iommu_type, name, vbasedev,
+ as, errp);
+}
+
+void vfio_device_detach(VFIODevice *vbasedev)
+{
+ if (!vbasedev->bcontainer) {
+ return;
+ }
+ VFIO_IOMMU_GET_CLASS(vbasedev->bcontainer)->detach_device(vbasedev);
+}
+
+void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer,
+ struct vfio_device_info *info)
+{
+ vbasedev->num_irqs = info->num_irqs;
+ vbasedev->num_regions = info->num_regions;
+ vbasedev->flags = info->flags;
+ vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET);
+
+ vbasedev->bcontainer = bcontainer;
+ QLIST_INSERT_HEAD(&bcontainer->device_list, vbasedev, container_next);
+
+ QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next);
+
+ vbasedev->reginfo = g_new0(struct vfio_region_info *,
+ vbasedev->num_regions);
+ if (vbasedev->use_region_fds) {
+ vbasedev->region_fds = g_new0(int, vbasedev->num_regions);
+ }
+}
+
+void vfio_device_unprepare(VFIODevice *vbasedev)
+{
+ int i;
+
+ for (i = 0; i < vbasedev->num_regions; i++) {
+ g_free(vbasedev->reginfo[i]);
+ if (vbasedev->region_fds != NULL && vbasedev->region_fds[i] != -1) {
+ close(vbasedev->region_fds[i]);
+ }
+
+ }
+
+ g_clear_pointer(&vbasedev->reginfo, g_free);
+ g_clear_pointer(&vbasedev->region_fds, g_free);
+
+ QLIST_REMOVE(vbasedev, container_next);
+ QLIST_REMOVE(vbasedev, global_next);
+ vbasedev->bcontainer = NULL;
+}
+
+/*
+ * Traditional ioctl() based io
+ */
+
+static int vfio_device_io_device_feature(VFIODevice *vbasedev,
+ struct vfio_device_feature *feature)
+{
+ int ret;
+
+ ret = ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature);
+
+ return ret < 0 ? -errno : ret;
+}
+
+static int vfio_device_io_get_region_info(VFIODevice *vbasedev,
+ struct vfio_region_info *info,
+ int *fd)
+{
+ int ret;
+
+ *fd = -1;
+
+ ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, info);
+
+ return ret < 0 ? -errno : ret;
+}
+
+static int vfio_device_io_get_irq_info(VFIODevice *vbasedev,
+ struct vfio_irq_info *info)
+{
+ int ret;
+
+ ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, info);
+
+ return ret < 0 ? -errno : ret;
+}
+
+static int vfio_device_io_set_irqs(VFIODevice *vbasedev,
+ struct vfio_irq_set *irqs)
+{
+ int ret;
+
+ ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irqs);
+
+ return ret < 0 ? -errno : ret;
+}
+
+static int vfio_device_io_region_read(VFIODevice *vbasedev, uint8_t index,
+ off_t off, uint32_t size, void *data)
+{
+ struct vfio_region_info *info;
+ int ret;
+
+ ret = vfio_device_get_region_info(vbasedev, index, &info);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = pread(vbasedev->fd, data, size, info->offset + off);
+
+ return ret < 0 ? -errno : ret;
+}
+
+static int vfio_device_io_region_write(VFIODevice *vbasedev, uint8_t index,
+ off_t off, uint32_t size, void *data,
+ bool post)
+{
+ struct vfio_region_info *info;
+ int ret;
+
+ ret = vfio_device_get_region_info(vbasedev, index, &info);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = pwrite(vbasedev->fd, data, size, info->offset + off);
+
+ return ret < 0 ? -errno : ret;
+}
+
+static VFIODeviceIOOps vfio_device_io_ops_ioctl = {
+ .device_feature = vfio_device_io_device_feature,
+ .get_region_info = vfio_device_io_get_region_info,
+ .get_irq_info = vfio_device_io_get_irq_info,
+ .set_irqs = vfio_device_io_set_irqs,
+ .region_read = vfio_device_io_region_read,
+ .region_write = vfio_device_io_region_write,
+};
diff --git a/hw/vfio/display.c b/hw/vfio/display.c
index ea87830..9c6f5aa 100644
--- a/hw/vfio/display.c
+++ b/hw/vfio/display.c
@@ -16,9 +16,9 @@
#include "qemu/error-report.h"
#include "hw/display/edid.h"
-#include "ui/console.h"
#include "qapi/error.h"
#include "pci.h"
+#include "vfio-display.h"
#include "trace.h"
#ifndef DRM_PLANE_TYPE_PRIMARY
@@ -104,7 +104,6 @@ static void vfio_display_edid_update(VFIOPCIDevice *vdev, bool enabled,
err:
trace_vfio_display_edid_write_error();
- return;
}
static void vfio_display_edid_ui_info(void *opaque, uint32_t idx,
@@ -130,10 +129,10 @@ static bool vfio_display_edid_init(VFIOPCIDevice *vdev, Error **errp)
int fd = vdev->vbasedev.fd;
int ret;
- ret = vfio_get_dev_region_info(&vdev->vbasedev,
- VFIO_REGION_TYPE_GFX,
- VFIO_REGION_SUBTYPE_GFX_EDID,
- &dpy->edid_info);
+ ret = vfio_device_get_region_info_type(&vdev->vbasedev,
+ VFIO_REGION_TYPE_GFX,
+ VFIO_REGION_SUBTYPE_GFX_EDID,
+ &dpy->edid_info);
if (ret) {
/* Failed to get GFX edid info, allow to go through without edid. */
return true;
@@ -214,6 +213,7 @@ static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev,
struct vfio_device_gfx_plane_info plane;
VFIODMABuf *dmabuf;
int fd, ret;
+ uint32_t offset = 0;
memset(&plane, 0, sizeof(plane));
plane.argsz = sizeof(plane);
@@ -246,10 +246,10 @@ static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev,
dmabuf = g_new0(VFIODMABuf, 1);
dmabuf->dmabuf_id = plane.dmabuf_id;
- dmabuf->buf = qemu_dmabuf_new(plane.width, plane.height,
- plane.stride, 0, 0, plane.width,
+ dmabuf->buf = qemu_dmabuf_new(plane.width, plane.height, &offset,
+ &plane.stride, 0, 0, plane.width,
plane.height, plane.drm_format,
- plane.drm_format_mod, fd, false, false);
+ plane.drm_format_mod, &fd, 1, false, false);
if (plane_type == DRM_PLANE_TYPE_CURSOR) {
vfio_display_update_cursor(dmabuf, &plane);
diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c
index ea15c79..d0dbab1 100644
--- a/hw/vfio/helpers.c
+++ b/hw/vfio/helpers.c
@@ -22,240 +22,11 @@
#include "qemu/osdep.h"
#include <sys/ioctl.h>
-#include "hw/vfio/vfio-common.h"
+#include "system/kvm.h"
+#include "hw/vfio/vfio-device.h"
#include "hw/hw.h"
-#include "trace.h"
#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "monitor/monitor.h"
-
-/*
- * Common VFIO interrupt disable
- */
-void vfio_disable_irqindex(VFIODevice *vbasedev, int index)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
- .index = index,
- .start = 0,
- .count = 0,
- };
-
- ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
- .index = index,
- .start = 0,
- .count = 1,
- };
-
- ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index)
-{
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
- .index = index,
- .start = 0,
- .count = 1,
- };
-
- ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-static inline const char *action_to_str(int action)
-{
- switch (action) {
- case VFIO_IRQ_SET_ACTION_MASK:
- return "MASK";
- case VFIO_IRQ_SET_ACTION_UNMASK:
- return "UNMASK";
- case VFIO_IRQ_SET_ACTION_TRIGGER:
- return "TRIGGER";
- default:
- return "UNKNOWN ACTION";
- }
-}
-
-static const char *index_to_str(VFIODevice *vbasedev, int index)
-{
- if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) {
- return NULL;
- }
-
- switch (index) {
- case VFIO_PCI_INTX_IRQ_INDEX:
- return "INTX";
- case VFIO_PCI_MSI_IRQ_INDEX:
- return "MSI";
- case VFIO_PCI_MSIX_IRQ_INDEX:
- return "MSIX";
- case VFIO_PCI_ERR_IRQ_INDEX:
- return "ERR";
- case VFIO_PCI_REQ_IRQ_INDEX:
- return "REQ";
- default:
- return NULL;
- }
-}
-
-bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex,
- int action, int fd, Error **errp)
-{
- ERRP_GUARD();
- g_autofree struct vfio_irq_set *irq_set = NULL;
- int argsz;
- const char *name;
- int32_t *pfd;
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
-
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action;
- irq_set->index = index;
- irq_set->start = subindex;
- irq_set->count = 1;
- pfd = (int32_t *)&irq_set->data;
- *pfd = fd;
-
- if (!ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
- return true;
- }
-
- error_setg_errno(errp, errno, "VFIO_DEVICE_SET_IRQS failure");
-
- name = index_to_str(vbasedev, index);
- if (name) {
- error_prepend(errp, "%s-%d: ", name, subindex);
- } else {
- error_prepend(errp, "index %d-%d: ", index, subindex);
- }
- error_prepend(errp,
- "Failed to %s %s eventfd signaling for interrupt ",
- fd < 0 ? "tear down" : "set up", action_to_str(action));
- return false;
-}
-
-/*
- * IO Port/MMIO - Beware of the endians, VFIO is always little endian
- */
-void vfio_region_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIORegion *region = opaque;
- VFIODevice *vbasedev = region->vbasedev;
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
-
- switch (size) {
- case 1:
- buf.byte = data;
- break;
- case 2:
- buf.word = cpu_to_le16(data);
- break;
- case 4:
- buf.dword = cpu_to_le32(data);
- break;
- case 8:
- buf.qword = cpu_to_le64(data);
- break;
- default:
- hw_error("vfio: unsupported write size, %u bytes", size);
- break;
- }
-
- if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) {
- error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64
- ",%d) failed: %m",
- __func__, vbasedev->name, region->nr,
- addr, data, size);
- }
-
- trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size);
-
- /*
- * A read or write to a BAR always signals an INTx EOI. This will
- * do nothing if not pending (including not in INTx mode). We assume
- * that a BAR access is in response to an interrupt and that BAR
- * accesses will service the interrupt. Unfortunately, we don't know
- * which access will service the interrupt, so we're potentially
- * getting quite a few host interrupts per guest interrupt.
- */
- vbasedev->ops->vfio_eoi(vbasedev);
-}
-
-uint64_t vfio_region_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIORegion *region = opaque;
- VFIODevice *vbasedev = region->vbasedev;
- union {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- uint64_t qword;
- } buf;
- uint64_t data = 0;
-
- if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) {
- error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m",
- __func__, vbasedev->name, region->nr,
- addr, size);
- return (uint64_t)-1;
- }
- switch (size) {
- case 1:
- data = buf.byte;
- break;
- case 2:
- data = le16_to_cpu(buf.word);
- break;
- case 4:
- data = le32_to_cpu(buf.dword);
- break;
- case 8:
- data = le64_to_cpu(buf.qword);
- break;
- default:
- hw_error("vfio: unsupported read size, %u bytes", size);
- break;
- }
-
- trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data);
-
- /* Same as write above */
- vbasedev->ops->vfio_eoi(vbasedev);
-
- return data;
-}
-
-const MemoryRegionOps vfio_region_ops = {
- .read = vfio_region_read,
- .write = vfio_region_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 8,
- },
-};
+#include "vfio-helpers.h"
int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size)
{
@@ -304,399 +75,126 @@ vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id)
return vfio_get_cap((void *)info, info->cap_offset, id);
}
-static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
- struct vfio_region_info *info)
+struct vfio_info_cap_header *
+vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id)
{
- struct vfio_info_cap_header *hdr;
- struct vfio_region_info_cap_sparse_mmap *sparse;
- int i, j;
-
- hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
- if (!hdr) {
- return -ENODEV;
- }
-
- sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header);
-
- trace_vfio_region_sparse_mmap_header(region->vbasedev->name,
- region->nr, sparse->nr_areas);
-
- region->mmaps = g_new0(VFIOMmap, sparse->nr_areas);
-
- for (i = 0, j = 0; i < sparse->nr_areas; i++) {
- if (sparse->areas[i].size) {
- trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset,
- sparse->areas[i].offset +
- sparse->areas[i].size - 1);
- region->mmaps[j].offset = sparse->areas[i].offset;
- region->mmaps[j].size = sparse->areas[i].size;
- j++;
- }
+ if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) {
+ return NULL;
}
- region->nr_mmaps = j;
- region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap));
-
- return 0;
+ return vfio_get_cap((void *)info, info->cap_offset, id);
}
-int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region,
- int index, const char *name)
+bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
+ unsigned int *avail)
{
- g_autofree struct vfio_region_info *info = NULL;
- int ret;
+ struct vfio_info_cap_header *hdr;
+ struct vfio_iommu_type1_info_dma_avail *cap;
- ret = vfio_get_region_info(vbasedev, index, &info);
- if (ret) {
- return ret;
+ /* If the capability cannot be found, assume no DMA limiting */
+ hdr = vfio_get_iommu_type1_info_cap(info,
+ VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL);
+ if (!hdr) {
+ return false;
}
- region->vbasedev = vbasedev;
- region->flags = info->flags;
- region->size = info->size;
- region->fd_offset = info->offset;
- region->nr = index;
-
- if (region->size) {
- region->mem = g_new0(MemoryRegion, 1);
- memory_region_init_io(region->mem, obj, &vfio_region_ops,
- region, name, region->size);
-
- if (!vbasedev->no_mmap &&
- region->flags & VFIO_REGION_INFO_FLAG_MMAP) {
-
- ret = vfio_setup_region_sparse_mmaps(region, info);
-
- if (ret) {
- region->nr_mmaps = 1;
- region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
- region->mmaps[0].offset = 0;
- region->mmaps[0].size = region->size;
- }
- }
+ if (avail != NULL) {
+ cap = (void *) hdr;
+ *avail = cap->avail;
}
- trace_vfio_region_setup(vbasedev->name, index, name,
- region->flags, region->fd_offset, region->size);
- return 0;
+ return true;
}
-static void vfio_subregion_unmap(VFIORegion *region, int index)
-{
- trace_vfio_region_unmap(memory_region_name(&region->mmaps[index].mem),
- region->mmaps[index].offset,
- region->mmaps[index].offset +
- region->mmaps[index].size - 1);
- memory_region_del_subregion(region->mem, &region->mmaps[index].mem);
- munmap(region->mmaps[index].mmap, region->mmaps[index].size);
- object_unparent(OBJECT(&region->mmaps[index].mem));
- region->mmaps[index].mmap = NULL;
-}
+#ifdef CONFIG_KVM
+/*
+ * We have a single VFIO pseudo device per KVM VM. Once created it lives
+ * for the life of the VM. Closing the file descriptor only drops our
+ * reference to it and the device's reference to kvm. Therefore once
+ * initialized, this file descriptor is only released on QEMU exit and
+ * we'll re-use it should another vfio device be attached before then.
+ */
+int vfio_kvm_device_fd = -1;
+#endif
-int vfio_region_mmap(VFIORegion *region)
+int vfio_kvm_device_add_fd(int fd, Error **errp)
{
- int i, prot = 0;
- char *name;
+#ifdef CONFIG_KVM
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_FILE,
+ .attr = KVM_DEV_VFIO_FILE_ADD,
+ .addr = (uint64_t)(unsigned long)&fd,
+ };
- if (!region->mem) {
+ if (!kvm_enabled()) {
return 0;
}
- prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
- prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
-
- for (i = 0; i < region->nr_mmaps; i++) {
- region->mmaps[i].mmap = mmap(NULL, region->mmaps[i].size, prot,
- MAP_SHARED, region->vbasedev->fd,
- region->fd_offset +
- region->mmaps[i].offset);
- if (region->mmaps[i].mmap == MAP_FAILED) {
- int ret = -errno;
-
- trace_vfio_region_mmap_fault(memory_region_name(region->mem), i,
- region->fd_offset +
- region->mmaps[i].offset,
- region->fd_offset +
- region->mmaps[i].offset +
- region->mmaps[i].size - 1, ret);
-
- region->mmaps[i].mmap = NULL;
-
- for (i--; i >= 0; i--) {
- vfio_subregion_unmap(region, i);
- }
-
- return ret;
- }
-
- name = g_strdup_printf("%s mmaps[%d]",
- memory_region_name(region->mem), i);
- memory_region_init_ram_device_ptr(&region->mmaps[i].mem,
- memory_region_owner(region->mem),
- name, region->mmaps[i].size,
- region->mmaps[i].mmap);
- g_free(name);
- memory_region_add_subregion(region->mem, region->mmaps[i].offset,
- &region->mmaps[i].mem);
-
- trace_vfio_region_mmap(memory_region_name(&region->mmaps[i].mem),
- region->mmaps[i].offset,
- region->mmaps[i].offset +
- region->mmaps[i].size - 1);
- }
-
- return 0;
-}
-
-void vfio_region_unmap(VFIORegion *region)
-{
- int i;
-
- if (!region->mem) {
- return;
- }
-
- for (i = 0; i < region->nr_mmaps; i++) {
- if (region->mmaps[i].mmap) {
- vfio_subregion_unmap(region, i);
- }
- }
-}
-
-void vfio_region_exit(VFIORegion *region)
-{
- int i;
-
- if (!region->mem) {
- return;
- }
+ if (vfio_kvm_device_fd < 0) {
+ struct kvm_create_device cd = {
+ .type = KVM_DEV_TYPE_VFIO,
+ };
- for (i = 0; i < region->nr_mmaps; i++) {
- if (region->mmaps[i].mmap) {
- memory_region_del_subregion(region->mem, &region->mmaps[i].mem);
+ if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
+ error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
+ return -errno;
}
- }
-
- trace_vfio_region_exit(region->vbasedev->name, region->nr);
-}
-
-void vfio_region_finalize(VFIORegion *region)
-{
- int i;
- if (!region->mem) {
- return;
+ vfio_kvm_device_fd = cd.fd;
}
- for (i = 0; i < region->nr_mmaps; i++) {
- if (region->mmaps[i].mmap) {
- munmap(region->mmaps[i].mmap, region->mmaps[i].size);
- object_unparent(OBJECT(&region->mmaps[i].mem));
- }
- }
-
- object_unparent(OBJECT(region->mem));
-
- g_free(region->mem);
- g_free(region->mmaps);
-
- trace_vfio_region_finalize(region->vbasedev->name, region->nr);
-
- region->mem = NULL;
- region->mmaps = NULL;
- region->nr_mmaps = 0;
- region->size = 0;
- region->flags = 0;
- region->nr = 0;
-}
-
-void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled)
-{
- int i;
-
- if (!region->mem) {
- return;
- }
-
- for (i = 0; i < region->nr_mmaps; i++) {
- if (region->mmaps[i].mmap) {
- memory_region_set_enabled(&region->mmaps[i].mem, enabled);
- }
- }
-
- trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem),
- enabled);
-}
-
-int vfio_get_region_info(VFIODevice *vbasedev, int index,
- struct vfio_region_info **info)
-{
- size_t argsz = sizeof(struct vfio_region_info);
-
- *info = g_malloc0(argsz);
-
- (*info)->index = index;
-retry:
- (*info)->argsz = argsz;
-
- if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) {
- g_free(*info);
- *info = NULL;
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
+ fd);
return -errno;
}
-
- if ((*info)->argsz > argsz) {
- argsz = (*info)->argsz;
- *info = g_realloc(*info, argsz);
-
- goto retry;
- }
-
+#endif
return 0;
}
-int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
- uint32_t subtype, struct vfio_region_info **info)
+int vfio_kvm_device_del_fd(int fd, Error **errp)
{
- int i;
-
- for (i = 0; i < vbasedev->num_regions; i++) {
- struct vfio_info_cap_header *hdr;
- struct vfio_region_info_cap_type *cap_type;
-
- if (vfio_get_region_info(vbasedev, i, info)) {
- continue;
- }
-
- hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE);
- if (!hdr) {
- g_free(*info);
- continue;
- }
-
- cap_type = container_of(hdr, struct vfio_region_info_cap_type, header);
-
- trace_vfio_get_dev_region(vbasedev->name, i,
- cap_type->type, cap_type->subtype);
-
- if (cap_type->type == type && cap_type->subtype == subtype) {
- return 0;
- }
-
- g_free(*info);
- }
-
- *info = NULL;
- return -ENODEV;
-}
-
-bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type)
-{
- g_autofree struct vfio_region_info *info = NULL;
- bool ret = false;
-
- if (!vfio_get_region_info(vbasedev, region, &info)) {
- if (vfio_get_region_info_cap(info, cap_type)) {
- ret = true;
- }
- }
-
- return ret;
-}
+#ifdef CONFIG_KVM
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_FILE,
+ .attr = KVM_DEV_VFIO_FILE_DEL,
+ .addr = (uint64_t)(unsigned long)&fd,
+ };
-bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp)
-{
- ERRP_GUARD();
- struct stat st;
-
- if (vbasedev->fd < 0) {
- if (stat(vbasedev->sysfsdev, &st) < 0) {
- error_setg_errno(errp, errno, "no such host device");
- error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev);
- return false;
- }
- /* User may specify a name, e.g: VFIO platform device */
- if (!vbasedev->name) {
- vbasedev->name = g_path_get_basename(vbasedev->sysfsdev);
- }
- } else {
- if (!vbasedev->iommufd) {
- error_setg(errp, "Use FD passing only with iommufd backend");
- return false;
- }
- /*
- * Give a name with fd so any function printing out vbasedev->name
- * will not break.
- */
- if (!vbasedev->name) {
- vbasedev->name = g_strdup_printf("VFIO_FD%d", vbasedev->fd);
- }
+ if (vfio_kvm_device_fd < 0) {
+ error_setg(errp, "KVM VFIO device isn't created yet");
+ return -EINVAL;
}
- return true;
-}
-
-void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp)
-{
- ERRP_GUARD();
- int fd = monitor_fd_param(monitor_cur(), str, errp);
-
- if (fd < 0) {
- error_prepend(errp, "Could not parse remote object fd %s:", str);
- return;
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
+ error_setg_errno(errp, errno,
+ "Failed to remove fd %d from KVM VFIO device", fd);
+ return -errno;
}
- vbasedev->fd = fd;
+#endif
+ return 0;
}
-void vfio_device_init(VFIODevice *vbasedev, int type, VFIODeviceOps *ops,
- DeviceState *dev, bool ram_discard)
+struct vfio_device_info *vfio_get_device_info(int fd)
{
- vbasedev->type = type;
- vbasedev->ops = ops;
- vbasedev->dev = dev;
- vbasedev->fd = -1;
-
- vbasedev->ram_block_discard_allowed = ram_discard;
-}
+ struct vfio_device_info *info;
+ uint32_t argsz = sizeof(*info);
-int vfio_device_get_aw_bits(VFIODevice *vdev)
-{
- /*
- * iova_ranges is a sorted list. For old kernels that support
- * VFIO but not support query of iova ranges, iova_ranges is NULL,
- * in this case HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX(64) is returned.
- */
- GList *l = g_list_last(vdev->bcontainer->iova_ranges);
-
- if (l) {
- Range *range = l->data;
- return range_get_last_bit(range) + 1;
- }
+ info = g_malloc0(argsz);
- return HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX;
-}
-
-bool vfio_device_is_mdev(VFIODevice *vbasedev)
-{
- g_autofree char *subsys = NULL;
- g_autofree char *tmp = NULL;
+retry:
+ info->argsz = argsz;
- if (!vbasedev->sysfsdev) {
- return false;
+ if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) {
+ g_free(info);
+ return NULL;
}
- tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev);
- subsys = realpath(tmp, NULL);
- return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0);
-}
-
-bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp)
-{
- HostIOMMUDevice *hiod = vbasedev->hiod;
-
- if (!hiod) {
- return true;
+ if (info->argsz > argsz) {
+ argsz = info->argsz;
+ info = g_realloc(info, argsz);
+ goto retry;
}
- return HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp);
+ return info;
}
diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
index d320d03..e7a9d1f 100644
--- a/hw/vfio/igd.c
+++ b/hw/vfio/igd.c
@@ -14,9 +14,12 @@
#include "qemu/units.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
+#include "qapi/qmp/qerror.h"
+#include "hw/boards.h"
#include "hw/hw.h"
#include "hw/nvram/fw_cfg.h"
#include "pci.h"
+#include "pci-quirks.h"
#include "trace.h"
/*
@@ -59,49 +62,151 @@
*/
static int igd_gen(VFIOPCIDevice *vdev)
{
- if ((vdev->device_id & 0xfff) == 0xa84) {
- return 8; /* Broxton */
+ /*
+ * Device IDs for Broxton/Apollo Lake are 0x0a84, 0x1a84, 0x1a85, 0x5a84
+ * and 0x5a85, match bit 11:1 here
+ * Prefix 0x0a is taken by Haswell, this rule should be matched first.
+ */
+ if ((vdev->device_id & 0xffe) == 0xa84) {
+ return 9;
}
switch (vdev->device_id & 0xff00) {
- /* Old, untested, unavailable, unknown */
- case 0x0000:
- case 0x2500:
- case 0x2700:
- case 0x2900:
- case 0x2a00:
- case 0x2e00:
- case 0x3500:
- case 0xa000:
- return -1;
- /* SandyBridge, IvyBridge, ValleyView, Haswell */
- case 0x0100:
- case 0x0400:
- case 0x0a00:
- case 0x0c00:
- case 0x0d00:
- case 0x0f00:
+ case 0x0100: /* SandyBridge, IvyBridge */
return 6;
- /* BroadWell, CherryView, SkyLake, KabyLake */
- case 0x1600:
- case 0x1900:
- case 0x2200:
- case 0x5900:
+ case 0x0400: /* Haswell */
+ case 0x0a00: /* Haswell */
+ case 0x0c00: /* Haswell */
+ case 0x0d00: /* Haswell */
+ case 0x0f00: /* Valleyview/Bay Trail */
+ return 7;
+ case 0x1600: /* Broadwell */
+ case 0x2200: /* Cherryview */
return 8;
+ case 0x1900: /* Skylake */
+ case 0x3100: /* Gemini Lake */
+ case 0x5900: /* Kaby Lake */
+ case 0x3e00: /* Coffee Lake */
+ case 0x9B00: /* Comet Lake */
+ return 9;
+ case 0x8A00: /* Ice Lake */
+ case 0x4500: /* Elkhart Lake */
+ case 0x4E00: /* Jasper Lake */
+ return 11;
+ case 0x9A00: /* Tiger Lake */
+ case 0x4C00: /* Rocket Lake */
+ case 0x4600: /* Alder Lake */
+ case 0xA700: /* Raptor Lake */
+ return 12;
}
- return 8; /* Assume newer is compatible */
+ /*
+ * Unfortunately, Intel changes it's specification quite often. This makes
+ * it impossible to use a suitable default value for unknown devices.
+ * Return -1 for not applying any generation-specific quirks.
+ */
+ return -1;
}
-typedef struct VFIOIGDQuirk {
- struct VFIOPCIDevice *vdev;
- uint32_t index;
- uint32_t bdsm;
-} VFIOIGDQuirk;
-
+#define IGD_ASLS 0xfc /* ASL Storage Register */
#define IGD_GMCH 0x50 /* Graphics Control Register */
#define IGD_BDSM 0x5c /* Base Data of Stolen Memory */
+#define IGD_BDSM_GEN11 0xc0 /* Base Data of Stolen Memory of gen 11 and later */
+
+#define IGD_GMCH_GEN6_GMS_SHIFT 3 /* SNB_GMCH in i915 */
+#define IGD_GMCH_GEN6_GMS_MASK 0x1f
+#define IGD_GMCH_GEN8_GMS_SHIFT 8 /* BDW_GMCH in i915 */
+#define IGD_GMCH_GEN8_GMS_MASK 0xff
+static uint64_t igd_stolen_memory_size(int gen, uint32_t gmch)
+{
+ uint64_t gms;
+
+ if (gen < 8) {
+ gms = (gmch >> IGD_GMCH_GEN6_GMS_SHIFT) & IGD_GMCH_GEN6_GMS_MASK;
+ } else {
+ gms = (gmch >> IGD_GMCH_GEN8_GMS_SHIFT) & IGD_GMCH_GEN8_GMS_MASK;
+ }
+
+ if (gen < 9) {
+ return gms * 32 * MiB;
+ } else {
+ if (gms < 0xf0) {
+ return gms * 32 * MiB;
+ } else {
+ return (gms - 0xf0 + 1) * 4 * MiB;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The OpRegion includes the Video BIOS Table, which seems important for
+ * telling the driver what sort of outputs it has. Without this, the device
+ * may work in the guest, but we may not get output. This also requires BIOS
+ * support to reserve and populate a section of guest memory sufficient for
+ * the table and to write the base address of that memory to the ASLS register
+ * of the IGD device.
+ */
+static bool vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
+ struct vfio_region_info *info,
+ Error **errp)
+{
+ int ret;
+
+ vdev->igd_opregion = g_malloc0(info->size);
+ ret = pread(vdev->vbasedev.fd, vdev->igd_opregion,
+ info->size, info->offset);
+ if (ret != info->size) {
+ error_setg(errp, "failed to read IGD OpRegion");
+ g_free(vdev->igd_opregion);
+ vdev->igd_opregion = NULL;
+ return false;
+ }
+
+ /*
+ * Provide fw_cfg with a copy of the OpRegion which the VM firmware is to
+ * allocate 32bit reserved memory for, copy these contents into, and write
+ * the reserved memory base address to the device ASLS register at 0xFC.
+ * Alignment of this reserved region seems flexible, but using a 4k page
+ * alignment seems to work well. This interface assumes a single IGD
+ * device, which may be at VM address 00:02.0 in legacy mode or another
+ * address in UPT mode.
+ *
+ * NB, there may be future use cases discovered where the VM should have
+ * direct interaction with the host OpRegion, in which case the write to
+ * the ASLS register would trigger MemoryRegion setup to enable that.
+ */
+ fw_cfg_add_file(fw_cfg_find(), "etc/igd-opregion",
+ vdev->igd_opregion, info->size);
+
+ trace_vfio_pci_igd_opregion_enabled(vdev->vbasedev.name);
+
+ return true;
+}
+
+static bool vfio_pci_igd_opregion_detect(VFIOPCIDevice *vdev,
+ struct vfio_region_info **opregion)
+{
+ int ret;
+
+ ret = vfio_device_get_region_info_type(&vdev->vbasedev,
+ VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, opregion);
+ if (ret) {
+ return false;
+ }
+
+ /* Hotplugging is not supported for opregion access */
+ if (vdev->pdev.qdev.hotplugged) {
+ warn_report("IGD device detected, but OpRegion is not supported "
+ "on hotplugged device.");
+ return false;
+ }
+
+ return true;
+}
/*
* The rather short list of registers that we copy from the host devices.
@@ -188,7 +293,8 @@ static void vfio_pci_igd_lpc_bridge_realize(PCIDevice *pdev, Error **errp)
}
}
-static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, void *data)
+static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -204,7 +310,7 @@ static const TypeInfo vfio_pci_igd_lpc_bridge_info = {
.name = "vfio-pci-igd-lpc-bridge",
.parent = TYPE_PCI_DEVICE,
.class_init = vfio_pci_igd_lpc_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -239,374 +345,373 @@ static int vfio_pci_igd_lpc_init(VFIOPCIDevice *vdev,
return ret;
}
-/*
- * IGD Gen8 and newer support up to 8MB for the GTT and use a 64bit PTE
- * entry, older IGDs use 2MB and 32bit. Each PTE maps a 4k page. Therefore
- * we either have 2M/4k * 4 = 2k or 8M/4k * 8 = 16k as the maximum iobar index
- * for programming the GTT.
- *
- * See linux:include/drm/i915_drm.h for shift and mask values.
- */
-static int vfio_igd_gtt_max(VFIOPCIDevice *vdev)
+static bool vfio_pci_igd_setup_lpc_bridge(VFIOPCIDevice *vdev, Error **errp)
{
- uint32_t gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, sizeof(gmch));
- int ggms, gen = igd_gen(vdev);
+ struct vfio_region_info *host = NULL;
+ struct vfio_region_info *lpc = NULL;
+ PCIDevice *lpc_bridge;
+ int ret;
+
+ /*
+ * Copying IDs or creating new devices are not supported on hotplug
+ */
+ if (vdev->pdev.qdev.hotplugged) {
+ error_setg(errp, "IGD LPC is not supported on hotplugged device");
+ return false;
+ }
- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, sizeof(gmch));
- ggms = (gmch >> (gen < 8 ? 8 : 6)) & 0x3;
- if (gen > 6) {
- ggms = 1 << ggms;
+ /*
+ * We need to create an LPC/ISA bridge at PCI bus address 00:1f.0 that we
+ * can stuff host values into, so if there's already one there and it's not
+ * one we can hack on, this quirk is no-go. Sorry Q35.
+ */
+ lpc_bridge = pci_find_device(pci_device_root_bus(&vdev->pdev),
+ 0, PCI_DEVFN(0x1f, 0));
+ if (lpc_bridge && !object_dynamic_cast(OBJECT(lpc_bridge),
+ "vfio-pci-igd-lpc-bridge")) {
+ error_setg(errp,
+ "Cannot create LPC bridge due to existing device at 1f.0");
+ return false;
}
- ggms *= MiB;
+ /*
+ * Check whether we have all the vfio device specific regions to
+ * support LPC quirk (added in Linux v4.6).
+ */
+ ret = vfio_device_get_region_info_type(&vdev->vbasedev,
+ VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG, &lpc);
+ if (ret) {
+ error_setg(errp, "IGD LPC bridge access is not supported by kernel");
+ return false;
+ }
- return (ggms / (4 * KiB)) * (gen < 8 ? 4 : 8);
-}
+ ret = vfio_device_get_region_info_type(&vdev->vbasedev,
+ VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
+ VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG, &host);
+ if (ret) {
+ error_setg(errp, "IGD host bridge access is not supported by kernel");
+ return false;
+ }
-/*
- * The IGD ROM will make use of stolen memory (GGMS) for support of VESA modes.
- * Somehow the host stolen memory range is used for this, but how the ROM gets
- * it is a mystery, perhaps it's hardcoded into the ROM. Thankfully though, it
- * reprograms the GTT through the IOBAR where we can trap it and transpose the
- * programming to the VM allocated buffer. That buffer gets reserved by the VM
- * firmware via the fw_cfg entry added below. Here we're just monitoring the
- * IOBAR address and data registers to detect a write sequence targeting the
- * GTTADR. This code is developed by observed behavior and doesn't have a
- * direct spec reference, unfortunately.
- */
-static uint64_t vfio_igd_quirk_data_read(void *opaque,
- hwaddr addr, unsigned size)
-{
- VFIOIGDQuirk *igd = opaque;
- VFIOPCIDevice *vdev = igd->vdev;
+ /* Create/modify LPC bridge */
+ ret = vfio_pci_igd_lpc_init(vdev, lpc);
+ if (ret) {
+ error_setg(errp, "Failed to create/modify LPC bridge for IGD");
+ return false;
+ }
- igd->index = ~0;
+ /* Stuff some host values into the VM PCI host bridge */
+ ret = vfio_pci_igd_host_init(vdev, host);
+ if (ret) {
+ error_setg(errp, "Failed to modify host bridge for IGD");
+ return false;
+ }
- return vfio_region_read(&vdev->bars[4].region, addr + 4, size);
+ return true;
}
-static void vfio_igd_quirk_data_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
+static bool vfio_pci_igd_override_gms(int gen, uint32_t gms, uint32_t *gmch)
{
- VFIOIGDQuirk *igd = opaque;
- VFIOPCIDevice *vdev = igd->vdev;
- uint64_t val = data;
- int gen = igd_gen(vdev);
-
- /*
- * Programming the GGMS starts at index 0x1 and uses every 4th index (ie.
- * 0x1, 0x5, 0x9, 0xd,...). For pre-Gen8 each 4-byte write is a whole PTE
- * entry, with 0th bit enable set. For Gen8 and up, PTEs are 64bit, so
- * entries 0x5 & 0xd are the high dword, in our case zero. Each PTE points
- * to a 4k page, which we translate to a page from the VM allocated region,
- * pointed to by the BDSM register. If this is not set, we fail.
- *
- * We trap writes to the full configured GTT size, but we typically only
- * see the vBIOS writing up to (nearly) the 1MB barrier. In fact it often
- * seems to miss the last entry for an even 1MB GTT. Doing a gratuitous
- * write of that last entry does work, but is hopefully unnecessary since
- * we clear the previous GTT on initialization.
- */
- if ((igd->index % 4 == 1) && igd->index < vfio_igd_gtt_max(vdev)) {
- if (gen < 8 || (igd->index % 8 == 1)) {
- uint32_t base;
-
- base = pci_get_long(vdev->pdev.config + IGD_BDSM);
- if (!base) {
- hw_error("vfio-igd: Guest attempted to program IGD GTT before "
- "BIOS reserved stolen memory. Unsupported BIOS?");
- }
-
- val = data - igd->bdsm + base;
+ bool ret = false;
+
+ if (gen == -1) {
+ error_report("x-igd-gms is not supported on this device");
+ } else if (gen < 8) {
+ if (gms <= 0x10) {
+ *gmch &= ~(IGD_GMCH_GEN6_GMS_MASK << IGD_GMCH_GEN6_GMS_SHIFT);
+ *gmch |= gms << IGD_GMCH_GEN6_GMS_SHIFT;
+ ret = true;
} else {
- val = 0; /* upper 32bits of pte, we only enable below 4G PTEs */
+ error_report(QERR_INVALID_PARAMETER_VALUE, "x-igd-gms", "0~0x10");
+ }
+ } else if (gen == 8) {
+ if (gms <= 0x40) {
+ *gmch &= ~(IGD_GMCH_GEN8_GMS_MASK << IGD_GMCH_GEN8_GMS_SHIFT);
+ *gmch |= gms << IGD_GMCH_GEN8_GMS_SHIFT;
+ ret = true;
+ } else {
+ error_report(QERR_INVALID_PARAMETER_VALUE, "x-igd-gms", "0~0x40");
+ }
+ } else {
+ /* 0x0 to 0x40: 32MB increments starting at 0MB */
+ /* 0xf0 to 0xfe: 4MB increments starting at 4MB */
+ if ((gms <= 0x40) || (gms >= 0xf0 && gms <= 0xfe)) {
+ *gmch &= ~(IGD_GMCH_GEN8_GMS_MASK << IGD_GMCH_GEN8_GMS_SHIFT);
+ *gmch |= gms << IGD_GMCH_GEN8_GMS_SHIFT;
+ ret = true;
+ } else {
+ error_report(QERR_INVALID_PARAMETER_VALUE,
+ "x-igd-gms", "0~0x40 or 0xf0~0xfe");
}
-
- trace_vfio_pci_igd_bar4_write(vdev->vbasedev.name,
- igd->index, data, val);
}
- vfio_region_write(&vdev->bars[4].region, addr + 4, val, size);
-
- igd->index = ~0;
+ return ret;
}
-static const MemoryRegionOps vfio_igd_data_quirk = {
- .read = vfio_igd_quirk_data_read,
- .write = vfio_igd_quirk_data_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
+#define IGD_GGC_MMIO_OFFSET 0x108040
+#define IGD_BDSM_MMIO_OFFSET 0x1080C0
-static uint64_t vfio_igd_quirk_index_read(void *opaque,
- hwaddr addr, unsigned size)
+void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr)
{
- VFIOIGDQuirk *igd = opaque;
- VFIOPCIDevice *vdev = igd->vdev;
+ VFIOQuirk *ggc_quirk, *bdsm_quirk;
+ VFIOConfigMirrorQuirk *ggc_mirror, *bdsm_mirror;
+ int gen;
- igd->index = ~0;
+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
+ !vfio_is_vga(vdev) || nr != 0) {
+ return;
+ }
- return vfio_region_read(&vdev->bars[4].region, addr, size);
-}
+ /* Only on IGD Gen6-12 device needs quirks in BAR 0 */
+ gen = igd_gen(vdev);
+ if (gen < 6) {
+ return;
+ }
-static void vfio_igd_quirk_index_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
-{
- VFIOIGDQuirk *igd = opaque;
- VFIOPCIDevice *vdev = igd->vdev;
+ if (vdev->igd_gms) {
+ ggc_quirk = vfio_quirk_alloc(1);
+ ggc_mirror = ggc_quirk->data = g_malloc0(sizeof(*ggc_mirror));
+ ggc_mirror->mem = ggc_quirk->mem;
+ ggc_mirror->vdev = vdev;
+ ggc_mirror->bar = nr;
+ ggc_mirror->offset = IGD_GGC_MMIO_OFFSET;
+ ggc_mirror->config_offset = IGD_GMCH;
+
+ memory_region_init_io(ggc_mirror->mem, OBJECT(vdev),
+ &vfio_generic_mirror_quirk, ggc_mirror,
+ "vfio-igd-ggc-quirk", 2);
+ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
+ ggc_mirror->offset, ggc_mirror->mem,
+ 1);
+
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, ggc_quirk, next);
+ }
- igd->index = data;
+ bdsm_quirk = vfio_quirk_alloc(1);
+ bdsm_mirror = bdsm_quirk->data = g_malloc0(sizeof(*bdsm_mirror));
+ bdsm_mirror->mem = bdsm_quirk->mem;
+ bdsm_mirror->vdev = vdev;
+ bdsm_mirror->bar = nr;
+ bdsm_mirror->offset = IGD_BDSM_MMIO_OFFSET;
+ bdsm_mirror->config_offset = (gen < 11) ? IGD_BDSM : IGD_BDSM_GEN11;
+
+ memory_region_init_io(bdsm_mirror->mem, OBJECT(vdev),
+ &vfio_generic_mirror_quirk, bdsm_mirror,
+ "vfio-igd-bdsm-quirk", (gen < 11) ? 4 : 8);
+ memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
+ bdsm_mirror->offset, bdsm_mirror->mem,
+ 1);
- vfio_region_write(&vdev->bars[4].region, addr, data, size);
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, bdsm_quirk, next);
}
-static const MemoryRegionOps vfio_igd_index_quirk = {
- .read = vfio_igd_quirk_index_read,
- .write = vfio_igd_quirk_index_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
+static bool vfio_pci_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp)
{
- g_autofree struct vfio_region_info *rom = NULL;
- g_autofree struct vfio_region_info *opregion = NULL;
- g_autofree struct vfio_region_info *host = NULL;
- g_autofree struct vfio_region_info *lpc = NULL;
- VFIOQuirk *quirk;
- VFIOIGDQuirk *igd;
- PCIDevice *lpc_bridge;
- int i, ret, ggms_mb, gms_mb = 0, gen;
+ struct vfio_region_info *opregion = NULL;
+ int ret, gen;
+ uint64_t gms_size = 0;
uint64_t *bdsm_size;
uint32_t gmch;
- uint16_t cmd_orig, cmd;
+ bool legacy_mode_enabled = false;
Error *err = NULL;
- /*
- * This must be an Intel VGA device at address 00:02.0 for us to even
- * consider enabling legacy mode. The vBIOS has dependencies on the
- * PCI bus address.
- */
if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
- !vfio_is_vga(vdev) || nr != 4 ||
- &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
- 0, PCI_DEVFN(0x2, 0))) {
- return;
+ !vfio_is_vga(vdev)) {
+ return true;
}
- /*
- * We need to create an LPC/ISA bridge at PCI bus address 00:1f.0 that we
- * can stuff host values into, so if there's already one there and it's not
- * one we can hack on, legacy mode is no-go. Sorry Q35.
- */
- lpc_bridge = pci_find_device(pci_device_root_bus(&vdev->pdev),
- 0, PCI_DEVFN(0x1f, 0));
- if (lpc_bridge && !object_dynamic_cast(OBJECT(lpc_bridge),
- "vfio-pci-igd-lpc-bridge")) {
- error_report("IGD device %s cannot support legacy mode due to existing "
- "devices at address 1f.0", vdev->vbasedev.name);
- return;
+ /* IGD device always comes with OpRegion */
+ if (!vfio_pci_igd_opregion_detect(vdev, &opregion)) {
+ return true;
}
+ info_report("OpRegion detected on Intel display %x.", vdev->device_id);
- /*
- * IGD is not a standard, they like to change their specs often. We
- * only attempt to support back to SandBridge and we hope that newer
- * devices maintain compatibility with generation 8.
- */
gen = igd_gen(vdev);
- if (gen != 6 && gen != 8) {
- error_report("IGD device %s is unsupported in legacy mode, "
- "try SandyBridge or newer", vdev->vbasedev.name);
- return;
- }
+ gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
/*
- * Most of what we're doing here is to enable the ROM to run, so if
- * there's no ROM, there's no point in setting up this quirk.
- * NB. We only seem to get BIOS ROMs, so a UEFI VM would need CSM support.
+ * For backward compatibility, enable legacy mode when
+ * - Device geneation is 6 to 9 (including both)
+ * - Machine type is i440fx (pc_piix)
+ * - IGD device is at guest BDF 00:02.0
+ * - Not manually disabled by x-igd-legacy-mode=off
*/
- ret = vfio_get_region_info(&vdev->vbasedev,
- VFIO_PCI_ROM_REGION_INDEX, &rom);
- if ((ret || !rom->size) && !vdev->pdev.romfile) {
- error_report("IGD device %s has no ROM, legacy mode disabled",
- vdev->vbasedev.name);
- return;
- }
+ if ((vdev->igd_legacy_mode != ON_OFF_AUTO_OFF) &&
+ (gen >= 6 && gen <= 9) &&
+ !strcmp(MACHINE_GET_CLASS(qdev_get_machine())->family, "pc_piix") &&
+ (&vdev->pdev == pci_find_device(pci_device_root_bus(&vdev->pdev),
+ 0, PCI_DEVFN(0x2, 0)))) {
+ /*
+ * IGD legacy mode requires:
+ * - VBIOS in ROM BAR or file
+ * - VGA IO/MMIO ranges are claimed by IGD
+ * - OpRegion
+ * - Same LPC bridge and Host bridge VID/DID/SVID/SSID as host
+ */
+ struct vfio_region_info *rom = NULL;
+
+ legacy_mode_enabled = true;
+ info_report("IGD legacy mode enabled, "
+ "use x-igd-legacy-mode=off to disable it if unwanted.");
+
+ /*
+ * Most of what we're doing here is to enable the ROM to run, so if
+ * there's no ROM, there's no point in setting up this quirk.
+ * NB. We only seem to get BIOS ROMs, so UEFI VM would need CSM support.
+ */
+ ret = vfio_device_get_region_info(&vdev->vbasedev,
+ VFIO_PCI_ROM_REGION_INDEX, &rom);
+ if ((ret || !rom->size) && !vdev->pdev.romfile) {
+ error_setg(&err, "Device has no ROM");
+ goto error;
+ }
- /*
- * Ignore the hotplug corner case, mark the ROM failed, we can't
- * create the devices we need for legacy mode in the hotplug scenario.
- */
- if (vdev->pdev.qdev.hotplugged) {
- error_report("IGD device %s hotplugged, ROM disabled, "
- "legacy mode disabled", vdev->vbasedev.name);
- vdev->rom_read_failed = true;
- return;
- }
+ /*
+ * If IGD VGA Disable is clear (expected) and VGA is not already
+ * enabled, try to enable it. Probably shouldn't be using legacy mode
+ * without VGA, but also no point in us enabling VGA if disabled in
+ * hardware.
+ */
+ if (!(gmch & 0x2) && !vdev->vga && !vfio_populate_vga(vdev, &err)) {
+ error_setg(&err, "Unable to enable VGA access");
+ goto error;
+ }
- /*
- * Check whether we have all the vfio device specific regions to
- * support legacy mode (added in Linux v4.6). If not, bail.
- */
- ret = vfio_get_dev_region_info(&vdev->vbasedev,
- VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
- VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion);
- if (ret) {
- error_report("IGD device %s does not support OpRegion access,"
- "legacy mode disabled", vdev->vbasedev.name);
- return;
+ /* Enable OpRegion and LPC bridge quirk */
+ vdev->features |= VFIO_FEATURE_ENABLE_IGD_OPREGION;
+ vdev->features |= VFIO_FEATURE_ENABLE_IGD_LPC;
+ } else if (vdev->igd_legacy_mode == ON_OFF_AUTO_ON) {
+ error_setg(&err,
+ "Machine is not i440fx, assigned BDF is not 00:02.0, "
+ "or device %04x (gen %d) doesn't support legacy mode",
+ vdev->device_id, gen);
+ goto error;
}
- ret = vfio_get_dev_region_info(&vdev->vbasedev,
- VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
- VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG, &host);
- if (ret) {
- error_report("IGD device %s does not support host bridge access,"
- "legacy mode disabled", vdev->vbasedev.name);
- return;
+ /* Setup OpRegion access */
+ if ((vdev->features & VFIO_FEATURE_ENABLE_IGD_OPREGION) &&
+ !vfio_pci_igd_opregion_init(vdev, opregion, errp)) {
+ goto error;
}
- ret = vfio_get_dev_region_info(&vdev->vbasedev,
- VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
- VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG, &lpc);
- if (ret) {
- error_report("IGD device %s does not support LPC bridge access,"
- "legacy mode disabled", vdev->vbasedev.name);
- return;
+ /* Setup LPC bridge / Host bridge PCI IDs */
+ if ((vdev->features & VFIO_FEATURE_ENABLE_IGD_LPC) &&
+ !vfio_pci_igd_setup_lpc_bridge(vdev, errp)) {
+ goto error;
}
- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
-
/*
- * If IGD VGA Disable is clear (expected) and VGA is not already enabled,
- * try to enable it. Probably shouldn't be using legacy mode without VGA,
- * but also no point in us enabling VGA if disabled in hardware.
+ * ASLS (OpRegion address) is read-only, emulated
+ * It contains HPA, guest firmware need to reprogram it with GPA.
*/
- if (!(gmch & 0x2) && !vdev->vga && !vfio_populate_vga(vdev, &err)) {
- error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
- error_report("IGD device %s failed to enable VGA access, "
- "legacy mode disabled", vdev->vbasedev.name);
- return;
- }
-
- /* Create our LPC/ISA bridge */
- ret = vfio_pci_igd_lpc_init(vdev, lpc);
- if (ret) {
- error_report("IGD device %s failed to create LPC bridge, "
- "legacy mode disabled", vdev->vbasedev.name);
- return;
- }
-
- /* Stuff some host values into the VM PCI host bridge */
- ret = vfio_pci_igd_host_init(vdev, host);
- if (ret) {
- error_report("IGD device %s failed to modify host bridge, "
- "legacy mode disabled", vdev->vbasedev.name);
- return;
- }
-
- /* Setup OpRegion access */
- if (!vfio_pci_igd_opregion_init(vdev, opregion, &err)) {
- error_append_hint(&err, "IGD legacy mode disabled\n");
- error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
- return;
- }
-
- /* Setup our quirk to munge GTT addresses to the VM allocated buffer */
- quirk = vfio_quirk_alloc(2);
- igd = quirk->data = g_malloc0(sizeof(*igd));
- igd->vdev = vdev;
- igd->index = ~0;
- igd->bdsm = vfio_pci_read_config(&vdev->pdev, IGD_BDSM, 4);
- igd->bdsm &= ~((1 * MiB) - 1); /* 1MB aligned */
-
- memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_igd_index_quirk,
- igd, "vfio-igd-index-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- 0, &quirk->mem[0], 1);
-
- memory_region_init_io(&quirk->mem[1], OBJECT(vdev), &vfio_igd_data_quirk,
- igd, "vfio-igd-data-quirk", 4);
- memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
- 4, &quirk->mem[1], 1);
+ pci_set_long(vdev->pdev.config + IGD_ASLS, 0);
+ pci_set_long(vdev->pdev.wmask + IGD_ASLS, ~0);
+ pci_set_long(vdev->emulated_config_bits + IGD_ASLS, ~0);
- QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+ /*
+ * Allow user to override dsm size using x-igd-gms option, in multiples of
+ * 32MiB. This option should only be used when the desired size cannot be
+ * set from DVMT Pre-Allocated option in host BIOS.
+ */
+ if (vdev->igd_gms) {
+ if (!vfio_pci_igd_override_gms(gen, vdev->igd_gms, &gmch)) {
+ return false;
+ }
- /* Determine the size of stolen memory needed for GTT */
- ggms_mb = (gmch >> (gen < 8 ? 8 : 6)) & 0x3;
- if (gen > 6) {
- ggms_mb = 1 << ggms_mb;
+ /* GMCH is read-only, emulated */
+ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
+ pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
+ pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
}
- /*
- * Assume we have no GMS memory, but allow it to be overridden by device
- * option (experimental). The spec doesn't actually allow zero GMS when
- * when IVD (IGD VGA Disable) is clear, but the claim is that it's unused,
- * so let's not waste VM memory for it.
- */
- gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
+ if (gen > 0) {
+ gms_size = igd_stolen_memory_size(gen, gmch);
- if (vdev->igd_gms) {
- if (vdev->igd_gms <= 0x10) {
- gms_mb = vdev->igd_gms * 32;
- gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8);
+ /* BDSM is read-write, emulated. BIOS needs to be able to write it */
+ if (gen < 11) {
+ pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
+ pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
+ pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
} else {
- error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms);
- vdev->igd_gms = 0;
+ pci_set_quad(vdev->pdev.config + IGD_BDSM_GEN11, 0);
+ pci_set_quad(vdev->pdev.wmask + IGD_BDSM_GEN11, ~0);
+ pci_set_quad(vdev->emulated_config_bits + IGD_BDSM_GEN11, ~0);
}
}
/*
* Request reserved memory for stolen memory via fw_cfg. VM firmware
* must allocate a 1MB aligned reserved memory region below 4GB with
- * the requested size (in bytes) for use by the Intel PCI class VGA
- * device at VM address 00:02.0. The base address of this reserved
- * memory region must be written to the device BDSM register at PCI
- * config offset 0x5C.
+ * the requested size (in bytes) for use by the IGD device. The base
+ * address of this reserved memory region must be written to the
+ * device BDSM register.
+ * For newer device without BDSM register, this fw_cfg item is 0.
*/
bdsm_size = g_malloc(sizeof(*bdsm_size));
- *bdsm_size = cpu_to_le64((ggms_mb + gms_mb) * MiB);
+ *bdsm_size = cpu_to_le64(gms_size);
fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size",
bdsm_size, sizeof(*bdsm_size));
- /* GMCH is read-only, emulated */
- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
- pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
- pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
+ trace_vfio_pci_igd_bdsm_enabled(vdev->vbasedev.name, (gms_size / MiB));
- /* BDSM is read-write, emulated. The BIOS needs to be able to write it */
- pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
- pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
- pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
+ return true;
+error:
/*
- * This IOBAR gives us access to GTTADR, which allows us to write to
- * the GTT itself. So let's go ahead and write zero to all the GTT
- * entries to avoid spurious DMA faults. Be sure I/O access is enabled
- * before talking to the device.
+ * When legacy mode is implicity enabled, continue on error,
+ * to keep compatibility
*/
- if (pread(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig),
- vdev->config_offset + PCI_COMMAND) != sizeof(cmd_orig)) {
- error_report("IGD device %s - failed to read PCI command register",
- vdev->vbasedev.name);
+ if (legacy_mode_enabled && (vdev->igd_legacy_mode == ON_OFF_AUTO_AUTO)) {
+ error_report_err(err);
+ error_report("IGD legacy mode disabled");
+ return true;
+ }
+
+ error_propagate(errp, err);
+ return false;
+}
+
+/*
+ * KVMGT/GVT-g vGPU exposes an emulated OpRegion. So far, users have to specify
+ * x-igd-opregion=on to enable the access.
+ * TODO: Check VID/DID and enable opregion access automatically
+ */
+static bool vfio_pci_kvmgt_config_quirk(VFIOPCIDevice *vdev, Error **errp)
+{
+ struct vfio_region_info *opregion = NULL;
+ int gen;
+
+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
+ !vfio_is_vga(vdev)) {
+ return true;
}
- cmd = cmd_orig | PCI_COMMAND_IO;
+ /* FIXME: Cherryview is Gen8, but don't support GVT-g */
+ gen = igd_gen(vdev);
+ if (gen != 8 && gen != 9) {
+ return true;
+ }
- if (pwrite(vdev->vbasedev.fd, &cmd, sizeof(cmd),
- vdev->config_offset + PCI_COMMAND) != sizeof(cmd)) {
- error_report("IGD device %s - failed to write PCI command register",
- vdev->vbasedev.name);
+ if (!vfio_pci_igd_opregion_detect(vdev, &opregion)) {
+ /* Should never reach here, KVMGT always emulates OpRegion */
+ return false;
}
- for (i = 1; i < vfio_igd_gtt_max(vdev); i += 4) {
- vfio_region_write(&vdev->bars[4].region, 0, i, 4);
- vfio_region_write(&vdev->bars[4].region, 4, 0, 4);
+ if ((vdev->features & VFIO_FEATURE_ENABLE_IGD_OPREGION) &&
+ !vfio_pci_igd_opregion_init(vdev, opregion, errp)) {
+ return false;
}
- if (pwrite(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig),
- vdev->config_offset + PCI_COMMAND) != sizeof(cmd_orig)) {
- error_report("IGD device %s - failed to restore PCI command register",
- vdev->vbasedev.name);
+ return true;
+}
+
+bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp)
+{
+ /* KVMGT/GVT-g vGPU is exposed as mdev */
+ if (vdev->vbasedev.mdev) {
+ return vfio_pci_kvmgt_config_quirk(vdev, errp);
}
- trace_vfio_pci_igd_bdsm_enabled(vdev->vbasedev.name, ggms_mb + gms_mb);
+ return vfio_pci_igd_config_quirk(vdev, errp);
}
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index e7bece4..d3efef7 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -15,20 +15,27 @@
#include <linux/vfio.h>
#include <linux/iommufd.h>
-#include "hw/vfio/vfio-common.h"
+#include "hw/vfio/vfio-device.h"
#include "qemu/error-report.h"
#include "trace.h"
#include "qapi/error.h"
-#include "sysemu/iommufd.h"
+#include "system/iommufd.h"
#include "hw/qdev-core.h"
-#include "sysemu/reset.h"
+#include "hw/vfio/vfio-cpr.h"
+#include "system/reset.h"
#include "qemu/cutils.h"
#include "qemu/chardev_open.h"
#include "pci.h"
-#include "exec/ram_addr.h"
+#include "vfio-iommufd.h"
+#include "vfio-helpers.h"
+#include "vfio-listener.h"
+
+#define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \
+ TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio"
static int iommufd_cdev_map(const VFIOContainerBase *bcontainer, hwaddr iova,
- ram_addr_t size, void *vaddr, bool readonly)
+ ram_addr_t size, void *vaddr, bool readonly,
+ MemoryRegion *mr)
{
const VFIOIOMMUFDContainer *container =
container_of(bcontainer, VFIOIOMMUFDContainer, bcontainer);
@@ -40,11 +47,28 @@ static int iommufd_cdev_map(const VFIOContainerBase *bcontainer, hwaddr iova,
static int iommufd_cdev_unmap(const VFIOContainerBase *bcontainer,
hwaddr iova, ram_addr_t size,
- IOMMUTLBEntry *iotlb)
+ IOMMUTLBEntry *iotlb, bool unmap_all)
{
const VFIOIOMMUFDContainer *container =
container_of(bcontainer, VFIOIOMMUFDContainer, bcontainer);
+ /* unmap in halves */
+ if (unmap_all) {
+ Int128 llsize = int128_rshift(int128_2_64(), 1);
+ int ret;
+
+ ret = iommufd_backend_unmap_dma(container->be, container->ioas_id,
+ 0, int128_get64(llsize));
+
+ if (ret == 0) {
+ ret = iommufd_backend_unmap_dma(container->be, container->ioas_id,
+ int128_get64(llsize),
+ int128_get64(llsize));
+ }
+
+ return ret;
+ }
+
/* TODO: Handle dma_unmap_bitmap with iotlb args (migration) */
return iommufd_backend_unmap_dma(container->be,
container->ioas_id, iova, size);
@@ -281,7 +305,8 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
{
ERRP_GUARD();
IOMMUFDBackend *iommufd = vbasedev->iommufd;
- uint32_t flags = 0;
+ uint32_t type, flags = 0;
+ uint64_t hw_caps;
VFIOIOASHwpt *hwpt;
uint32_t hwpt_id;
int ret;
@@ -318,7 +343,12 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
* vfio_migration_realize() may decide to use VF dirty tracking
* instead.
*/
- if (vbasedev->hiod->caps.hw_caps & IOMMU_HW_CAP_DIRTY_TRACKING) {
+ if (!iommufd_backend_get_device_info(vbasedev->iommufd, vbasedev->devid,
+ &type, NULL, 0, &hw_caps, errp)) {
+ return false;
+ }
+
+ if (hw_caps & IOMMU_HW_CAP_DIRTY_TRACKING) {
flags = IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
}
@@ -404,7 +434,8 @@ static void iommufd_cdev_container_destroy(VFIOIOMMUFDContainer *container)
if (!QLIST_EMPTY(&bcontainer->device_list)) {
return;
}
- memory_listener_unregister(&bcontainer->listener);
+ vfio_cpr_unregister_container(bcontainer);
+ vfio_listener_unregister(bcontainer);
iommufd_backend_free_id(container->be, container->ioas_id);
object_unref(container);
}
@@ -486,18 +517,7 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
goto err_connect_bind;
}
- space = vfio_get_address_space(as);
-
- /*
- * The HostIOMMUDevice data from legacy backend is static and doesn't need
- * any information from the (type1-iommu) backend to be initialized. In
- * contrast however, the IOMMUFD HostIOMMUDevice data requires the iommufd
- * FD to be connected and having a devid to be able to successfully call
- * iommufd_backend_get_device_info().
- */
- if (!vfio_device_hiod_realize(vbasedev, errp)) {
- goto err_alloc_ioas;
- }
+ space = vfio_address_space_get(as);
/* try to attach to an existing container in this space */
QLIST_FOREACH(bcontainer, &space->containers, next) {
@@ -515,8 +535,8 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
} else {
ret = iommufd_cdev_ram_block_discard_disable(true);
if (ret) {
- error_setg(errp,
- "Cannot set discarding of RAM broken (%d)", ret);
+ error_setg_errno(errp, -ret,
+ "Cannot set discarding of RAM broken");
goto err_discard_disable;
}
goto found_container;
@@ -544,6 +564,7 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
ret = iommufd_cdev_ram_block_discard_disable(true);
if (ret) {
+ error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
goto err_discard_disable;
}
@@ -555,12 +576,11 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
bcontainer->pgsizes = qemu_real_host_page_size();
}
- bcontainer->listener = vfio_memory_listener;
- memory_listener_register(&bcontainer->listener, bcontainer->space->as);
+ if (!vfio_listener_register(bcontainer, errp)) {
+ goto err_listener_register;
+ }
- if (bcontainer->error) {
- error_propagate_prepend(errp, bcontainer->error,
- "memory listener initialization failed: ");
+ if (!vfio_cpr_register_container(bcontainer, errp)) {
goto err_listener_register;
}
@@ -573,7 +593,12 @@ found_container:
goto err_listener_register;
}
- if (!vfio_cpr_register_container(bcontainer, errp)) {
+ /*
+ * Do not move this code before attachment! The nested IOMMU support
+ * needs device and hwpt id which are generated only after attachment.
+ */
+ if (!vfio_device_hiod_create_and_realize(vbasedev,
+ TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO, errp)) {
goto err_listener_register;
}
@@ -585,14 +610,7 @@ found_container:
iommufd_cdev_ram_block_discard_disable(false);
}
- vbasedev->group = 0;
- vbasedev->num_irqs = dev_info.num_irqs;
- vbasedev->num_regions = dev_info.num_regions;
- vbasedev->flags = dev_info.flags;
- vbasedev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
- vbasedev->bcontainer = bcontainer;
- QLIST_INSERT_HEAD(&bcontainer->device_list, vbasedev, container_next);
- QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next);
+ vfio_device_prepare(vbasedev, bcontainer, &dev_info);
trace_iommufd_cdev_device_info(vbasedev->name, devfd, vbasedev->num_irqs,
vbasedev->num_regions, vbasedev->flags);
@@ -605,7 +623,7 @@ err_discard_disable:
err_attach_container:
iommufd_cdev_container_destroy(container);
err_alloc_ioas:
- vfio_put_address_space(space);
+ vfio_address_space_put(space);
iommufd_cdev_unbind_and_disconnect(vbasedev);
err_connect_bind:
close(vbasedev->fd);
@@ -619,18 +637,16 @@ static void iommufd_cdev_detach(VFIODevice *vbasedev)
VFIOIOMMUFDContainer *container = container_of(bcontainer,
VFIOIOMMUFDContainer,
bcontainer);
- QLIST_REMOVE(vbasedev, global_next);
- QLIST_REMOVE(vbasedev, container_next);
- vbasedev->bcontainer = NULL;
+ vfio_device_unprepare(vbasedev);
if (!vbasedev->ram_block_discard_allowed) {
iommufd_cdev_ram_block_discard_disable(false);
}
- vfio_cpr_unregister_container(bcontainer);
+ object_unref(vbasedev->hiod);
iommufd_cdev_detach_container(vbasedev, container);
iommufd_cdev_container_destroy(container);
- vfio_put_address_space(space);
+ vfio_address_space_put(space);
iommufd_cdev_unbind_and_disconnect(vbasedev);
close(vbasedev->fd);
@@ -786,12 +802,10 @@ out_single:
return ret;
}
-static void vfio_iommu_iommufd_class_init(ObjectClass *klass, void *data)
+static void vfio_iommu_iommufd_class_init(ObjectClass *klass, const void *data)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
- vioc->hiod_typename = TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO;
-
vioc->dma_map = iommufd_cdev_map;
vioc->dma_unmap = iommufd_cdev_unmap;
vioc->attach_device = iommufd_cdev_attach;
@@ -801,21 +815,38 @@ static void vfio_iommu_iommufd_class_init(ObjectClass *klass, void *data)
vioc->query_dirty_bitmap = iommufd_query_dirty_bitmap;
};
+static bool
+host_iommu_device_iommufd_vfio_attach_hwpt(HostIOMMUDeviceIOMMUFD *idev,
+ uint32_t hwpt_id, Error **errp)
+{
+ VFIODevice *vbasedev = HOST_IOMMU_DEVICE(idev)->agent;
+
+ return !iommufd_cdev_attach_ioas_hwpt(vbasedev, hwpt_id, errp);
+}
+
+static bool
+host_iommu_device_iommufd_vfio_detach_hwpt(HostIOMMUDeviceIOMMUFD *idev,
+ Error **errp)
+{
+ VFIODevice *vbasedev = HOST_IOMMU_DEVICE(idev)->agent;
+
+ return iommufd_cdev_detach_ioas_hwpt(vbasedev, errp);
+}
+
static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
Error **errp)
{
VFIODevice *vdev = opaque;
+ HostIOMMUDeviceIOMMUFD *idev;
HostIOMMUDeviceCaps *caps = &hiod->caps;
+ VendorCaps *vendor_caps = &caps->vendor_caps;
enum iommu_hw_info_type type;
- union {
- struct iommu_hw_info_vtd vtd;
- } data;
uint64_t hw_caps;
hiod->agent = opaque;
- if (!iommufd_backend_get_device_info(vdev->iommufd, vdev->devid,
- &type, &data, sizeof(data),
+ if (!iommufd_backend_get_device_info(vdev->iommufd, vdev->devid, &type,
+ vendor_caps, sizeof(*vendor_caps),
&hw_caps, errp)) {
return false;
}
@@ -824,6 +855,11 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
caps->type = type;
caps->hw_caps = hw_caps;
+ idev = HOST_IOMMU_DEVICE_IOMMUFD(hiod);
+ idev->iommufd = vdev->iommufd;
+ idev->devid = vdev->devid;
+ idev->hwpt_id = vdev->hwpt->hwpt_id;
+
return true;
}
@@ -846,13 +882,17 @@ hiod_iommufd_vfio_get_page_size_mask(HostIOMMUDevice *hiod)
}
-static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data)
+static void hiod_iommufd_vfio_class_init(ObjectClass *oc, const void *data)
{
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
+ HostIOMMUDeviceIOMMUFDClass *idevc = HOST_IOMMU_DEVICE_IOMMUFD_CLASS(oc);
hiodc->realize = hiod_iommufd_vfio_realize;
hiodc->get_iova_ranges = hiod_iommufd_vfio_get_iova_ranges;
hiodc->get_page_size_mask = hiod_iommufd_vfio_get_page_size_mask;
+
+ idevc->attach_hwpt = host_iommu_device_iommufd_vfio_attach_hwpt;
+ idevc->detach_hwpt = host_iommu_device_iommufd_vfio_detach_hwpt;
};
static const TypeInfo types[] = {
diff --git a/hw/vfio/common.c b/hw/vfio/listener.c
index 36d0cf6..f498e23 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/listener.c
@@ -25,156 +25,38 @@
#endif
#include <linux/vfio.h>
-#include "hw/vfio/vfio-common.h"
+#include "hw/vfio/vfio-device.h"
#include "hw/vfio/pci.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-#include "exec/ram_addr.h"
+#include "system/address-spaces.h"
+#include "system/memory.h"
+#include "system/ram_addr.h"
#include "hw/hw.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/range.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/kvm.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "trace.h"
#include "qapi/error.h"
#include "migration/misc.h"
-#include "migration/blocker.h"
#include "migration/qemu-file.h"
-#include "sysemu/tpm.h"
-
-VFIODeviceList vfio_device_list =
- QLIST_HEAD_INITIALIZER(vfio_device_list);
-static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
- QLIST_HEAD_INITIALIZER(vfio_address_spaces);
-
-#ifdef CONFIG_KVM
-/*
- * We have a single VFIO pseudo device per KVM VM. Once created it lives
- * for the life of the VM. Closing the file descriptor only drops our
- * reference to it and the device's reference to kvm. Therefore once
- * initialized, this file descriptor is only released on QEMU exit and
- * we'll re-use it should another vfio device be attached before then.
- */
-int vfio_kvm_device_fd = -1;
-#endif
+#include "system/tcg.h"
+#include "system/tpm.h"
+#include "vfio-migration-internal.h"
+#include "vfio-helpers.h"
+#include "vfio-listener.h"
/*
* Device state interfaces
*/
-bool vfio_mig_active(void)
-{
- VFIODevice *vbasedev;
-
- if (QLIST_EMPTY(&vfio_device_list)) {
- return false;
- }
- QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
- if (vbasedev->migration_blocker) {
- return false;
- }
- }
- return true;
-}
-
-static Error *multiple_devices_migration_blocker;
-
-/*
- * Multiple devices migration is allowed only if all devices support P2P
- * migration. Single device migration is allowed regardless of P2P migration
- * support.
- */
-static bool vfio_multiple_devices_migration_is_supported(void)
+static bool vfio_log_sync_needed(const VFIOContainerBase *bcontainer)
{
VFIODevice *vbasedev;
- unsigned int device_num = 0;
- bool all_support_p2p = true;
-
- QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
- if (vbasedev->migration) {
- device_num++;
- if (!(vbasedev->migration->mig_flags & VFIO_MIGRATION_P2P)) {
- all_support_p2p = false;
- }
- }
- }
-
- return all_support_p2p || device_num <= 1;
-}
-
-int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp)
-{
- int ret;
-
- if (vfio_multiple_devices_migration_is_supported()) {
- return 0;
- }
-
- if (vbasedev->enable_migration == ON_OFF_AUTO_ON) {
- error_setg(errp, "Multiple VFIO devices migration is supported only if "
- "all of them support P2P migration");
- return -EINVAL;
- }
-
- if (multiple_devices_migration_blocker) {
- return 0;
- }
-
- error_setg(&multiple_devices_migration_blocker,
- "Multiple VFIO devices migration is supported only if all of "
- "them support P2P migration");
- ret = migrate_add_blocker_normal(&multiple_devices_migration_blocker, errp);
-
- return ret;
-}
-
-void vfio_unblock_multiple_devices_migration(void)
-{
- if (!multiple_devices_migration_blocker ||
- !vfio_multiple_devices_migration_is_supported()) {
- return;
- }
-
- migrate_del_blocker(&multiple_devices_migration_blocker);
-}
-
-bool vfio_viommu_preset(VFIODevice *vbasedev)
-{
- return vbasedev->bcontainer->space->as != &address_space_memory;
-}
-
-static void vfio_set_migration_error(int ret)
-{
- if (migration_is_setup_or_active()) {
- migration_file_set_error(ret, NULL);
- }
-}
-
-bool vfio_device_state_is_running(VFIODevice *vbasedev)
-{
- VFIOMigration *migration = vbasedev->migration;
-
- return migration->device_state == VFIO_DEVICE_STATE_RUNNING ||
- migration->device_state == VFIO_DEVICE_STATE_RUNNING_P2P;
-}
-
-bool vfio_device_state_is_precopy(VFIODevice *vbasedev)
-{
- VFIOMigration *migration = vbasedev->migration;
-
- return migration->device_state == VFIO_DEVICE_STATE_PRE_COPY ||
- migration->device_state == VFIO_DEVICE_STATE_PRE_COPY_P2P;
-}
-
-static bool vfio_devices_all_dirty_tracking(VFIOContainerBase *bcontainer)
-{
- VFIODevice *vbasedev;
-
- if (!migration_is_active() && !migration_is_device()) {
+ if (!vfio_container_dirty_tracking_is_started(bcontainer)) {
return false;
}
@@ -194,52 +76,6 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainerBase *bcontainer)
return true;
}
-bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer)
-{
- VFIODevice *vbasedev;
-
- QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
- if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) {
- return false;
- }
- if (!vbasedev->dirty_pages_supported) {
- return false;
- }
- }
-
- return true;
-}
-
-/*
- * Check if all VFIO devices are running and migration is active, which is
- * essentially equivalent to the migration being in pre-copy phase.
- */
-bool
-vfio_devices_all_running_and_mig_active(const VFIOContainerBase *bcontainer)
-{
- VFIODevice *vbasedev;
-
- if (!migration_is_active()) {
- return false;
- }
-
- QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
- VFIOMigration *migration = vbasedev->migration;
-
- if (!migration) {
- return false;
- }
-
- if (vfio_device_state_is_running(vbasedev) ||
- vfio_device_state_is_precopy(vbasedev)) {
- continue;
- } else {
- return false;
- }
- }
- return true;
-}
-
static bool vfio_listener_skipped_section(MemoryRegionSection *section)
{
return (!memory_region_is_ram(section->mr) &&
@@ -254,16 +90,17 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section)
section->offset_within_address_space & (1ULL << 63);
}
-/* Called with rcu_read_lock held. */
-static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
- ram_addr_t *ram_addr, bool *read_only,
- Error **errp)
+/*
+ * Called with rcu_read_lock held.
+ * The returned MemoryRegion must not be accessed after calling rcu_read_unlock.
+ */
+static MemoryRegion *vfio_translate_iotlb(IOMMUTLBEntry *iotlb, hwaddr *xlat_p,
+ Error **errp)
{
- bool ret, mr_has_discard_manager;
+ MemoryRegion *mr;
- ret = memory_get_xlat_addr(iotlb, vaddr, ram_addr, read_only,
- &mr_has_discard_manager, errp);
- if (ret && mr_has_discard_manager) {
+ mr = memory_translate_iotlb(iotlb, xlat_p, errp);
+ if (mr && memory_region_has_ram_discard_manager(mr)) {
/*
* Malicious VMs might trigger discarding of IOMMU-mapped memory. The
* pages will remain pinned inside vfio until unmapped, resulting in a
@@ -282,7 +119,7 @@ static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
" intended via an IOMMU. It's possible to mitigate "
" by setting/adjusting RLIMIT_MEMLOCK.");
}
- return ret;
+ return mr;
}
static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
@@ -290,6 +127,8 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
VFIOContainerBase *bcontainer = giommu->bcontainer;
hwaddr iova = iotlb->iova + giommu->iommu_offset;
+ MemoryRegion *mr;
+ hwaddr xlat;
void *vaddr;
int ret;
Error *local_err = NULL;
@@ -298,9 +137,14 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
iova, iova + iotlb->addr_mask);
if (iotlb->target_as != &address_space_memory) {
- error_report("Wrong target AS \"%s\", only system memory is allowed",
- iotlb->target_as->name ? iotlb->target_as->name : "none");
- vfio_set_migration_error(-EINVAL);
+ error_setg(&local_err,
+ "Wrong target AS \"%s\", only system memory is allowed",
+ iotlb->target_as->name ? iotlb->target_as->name : "none");
+ if (migration_is_running()) {
+ migration_file_set_error(-EINVAL, local_err);
+ } else {
+ error_report_err(local_err);
+ }
return;
}
@@ -309,10 +153,14 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
bool read_only;
- if (!vfio_get_xlat_addr(iotlb, &vaddr, NULL, &read_only, &local_err)) {
+ mr = vfio_translate_iotlb(iotlb, &xlat, &local_err);
+ if (!mr) {
error_report_err(local_err);
goto out;
}
+ vaddr = memory_region_get_ram_ptr(mr) + xlat;
+ read_only = !(iotlb->perm & IOMMU_WO) || mr->readonly;
+
/*
* vaddr is only valid until rcu_read_unlock(). But after
* vfio_dma_map has set up the mapping the pages will be
@@ -322,7 +170,7 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
*/
ret = vfio_container_dma_map(bcontainer, iova,
iotlb->addr_mask + 1, vaddr,
- read_only);
+ read_only, mr);
if (ret) {
error_report("vfio_container_dma_map(%p, 0x%"HWADDR_PRIx", "
"0x%"HWADDR_PRIx", %p) = %d (%s)",
@@ -331,13 +179,18 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
}
} else {
ret = vfio_container_dma_unmap(bcontainer, iova,
- iotlb->addr_mask + 1, iotlb);
+ iotlb->addr_mask + 1, iotlb, false);
if (ret) {
- error_report("vfio_container_dma_unmap(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx") = %d (%s)",
- bcontainer, iova,
- iotlb->addr_mask + 1, ret, strerror(-ret));
- vfio_set_migration_error(ret);
+ error_setg(&local_err,
+ "vfio_container_dma_unmap(%p, 0x%"HWADDR_PRIx", "
+ "0x%"HWADDR_PRIx") = %d (%s)",
+ bcontainer, iova,
+ iotlb->addr_mask + 1, ret, strerror(-ret));
+ if (migration_is_running()) {
+ migration_file_set_error(ret, local_err);
+ } else {
+ error_report_err(local_err);
+ }
}
}
out:
@@ -355,7 +208,7 @@ static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl,
int ret;
/* Unmap with a single call. */
- ret = vfio_container_dma_unmap(bcontainer, iova, size , NULL);
+ ret = vfio_container_dma_unmap(bcontainer, iova, size , NULL, false);
if (ret) {
error_report("%s: vfio_container_dma_unmap() failed: %s", __func__,
strerror(-ret));
@@ -387,7 +240,7 @@ static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
vaddr = memory_region_get_ram_ptr(section->mr) + start;
ret = vfio_container_dma_map(bcontainer, iova, next - start,
- vaddr, section->readonly);
+ vaddr, section->readonly, section->mr);
if (ret) {
/* Rollback */
vfio_ram_discard_notify_discard(rdl, section);
@@ -397,17 +250,18 @@ static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
return 0;
}
-static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer,
+static void vfio_ram_discard_register_listener(VFIOContainerBase *bcontainer,
MemoryRegionSection *section)
{
RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr);
+ int target_page_size = qemu_target_page_size();
VFIORamDiscardListener *vrdl;
/* Ignore some corner cases not relevant in practice. */
- g_assert(QEMU_IS_ALIGNED(section->offset_within_region, TARGET_PAGE_SIZE));
+ g_assert(QEMU_IS_ALIGNED(section->offset_within_region, target_page_size));
g_assert(QEMU_IS_ALIGNED(section->offset_within_address_space,
- TARGET_PAGE_SIZE));
- g_assert(QEMU_IS_ALIGNED(int128_get64(section->size), TARGET_PAGE_SIZE));
+ target_page_size));
+ g_assert(QEMU_IS_ALIGNED(int128_get64(section->size), target_page_size));
vrdl = g_new0(VFIORamDiscardListener, 1);
vrdl->bcontainer = bcontainer;
@@ -471,7 +325,7 @@ static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer,
}
}
-static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer,
+static void vfio_ram_discard_unregister_listener(VFIOContainerBase *bcontainer,
MemoryRegionSection *section)
{
RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr);
@@ -564,11 +418,76 @@ static bool vfio_get_section_iova_range(VFIOContainerBase *bcontainer,
return true;
}
+static void vfio_listener_begin(MemoryListener *listener)
+{
+ VFIOContainerBase *bcontainer = container_of(listener, VFIOContainerBase,
+ listener);
+ void (*listener_begin)(VFIOContainerBase *bcontainer);
+
+ listener_begin = VFIO_IOMMU_GET_CLASS(bcontainer)->listener_begin;
+
+ if (listener_begin) {
+ listener_begin(bcontainer);
+ }
+}
+
+static void vfio_listener_commit(MemoryListener *listener)
+{
+ VFIOContainerBase *bcontainer = container_of(listener, VFIOContainerBase,
+ listener);
+ void (*listener_commit)(VFIOContainerBase *bcontainer);
+
+ listener_commit = VFIO_IOMMU_GET_CLASS(bcontainer)->listener_commit;
+
+ if (listener_commit) {
+ listener_commit(bcontainer);
+ }
+}
+
+static void vfio_device_error_append(VFIODevice *vbasedev, Error **errp)
+{
+ /*
+ * MMIO region mapping failures are not fatal but in this case PCI
+ * peer-to-peer transactions are broken.
+ */
+ if (vbasedev && vbasedev->type == VFIO_DEVICE_TYPE_PCI) {
+ error_append_hint(errp, "%s: PCI peer-to-peer transactions "
+ "on BARs are not supported.\n", vbasedev->name);
+ }
+}
+
+VFIORamDiscardListener *vfio_find_ram_discard_listener(
+ VFIOContainerBase *bcontainer, MemoryRegionSection *section)
+{
+ VFIORamDiscardListener *vrdl = NULL;
+
+ QLIST_FOREACH(vrdl, &bcontainer->vrdl_list, next) {
+ if (vrdl->mr == section->mr &&
+ vrdl->offset_within_address_space ==
+ section->offset_within_address_space) {
+ break;
+ }
+ }
+
+ if (!vrdl) {
+ hw_error("vfio: Trying to sync missing RAM discard listener");
+ /* does not return */
+ }
+ return vrdl;
+}
+
static void vfio_listener_region_add(MemoryListener *listener,
MemoryRegionSection *section)
{
VFIOContainerBase *bcontainer = container_of(listener, VFIOContainerBase,
listener);
+ vfio_container_region_add(bcontainer, section, false);
+}
+
+void vfio_container_region_add(VFIOContainerBase *bcontainer,
+ MemoryRegionSection *section,
+ bool cpr_remap)
+{
hwaddr iova, end;
Int128 llend, llsize;
void *vaddr;
@@ -591,8 +510,9 @@ static void vfio_listener_region_add(MemoryListener *listener,
return;
}
+ /* PPC64/pseries machine only */
if (!vfio_container_add_section_window(bcontainer, section, &err)) {
- goto fail;
+ goto mmio_dma_error;
}
memory_region_ref(section->mr);
@@ -603,6 +523,11 @@ static void vfio_listener_region_add(MemoryListener *listener,
int iommu_idx;
trace_vfio_listener_region_add_iommu(section->mr->name, iova, end);
+
+ if (cpr_remap) {
+ vfio_cpr_giommu_remap(bcontainer, section);
+ }
+
/*
* FIXME: For VFIO iommu types which have KVM acceleration to
* avoid bouncing all map/unmaps through qemu this way, this
@@ -645,7 +570,12 @@ static void vfio_listener_region_add(MemoryListener *listener,
* about changes.
*/
if (memory_region_has_ram_discard_manager(section->mr)) {
- vfio_register_ram_discard_listener(bcontainer, section);
+ if (!cpr_remap) {
+ vfio_ram_discard_register_listener(bcontainer, section);
+ } else if (!vfio_cpr_ram_discard_register_listener(bcontainer,
+ section)) {
+ goto fail;
+ }
return;
}
@@ -671,15 +601,19 @@ static void vfio_listener_region_add(MemoryListener *listener,
}
ret = vfio_container_dma_map(bcontainer, iova, int128_get64(llsize),
- vaddr, section->readonly);
+ vaddr, section->readonly, section->mr);
if (ret) {
error_setg(&err, "vfio_container_dma_map(%p, 0x%"HWADDR_PRIx", "
"0x%"HWADDR_PRIx", %p) = %d (%s)",
bcontainer, iova, int128_get64(llsize), vaddr, ret,
strerror(-ret));
+ mmio_dma_error:
if (memory_region_is_ram_device(section->mr)) {
/* Allow unexpected mappings not to be fatal for RAM devices */
- error_report_err(err);
+ VFIODevice *vbasedev =
+ vfio_get_vfio_device(memory_region_owner(section->mr));
+ vfio_device_error_append(vbasedev, &err);
+ warn_report_err_once(err);
return;
}
goto fail;
@@ -688,16 +622,12 @@ static void vfio_listener_region_add(MemoryListener *listener,
return;
fail:
- if (memory_region_is_ram_device(section->mr)) {
- error_reportf_err(err, "PCI p2p may not work: ");
- return;
- }
- /*
- * On the initfn path, store the first error in the container so we
- * can gracefully fail. Runtime, there's not much we can do other
- * than throw a hardware error.
- */
if (!bcontainer->initialized) {
+ /*
+ * At machine init time or when the device is attached to the
+ * VM, store the first error in the container so we can
+ * gracefully fail the device realize routine.
+ */
if (!bcontainer->error) {
error_propagate_prepend(&bcontainer->error, err,
"Region %s: ",
@@ -706,6 +636,10 @@ fail:
error_free(err);
}
} else {
+ /*
+ * At runtime, there's not much we can do other than throw a
+ * hardware error.
+ */
error_report_err(err);
hw_error("vfio: DMA mapping failed, unable to continue");
}
@@ -764,27 +698,20 @@ static void vfio_listener_region_del(MemoryListener *listener,
pgmask = (1ULL << ctz64(bcontainer->pgsizes)) - 1;
try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask));
} else if (memory_region_has_ram_discard_manager(section->mr)) {
- vfio_unregister_ram_discard_listener(bcontainer, section);
+ vfio_ram_discard_unregister_listener(bcontainer, section);
/* Unregistering will trigger an unmap. */
try_unmap = false;
}
if (try_unmap) {
+ bool unmap_all = false;
+
if (int128_eq(llsize, int128_2_64())) {
- /* The unmap ioctl doesn't accept a full 64-bit span. */
- llsize = int128_rshift(llsize, 1);
- ret = vfio_container_dma_unmap(bcontainer, iova,
- int128_get64(llsize), NULL);
- if (ret) {
- error_report("vfio_container_dma_unmap(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx") = %d (%s)",
- bcontainer, iova, int128_get64(llsize), ret,
- strerror(-ret));
- }
- iova += int128_get64(llsize);
+ unmap_all = true;
+ llsize = int128_zero();
}
- ret = vfio_container_dma_unmap(bcontainer, iova,
- int128_get64(llsize), NULL);
+ ret = vfio_container_dma_unmap(bcontainer, iova, int128_get64(llsize),
+ NULL, unmap_all);
if (ret) {
error_report("vfio_container_dma_unmap(%p, 0x%"HWADDR_PRIx", "
"0x%"HWADDR_PRIx") = %d (%s)",
@@ -795,6 +722,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
memory_region_unref(section->mr);
+ /* PPC64/pseries machine only */
vfio_container_del_section_window(bcontainer, section);
}
@@ -936,13 +864,17 @@ static void vfio_devices_dma_logging_stop(VFIOContainerBase *bcontainer)
VFIO_DEVICE_FEATURE_DMA_LOGGING_STOP;
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
+ int ret;
+
if (!vbasedev->dirty_tracking) {
continue;
}
- if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) {
+ ret = vbasedev->io_ops->device_feature(vbasedev, feature);
+
+ if (ret != 0) {
warn_report("%s: Failed to stop DMA logging, err %d (%s)",
- vbasedev->name, -errno, strerror(errno));
+ vbasedev->name, -ret, strerror(-ret));
}
vbasedev->dirty_tracking = false;
}
@@ -1043,10 +975,9 @@ static bool vfio_devices_dma_logging_start(VFIOContainerBase *bcontainer,
continue;
}
- ret = ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature);
+ ret = vbasedev->io_ops->device_feature(vbasedev, feature);
if (ret) {
- ret = -errno;
- error_setg_errno(errp, errno, "%s: Failed to start DMA logging",
+ error_setg_errno(errp, -ret, "%s: Failed to start DMA logging",
vbasedev->name);
goto out;
}
@@ -1071,7 +1002,7 @@ static bool vfio_listener_log_global_start(MemoryListener *listener,
listener);
bool ret;
- if (vfio_devices_all_device_dirty_tracking(bcontainer)) {
+ if (vfio_container_devices_dirty_tracking_is_supported(bcontainer)) {
ret = vfio_devices_dma_logging_start(bcontainer, errp);
} else {
ret = vfio_container_set_dirty_page_tracking(bcontainer, true, errp) == 0;
@@ -1090,7 +1021,7 @@ static void vfio_listener_log_global_stop(MemoryListener *listener)
Error *local_err = NULL;
int ret = 0;
- if (vfio_devices_all_device_dirty_tracking(bcontainer)) {
+ if (vfio_container_devices_dirty_tracking_is_supported(bcontainer)) {
vfio_devices_dma_logging_stop(bcontainer);
} else {
ret = vfio_container_set_dirty_page_tracking(bcontainer, false,
@@ -1100,102 +1031,12 @@ static void vfio_listener_log_global_stop(MemoryListener *listener)
if (ret) {
error_prepend(&local_err,
"vfio: Could not stop dirty page tracking - ");
- error_report_err(local_err);
- vfio_set_migration_error(ret);
- }
-}
-
-static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova,
- hwaddr size, void *bitmap)
-{
- uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) +
- sizeof(struct vfio_device_feature_dma_logging_report),
- sizeof(uint64_t))] = {};
- struct vfio_device_feature *feature = (struct vfio_device_feature *)buf;
- struct vfio_device_feature_dma_logging_report *report =
- (struct vfio_device_feature_dma_logging_report *)feature->data;
-
- report->iova = iova;
- report->length = size;
- report->page_size = qemu_real_host_page_size();
- report->bitmap = (uintptr_t)bitmap;
-
- feature->argsz = sizeof(buf);
- feature->flags = VFIO_DEVICE_FEATURE_GET |
- VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT;
-
- if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) {
- return -errno;
- }
-
- return 0;
-}
-
-int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
- VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp)
-{
- VFIODevice *vbasedev;
- int ret;
-
- QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
- ret = vfio_device_dma_logging_report(vbasedev, iova, size,
- vbmap->bitmap);
- if (ret) {
- error_setg_errno(errp, -ret,
- "%s: Failed to get DMA logging report, iova: "
- "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx,
- vbasedev->name, iova, size);
-
- return ret;
+ if (migration_is_running()) {
+ migration_file_set_error(ret, local_err);
+ } else {
+ error_report_err(local_err);
}
}
-
- return 0;
-}
-
-int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova,
- uint64_t size, ram_addr_t ram_addr, Error **errp)
-{
- bool all_device_dirty_tracking =
- vfio_devices_all_device_dirty_tracking(bcontainer);
- uint64_t dirty_pages;
- VFIOBitmap vbmap;
- int ret;
-
- if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) {
- cpu_physical_memory_set_dirty_range(ram_addr, size,
- tcg_enabled() ? DIRTY_CLIENTS_ALL :
- DIRTY_CLIENTS_NOCODE);
- return 0;
- }
-
- ret = vfio_bitmap_alloc(&vbmap, size);
- if (ret) {
- error_setg_errno(errp, -ret,
- "Failed to allocate dirty tracking bitmap");
- return ret;
- }
-
- if (all_device_dirty_tracking) {
- ret = vfio_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
- errp);
- } else {
- ret = vfio_container_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
- errp);
- }
-
- if (ret) {
- goto out;
- }
-
- dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr,
- vbmap.pages);
-
- trace_vfio_get_dirty_bitmap(iova, size, vbmap.size, ram_addr, dirty_pages);
-out:
- g_free(vbmap.bitmap);
-
- return ret;
}
typedef struct {
@@ -1213,29 +1054,32 @@ static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
ram_addr_t translated_addr;
Error *local_err = NULL;
int ret = -EINVAL;
+ MemoryRegion *mr;
+ hwaddr xlat;
trace_vfio_iommu_map_dirty_notify(iova, iova + iotlb->addr_mask);
if (iotlb->target_as != &address_space_memory) {
- error_report("Wrong target AS \"%s\", only system memory is allowed",
- iotlb->target_as->name ? iotlb->target_as->name : "none");
+ error_setg(&local_err,
+ "Wrong target AS \"%s\", only system memory is allowed",
+ iotlb->target_as->name ? iotlb->target_as->name : "none");
goto out;
}
rcu_read_lock();
- if (!vfio_get_xlat_addr(iotlb, NULL, &translated_addr, NULL, &local_err)) {
- error_report_err(local_err);
+ mr = vfio_translate_iotlb(iotlb, &xlat, &local_err);
+ if (!mr) {
goto out_unlock;
}
+ translated_addr = memory_region_get_ram_addr(mr) + xlat;
- ret = vfio_get_dirty_bitmap(bcontainer, iova, iotlb->addr_mask + 1,
+ ret = vfio_container_query_dirty_bitmap(bcontainer, iova, iotlb->addr_mask + 1,
translated_addr, &local_err);
if (ret) {
error_prepend(&local_err,
"vfio_iommu_map_dirty_notify(%p, 0x%"HWADDR_PRIx", "
"0x%"HWADDR_PRIx") failed - ", bcontainer, iova,
iotlb->addr_mask + 1);
- error_report_err(local_err);
}
out_unlock:
@@ -1243,11 +1087,15 @@ out_unlock:
out:
if (ret) {
- vfio_set_migration_error(ret);
+ if (migration_is_running()) {
+ migration_file_set_error(ret, local_err);
+ } else {
+ error_report_err(local_err);
+ }
}
}
-static int vfio_ram_discard_get_dirty_bitmap(MemoryRegionSection *section,
+static int vfio_ram_discard_query_dirty_bitmap(MemoryRegionSection *section,
void *opaque)
{
const hwaddr size = int128_get64(section->size);
@@ -1262,7 +1110,7 @@ static int vfio_ram_discard_get_dirty_bitmap(MemoryRegionSection *section,
* Sync the whole mapped region (spanning multiple individual mappings)
* in one go.
*/
- ret = vfio_get_dirty_bitmap(vrdl->bcontainer, iova, size, ram_addr,
+ ret = vfio_container_query_dirty_bitmap(vrdl->bcontainer, iova, size, ram_addr,
&local_err);
if (ret) {
error_report_err(local_err);
@@ -1275,26 +1123,15 @@ vfio_sync_ram_discard_listener_dirty_bitmap(VFIOContainerBase *bcontainer,
MemoryRegionSection *section)
{
RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr);
- VFIORamDiscardListener *vrdl = NULL;
-
- QLIST_FOREACH(vrdl, &bcontainer->vrdl_list, next) {
- if (vrdl->mr == section->mr &&
- vrdl->offset_within_address_space ==
- section->offset_within_address_space) {
- break;
- }
- }
-
- if (!vrdl) {
- hw_error("vfio: Trying to sync missing RAM discard listener");
- }
+ VFIORamDiscardListener *vrdl =
+ vfio_find_ram_discard_listener(bcontainer, section);
/*
* We only want/can synchronize the bitmap for actually mapped parts -
* which correspond to populated parts. Replay all populated parts.
*/
return ram_discard_manager_replay_populated(rdm, section,
- vfio_ram_discard_get_dirty_bitmap,
+ vfio_ram_discard_query_dirty_bitmap,
&vrdl);
}
@@ -1356,7 +1193,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainerBase *bcontainer,
ram_addr = memory_region_get_ram_addr(section->mr) +
section->offset_within_region;
- return vfio_get_dirty_bitmap(bcontainer,
+ return vfio_container_query_dirty_bitmap(bcontainer,
REAL_HOST_PAGE_ALIGN(section->offset_within_address_space),
int128_get64(section->size), ram_addr, errp);
}
@@ -1373,17 +1210,22 @@ static void vfio_listener_log_sync(MemoryListener *listener,
return;
}
- if (vfio_devices_all_dirty_tracking(bcontainer)) {
+ if (vfio_log_sync_needed(bcontainer)) {
ret = vfio_sync_dirty_bitmap(bcontainer, section, &local_err);
if (ret) {
- error_report_err(local_err);
- vfio_set_migration_error(ret);
+ if (migration_is_running()) {
+ migration_file_set_error(ret, local_err);
+ } else {
+ error_report_err(local_err);
+ }
}
}
}
-const MemoryListener vfio_memory_listener = {
+static const MemoryListener vfio_memory_listener = {
.name = "vfio",
+ .begin = vfio_listener_begin,
+ .commit = vfio_listener_commit,
.region_add = vfio_listener_region_add,
.region_del = vfio_listener_region_del,
.log_global_start = vfio_listener_log_global_start,
@@ -1391,183 +1233,21 @@ const MemoryListener vfio_memory_listener = {
.log_sync = vfio_listener_log_sync,
};
-void vfio_reset_handler(void *opaque)
-{
- VFIODevice *vbasedev;
-
- QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
- if (vbasedev->dev->realized) {
- vbasedev->ops->vfio_compute_needs_reset(vbasedev);
- }
- }
-
- QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
- if (vbasedev->dev->realized && vbasedev->needs_reset) {
- vbasedev->ops->vfio_hot_reset_multi(vbasedev);
- }
- }
-}
-
-int vfio_kvm_device_add_fd(int fd, Error **errp)
-{
-#ifdef CONFIG_KVM
- struct kvm_device_attr attr = {
- .group = KVM_DEV_VFIO_FILE,
- .attr = KVM_DEV_VFIO_FILE_ADD,
- .addr = (uint64_t)(unsigned long)&fd,
- };
-
- if (!kvm_enabled()) {
- return 0;
- }
-
- if (vfio_kvm_device_fd < 0) {
- struct kvm_create_device cd = {
- .type = KVM_DEV_TYPE_VFIO,
- };
-
- if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
- error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
- return -errno;
- }
-
- vfio_kvm_device_fd = cd.fd;
- }
-
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
- error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
- fd);
- return -errno;
- }
-#endif
- return 0;
-}
-
-int vfio_kvm_device_del_fd(int fd, Error **errp)
-{
-#ifdef CONFIG_KVM
- struct kvm_device_attr attr = {
- .group = KVM_DEV_VFIO_FILE,
- .attr = KVM_DEV_VFIO_FILE_DEL,
- .addr = (uint64_t)(unsigned long)&fd,
- };
-
- if (vfio_kvm_device_fd < 0) {
- error_setg(errp, "KVM VFIO device isn't created yet");
- return -EINVAL;
- }
-
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
- error_setg_errno(errp, errno,
- "Failed to remove fd %d from KVM VFIO device", fd);
- return -errno;
- }
-#endif
- return 0;
-}
-
-VFIOAddressSpace *vfio_get_address_space(AddressSpace *as)
-{
- VFIOAddressSpace *space;
-
- QLIST_FOREACH(space, &vfio_address_spaces, list) {
- if (space->as == as) {
- return space;
- }
- }
-
- /* No suitable VFIOAddressSpace, create a new one */
- space = g_malloc0(sizeof(*space));
- space->as = as;
- QLIST_INIT(&space->containers);
-
- if (QLIST_EMPTY(&vfio_address_spaces)) {
- qemu_register_reset(vfio_reset_handler, NULL);
- }
-
- QLIST_INSERT_HEAD(&vfio_address_spaces, space, list);
-
- return space;
-}
-
-void vfio_put_address_space(VFIOAddressSpace *space)
-{
- if (!QLIST_EMPTY(&space->containers)) {
- return;
- }
-
- QLIST_REMOVE(space, list);
- g_free(space);
-
- if (QLIST_EMPTY(&vfio_address_spaces)) {
- qemu_unregister_reset(vfio_reset_handler, NULL);
- }
-}
-
-void vfio_address_space_insert(VFIOAddressSpace *space,
- VFIOContainerBase *bcontainer)
-{
- QLIST_INSERT_HEAD(&space->containers, bcontainer, next);
- bcontainer->space = space;
-}
-
-struct vfio_device_info *vfio_get_device_info(int fd)
-{
- struct vfio_device_info *info;
- uint32_t argsz = sizeof(*info);
-
- info = g_malloc0(argsz);
-
-retry:
- info->argsz = argsz;
-
- if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) {
- g_free(info);
- return NULL;
- }
-
- if (info->argsz > argsz) {
- argsz = info->argsz;
- info = g_realloc(info, argsz);
- goto retry;
- }
-
- return info;
-}
-
-bool vfio_attach_device(char *name, VFIODevice *vbasedev,
- AddressSpace *as, Error **errp)
+bool vfio_listener_register(VFIOContainerBase *bcontainer, Error **errp)
{
- const VFIOIOMMUClass *ops =
- VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY));
- HostIOMMUDevice *hiod = NULL;
-
- if (vbasedev->iommufd) {
- ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD));
- }
-
- assert(ops);
+ bcontainer->listener = vfio_memory_listener;
+ memory_listener_register(&bcontainer->listener, bcontainer->space->as);
-
- if (!vbasedev->mdev) {
- hiod = HOST_IOMMU_DEVICE(object_new(ops->hiod_typename));
- vbasedev->hiod = hiod;
- }
-
- if (!ops->attach_device(name, vbasedev, as, errp)) {
- object_unref(hiod);
- vbasedev->hiod = NULL;
+ if (bcontainer->error) {
+ error_propagate_prepend(errp, bcontainer->error,
+ "memory listener initialization failed: ");
return false;
}
return true;
}
-void vfio_detach_device(VFIODevice *vbasedev)
+void vfio_listener_unregister(VFIOContainerBase *bcontainer)
{
- if (!vbasedev->bcontainer) {
- return;
- }
- object_unref(vbasedev->hiod);
- VFIO_IOMMU_GET_CLASS(vbasedev->bcontainer)->detach_device(vbasedev);
+ memory_listener_unregister(&bcontainer->listener);
}
diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build
index bba776f..63ea393 100644
--- a/hw/vfio/meson.build
+++ b/hw/vfio/meson.build
@@ -1,26 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
vfio_ss = ss.source_set()
vfio_ss.add(files(
- 'helpers.c',
- 'common.c',
+ 'listener.c',
'container-base.c',
'container.c',
- 'migration.c',
- 'cpr.c',
+ 'helpers.c',
))
vfio_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr.c'))
-vfio_ss.add(when: 'CONFIG_IOMMUFD', if_true: files(
- 'iommufd.c',
-))
vfio_ss.add(when: 'CONFIG_VFIO_PCI', if_true: files(
- 'display.c',
'pci-quirks.c',
'pci.c',
))
vfio_ss.add(when: 'CONFIG_VFIO_CCW', if_true: files('ccw.c'))
vfio_ss.add(when: 'CONFIG_VFIO_PLATFORM', if_true: files('platform.c'))
-vfio_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c'))
-vfio_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c'))
vfio_ss.add(when: 'CONFIG_VFIO_AP', if_true: files('ap.c'))
vfio_ss.add(when: 'CONFIG_VFIO_IGD', if_true: files('igd.c'))
specific_ss.add_all(when: 'CONFIG_VFIO', if_true: vfio_ss)
+
+system_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c'))
+system_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c'))
+system_ss.add(when: 'CONFIG_VFIO', if_true: files(
+ 'cpr.c',
+ 'cpr-legacy.c',
+ 'device.c',
+ 'migration.c',
+ 'migration-multifd.c',
+ 'region.c',
+))
+system_ss.add(when: ['CONFIG_VFIO', 'CONFIG_IOMMUFD'], if_true: files(
+ 'iommufd.c',
+))
+system_ss.add(when: 'CONFIG_VFIO_PCI', if_true: files(
+ 'display.c',
+))
diff --git a/hw/vfio/migration-multifd.c b/hw/vfio/migration-multifd.c
new file mode 100644
index 0000000..850a319
--- /dev/null
+++ b/hw/vfio/migration-multifd.c
@@ -0,0 +1,685 @@
+/*
+ * Multifd VFIO migration
+ *
+ * Copyright (C) 2024,2025 Oracle and/or its affiliates.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/vfio/vfio-device.h"
+#include "migration/misc.h"
+#include "qapi/error.h"
+#include "qemu/bswap.h"
+#include "qemu/error-report.h"
+#include "qemu/lockable.h"
+#include "qemu/main-loop.h"
+#include "qemu/thread.h"
+#include "io/channel-buffer.h"
+#include "migration/qemu-file.h"
+#include "migration-multifd.h"
+#include "vfio-migration-internal.h"
+#include "trace.h"
+
+#define VFIO_DEVICE_STATE_CONFIG_STATE (1)
+
+#define VFIO_DEVICE_STATE_PACKET_VER_CURRENT (0)
+
+typedef struct VFIODeviceStatePacket {
+ uint32_t version;
+ uint32_t idx;
+ uint32_t flags;
+ uint8_t data[0];
+} QEMU_PACKED VFIODeviceStatePacket;
+
+/* type safety */
+typedef struct VFIOStateBuffers {
+ GArray *array;
+} VFIOStateBuffers;
+
+typedef struct VFIOStateBuffer {
+ bool is_present;
+ char *data;
+ size_t len;
+} VFIOStateBuffer;
+
+typedef struct VFIOMultifd {
+ bool load_bufs_thread_running;
+ bool load_bufs_thread_want_exit;
+
+ VFIOStateBuffers load_bufs;
+ QemuCond load_bufs_buffer_ready_cond;
+ QemuCond load_bufs_thread_finished_cond;
+ QemuMutex load_bufs_mutex; /* Lock order: this lock -> BQL */
+ uint32_t load_buf_idx;
+ uint32_t load_buf_idx_last;
+} VFIOMultifd;
+
+static void vfio_state_buffer_clear(gpointer data)
+{
+ VFIOStateBuffer *lb = data;
+
+ if (!lb->is_present) {
+ return;
+ }
+
+ g_clear_pointer(&lb->data, g_free);
+ lb->is_present = false;
+}
+
+static void vfio_state_buffers_init(VFIOStateBuffers *bufs)
+{
+ bufs->array = g_array_new(FALSE, TRUE, sizeof(VFIOStateBuffer));
+ g_array_set_clear_func(bufs->array, vfio_state_buffer_clear);
+}
+
+static void vfio_state_buffers_destroy(VFIOStateBuffers *bufs)
+{
+ g_clear_pointer(&bufs->array, g_array_unref);
+}
+
+static void vfio_state_buffers_assert_init(VFIOStateBuffers *bufs)
+{
+ assert(bufs->array);
+}
+
+static unsigned int vfio_state_buffers_size_get(VFIOStateBuffers *bufs)
+{
+ return bufs->array->len;
+}
+
+static void vfio_state_buffers_size_set(VFIOStateBuffers *bufs,
+ unsigned int size)
+{
+ g_array_set_size(bufs->array, size);
+}
+
+static VFIOStateBuffer *vfio_state_buffers_at(VFIOStateBuffers *bufs,
+ unsigned int idx)
+{
+ return &g_array_index(bufs->array, VFIOStateBuffer, idx);
+}
+
+/* called with load_bufs_mutex locked */
+static bool vfio_load_state_buffer_insert(VFIODevice *vbasedev,
+ VFIODeviceStatePacket *packet,
+ size_t packet_total_size,
+ Error **errp)
+{
+ VFIOMigration *migration = vbasedev->migration;
+ VFIOMultifd *multifd = migration->multifd;
+ VFIOStateBuffer *lb;
+
+ vfio_state_buffers_assert_init(&multifd->load_bufs);
+ if (packet->idx >= vfio_state_buffers_size_get(&multifd->load_bufs)) {
+ vfio_state_buffers_size_set(&multifd->load_bufs, packet->idx + 1);
+ }
+
+ lb = vfio_state_buffers_at(&multifd->load_bufs, packet->idx);
+ if (lb->is_present) {
+ error_setg(errp, "%s: state buffer %" PRIu32 " already filled",
+ vbasedev->name, packet->idx);
+ return false;
+ }
+
+ assert(packet->idx >= multifd->load_buf_idx);
+
+ lb->data = g_memdup2(&packet->data, packet_total_size - sizeof(*packet));
+ lb->len = packet_total_size - sizeof(*packet);
+ lb->is_present = true;
+
+ return true;
+}
+
+bool vfio_multifd_load_state_buffer(void *opaque, char *data, size_t data_size,
+ Error **errp)
+{
+ VFIODevice *vbasedev = opaque;
+ VFIOMigration *migration = vbasedev->migration;
+ VFIOMultifd *multifd = migration->multifd;
+ VFIODeviceStatePacket *packet = (VFIODeviceStatePacket *)data;
+
+ if (!vfio_multifd_transfer_enabled(vbasedev)) {
+ error_setg(errp,
+ "%s: got device state packet but not doing multifd transfer",
+ vbasedev->name);
+ return false;
+ }
+
+ assert(multifd);
+
+ if (data_size < sizeof(*packet)) {
+ error_setg(errp, "%s: packet too short at %zu (min is %zu)",
+ vbasedev->name, data_size, sizeof(*packet));
+ return false;
+ }
+
+ packet->version = be32_to_cpu(packet->version);
+ if (packet->version != VFIO_DEVICE_STATE_PACKET_VER_CURRENT) {
+ error_setg(errp, "%s: packet has unknown version %" PRIu32,
+ vbasedev->name, packet->version);
+ return false;
+ }
+
+ packet->idx = be32_to_cpu(packet->idx);
+ packet->flags = be32_to_cpu(packet->flags);
+
+ if (packet->idx == UINT32_MAX) {
+ error_setg(errp, "%s: packet index is invalid", vbasedev->name);
+ return false;
+ }
+
+ trace_vfio_load_state_device_buffer_incoming(vbasedev->name, packet->idx);
+
+ /*
+ * Holding BQL here would violate the lock order and can cause
+ * a deadlock once we attempt to lock load_bufs_mutex below.
+ */
+ assert(!bql_locked());
+
+ WITH_QEMU_LOCK_GUARD(&multifd->load_bufs_mutex) {
+ /* config state packet should be the last one in the stream */
+ if (packet->flags & VFIO_DEVICE_STATE_CONFIG_STATE) {
+ multifd->load_buf_idx_last = packet->idx;
+ }
+
+ if (!vfio_load_state_buffer_insert(vbasedev, packet, data_size,
+ errp)) {
+ return false;
+ }
+
+ qemu_cond_signal(&multifd->load_bufs_buffer_ready_cond);
+ }
+
+ return true;
+}
+
+static bool vfio_load_bufs_thread_load_config(VFIODevice *vbasedev,
+ Error **errp)
+{
+ VFIOMigration *migration = vbasedev->migration;
+ VFIOMultifd *multifd = migration->multifd;
+ VFIOStateBuffer *lb;
+ g_autoptr(QIOChannelBuffer) bioc = NULL;
+ g_autoptr(QEMUFile) f_out = NULL, f_in = NULL;
+ uint64_t mig_header;
+ int ret;
+
+ assert(multifd->load_buf_idx == multifd->load_buf_idx_last);
+ lb = vfio_state_buffers_at(&multifd->load_bufs, multifd->load_buf_idx);
+ assert(lb->is_present);
+
+ bioc = qio_channel_buffer_new(lb->len);
+ qio_channel_set_name(QIO_CHANNEL(bioc), "vfio-device-config-load");
+
+ f_out = qemu_file_new_output(QIO_CHANNEL(bioc));
+ qemu_put_buffer(f_out, (uint8_t *)lb->data, lb->len);
+
+ ret = qemu_fflush(f_out);
+ if (ret) {
+ error_setg(errp, "%s: load config state flush failed: %d",
+ vbasedev->name, ret);
+ return false;
+ }
+
+ qio_channel_io_seek(QIO_CHANNEL(bioc), 0, 0, NULL);
+ f_in = qemu_file_new_input(QIO_CHANNEL(bioc));
+
+ mig_header = qemu_get_be64(f_in);
+ if (mig_header != VFIO_MIG_FLAG_DEV_CONFIG_STATE) {
+ error_setg(errp, "%s: expected FLAG_DEV_CONFIG_STATE but got %" PRIx64,
+ vbasedev->name, mig_header);
+ return false;
+ }
+
+ bql_lock();
+ ret = vfio_load_device_config_state(f_in, vbasedev);
+ bql_unlock();
+
+ if (ret < 0) {
+ error_setg(errp, "%s: vfio_load_device_config_state() failed: %d",
+ vbasedev->name, ret);
+ return false;
+ }
+
+ return true;
+}
+
+static VFIOStateBuffer *vfio_load_state_buffer_get(VFIOMultifd *multifd)
+{
+ VFIOStateBuffer *lb;
+ unsigned int bufs_len;
+
+ bufs_len = vfio_state_buffers_size_get(&multifd->load_bufs);
+ if (multifd->load_buf_idx >= bufs_len) {
+ assert(multifd->load_buf_idx == bufs_len);
+ return NULL;
+ }
+
+ lb = vfio_state_buffers_at(&multifd->load_bufs,
+ multifd->load_buf_idx);
+ if (!lb->is_present) {
+ return NULL;
+ }
+
+ return lb;
+}
+
+static bool vfio_load_state_buffer_write(VFIODevice *vbasedev,
+ VFIOStateBuffer *lb,
+ Error **errp)
+{
+ VFIOMigration *migration = vbasedev->migration;
+ VFIOMultifd *multifd = migration->multifd;
+ g_autofree char *buf = NULL;
+ char *buf_cur;
+ size_t buf_len;
+
+ if (!lb->len) {
+ return true;
+ }
+
+ trace_vfio_load_state_device_buffer_load_start(vbasedev->name,
+ multifd->load_buf_idx);
+
+ /* lb might become re-allocated when we drop the lock */
+ buf = g_steal_pointer(&lb->data);
+ buf_cur = buf;
+ buf_len = lb->len;
+ while (buf_len > 0) {
+ ssize_t wr_ret;
+ int errno_save;
+
+ /*
+ * Loading data to the device takes a while,
+ * drop the lock during this process.
+ */
+ qemu_mutex_unlock(&multifd->load_bufs_mutex);
+ wr_ret = write(migration->data_fd, buf_cur, buf_len);
+ errno_save = errno;
+ qemu_mutex_lock(&multifd->load_bufs_mutex);
+
+ if (wr_ret < 0) {
+ error_setg(errp,
+ "%s: writing state buffer %" PRIu32 " failed: %d",
+ vbasedev->name, multifd->load_buf_idx, errno_save);
+ return false;
+ }
+
+ assert(wr_ret <= buf_len);
+ buf_len -= wr_ret;
+ buf_cur += wr_ret;
+ }
+
+ trace_vfio_load_state_device_buffer_load_end(vbasedev->name,
+ multifd->load_buf_idx);
+
+ return true;
+}
+
+static bool vfio_load_bufs_thread_want_exit(VFIOMultifd *multifd,
+ bool *should_quit)
+{
+ return multifd->load_bufs_thread_want_exit || qatomic_read(should_quit);
+}
+
+/*
+ * This thread is spawned by vfio_multifd_switchover_start() which gets
+ * called upon encountering the switchover point marker in main migration
+ * stream.
+ *
+ * It exits after either:
+ * * completing loading the remaining device state and device config, OR:
+ * * encountering some error while doing the above, OR:
+ * * being forcefully aborted by the migration core by it setting should_quit
+ * or by vfio_load_cleanup_load_bufs_thread() setting
+ * multifd->load_bufs_thread_want_exit.
+ */
+static bool vfio_load_bufs_thread(void *opaque, bool *should_quit, Error **errp)
+{
+ VFIODevice *vbasedev = opaque;
+ VFIOMigration *migration = vbasedev->migration;
+ VFIOMultifd *multifd = migration->multifd;
+ bool ret = false;
+
+ trace_vfio_load_bufs_thread_start(vbasedev->name);
+
+ assert(multifd);
+ QEMU_LOCK_GUARD(&multifd->load_bufs_mutex);
+
+ assert(multifd->load_bufs_thread_running);
+
+ while (true) {
+ VFIOStateBuffer *lb;
+
+ /*
+ * Always check cancellation first after the buffer_ready wait below in
+ * case that cond was signalled by vfio_load_cleanup_load_bufs_thread().
+ */
+ if (vfio_load_bufs_thread_want_exit(multifd, should_quit)) {
+ error_setg(errp, "operation cancelled");
+ goto thread_exit;
+ }
+
+ assert(multifd->load_buf_idx <= multifd->load_buf_idx_last);
+
+ lb = vfio_load_state_buffer_get(multifd);
+ if (!lb) {
+ trace_vfio_load_state_device_buffer_starved(vbasedev->name,
+ multifd->load_buf_idx);
+ qemu_cond_wait(&multifd->load_bufs_buffer_ready_cond,
+ &multifd->load_bufs_mutex);
+ continue;
+ }
+
+ if (multifd->load_buf_idx == multifd->load_buf_idx_last) {
+ break;
+ }
+
+ if (multifd->load_buf_idx == 0) {
+ trace_vfio_load_state_device_buffer_start(vbasedev->name);
+ }
+
+ if (!vfio_load_state_buffer_write(vbasedev, lb, errp)) {
+ goto thread_exit;
+ }
+
+ if (multifd->load_buf_idx == multifd->load_buf_idx_last - 1) {
+ trace_vfio_load_state_device_buffer_end(vbasedev->name);
+ }
+
+ multifd->load_buf_idx++;
+ }
+
+ if (!vfio_load_bufs_thread_load_config(vbasedev, errp)) {
+ goto thread_exit;
+ }
+
+ ret = true;
+
+thread_exit:
+ /*
+ * Notify possibly waiting vfio_load_cleanup_load_bufs_thread() that
+ * this thread is exiting.
+ */
+ multifd->load_bufs_thread_running = false;
+ qemu_cond_signal(&multifd->load_bufs_thread_finished_cond);
+
+ trace_vfio_load_bufs_thread_end(vbasedev->name);
+
+ return ret;
+}
+
+static VFIOMultifd *vfio_multifd_new(void)
+{
+ VFIOMultifd *multifd = g_new(VFIOMultifd, 1);
+
+ vfio_state_buffers_init(&multifd->load_bufs);
+
+ qemu_mutex_init(&multifd->load_bufs_mutex);
+
+ multifd->load_buf_idx = 0;
+ multifd->load_buf_idx_last = UINT32_MAX;
+ qemu_cond_init(&multifd->load_bufs_buffer_ready_cond);
+
+ multifd->load_bufs_thread_running = false;
+ multifd->load_bufs_thread_want_exit = false;
+ qemu_cond_init(&multifd->load_bufs_thread_finished_cond);
+
+ return multifd;
+}
+
+/*
+ * Terminates vfio_load_bufs_thread by setting
+ * multifd->load_bufs_thread_want_exit and signalling all the conditions
+ * the thread could be blocked on.
+ *
+ * Waits for the thread to signal that it had finished.
+ */
+static void vfio_load_cleanup_load_bufs_thread(VFIOMultifd *multifd)
+{
+ /* The lock order is load_bufs_mutex -> BQL so unlock BQL here first */
+ bql_unlock();
+ WITH_QEMU_LOCK_GUARD(&multifd->load_bufs_mutex) {
+ while (multifd->load_bufs_thread_running) {
+ multifd->load_bufs_thread_want_exit = true;
+
+ qemu_cond_signal(&multifd->load_bufs_buffer_ready_cond);
+ qemu_cond_wait(&multifd->load_bufs_thread_finished_cond,
+ &multifd->load_bufs_mutex);
+ }
+ }
+ bql_lock();
+}
+
+static void vfio_multifd_free(VFIOMultifd *multifd)
+{
+ vfio_load_cleanup_load_bufs_thread(multifd);
+
+ qemu_cond_destroy(&multifd->load_bufs_thread_finished_cond);
+ vfio_state_buffers_destroy(&multifd->load_bufs);
+ qemu_cond_destroy(&multifd->load_bufs_buffer_ready_cond);
+ qemu_mutex_destroy(&multifd->load_bufs_mutex);
+
+ g_free(multifd);
+}
+
+void vfio_multifd_cleanup(VFIODevice *vbasedev)
+{
+ VFIOMigration *migration = vbasedev->migration;
+
+ g_clear_pointer(&migration->multifd, vfio_multifd_free);
+}
+
+bool vfio_multifd_transfer_supported(void)
+{
+ return multifd_device_state_supported() &&
+ migrate_send_switchover_start();
+}
+
+bool vfio_multifd_transfer_enabled(VFIODevice *vbasedev)
+{
+ VFIOMigration *migration = vbasedev->migration;
+
+ return migration->multifd_transfer;
+}
+
+bool vfio_multifd_setup(VFIODevice *vbasedev, bool alloc_multifd, Error **errp)
+{
+ VFIOMigration *migration = vbasedev->migration;
+
+ /*
+ * Make a copy of this setting at the start in case it is changed
+ * mid-migration.
+ */
+ if (vbasedev->migration_multifd_transfer == ON_OFF_AUTO_AUTO) {
+ migration->multifd_transfer = vfio_multifd_transfer_supported();
+ } else {
+ migration->multifd_transfer =
+ vbasedev->migration_multifd_transfer == ON_OFF_AUTO_ON;
+ }
+
+ if (!vfio_multifd_transfer_enabled(vbasedev)) {
+ /* Nothing further to check or do */
+ return true;
+ }
+
+ if (!vfio_multifd_transfer_supported()) {
+ error_setg(errp,
+ "%s: Multifd device transfer requested but unsupported in the current config",
+ vbasedev->name);
+ return false;
+ }
+
+ if (alloc_multifd) {
+ assert(!migration->multifd);
+ migration->multifd = vfio_multifd_new();
+ }
+
+ return true;
+}
+
+void vfio_multifd_emit_dummy_eos(VFIODevice *vbasedev, QEMUFile *f)
+{
+ assert(vfio_multifd_transfer_enabled(vbasedev));
+
+ /*
+ * Emit dummy NOP data on the main migration channel since the actual
+ * device state transfer is done via multifd channels.
+ */
+ qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE);
+}
+
+static bool
+vfio_save_complete_precopy_thread_config_state(VFIODevice *vbasedev,
+ char *idstr,
+ uint32_t instance_id,
+ uint32_t idx,
+ Error **errp)
+{
+ g_autoptr(QIOChannelBuffer) bioc = NULL;
+ g_autoptr(QEMUFile) f = NULL;
+ int ret;
+ g_autofree VFIODeviceStatePacket *packet = NULL;
+ size_t packet_len;
+
+ bioc = qio_channel_buffer_new(0);
+ qio_channel_set_name(QIO_CHANNEL(bioc), "vfio-device-config-save");
+
+ f = qemu_file_new_output(QIO_CHANNEL(bioc));
+
+ if (vfio_save_device_config_state(f, vbasedev, errp)) {
+ return false;
+ }
+
+ ret = qemu_fflush(f);
+ if (ret) {
+ error_setg(errp, "%s: save config state flush failed: %d",
+ vbasedev->name, ret);
+ return false;
+ }
+
+ packet_len = sizeof(*packet) + bioc->usage;
+ packet = g_malloc0(packet_len);
+ packet->version = cpu_to_be32(VFIO_DEVICE_STATE_PACKET_VER_CURRENT);
+ packet->idx = cpu_to_be32(idx);
+ packet->flags = cpu_to_be32(VFIO_DEVICE_STATE_CONFIG_STATE);
+ memcpy(&packet->data, bioc->data, bioc->usage);
+
+ if (!multifd_queue_device_state(idstr, instance_id,
+ (char *)packet, packet_len)) {
+ error_setg(errp, "%s: multifd config data queuing failed",
+ vbasedev->name);
+ return false;
+ }
+
+ vfio_migration_add_bytes_transferred(packet_len);
+
+ return true;
+}
+
+/*
+ * This thread is spawned by the migration core directly via
+ * .save_live_complete_precopy_thread SaveVMHandler.
+ *
+ * It exits after either:
+ * * completing saving the remaining device state and device config, OR:
+ * * encountering some error while doing the above, OR:
+ * * being forcefully aborted by the migration core by
+ * multifd_device_state_save_thread_should_exit() returning true.
+ */
+bool
+vfio_multifd_save_complete_precopy_thread(SaveLiveCompletePrecopyThreadData *d,
+ Error **errp)
+{
+ VFIODevice *vbasedev = d->handler_opaque;
+ VFIOMigration *migration = vbasedev->migration;
+ bool ret = false;
+ g_autofree VFIODeviceStatePacket *packet = NULL;
+ uint32_t idx;
+
+ if (!vfio_multifd_transfer_enabled(vbasedev)) {
+ /* Nothing to do, vfio_save_complete_precopy() does the transfer. */
+ return true;
+ }
+
+ trace_vfio_save_complete_precopy_thread_start(vbasedev->name,
+ d->idstr, d->instance_id);
+
+ /* We reach here with device state STOP or STOP_COPY only */
+ if (vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_STOP_COPY,
+ VFIO_DEVICE_STATE_STOP, errp)) {
+ goto thread_exit;
+ }
+
+ packet = g_malloc0(sizeof(*packet) + migration->data_buffer_size);
+ packet->version = cpu_to_be32(VFIO_DEVICE_STATE_PACKET_VER_CURRENT);
+
+ for (idx = 0; ; idx++) {
+ ssize_t data_size;
+ size_t packet_size;
+
+ if (multifd_device_state_save_thread_should_exit()) {
+ error_setg(errp, "operation cancelled");
+ goto thread_exit;
+ }
+
+ data_size = read(migration->data_fd, &packet->data,
+ migration->data_buffer_size);
+ if (data_size < 0) {
+ error_setg(errp, "%s: reading state buffer %" PRIu32 " failed: %d",
+ vbasedev->name, idx, errno);
+ goto thread_exit;
+ } else if (data_size == 0) {
+ break;
+ }
+
+ packet->idx = cpu_to_be32(idx);
+ packet_size = sizeof(*packet) + data_size;
+
+ if (!multifd_queue_device_state(d->idstr, d->instance_id,
+ (char *)packet, packet_size)) {
+ error_setg(errp, "%s: multifd data queuing failed", vbasedev->name);
+ goto thread_exit;
+ }
+
+ vfio_migration_add_bytes_transferred(packet_size);
+ }
+
+ if (!vfio_save_complete_precopy_thread_config_state(vbasedev,
+ d->idstr,
+ d->instance_id,
+ idx, errp)) {
+ goto thread_exit;
+ }
+
+ ret = true;
+
+thread_exit:
+ trace_vfio_save_complete_precopy_thread_end(vbasedev->name, ret);
+
+ return ret;
+}
+
+int vfio_multifd_switchover_start(VFIODevice *vbasedev)
+{
+ VFIOMigration *migration = vbasedev->migration;
+ VFIOMultifd *multifd = migration->multifd;
+
+ assert(multifd);
+
+ /* The lock order is load_bufs_mutex -> BQL so unlock BQL here first */
+ bql_unlock();
+ WITH_QEMU_LOCK_GUARD(&multifd->load_bufs_mutex) {
+ assert(!multifd->load_bufs_thread_running);
+ multifd->load_bufs_thread_running = true;
+ }
+ bql_lock();
+
+ qemu_loadvm_start_load_thread(vfio_load_bufs_thread, vbasedev);
+
+ return 0;
+}
diff --git a/hw/vfio/migration-multifd.h b/hw/vfio/migration-multifd.h
new file mode 100644
index 0000000..0bab632
--- /dev/null
+++ b/hw/vfio/migration-multifd.h
@@ -0,0 +1,34 @@
+/*
+ * Multifd VFIO migration
+ *
+ * Copyright (C) 2024,2025 Oracle and/or its affiliates.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VFIO_MIGRATION_MULTIFD_H
+#define HW_VFIO_MIGRATION_MULTIFD_H
+
+#include "hw/vfio/vfio-device.h"
+
+bool vfio_multifd_setup(VFIODevice *vbasedev, bool alloc_multifd, Error **errp);
+void vfio_multifd_cleanup(VFIODevice *vbasedev);
+
+bool vfio_multifd_transfer_supported(void);
+bool vfio_multifd_transfer_enabled(VFIODevice *vbasedev);
+
+bool vfio_multifd_load_state_buffer(void *opaque, char *data, size_t data_size,
+ Error **errp);
+
+void vfio_multifd_emit_dummy_eos(VFIODevice *vbasedev, QEMUFile *f);
+
+bool
+vfio_multifd_save_complete_precopy_thread(SaveLiveCompletePrecopyThreadData *d,
+ Error **errp);
+
+int vfio_multifd_switchover_start(VFIODevice *vbasedev);
+
+#endif
diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index 262d42a..b76697bd 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -15,38 +15,23 @@
#include <linux/vfio.h>
#include <sys/ioctl.h>
-#include "sysemu/runstate.h"
-#include "hw/vfio/vfio-common.h"
+#include "system/runstate.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio/vfio-migration.h"
#include "migration/misc.h"
#include "migration/savevm.h"
#include "migration/vmstate.h"
#include "migration/qemu-file.h"
#include "migration/register.h"
#include "migration/blocker.h"
+#include "migration-multifd.h"
#include "qapi/error.h"
#include "qapi/qapi-events-vfio.h"
#include "exec/ramlist.h"
-#include "exec/ram_addr.h"
#include "pci.h"
#include "trace.h"
#include "hw/hw.h"
-
-/*
- * Flags to be used as unique delimiters for VFIO devices in the migration
- * stream. These flags are composed as:
- * 0xffffffff => MSB 32-bit all 1s
- * 0xef10 => Magic ID, represents emulated (virtual) function IO
- * 0x0000 => 16-bits reserved for flags
- *
- * The beginning of state information is marked by _DEV_CONFIG_STATE,
- * _DEV_SETUP_STATE, or _DEV_DATA_STATE, respectively. The end of a
- * certain state information is marked by _END_OF_STATE.
- */
-#define VFIO_MIG_FLAG_END_OF_STATE (0xffffffffef100001ULL)
-#define VFIO_MIG_FLAG_DEV_CONFIG_STATE (0xffffffffef100002ULL)
-#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL)
-#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL)
-#define VFIO_MIG_FLAG_DEV_INIT_DATA_SENT (0xffffffffef100005ULL)
+#include "vfio-migration-internal.h"
/*
* This is an arbitrary size based on migration of mlx5 devices, where typically
@@ -55,7 +40,7 @@
*/
#define VFIO_MIG_DEFAULT_DATA_BUFFER_SIZE (1 * MiB)
-static int64_t bytes_transferred;
+static unsigned long bytes_transferred;
static const char *mig_state_to_str(enum vfio_device_mig_state state)
{
@@ -81,7 +66,7 @@ static const char *mig_state_to_str(enum vfio_device_mig_state state)
}
}
-static VfioMigrationState
+static QapiVfioMigrationState
mig_state_to_qapi_state(enum vfio_device_mig_state state)
{
switch (state) {
@@ -136,10 +121,10 @@ static void vfio_migration_set_device_state(VFIODevice *vbasedev,
vfio_migration_send_event(vbasedev);
}
-static int vfio_migration_set_state(VFIODevice *vbasedev,
- enum vfio_device_mig_state new_state,
- enum vfio_device_mig_state recover_state,
- Error **errp)
+int vfio_migration_set_state(VFIODevice *vbasedev,
+ enum vfio_device_mig_state new_state,
+ enum vfio_device_mig_state recover_state,
+ Error **errp)
{
VFIOMigration *migration = vbasedev->migration;
uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) +
@@ -254,8 +239,7 @@ static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev,
return ret;
}
-static int vfio_save_device_config_state(QEMUFile *f, void *opaque,
- Error **errp)
+int vfio_save_device_config_state(QEMUFile *f, void *opaque, Error **errp)
{
VFIODevice *vbasedev = opaque;
int ret;
@@ -280,11 +264,13 @@ static int vfio_save_device_config_state(QEMUFile *f, void *opaque,
return ret;
}
-static int vfio_load_device_config_state(QEMUFile *f, void *opaque)
+int vfio_load_device_config_state(QEMUFile *f, void *opaque)
{
VFIODevice *vbasedev = opaque;
uint64_t data;
+ trace_vfio_load_device_config_state_start(vbasedev->name);
+
if (vbasedev->ops && vbasedev->ops->vfio_load_config) {
int ret;
@@ -303,7 +289,7 @@ static int vfio_load_device_config_state(QEMUFile *f, void *opaque)
return -EINVAL;
}
- trace_vfio_load_device_config_state(vbasedev->name);
+ trace_vfio_load_device_config_state_end(vbasedev->name);
return qemu_file_get_error(f);
}
@@ -370,6 +356,10 @@ static ssize_t vfio_save_block(QEMUFile *f, VFIOMigration *migration)
* please refer to the Linux kernel VFIO uAPI.
*/
if (errno == ENOMSG) {
+ if (!migration->event_precopy_empty_hit) {
+ trace_vfio_save_block_precopy_empty_hit(migration->vbasedev->name);
+ migration->event_precopy_empty_hit = true;
+ }
return 0;
}
@@ -379,10 +369,13 @@ static ssize_t vfio_save_block(QEMUFile *f, VFIOMigration *migration)
return 0;
}
+ /* Non-empty read: re-arm the trace event */
+ migration->event_precopy_empty_hit = false;
+
qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE);
qemu_put_be64(f, data_size);
qemu_put_buffer(f, migration->data_buffer, data_size);
- bytes_transferred += data_size;
+ vfio_migration_add_bytes_transferred(data_size);
trace_vfio_save_block(migration->vbasedev->name, data_size);
@@ -460,6 +453,10 @@ static int vfio_save_setup(QEMUFile *f, void *opaque, Error **errp)
uint64_t stop_copy_size = VFIO_MIG_DEFAULT_DATA_BUFFER_SIZE;
int ret;
+ if (!vfio_multifd_setup(vbasedev, false, errp)) {
+ return -EINVAL;
+ }
+
qemu_put_be64(f, VFIO_MIG_FLAG_DEV_SETUP_STATE);
vfio_query_stop_copy_size(vbasedev, &stop_copy_size);
@@ -472,6 +469,9 @@ static int vfio_save_setup(QEMUFile *f, void *opaque, Error **errp)
return -ENOMEM;
}
+ migration->event_save_iterate_started = false;
+ migration->event_precopy_empty_hit = false;
+
if (vfio_precopy_supported(vbasedev)) {
switch (migration->device_state) {
case VFIO_DEVICE_STATE_RUNNING:
@@ -513,6 +513,9 @@ static void vfio_save_cleanup(void *opaque)
Error *local_err = NULL;
int ret;
+ /* Currently a NOP, done for symmetry with load_cleanup() */
+ vfio_multifd_cleanup(vbasedev);
+
/*
* Changing device state from STOP_COPY to STOP can take time. Do it here,
* after migration has completed, so it won't increase downtime.
@@ -576,9 +579,6 @@ static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy,
if (vfio_device_state_is_precopy(vbasedev)) {
vfio_query_precopy_size(migration);
-
- *must_precopy +=
- migration->precopy_init_size + migration->precopy_dirty_size;
}
trace_vfio_state_pending_exact(vbasedev->name, *must_precopy, *can_postcopy,
@@ -605,6 +605,11 @@ static int vfio_save_iterate(QEMUFile *f, void *opaque)
VFIOMigration *migration = vbasedev->migration;
ssize_t data_size;
+ if (!migration->event_save_iterate_started) {
+ trace_vfio_save_iterate_start(vbasedev->name);
+ migration->event_save_iterate_started = true;
+ }
+
data_size = vfio_save_block(f, migration);
if (data_size < 0) {
return data_size;
@@ -633,6 +638,13 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque)
int ret;
Error *local_err = NULL;
+ if (vfio_multifd_transfer_enabled(vbasedev)) {
+ vfio_multifd_emit_dummy_eos(vbasedev, f);
+ return 0;
+ }
+
+ trace_vfio_save_complete_precopy_start(vbasedev->name);
+
/* We reach here with device state STOP or STOP_COPY only */
ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_STOP_COPY,
VFIO_DEVICE_STATE_STOP, &local_err);
@@ -662,6 +674,11 @@ static void vfio_save_state(QEMUFile *f, void *opaque)
Error *local_err = NULL;
int ret;
+ if (vfio_multifd_transfer_enabled(vbasedev)) {
+ vfio_multifd_emit_dummy_eos(vbasedev, f);
+ return;
+ }
+
ret = vfio_save_device_config_state(f, opaque, &local_err);
if (ret) {
error_prepend(&local_err,
@@ -674,15 +691,28 @@ static void vfio_save_state(QEMUFile *f, void *opaque)
static int vfio_load_setup(QEMUFile *f, void *opaque, Error **errp)
{
VFIODevice *vbasedev = opaque;
+ VFIOMigration *migration = vbasedev->migration;
+ int ret;
- return vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RESUMING,
- vbasedev->migration->device_state, errp);
+ if (!vfio_multifd_setup(vbasedev, true, errp)) {
+ return -EINVAL;
+ }
+
+ ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RESUMING,
+ migration->device_state, errp);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
}
static int vfio_load_cleanup(void *opaque)
{
VFIODevice *vbasedev = opaque;
+ vfio_multifd_cleanup(vbasedev);
+
vfio_migration_cleanup(vbasedev);
trace_vfio_load_cleanup(vbasedev->name);
@@ -703,6 +733,13 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id)
switch (data) {
case VFIO_MIG_FLAG_DEV_CONFIG_STATE:
{
+ if (vfio_multifd_transfer_enabled(vbasedev)) {
+ error_report("%s: got DEV_CONFIG_STATE in main migration "
+ "channel but doing multifd transfer",
+ vbasedev->name);
+ return -EINVAL;
+ }
+
return vfio_load_device_config_state(f, opaque);
}
case VFIO_MIG_FLAG_DEV_SETUP_STATE:
@@ -768,6 +805,17 @@ static bool vfio_switchover_ack_needed(void *opaque)
return vfio_precopy_supported(vbasedev);
}
+static int vfio_switchover_start(void *opaque)
+{
+ VFIODevice *vbasedev = opaque;
+
+ if (vfio_multifd_transfer_enabled(vbasedev)) {
+ return vfio_multifd_switchover_start(vbasedev);
+ }
+
+ return 0;
+}
+
static const SaveVMHandlers savevm_vfio_handlers = {
.save_prepare = vfio_save_prepare,
.save_setup = vfio_save_setup,
@@ -782,6 +830,12 @@ static const SaveVMHandlers savevm_vfio_handlers = {
.load_cleanup = vfio_load_cleanup,
.load_state = vfio_load_state,
.switchover_ack_needed = vfio_switchover_ack_needed,
+ /*
+ * Multifd support
+ */
+ .load_state_buffer = vfio_multifd_load_state_buffer,
+ .switchover_start = vfio_switchover_start,
+ .save_live_complete_precopy_thread = vfio_multifd_save_complete_precopy_thread,
};
/* ---------------------------------------------------------------------- */
@@ -962,13 +1016,72 @@ static int vfio_migration_init(VFIODevice *vbasedev)
vfio_vmstate_change_prepare :
NULL;
migration->vm_state = qdev_add_vm_change_state_handler_full(
- vbasedev->dev, vfio_vmstate_change, prepare_cb, vbasedev);
+ vbasedev->dev, vfio_vmstate_change, prepare_cb, NULL, vbasedev);
migration_add_notifier(&migration->migration_state,
vfio_migration_state_notifier);
return 0;
}
+static Error *multiple_devices_migration_blocker;
+
+/*
+ * Multiple devices migration is allowed only if all devices support P2P
+ * migration. Single device migration is allowed regardless of P2P migration
+ * support.
+ */
+static bool vfio_multiple_devices_migration_is_supported(void)
+{
+ VFIODevice *vbasedev;
+ unsigned int device_num = 0;
+ bool all_support_p2p = true;
+
+ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
+ if (vbasedev->migration) {
+ device_num++;
+
+ if (!(vbasedev->migration->mig_flags & VFIO_MIGRATION_P2P)) {
+ all_support_p2p = false;
+ }
+ }
+ }
+
+ return all_support_p2p || device_num <= 1;
+}
+
+static int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp)
+{
+ if (vfio_multiple_devices_migration_is_supported()) {
+ return 0;
+ }
+
+ if (vbasedev->enable_migration == ON_OFF_AUTO_ON) {
+ error_setg(errp, "Multiple VFIO devices migration is supported only if "
+ "all of them support P2P migration");
+ return -EINVAL;
+ }
+
+ if (multiple_devices_migration_blocker) {
+ return 0;
+ }
+
+ error_setg(&multiple_devices_migration_blocker,
+ "Multiple VFIO devices migration is supported only if all of "
+ "them support P2P migration");
+ return migrate_add_blocker_normal(&multiple_devices_migration_blocker,
+ errp);
+}
+
+static void vfio_unblock_multiple_devices_migration(void)
+{
+ if (!multiple_devices_migration_blocker ||
+ !vfio_multiple_devices_migration_is_supported()) {
+ return;
+ }
+
+ migrate_del_blocker(&multiple_devices_migration_blocker);
+}
+
static void vfio_migration_deinit(VFIODevice *vbasedev)
{
VFIOMigration *migration = vbasedev->migration;
@@ -995,14 +1108,40 @@ static int vfio_block_migration(VFIODevice *vbasedev, Error *err, Error **errp)
/* ---------------------------------------------------------------------- */
-int64_t vfio_mig_bytes_transferred(void)
+int64_t vfio_migration_bytes_transferred(void)
{
- return bytes_transferred;
+ return MIN(qatomic_read(&bytes_transferred), INT64_MAX);
}
-void vfio_reset_bytes_transferred(void)
+void vfio_migration_reset_bytes_transferred(void)
{
- bytes_transferred = 0;
+ qatomic_set(&bytes_transferred, 0);
+}
+
+void vfio_migration_add_bytes_transferred(unsigned long val)
+{
+ qatomic_add(&bytes_transferred, val);
+}
+
+bool vfio_migration_active(void)
+{
+ VFIODevice *vbasedev;
+
+ if (QLIST_EMPTY(&vfio_device_list)) {
+ return false;
+ }
+
+ QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
+ if (vbasedev->migration_blocker) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool vfio_viommu_preset(VFIODevice *vbasedev)
+{
+ return vbasedev->bcontainer->space->as != &address_space_memory;
}
/*
@@ -1081,3 +1220,19 @@ void vfio_migration_exit(VFIODevice *vbasedev)
migrate_del_blocker(&vbasedev->migration_blocker);
}
+
+bool vfio_device_state_is_running(VFIODevice *vbasedev)
+{
+ VFIOMigration *migration = vbasedev->migration;
+
+ return migration->device_state == VFIO_DEVICE_STATE_RUNNING ||
+ migration->device_state == VFIO_DEVICE_STATE_RUNNING_P2P;
+}
+
+bool vfio_device_state_is_precopy(VFIODevice *vbasedev)
+{
+ VFIOMigration *migration = vbasedev->migration;
+
+ return migration->device_state == VFIO_DEVICE_STATE_PRE_COPY ||
+ migration->device_state == VFIO_DEVICE_STATE_PRE_COPY_P2P;
+}
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index 39dae72..3f00225 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -25,6 +25,7 @@
#include "hw/nvram/fw_cfg.h"
#include "hw/qdev-properties.h"
#include "pci.h"
+#include "pci-quirks.h"
#include "trace.h"
/*
@@ -66,40 +67,6 @@ bool vfio_opt_rom_in_denylist(VFIOPCIDevice *vdev)
* Device specific region quirks (mostly backdoors to PCI config space)
*/
-/*
- * The generic window quirks operate on an address and data register,
- * vfio_generic_window_address_quirk handles the address register and
- * vfio_generic_window_data_quirk handles the data register. These ops
- * pass reads and writes through to hardware until a value matching the
- * stored address match/mask is written. When this occurs, the data
- * register access emulated PCI config space for the device rather than
- * passing through accesses. This enables devices where PCI config space
- * is accessible behind a window register to maintain the virtualization
- * provided through vfio.
- */
-typedef struct VFIOConfigWindowMatch {
- uint32_t match;
- uint32_t mask;
-} VFIOConfigWindowMatch;
-
-typedef struct VFIOConfigWindowQuirk {
- struct VFIOPCIDevice *vdev;
-
- uint32_t address_val;
-
- uint32_t address_offset;
- uint32_t data_offset;
-
- bool window_enabled;
- uint8_t bar;
-
- MemoryRegion *addr_mem;
- MemoryRegion *data_mem;
-
- uint32_t nr_matches;
- VFIOConfigWindowMatch matches[];
-} VFIOConfigWindowQuirk;
-
static uint64_t vfio_generic_window_quirk_address_read(void *opaque,
hwaddr addr,
unsigned size)
@@ -135,7 +102,7 @@ static void vfio_generic_window_quirk_address_write(void *opaque, hwaddr addr,
}
}
-static const MemoryRegionOps vfio_generic_window_address_quirk = {
+const MemoryRegionOps vfio_generic_window_address_quirk = {
.read = vfio_generic_window_quirk_address_read,
.write = vfio_generic_window_quirk_address_write,
.endianness = DEVICE_LITTLE_ENDIAN,
@@ -178,26 +145,12 @@ static void vfio_generic_window_quirk_data_write(void *opaque, hwaddr addr,
addr + window->data_offset, data, size);
}
-static const MemoryRegionOps vfio_generic_window_data_quirk = {
+const MemoryRegionOps vfio_generic_window_data_quirk = {
.read = vfio_generic_window_quirk_data_read,
.write = vfio_generic_window_quirk_data_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
-/*
- * The generic mirror quirk handles devices which expose PCI config space
- * through a region within a BAR. When enabled, reads and writes are
- * redirected through to emulated PCI config space. XXX if PCI config space
- * used memory regions, this could just be an alias.
- */
-typedef struct VFIOConfigMirrorQuirk {
- struct VFIOPCIDevice *vdev;
- uint32_t offset;
- uint8_t bar;
- MemoryRegion *mem;
- uint8_t data[];
-} VFIOConfigMirrorQuirk;
-
static uint64_t vfio_generic_quirk_mirror_read(void *opaque,
hwaddr addr, unsigned size)
{
@@ -209,6 +162,7 @@ static uint64_t vfio_generic_quirk_mirror_read(void *opaque,
(void)vfio_region_read(&vdev->bars[mirror->bar].region,
addr + mirror->offset, size);
+ addr += mirror->config_offset;
data = vfio_pci_read_config(&vdev->pdev, addr, size);
trace_vfio_quirk_generic_mirror_read(vdev->vbasedev.name,
memory_region_name(mirror->mem),
@@ -222,13 +176,14 @@ static void vfio_generic_quirk_mirror_write(void *opaque, hwaddr addr,
VFIOConfigMirrorQuirk *mirror = opaque;
VFIOPCIDevice *vdev = mirror->vdev;
+ addr += mirror->config_offset;
vfio_pci_write_config(&vdev->pdev, addr, data, size);
trace_vfio_quirk_generic_mirror_write(vdev->vbasedev.name,
memory_region_name(mirror->mem),
addr, data);
}
-static const MemoryRegionOps vfio_generic_mirror_quirk = {
+const MemoryRegionOps vfio_generic_mirror_quirk = {
.read = vfio_generic_quirk_mirror_read,
.write = vfio_generic_quirk_mirror_write,
.endianness = DEVICE_LITTLE_ENDIAN,
@@ -448,7 +403,7 @@ static void vfio_probe_ati_bar4_quirk(VFIOPCIDevice *vdev, int nr)
/* This windows doesn't seem to be used except by legacy VGA code */
if (!vfio_pci_is(vdev, PCI_VENDOR_ID_ATI, PCI_ANY_ID) ||
- !vdev->vga || nr != 4) {
+ !vdev->vga || nr != 4 || !vdev->bars[4].ioport) {
return;
}
@@ -1159,59 +1114,19 @@ static void vfio_probe_rtl8168_bar2_quirk(VFIOPCIDevice *vdev, int nr)
trace_vfio_quirk_rtl8168_probe(vdev->vbasedev.name);
}
-#define IGD_ASLS 0xfc /* ASL Storage Register */
-
/*
- * The OpRegion includes the Video BIOS Table, which seems important for
- * telling the driver what sort of outputs it has. Without this, the device
- * may work in the guest, but we may not get output. This also requires BIOS
- * support to reserve and populate a section of guest memory sufficient for
- * the table and to write the base address of that memory to the ASLS register
- * of the IGD device.
+ * Common quirk probe entry points.
*/
-bool vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
- struct vfio_region_info *info, Error **errp)
+bool vfio_config_quirk_setup(VFIOPCIDevice *vdev, Error **errp)
{
- int ret;
-
- vdev->igd_opregion = g_malloc0(info->size);
- ret = pread(vdev->vbasedev.fd, vdev->igd_opregion,
- info->size, info->offset);
- if (ret != info->size) {
- error_setg(errp, "failed to read IGD OpRegion");
- g_free(vdev->igd_opregion);
- vdev->igd_opregion = NULL;
+#ifdef CONFIG_VFIO_IGD
+ if (!vfio_probe_igd_config_quirk(vdev, errp)) {
return false;
}
-
- /*
- * Provide fw_cfg with a copy of the OpRegion which the VM firmware is to
- * allocate 32bit reserved memory for, copy these contents into, and write
- * the reserved memory base address to the device ASLS register at 0xFC.
- * Alignment of this reserved region seems flexible, but using a 4k page
- * alignment seems to work well. This interface assumes a single IGD
- * device, which may be at VM address 00:02.0 in legacy mode or another
- * address in UPT mode.
- *
- * NB, there may be future use cases discovered where the VM should have
- * direct interaction with the host OpRegion, in which case the write to
- * the ASLS register would trigger MemoryRegion setup to enable that.
- */
- fw_cfg_add_file(fw_cfg_find(), "etc/igd-opregion",
- vdev->igd_opregion, info->size);
-
- trace_vfio_pci_igd_opregion_enabled(vdev->vbasedev.name);
-
- pci_set_long(vdev->pdev.config + IGD_ASLS, 0);
- pci_set_long(vdev->pdev.wmask + IGD_ASLS, ~0);
- pci_set_long(vdev->emulated_config_bits + IGD_ASLS, ~0);
-
+#endif
return true;
}
-/*
- * Common quirk probe entry points.
- */
void vfio_vga_quirk_setup(VFIOPCIDevice *vdev)
{
vfio_vga_probe_ati_3c3_quirk(vdev);
@@ -1259,7 +1174,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
vfio_probe_nvidia_bar0_quirk(vdev, nr);
vfio_probe_rtl8168_bar2_quirk(vdev, nr);
#ifdef CONFIG_VFIO_IGD
- vfio_probe_igd_bar4_quirk(vdev, nr);
+ vfio_probe_igd_bar0_quirk(vdev, nr);
#endif
}
@@ -1498,7 +1413,7 @@ static void get_nv_gpudirect_clique_id(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint8_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint8(v, name, ptr, errp);
@@ -1508,7 +1423,7 @@ static void set_nv_gpudirect_clique_id(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint8_t value, *ptr = object_field_prop_ptr(obj, prop);
if (!visit_type_uint8(v, name, &value, errp)) {
@@ -1524,7 +1439,7 @@ static void set_nv_gpudirect_clique_id(Object *obj, Visitor *v,
}
const PropertyInfo qdev_prop_nv_gpudirect_clique = {
- .name = "uint4",
+ .type = "uint8",
.description = "NVIDIA GPUDirect Clique ID (0 - 15)",
.get = get_nv_gpudirect_clique_id,
.set = set_nv_gpudirect_clique_id,
diff --git a/hw/vfio/pci-quirks.h b/hw/vfio/pci-quirks.h
new file mode 100644
index 0000000..d1532e3
--- /dev/null
+++ b/hw/vfio/pci-quirks.h
@@ -0,0 +1,72 @@
+/*
+ * vfio generic region quirks (mostly backdoors to PCI config space)
+ *
+ * Copyright Red Hat, Inc. 2012-2015
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+#ifndef HW_VFIO_VFIO_PCI_QUIRKS_H
+#define HW_VFIO_VFIO_PCI_QUIRKS_H
+
+#include "qemu/osdep.h"
+#include "exec/memop.h"
+
+/*
+ * The generic window quirks operate on an address and data register,
+ * vfio_generic_window_address_quirk handles the address register and
+ * vfio_generic_window_data_quirk handles the data register. These ops
+ * pass reads and writes through to hardware until a value matching the
+ * stored address match/mask is written. When this occurs, the data
+ * register access emulated PCI config space for the device rather than
+ * passing through accesses. This enables devices where PCI config space
+ * is accessible behind a window register to maintain the virtualization
+ * provided through vfio.
+ */
+typedef struct VFIOConfigWindowMatch {
+ uint32_t match;
+ uint32_t mask;
+} VFIOConfigWindowMatch;
+
+typedef struct VFIOConfigWindowQuirk {
+ struct VFIOPCIDevice *vdev;
+
+ uint32_t address_val;
+
+ uint32_t address_offset;
+ uint32_t data_offset;
+
+ bool window_enabled;
+ uint8_t bar;
+
+ MemoryRegion *addr_mem;
+ MemoryRegion *data_mem;
+
+ uint32_t nr_matches;
+ VFIOConfigWindowMatch matches[];
+} VFIOConfigWindowQuirk;
+
+extern const MemoryRegionOps vfio_generic_window_address_quirk;
+extern const MemoryRegionOps vfio_generic_window_data_quirk;
+
+/*
+ * The generic mirror quirk handles devices which expose PCI config space
+ * through a region within a BAR. When enabled, reads and writes are
+ * redirected through to emulated PCI config space. XXX if PCI config space
+ * used memory regions, this could just be an alias.
+ */
+typedef struct VFIOConfigMirrorQuirk {
+ struct VFIOPCIDevice *vdev;
+ uint32_t offset; /* Offset in BAR */
+ uint32_t config_offset; /* Offset in PCI config space */
+ uint8_t bar;
+ MemoryRegion *mem;
+ uint8_t data[];
+} VFIOConfigMirrorQuirk;
+
+extern const MemoryRegionOps vfio_generic_mirror_quirk;
+
+#endif /* HW_VFIO_VFIO_PCI_QUIRKS_H */
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 2407720..fa25bde 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -30,20 +30,23 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "migration/vmstate.h"
-#include "qapi/qmp/qdict.h"
+#include "migration/cpr.h"
+#include "qobject/qdict.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/range.h"
#include "qemu/units.h"
-#include "sysemu/kvm.h"
-#include "sysemu/runstate.h"
+#include "system/kvm.h"
+#include "system/runstate.h"
#include "pci.h"
#include "trace.h"
#include "qapi/error.h"
#include "migration/blocker.h"
#include "migration/qemu-file.h"
-#include "sysemu/iommufd.h"
+#include "system/iommufd.h"
+#include "vfio-migration-internal.h"
+#include "vfio-helpers.h"
#define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug"
@@ -54,6 +57,23 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev);
static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
static void vfio_msi_disable_common(VFIOPCIDevice *vdev);
+static bool vfio_notifier_init(VFIOPCIDevice *vdev, EventNotifier *e,
+ const char *name, int nr, Error **errp)
+{
+ int ret = event_notifier_init(e, 0);
+
+ if (ret) {
+ error_setg_errno(errp, -ret, "vfio_notifier_init %s failed", name);
+ }
+ return !ret;
+}
+
+static void vfio_notifier_cleanup(VFIOPCIDevice *vdev, EventNotifier *e,
+ const char *name, int nr)
+{
+ event_notifier_cleanup(e);
+}
+
/*
* Disabling BAR mmaping can be slow, but toggling it around INTx can
* also be a huge overhead. We try to get the best of both worlds by
@@ -101,7 +121,7 @@ static void vfio_intx_interrupt(void *opaque)
}
}
-static void vfio_intx_eoi(VFIODevice *vbasedev)
+void vfio_pci_intx_eoi(VFIODevice *vbasedev)
{
VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
@@ -109,11 +129,11 @@ static void vfio_intx_eoi(VFIODevice *vbasedev)
return;
}
- trace_vfio_intx_eoi(vbasedev->name);
+ trace_vfio_pci_intx_eoi(vbasedev->name);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
- vfio_unmask_single_irqindex(vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_device_irq_unmask(vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
}
static bool vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp)
@@ -129,13 +149,12 @@ static bool vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp)
/* Get to a known interrupt state */
qemu_set_fd_handler(irq_fd, NULL, NULL, vdev);
- vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_device_irq_mask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
/* Get an eventfd for resample/unmask */
- if (event_notifier_init(&vdev->intx.unmask, 0)) {
- error_setg(errp, "event_notifier_init failed eoi");
+ if (!vfio_notifier_init(vdev, &vdev->intx.unmask, "intx-unmask", 0, errp)) {
goto fail;
}
@@ -147,15 +166,15 @@ static bool vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp)
goto fail_irqfd;
}
- if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0,
- VFIO_IRQ_SET_ACTION_UNMASK,
- event_notifier_get_fd(&vdev->intx.unmask),
- errp)) {
+ if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0,
+ VFIO_IRQ_SET_ACTION_UNMASK,
+ event_notifier_get_fd(&vdev->intx.unmask),
+ errp)) {
goto fail_vfio;
}
/* Let'em rip */
- vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_device_irq_unmask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.kvm_accel = true;
@@ -167,10 +186,10 @@ fail_vfio:
kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &vdev->intx.interrupt,
vdev->intx.route.irq);
fail_irqfd:
- event_notifier_cleanup(&vdev->intx.unmask);
+ vfio_notifier_cleanup(vdev, &vdev->intx.unmask, "intx-unmask", 0);
fail:
qemu_set_fd_handler(irq_fd, vfio_intx_interrupt, NULL, vdev);
- vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_device_irq_unmask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
return false;
#else
return true;
@@ -188,7 +207,7 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev)
* Get to a known state, hardware masked, QEMU ready to accept new
* interrupts, QEMU IRQ de-asserted.
*/
- vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_device_irq_mask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
@@ -199,7 +218,7 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev)
}
/* We only need to close the eventfd for VFIO to cleanup the kernel side */
- event_notifier_cleanup(&vdev->intx.unmask);
+ vfio_notifier_cleanup(vdev, &vdev->intx.unmask, "intx-unmask", 0);
/* QEMU starts listening for interrupt events. */
qemu_set_fd_handler(event_notifier_get_fd(&vdev->intx.interrupt),
@@ -208,7 +227,7 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev)
vdev->intx.kvm_accel = false;
/* If we've missed an event, let it re-fire through QEMU */
- vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_device_irq_unmask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
trace_vfio_intx_disable_kvm(vdev->vbasedev.name);
#endif
@@ -234,12 +253,12 @@ static void vfio_intx_update(VFIOPCIDevice *vdev, PCIINTxRoute *route)
}
/* Re-enable the interrupt in cased we missed an EOI */
- vfio_intx_eoi(&vdev->vbasedev);
+ vfio_pci_intx_eoi(&vdev->vbasedev);
}
static void vfio_intx_routing_notifier(PCIDevice *pdev)
{
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
PCIINTxRoute route;
if (vdev->interrupt != VFIO_INT_INTx) {
@@ -266,7 +285,6 @@ static bool vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1);
Error *err = NULL;
int32_t fd;
- int ret;
if (!pin) {
@@ -289,18 +307,17 @@ static bool vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
}
#endif
- ret = event_notifier_init(&vdev->intx.interrupt, 0);
- if (ret) {
- error_setg_errno(errp, -ret, "event_notifier_init failed");
+ if (!vfio_notifier_init(vdev, &vdev->intx.interrupt, "intx-interrupt", 0,
+ errp)) {
return false;
}
fd = event_notifier_get_fd(&vdev->intx.interrupt);
qemu_set_fd_handler(fd, vfio_intx_interrupt, NULL, vdev);
- if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0,
+ if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0,
VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) {
qemu_set_fd_handler(fd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->intx.interrupt);
+ vfio_notifier_cleanup(vdev, &vdev->intx.interrupt, "intx-interrupt", 0);
return false;
}
@@ -320,20 +337,25 @@ static void vfio_intx_disable(VFIOPCIDevice *vdev)
timer_del(vdev->intx.mmap_timer);
vfio_intx_disable_kvm(vdev);
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
+ vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.pending = false;
pci_irq_deassert(&vdev->pdev);
vfio_mmap_set_enabled(vdev, true);
fd = event_notifier_get_fd(&vdev->intx.interrupt);
qemu_set_fd_handler(fd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->intx.interrupt);
+ vfio_notifier_cleanup(vdev, &vdev->intx.interrupt, "intx-interrupt", 0);
vdev->interrupt = VFIO_INT_NONE;
trace_vfio_intx_disable(vdev->vbasedev.name);
}
+bool vfio_pci_intx_enable(VFIOPCIDevice *vdev, Error **errp)
+{
+ return vfio_intx_enable(vdev, errp);
+}
+
/*
* MSI/X
*/
@@ -379,7 +401,7 @@ static void vfio_msi_interrupt(void *opaque)
static int vfio_enable_msix_no_vec(VFIOPCIDevice *vdev)
{
g_autofree struct vfio_irq_set *irq_set = NULL;
- int ret = 0, argsz;
+ int argsz;
int32_t *fd;
argsz = sizeof(*irq_set) + sizeof(*fd);
@@ -394,9 +416,7 @@ static int vfio_enable_msix_no_vec(VFIOPCIDevice *vdev)
fd = (int32_t *)&irq_set->data;
*fd = -1;
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
-
- return ret;
+ return vdev->vbasedev.io_ops->set_irqs(&vdev->vbasedev, irq_set);
}
static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix)
@@ -453,15 +473,15 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix)
fds[i] = fd;
}
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
+ ret = vdev->vbasedev.io_ops->set_irqs(&vdev->vbasedev, irq_set);
g_free(irq_set);
return ret;
}
-static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
- int vector_n, bool msix)
+void vfio_pci_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
+ int vector_n, bool msix)
{
if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi)) {
return;
@@ -471,13 +491,16 @@ static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
vector_n, &vdev->pdev);
}
-static void vfio_connect_kvm_msi_virq(VFIOMSIVector *vector)
+static void vfio_connect_kvm_msi_virq(VFIOMSIVector *vector, int nr)
{
+ const char *name = "kvm_interrupt";
+
if (vector->virq < 0) {
return;
}
- if (event_notifier_init(&vector->kvm_interrupt, 0)) {
+ if (!vfio_notifier_init(vector->vdev, &vector->kvm_interrupt, name, nr,
+ NULL)) {
goto fail_notifier;
}
@@ -489,19 +512,20 @@ static void vfio_connect_kvm_msi_virq(VFIOMSIVector *vector)
return;
fail_kvm:
- event_notifier_cleanup(&vector->kvm_interrupt);
+ vfio_notifier_cleanup(vector->vdev, &vector->kvm_interrupt, name, nr);
fail_notifier:
kvm_irqchip_release_virq(kvm_state, vector->virq);
vector->virq = -1;
}
-static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector)
+static void vfio_remove_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
+ int nr)
{
kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt,
vector->virq);
kvm_irqchip_release_virq(kvm_state, vector->virq);
vector->virq = -1;
- event_notifier_cleanup(&vector->kvm_interrupt);
+ vfio_notifier_cleanup(vdev, &vector->kvm_interrupt, "kvm_interrupt", nr);
}
static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg,
@@ -511,10 +535,47 @@ static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg,
kvm_irqchip_commit_routes(kvm_state);
}
+static void set_irq_signalling(VFIODevice *vbasedev, VFIOMSIVector *vector,
+ unsigned int nr)
+{
+ Error *err = NULL;
+ int32_t fd;
+
+ if (vector->virq >= 0) {
+ fd = event_notifier_get_fd(&vector->kvm_interrupt);
+ } else {
+ fd = event_notifier_get_fd(&vector->interrupt);
+ }
+
+ if (!vfio_device_irq_set_signaling(vbasedev, VFIO_PCI_MSIX_IRQ_INDEX, nr,
+ VFIO_IRQ_SET_ACTION_TRIGGER,
+ fd, &err)) {
+ error_reportf_err(err, VFIO_MSG_PREFIX, vbasedev->name);
+ }
+}
+
+void vfio_pci_vector_init(VFIOPCIDevice *vdev, int nr)
+{
+ VFIOMSIVector *vector = &vdev->msi_vectors[nr];
+ PCIDevice *pdev = &vdev->pdev;
+ Error *local_err = NULL;
+
+ vector->vdev = vdev;
+ vector->virq = -1;
+ if (!vfio_notifier_init(vdev, &vector->interrupt, "interrupt", nr,
+ &local_err)) {
+ error_report_err(local_err);
+ }
+ vector->use = true;
+ if (vdev->interrupt == VFIO_INT_MSIX) {
+ msix_vector_use(pdev, nr);
+ }
+}
+
static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
MSIMessage *msg, IOHandler *handler)
{
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
VFIOMSIVector *vector;
int ret;
bool resizing = !!(vdev->nr_vectors < nr + 1);
@@ -524,13 +585,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
vector = &vdev->msi_vectors[nr];
if (!vector->use) {
- vector->vdev = vdev;
- vector->virq = -1;
- if (event_notifier_init(&vector->interrupt, 0)) {
- error_report("vfio: Error: event_notifier_init failed");
- }
- vector->use = true;
- msix_vector_use(pdev, nr);
+ vfio_pci_vector_init(vdev, nr);
}
qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
@@ -542,19 +597,19 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
*/
if (vector->virq >= 0) {
if (!msg) {
- vfio_remove_kvm_msi_virq(vector);
+ vfio_remove_kvm_msi_virq(vdev, vector, nr);
} else {
vfio_update_kvm_msi_virq(vector, *msg, pdev);
}
} else {
if (msg) {
if (vdev->defer_kvm_irq_routing) {
- vfio_add_kvm_msi_virq(vdev, vector, nr, true);
+ vfio_pci_add_kvm_msi_virq(vdev, vector, nr, true);
} else {
vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state);
- vfio_add_kvm_msi_virq(vdev, vector, nr, true);
+ vfio_pci_add_kvm_msi_virq(vdev, vector, nr, true);
kvm_irqchip_commit_route_changes(&vfio_route_change);
- vfio_connect_kvm_msi_virq(vector);
+ vfio_connect_kvm_msi_virq(vector, nr);
}
}
}
@@ -576,27 +631,14 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
if (!vdev->defer_kvm_irq_routing) {
if (vdev->msix->noresize && resizing) {
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
+ vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
ret = vfio_enable_vectors(vdev, true);
if (ret) {
- error_report("vfio: failed to enable vectors, %d", ret);
+ error_report("vfio: failed to enable vectors, %s",
+ strerror(-ret));
}
} else {
- Error *err = NULL;
- int32_t fd;
-
- if (vector->virq >= 0) {
- fd = event_notifier_get_fd(&vector->kvm_interrupt);
- } else {
- fd = event_notifier_get_fd(&vector->interrupt);
- }
-
- if (!vfio_set_irq_signaling(&vdev->vbasedev,
- VFIO_PCI_MSIX_IRQ_INDEX, nr,
- VFIO_IRQ_SET_ACTION_TRIGGER, fd,
- &err)) {
- error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
- }
+ set_irq_signalling(&vdev->vbasedev, vector, nr);
}
}
@@ -619,7 +661,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev,
static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
{
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
VFIOMSIVector *vector = &vdev->msi_vectors[nr];
trace_vfio_msix_vector_release(vdev->vbasedev.name, nr);
@@ -636,7 +678,7 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
int32_t fd = event_notifier_get_fd(&vector->interrupt);
Error *err = NULL;
- if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX,
+ if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX,
nr, VFIO_IRQ_SET_ACTION_TRIGGER, fd,
&err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
@@ -644,14 +686,14 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
}
}
-static void vfio_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev)
+void vfio_pci_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev)
{
assert(!vdev->defer_kvm_irq_routing);
vdev->defer_kvm_irq_routing = true;
vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state);
}
-static void vfio_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev)
+void vfio_pci_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev)
{
int i;
@@ -661,7 +703,7 @@ static void vfio_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev)
kvm_irqchip_commit_route_changes(&vfio_route_change);
for (i = 0; i < vdev->nr_vectors; i++) {
- vfio_connect_kvm_msi_virq(&vdev->msi_vectors[i]);
+ vfio_connect_kvm_msi_virq(&vdev->msi_vectors[i], i);
}
}
@@ -681,19 +723,20 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev)
* routes once rather than per vector provides a substantial
* performance improvement.
*/
- vfio_prepare_kvm_msi_virq_batch(vdev);
+ vfio_pci_prepare_kvm_msi_virq_batch(vdev);
if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use,
vfio_msix_vector_release, NULL)) {
error_report("vfio: msix_set_vector_notifiers failed");
}
- vfio_commit_kvm_msi_virq_batch(vdev);
+ vfio_pci_commit_kvm_msi_virq_batch(vdev);
if (vdev->nr_vectors) {
ret = vfio_enable_vectors(vdev, true);
if (ret) {
- error_report("vfio: failed to enable vectors, %d", ret);
+ error_report("vfio: failed to enable vectors, %s",
+ strerror(-ret));
}
} else {
/*
@@ -710,7 +753,8 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev)
*/
ret = vfio_enable_msix_no_vec(vdev);
if (ret) {
- error_report("vfio: failed to enable MSI-X, %d", ret);
+ error_report("vfio: failed to enable MSI-X, %s",
+ strerror(-ret));
}
}
@@ -730,19 +774,21 @@ retry:
* Deferring to commit the KVM routes once rather than per vector
* provides a substantial performance improvement.
*/
- vfio_prepare_kvm_msi_virq_batch(vdev);
+ vfio_pci_prepare_kvm_msi_virq_batch(vdev);
vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->nr_vectors);
for (i = 0; i < vdev->nr_vectors; i++) {
VFIOMSIVector *vector = &vdev->msi_vectors[i];
+ Error *local_err = NULL;
vector->vdev = vdev;
vector->virq = -1;
vector->use = true;
- if (event_notifier_init(&vector->interrupt, 0)) {
- error_report("vfio: Error: event_notifier_init failed");
+ if (!vfio_notifier_init(vdev, &vector->interrupt, "interrupt", i,
+ &local_err)) {
+ error_report_err(local_err);
}
qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
@@ -752,10 +798,10 @@ retry:
* Attempt to enable route through KVM irqchip,
* default to userspace handling if unavailable.
*/
- vfio_add_kvm_msi_virq(vdev, vector, i, false);
+ vfio_pci_add_kvm_msi_virq(vdev, vector, i, false);
}
- vfio_commit_kvm_msi_virq_batch(vdev);
+ vfio_pci_commit_kvm_msi_virq_batch(vdev);
/* Set interrupt type prior to possible interrupts */
vdev->interrupt = VFIO_INT_MSI;
@@ -763,7 +809,8 @@ retry:
ret = vfio_enable_vectors(vdev, false);
if (ret) {
if (ret < 0) {
- error_report("vfio: Error: Failed to setup MSI fds: %m");
+ error_report("vfio: Error: Failed to setup MSI fds: %s",
+ strerror(-ret));
} else {
error_report("vfio: Error: Failed to enable %d "
"MSI vectors, retry with %d", vdev->nr_vectors, ret);
@@ -797,11 +844,11 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev)
VFIOMSIVector *vector = &vdev->msi_vectors[i];
if (vdev->msi_vectors[i].use) {
if (vector->virq >= 0) {
- vfio_remove_kvm_msi_virq(vector);
+ vfio_remove_kvm_msi_virq(vdev, vector, i);
}
qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
NULL, NULL, NULL);
- event_notifier_cleanup(&vector->interrupt);
+ vfio_notifier_cleanup(vdev, &vector->interrupt, "interrupt", i);
}
}
@@ -833,7 +880,7 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev)
* Always clear MSI-X IRQ index. A PF device could have enabled
* MSI-X with no vectors. See vfio_msix_enable().
*/
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
+ vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
vfio_msi_disable_common(vdev);
if (!vfio_intx_enable(vdev, &err)) {
@@ -850,7 +897,7 @@ static void vfio_msi_disable(VFIOPCIDevice *vdev)
{
Error *err = NULL;
- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX);
+ vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX);
vfio_msi_disable_common(vdev);
vfio_intx_enable(vdev, &err);
if (err) {
@@ -879,18 +926,22 @@ static void vfio_update_msi(VFIOPCIDevice *vdev)
static void vfio_pci_load_rom(VFIOPCIDevice *vdev)
{
- g_autofree struct vfio_region_info *reg_info = NULL;
+ VFIODevice *vbasedev = &vdev->vbasedev;
+ struct vfio_region_info *reg_info = NULL;
uint64_t size;
off_t off = 0;
ssize_t bytes;
+ int ret;
+
+ ret = vfio_device_get_region_info(vbasedev, VFIO_PCI_ROM_REGION_INDEX,
+ &reg_info);
- if (vfio_get_region_info(&vdev->vbasedev,
- VFIO_PCI_ROM_REGION_INDEX, &reg_info)) {
- error_report("vfio: Error getting ROM info: %m");
+ if (ret != 0) {
+ error_report("vfio: Error getting ROM info: %s", strerror(-ret));
return;
}
- trace_vfio_pci_load_rom(vdev->vbasedev.name, (unsigned long)reg_info->size,
+ trace_vfio_pci_load_rom(vbasedev->name, (unsigned long)reg_info->size,
(unsigned long)reg_info->offset,
(unsigned long)reg_info->flags);
@@ -899,8 +950,7 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev)
if (!vdev->rom_size) {
vdev->rom_read_failed = true;
- error_report("vfio-pci: Cannot read device rom at "
- "%s", vdev->vbasedev.name);
+ error_report("vfio-pci: Cannot read device rom at %s", vbasedev->name);
error_printf("Device option ROM contents are probably invalid "
"(check dmesg).\nSkip option ROM probe with rombar=0, "
"or load from file with romfile=\n");
@@ -911,18 +961,22 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev)
memset(vdev->rom, 0xff, size);
while (size) {
- bytes = pread(vdev->vbasedev.fd, vdev->rom + off,
- size, vdev->rom_offset + off);
+ bytes = vbasedev->io_ops->region_read(vbasedev,
+ VFIO_PCI_ROM_REGION_INDEX,
+ off, size, vdev->rom + off);
+
if (bytes == 0) {
break;
} else if (bytes > 0) {
off += bytes;
size -= bytes;
} else {
- if (errno == EINTR || errno == EAGAIN) {
+ if (bytes == -EINTR || bytes == -EAGAIN) {
continue;
}
- error_report("vfio: Error reading device ROM: %m");
+ error_report("vfio: Error reading device ROM: %s",
+ strreaderror(bytes));
+
break;
}
}
@@ -958,6 +1012,24 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev)
}
}
+/* "Raw" read of underlying config space. */
+static int vfio_pci_config_space_read(VFIOPCIDevice *vdev, off_t offset,
+ uint32_t size, void *data)
+{
+ return vdev->vbasedev.io_ops->region_read(&vdev->vbasedev,
+ VFIO_PCI_CONFIG_REGION_INDEX,
+ offset, size, data);
+}
+
+/* "Raw" write of underlying config space. */
+static int vfio_pci_config_space_write(VFIOPCIDevice *vdev, off_t offset,
+ uint32_t size, void *data)
+{
+ return vdev->vbasedev.io_ops->region_write(&vdev->vbasedev,
+ VFIO_PCI_CONFIG_REGION_INDEX,
+ offset, size, data, false);
+}
+
static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size)
{
VFIOPCIDevice *vdev = opaque;
@@ -1010,11 +1082,9 @@ static const MemoryRegionOps vfio_rom_ops = {
static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
{
+ VFIODevice *vbasedev = &vdev->vbasedev;
uint32_t orig, size = cpu_to_le32((uint32_t)PCI_ROM_ADDRESS_MASK);
- off_t offset = vdev->config_offset + PCI_ROM_ADDRESS;
- DeviceState *dev = DEVICE(vdev);
char *name;
- int fd = vdev->vbasedev.fd;
if (vdev->pdev.romfile || !vdev->pdev.rom_bar) {
/* Since pci handles romfile, just print a message and return */
@@ -1031,11 +1101,12 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
* Use the same size ROM BAR as the physical device. The contents
* will get filled in later when the guest tries to read it.
*/
- if (pread(fd, &orig, 4, offset) != 4 ||
- pwrite(fd, &size, 4, offset) != 4 ||
- pread(fd, &size, 4, offset) != 4 ||
- pwrite(fd, &orig, 4, offset) != 4) {
- error_report("%s(%s) failed: %m", __func__, vdev->vbasedev.name);
+ if (vfio_pci_config_space_read(vdev, PCI_ROM_ADDRESS, 4, &orig) != 4 ||
+ vfio_pci_config_space_write(vdev, PCI_ROM_ADDRESS, 4, &size) != 4 ||
+ vfio_pci_config_space_read(vdev, PCI_ROM_ADDRESS, 4, &size) != 4 ||
+ vfio_pci_config_space_write(vdev, PCI_ROM_ADDRESS, 4, &orig) != 4) {
+
+ error_report("%s(%s) ROM access failed", __func__, vbasedev->name);
return;
}
@@ -1046,12 +1117,12 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
}
if (vfio_opt_rom_in_denylist(vdev)) {
- if (dev->opts && qdict_haskey(dev->opts, "rombar")) {
+ if (vdev->pdev.rom_bar > 0) {
warn_report("Device at %s is known to cause system instability"
" issues during option rom execution",
vdev->vbasedev.name);
error_printf("Proceeding anyway since user specified"
- " non zero value for rombar\n");
+ " positive value for rombar\n");
} else {
warn_report("Rom loading for device at %s has been disabled"
" due to system instability issues",
@@ -1168,7 +1239,7 @@ static const MemoryRegionOps vfio_vga_ops = {
*/
static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar)
{
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
VFIORegion *region = &vdev->bars[bar].region;
MemoryRegion *mmap_mr, *region_mr, *base_mr;
PCIIORegion *r;
@@ -1214,7 +1285,8 @@ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar)
*/
uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
{
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
@@ -1227,12 +1299,12 @@ uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
if (~emu_bits & (0xffffffffU >> (32 - len * 8))) {
ssize_t ret;
- ret = pread(vdev->vbasedev.fd, &phys_val, len,
- vdev->config_offset + addr);
+ ret = vfio_pci_config_space_read(vdev, addr, len, &phys_val);
if (ret != len) {
- error_report("%s(%s, 0x%x, 0x%x) failed: %m",
- __func__, vdev->vbasedev.name, addr, len);
- return -errno;
+ error_report("%s(%s, 0x%x, 0x%x) failed: %s",
+ __func__, vbasedev->name, addr, len,
+ strreaderror(ret));
+ return -1;
}
phys_val = le32_to_cpu(phys_val);
}
@@ -1247,16 +1319,19 @@ uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
void vfio_pci_write_config(PCIDevice *pdev,
uint32_t addr, uint32_t val, int len)
{
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
uint32_t val_le = cpu_to_le32(val);
+ int ret;
trace_vfio_pci_write_config(vdev->vbasedev.name, addr, val, len);
/* Write everything to VFIO, let it filter out what we can't write */
- if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr)
- != len) {
- error_report("%s(%s, 0x%x, 0x%x, 0x%x) failed: %m",
- __func__, vdev->vbasedev.name, addr, val, len);
+ ret = vfio_pci_config_space_write(vdev, addr, len, &val_le);
+ if (ret != len) {
+ error_report("%s(%s, 0x%x, 0x%x, 0x%x) failed: %s",
+ __func__, vbasedev->name, addr, val, len,
+ strwriteerror(ret));
}
/* MSI/MSI-X Enabling/Disabling */
@@ -1344,9 +1419,11 @@ static bool vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
int ret, entries;
Error *err = NULL;
- if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
- vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
- error_setg_errno(errp, errno, "failed reading MSI PCI_CAP_FLAGS");
+ ret = vfio_pci_config_space_read(vdev, pos + PCI_CAP_FLAGS,
+ sizeof(ctrl), &ctrl);
+ if (ret != sizeof(ctrl)) {
+ error_setg(errp, "failed reading MSI PCI_CAP_FLAGS: %s",
+ strreaderror(ret));
return false;
}
ctrl = le16_to_cpu(ctrl);
@@ -1379,8 +1456,8 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev)
* If the host driver allows mapping of a MSIX data, we are going to
* do map the entire BAR and emulate MSIX table on top of that.
*/
- if (vfio_has_region_cap(&vdev->vbasedev, region->nr,
- VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) {
+ if (vfio_device_has_region_cap(&vdev->vbasedev, region->nr,
+ VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) {
return;
}
@@ -1452,7 +1529,7 @@ static bool vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp)
int target_bar = -1;
size_t msix_sz;
- if (!vdev->msix || vdev->msix_relo == OFF_AUTOPCIBAR_OFF) {
+ if (!vdev->msix || vdev->msix_relo == OFF_AUTO_PCIBAR_OFF) {
return true;
}
@@ -1464,7 +1541,7 @@ static bool vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp)
/* PCI BARs must be a power of 2 */
msix_sz = pow2ceil(msix_sz);
- if (vdev->msix_relo == OFF_AUTOPCIBAR_AUTO) {
+ if (vdev->msix_relo == OFF_AUTO_PCIBAR_AUTO) {
/*
* TODO: Lookup table for known devices.
*
@@ -1479,7 +1556,7 @@ static bool vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp)
return false;
}
} else {
- target_bar = (int)(vdev->msix_relo - OFF_AUTOPCIBAR_BAR0);
+ target_bar = (int)(vdev->msix_relo - OFF_AUTO_PCIBAR_BAR0);
}
/* I/O port BARs cannot host MSI-X structures */
@@ -1553,31 +1630,35 @@ static bool vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
uint8_t pos;
uint16_t ctrl;
uint32_t table, pba;
- int ret, fd = vdev->vbasedev.fd;
- struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info),
- .index = VFIO_PCI_MSIX_IRQ_INDEX };
+ struct vfio_irq_info irq_info;
VFIOMSIXInfo *msix;
+ int ret;
pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX);
if (!pos) {
return true;
}
- if (pread(fd, &ctrl, sizeof(ctrl),
- vdev->config_offset + pos + PCI_MSIX_FLAGS) != sizeof(ctrl)) {
- error_setg_errno(errp, errno, "failed to read PCI MSIX FLAGS");
+ ret = vfio_pci_config_space_read(vdev, pos + PCI_MSIX_FLAGS,
+ sizeof(ctrl), &ctrl);
+ if (ret != sizeof(ctrl)) {
+ error_setg(errp, "failed to read PCI MSIX FLAGS: %s",
+ strreaderror(ret));
return false;
}
- if (pread(fd, &table, sizeof(table),
- vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) {
- error_setg_errno(errp, errno, "failed to read PCI MSIX TABLE");
+ ret = vfio_pci_config_space_read(vdev, pos + PCI_MSIX_TABLE,
+ sizeof(table), &table);
+ if (ret != sizeof(table)) {
+ error_setg(errp, "failed to read PCI MSIX TABLE: %s",
+ strreaderror(ret));
return false;
}
- if (pread(fd, &pba, sizeof(pba),
- vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) {
- error_setg_errno(errp, errno, "failed to read PCI MSIX PBA");
+ ret = vfio_pci_config_space_read(vdev, pos + PCI_MSIX_PBA,
+ sizeof(pba), &pba);
+ if (ret != sizeof(pba)) {
+ error_setg(errp, "failed to read PCI MSIX PBA: %s", strreaderror(ret));
return false;
}
@@ -1592,7 +1673,8 @@ static bool vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
+ ret = vfio_device_get_irq_info(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX,
+ &irq_info);
if (ret < 0) {
error_setg_errno(errp, -ret, "failed to get MSI-X irq info");
g_free(msix);
@@ -1624,7 +1706,7 @@ static bool vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
} else if (vfio_pci_is(vdev, PCI_VENDOR_ID_BAIDU,
PCI_DEVICE_ID_KUNLUN_VF)) {
msix->pba_offset = 0xb400;
- } else if (vdev->msix_relo == OFF_AUTOPCIBAR_OFF) {
+ } else if (vdev->msix_relo == OFF_AUTO_PCIBAR_OFF) {
error_setg(errp, "hardware reports invalid configuration, "
"MSIX PBA outside of specified BAR");
g_free(msix);
@@ -1699,7 +1781,7 @@ static bool vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
return true;
}
-static void vfio_teardown_msi(VFIOPCIDevice *vdev)
+void vfio_pci_teardown_msi(VFIOPCIDevice *vdev)
{
msi_uninit(&vdev->pdev);
@@ -1736,10 +1818,10 @@ static void vfio_bar_prepare(VFIOPCIDevice *vdev, int nr)
}
/* Determine what type of BAR this is for registration */
- ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar),
- vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr));
+ ret = vfio_pci_config_space_read(vdev, PCI_BASE_ADDRESS_0 + (4 * nr),
+ sizeof(pci_bar), &pci_bar);
if (ret != sizeof(pci_bar)) {
- error_report("vfio: Failed to read BAR %d (%m)", nr);
+ error_report("vfio: Failed to read BAR %d: %s", nr, strreaderror(ret));
return;
}
@@ -1749,6 +1831,9 @@ static void vfio_bar_prepare(VFIOPCIDevice *vdev, int nr)
bar->type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK :
~PCI_BASE_ADDRESS_MEM_MASK);
bar->size = bar->region.size;
+
+ /* IO regions are sync, memory can be async */
+ bar->region.post_wr = (bar->ioport == 0);
}
static void vfio_bars_prepare(VFIOPCIDevice *vdev)
@@ -1795,7 +1880,7 @@ static void vfio_bars_register(VFIOPCIDevice *vdev)
}
}
-static void vfio_bars_exit(VFIOPCIDevice *vdev)
+void vfio_pci_bars_exit(VFIOPCIDevice *vdev)
{
int i;
@@ -2216,8 +2301,12 @@ static bool vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
break;
case PCI_CAP_ID_PM:
vfio_check_pm_reset(vdev, pos);
- vdev->pm_cap = pos;
- ret = pci_add_capability(pdev, cap_id, pos, size, errp) >= 0;
+ ret = pci_pm_init(pdev, pos, errp) >= 0;
+ /*
+ * PCI-core config space emulation needs write access to the power
+ * state enabled for tracking BAR mapping relative to PM state.
+ */
+ pci_set_word(pdev->wmask + pos + PCI_PM_CTRL, PCI_PM_CTRL_STATE_MASK);
break;
case PCI_CAP_ID_AF:
vfio_check_af_flr(vdev, pos);
@@ -2380,10 +2469,9 @@ static void vfio_add_ext_cap(VFIOPCIDevice *vdev)
}
g_free(config);
- return;
}
-static bool vfio_add_capabilities(VFIOPCIDevice *vdev, Error **errp)
+bool vfio_pci_add_capabilities(VFIOPCIDevice *vdev, Error **errp)
{
PCIDevice *pdev = &vdev->pdev;
@@ -2407,18 +2495,27 @@ void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
vfio_disable_interrupts(vdev);
+ /*
+ * Stop any ongoing DMA by disconnecting I/O, MMIO, and bus master.
+ * Also put INTx Disable in known state.
+ */
+ cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
+ cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_INTX_DISABLE);
+ vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
+
/* Make sure the device is in D0 */
- if (vdev->pm_cap) {
+ if (pdev->pm_cap) {
uint16_t pmcsr;
uint8_t state;
- pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
+ pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
state = pmcsr & PCI_PM_CTRL_STATE_MASK;
if (state) {
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
+ vfio_pci_write_config(pdev, pdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
/* vfio handles the necessary delay here */
- pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
+ pmcsr = vfio_pci_read_config(pdev, pdev->pm_cap + PCI_PM_CTRL, 2);
state = pmcsr & PCI_PM_CTRL_STATE_MASK;
if (state) {
error_report("vfio: Unable to power on device, stuck in D%d",
@@ -2426,34 +2523,27 @@ void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
}
}
}
-
- /*
- * Stop any ongoing DMA by disconnecting I/O, MMIO, and bus master.
- * Also put INTx Disable in known state.
- */
- cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
- cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
- PCI_COMMAND_INTX_DISABLE);
- vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
}
void vfio_pci_post_reset(VFIOPCIDevice *vdev)
{
+ VFIODevice *vbasedev = &vdev->vbasedev;
Error *err = NULL;
- int nr;
+ int ret, nr;
if (!vfio_intx_enable(vdev, &err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
for (nr = 0; nr < PCI_NUM_REGIONS - 1; ++nr) {
- off_t addr = vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr);
+ off_t addr = PCI_BASE_ADDRESS_0 + (4 * nr);
uint32_t val = 0;
uint32_t len = sizeof(val);
- if (pwrite(vdev->vbasedev.fd, &val, len, addr) != len) {
- error_report("%s(%s) reset bar %d failed: %m", __func__,
- vdev->vbasedev.name, nr);
+ ret = vfio_pci_config_space_write(vdev, addr, len, &val);
+ if (ret != len) {
+ error_report("%s(%s) reset bar %d failed: %s", __func__,
+ vbasedev->name, nr, strwriteerror(ret));
}
}
@@ -2657,7 +2747,7 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f)
static VFIODeviceOps vfio_pci_ops = {
.vfio_compute_needs_reset = vfio_pci_compute_needs_reset,
.vfio_hot_reset_multi = vfio_pci_hot_reset_multi,
- .vfio_eoi = vfio_intx_eoi,
+ .vfio_eoi = vfio_pci_intx_eoi,
.vfio_get_object = vfio_pci_get_object,
.vfio_save_config = vfio_pci_save_config,
.vfio_load_config = vfio_pci_load_config,
@@ -2666,10 +2756,10 @@ static VFIODeviceOps vfio_pci_ops = {
bool vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp)
{
VFIODevice *vbasedev = &vdev->vbasedev;
- g_autofree struct vfio_region_info *reg_info = NULL;
+ struct vfio_region_info *reg_info = NULL;
int ret;
- ret = vfio_get_region_info(vbasedev, VFIO_PCI_VGA_REGION_INDEX, &reg_info);
+ ret = vfio_device_get_region_info(vbasedev, VFIO_PCI_VGA_REGION_INDEX, &reg_info);
if (ret) {
error_setg_errno(errp, -ret,
"failed getting region info for VGA region index %d",
@@ -2728,11 +2818,11 @@ bool vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp)
return true;
}
-static bool vfio_populate_device(VFIOPCIDevice *vdev, Error **errp)
+bool vfio_pci_populate_device(VFIOPCIDevice *vdev, Error **errp)
{
VFIODevice *vbasedev = &vdev->vbasedev;
- g_autofree struct vfio_region_info *reg_info = NULL;
- struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
+ struct vfio_region_info *reg_info = NULL;
+ struct vfio_irq_info irq_info;
int i, ret = -1;
/* Sanity check device */
@@ -2767,14 +2857,14 @@ static bool vfio_populate_device(VFIOPCIDevice *vdev, Error **errp)
QLIST_INIT(&vdev->bars[i].quirks);
}
- ret = vfio_get_region_info(vbasedev,
- VFIO_PCI_CONFIG_REGION_INDEX, &reg_info);
+ ret = vfio_device_get_region_info(vbasedev,
+ VFIO_PCI_CONFIG_REGION_INDEX, &reg_info);
if (ret) {
error_setg_errno(errp, -ret, "failed to get config info");
return false;
}
- trace_vfio_populate_device_config(vdev->vbasedev.name,
+ trace_vfio_pci_populate_device_config(vdev->vbasedev.name,
(unsigned long)reg_info->size,
(unsigned long)reg_info->offset,
(unsigned long)reg_info->flags);
@@ -2793,12 +2883,10 @@ static bool vfio_populate_device(VFIOPCIDevice *vdev, Error **errp)
}
}
- irq_info.index = VFIO_PCI_ERR_IRQ_INDEX;
-
- ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
+ ret = vfio_device_get_irq_info(vbasedev, VFIO_PCI_ERR_IRQ_INDEX, &irq_info);
if (ret) {
/* This can fail for an old kernel or legacy PCI dev */
- trace_vfio_populate_device_get_irq_info_failure(strerror(errno));
+ trace_vfio_pci_populate_device_get_irq_info_failure(strerror(-ret));
} else if (irq_info.count == 1) {
vdev->pci_aer = true;
} else {
@@ -2810,9 +2898,21 @@ static bool vfio_populate_device(VFIOPCIDevice *vdev, Error **errp)
return true;
}
-static void vfio_pci_put_device(VFIOPCIDevice *vdev)
+void vfio_pci_put_device(VFIOPCIDevice *vdev)
{
- vfio_detach_device(&vdev->vbasedev);
+ vfio_display_finalize(vdev);
+ vfio_bars_finalize(vdev);
+ g_free(vdev->emulated_config_bits);
+ g_free(vdev->rom);
+ /*
+ * XXX Leaking igd_opregion is not an oversight, we can't remove the
+ * fw_cfg entry therefore leaking this allocation seems like the safest
+ * option.
+ *
+ * g_free(vdev->igd_opregion);
+ */
+
+ vfio_device_detach(&vdev->vbasedev);
g_free(vdev->vbasedev.name);
g_free(vdev->msix);
@@ -2846,7 +2946,7 @@ static void vfio_err_notifier_handler(void *opaque)
* and continue after disabling error recovery support for the
* device.
*/
-static void vfio_register_err_notifier(VFIOPCIDevice *vdev)
+void vfio_pci_register_err_notifier(VFIOPCIDevice *vdev)
{
Error *err = NULL;
int32_t fd;
@@ -2855,8 +2955,9 @@ static void vfio_register_err_notifier(VFIOPCIDevice *vdev)
return;
}
- if (event_notifier_init(&vdev->err_notifier, 0)) {
- error_report("vfio: Unable to init event notifier for error detection");
+ if (!vfio_notifier_init(vdev, &vdev->err_notifier, "err_notifier", 0,
+ &err)) {
+ error_report_err(err);
vdev->pci_aer = false;
return;
}
@@ -2864,11 +2965,11 @@ static void vfio_register_err_notifier(VFIOPCIDevice *vdev)
fd = event_notifier_get_fd(&vdev->err_notifier);
qemu_set_fd_handler(fd, vfio_err_notifier_handler, NULL, vdev);
- if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
+ if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
qemu_set_fd_handler(fd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->err_notifier);
+ vfio_notifier_cleanup(vdev, &vdev->err_notifier, "err_notifier", 0);
vdev->pci_aer = false;
}
}
@@ -2881,13 +2982,13 @@ static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev)
return;
}
- if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
+ if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
qemu_set_fd_handler(event_notifier_get_fd(&vdev->err_notifier),
NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->err_notifier);
+ vfio_notifier_cleanup(vdev, &vdev->err_notifier, "err_notifier", 0);
}
static void vfio_req_notifier_handler(void *opaque)
@@ -2905,35 +3006,37 @@ static void vfio_req_notifier_handler(void *opaque)
}
}
-static void vfio_register_req_notifier(VFIOPCIDevice *vdev)
+void vfio_pci_register_req_notifier(VFIOPCIDevice *vdev)
{
- struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info),
- .index = VFIO_PCI_REQ_IRQ_INDEX };
+ struct vfio_irq_info irq_info;
Error *err = NULL;
int32_t fd;
+ int ret;
if (!(vdev->features & VFIO_FEATURE_ENABLE_REQ)) {
return;
}
- if (ioctl(vdev->vbasedev.fd,
- VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0 || irq_info.count < 1) {
+ ret = vfio_device_get_irq_info(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX,
+ &irq_info);
+ if (ret < 0 || irq_info.count < 1) {
return;
}
- if (event_notifier_init(&vdev->req_notifier, 0)) {
- error_report("vfio: Unable to init event notifier for device request");
+ if (!vfio_notifier_init(vdev, &vdev->req_notifier, "req_notifier", 0,
+ &err)) {
+ error_report_err(err);
return;
}
fd = event_notifier_get_fd(&vdev->req_notifier);
qemu_set_fd_handler(fd, vfio_req_notifier_handler, NULL, vdev);
- if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
+ if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
qemu_set_fd_handler(fd, NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->req_notifier);
+ vfio_notifier_cleanup(vdev, &vdev->req_notifier, "req_notifier", 0);
} else {
vdev->req_enabled = true;
}
@@ -2947,87 +3050,33 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
return;
}
- if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
+ if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
qemu_set_fd_handler(event_notifier_get_fd(&vdev->req_notifier),
NULL, NULL, vdev);
- event_notifier_cleanup(&vdev->req_notifier);
+ vfio_notifier_cleanup(vdev, &vdev->req_notifier, "req_notifier", 0);
vdev->req_enabled = false;
}
-static void vfio_realize(PCIDevice *pdev, Error **errp)
+bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp)
{
- ERRP_GUARD();
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ PCIDevice *pdev = &vdev->pdev;
VFIODevice *vbasedev = &vdev->vbasedev;
- int i, ret;
- char uuid[UUID_STR_LEN];
- g_autofree char *name = NULL;
-
- if (vbasedev->fd < 0 && !vbasedev->sysfsdev) {
- if (!(~vdev->host.domain || ~vdev->host.bus ||
- ~vdev->host.slot || ~vdev->host.function)) {
- error_setg(errp, "No provided host device");
- error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
-#ifdef CONFIG_IOMMUFD
- "or -device vfio-pci,fd=DEVICE_FD "
-#endif
- "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
- return;
- }
- vbasedev->sysfsdev =
- g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x",
- vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function);
- }
-
- if (!vfio_device_get_name(vbasedev, errp)) {
- return;
- }
-
- /*
- * Mediated devices *might* operate compatibly with discarding of RAM, but
- * we cannot know for certain, it depends on whether the mdev vendor driver
- * stays in sync with the active working set of the guest driver. Prevent
- * the x-balloon-allowed option unless this is minimally an mdev device.
- */
- vbasedev->mdev = vfio_device_is_mdev(vbasedev);
-
- trace_vfio_mdev(vbasedev->name, vbasedev->mdev);
-
- if (vbasedev->ram_block_discard_allowed && !vbasedev->mdev) {
- error_setg(errp, "x-balloon-allowed only potentially compatible "
- "with mdev devices");
- goto error;
- }
-
- if (!qemu_uuid_is_null(&vdev->vf_token)) {
- qemu_uuid_unparse(&vdev->vf_token, uuid);
- name = g_strdup_printf("%s vf_token=%s", vbasedev->name, uuid);
- } else {
- name = g_strdup(vbasedev->name);
- }
-
- if (!vfio_attach_device(name, vbasedev,
- pci_device_iommu_address_space(pdev), errp)) {
- goto error;
- }
+ uint32_t config_space_size;
+ int ret;
- if (!vfio_populate_device(vdev, errp)) {
- goto error;
- }
+ config_space_size = MIN(pci_config_size(&vdev->pdev), vdev->config_size);
/* Get a copy of config space */
- ret = pread(vbasedev->fd, vdev->pdev.config,
- MIN(pci_config_size(&vdev->pdev), vdev->config_size),
- vdev->config_offset);
- if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
- ret = ret < 0 ? -errno : -EFAULT;
- error_setg_errno(errp, -ret, "failed to read device config space");
- goto error;
+ ret = vfio_pci_config_space_read(vdev, 0, config_space_size,
+ vdev->pdev.config);
+ if (ret < (int)config_space_size) {
+ ret = ret < 0 ? -ret : EFAULT;
+ error_setg_errno(errp, ret, "failed to read device config space");
+ return false;
}
/* vfio emulates a lot for us, but some bits need extra love */
@@ -3046,7 +3095,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (vdev->vendor_id != PCI_ANY_ID) {
if (vdev->vendor_id >= 0xffff) {
error_setg(errp, "invalid PCI vendor ID provided");
- goto error;
+ return false;
}
vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0);
trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id);
@@ -3057,7 +3106,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (vdev->device_id != PCI_ANY_ID) {
if (vdev->device_id > 0xffff) {
error_setg(errp, "invalid PCI device ID provided");
- goto error;
+ return false;
}
vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0);
trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id);
@@ -3068,7 +3117,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (vdev->sub_vendor_id != PCI_ANY_ID) {
if (vdev->sub_vendor_id > 0xffff) {
error_setg(errp, "invalid PCI subsystem vendor ID provided");
- goto error;
+ return false;
}
vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID,
vdev->sub_vendor_id, ~0);
@@ -3079,7 +3128,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (vdev->sub_device_id != PCI_ANY_ID) {
if (vdev->sub_device_id > 0xffff) {
error_setg(errp, "invalid PCI subsystem device ID provided");
- goto error;
+ return false;
}
vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0);
trace_vfio_pci_emulated_sub_device_id(vbasedev->name,
@@ -3110,53 +3159,17 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
vfio_bars_prepare(vdev);
if (!vfio_msix_early_setup(vdev, errp)) {
- goto error;
+ return false;
}
vfio_bars_register(vdev);
- if (!vbasedev->mdev &&
- !pci_device_set_iommu_device(pdev, vbasedev->hiod, errp)) {
- error_prepend(errp, "Failed to set iommu_device: ");
- goto out_teardown;
- }
-
- if (!vfio_add_capabilities(vdev, errp)) {
- goto out_unset_idev;
- }
-
- if (vdev->vga) {
- vfio_vga_quirk_setup(vdev);
- }
-
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- vfio_bar_quirk_setup(vdev, i);
- }
-
- if (!vdev->igd_opregion &&
- vdev->features & VFIO_FEATURE_ENABLE_IGD_OPREGION) {
- g_autofree struct vfio_region_info *opregion = NULL;
-
- if (vdev->pdev.qdev.hotplugged) {
- error_setg(errp,
- "cannot support IGD OpRegion feature on hotplugged "
- "device");
- goto out_unset_idev;
- }
-
- ret = vfio_get_dev_region_info(vbasedev,
- VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
- VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion);
- if (ret) {
- error_setg_errno(errp, -ret,
- "does not support requested IGD OpRegion feature");
- goto out_unset_idev;
- }
+ return true;
+}
- if (!vfio_pci_igd_opregion_init(vdev, opregion, errp)) {
- goto out_unset_idev;
- }
- }
+bool vfio_pci_interrupt_setup(VFIOPCIDevice *vdev, Error **errp)
+{
+ PCIDevice *pdev = &vdev->pdev;
/* QEMU emulates all of MSI & MSIX */
if (pdev->cap_present & QEMU_PCI_CAP_MSIX) {
@@ -3171,14 +3184,111 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) {
vdev->intx.mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- vfio_intx_mmap_enable, vdev);
+ vfio_intx_mmap_enable, vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev,
vfio_intx_routing_notifier);
vdev->irqchip_change_notifier.notify = vfio_irqchip_change;
kvm_irqchip_add_change_notifier(&vdev->irqchip_change_notifier);
if (!vfio_intx_enable(vdev, errp)) {
- goto out_deregister;
+ timer_free(vdev->intx.mmap_timer);
+ pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
+ kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void vfio_pci_realize(PCIDevice *pdev, Error **errp)
+{
+ ERRP_GUARD();
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
+ int i;
+ char uuid[UUID_STR_LEN];
+ g_autofree char *name = NULL;
+
+ if (vbasedev->fd < 0 && !vbasedev->sysfsdev) {
+ if (!(~vdev->host.domain || ~vdev->host.bus ||
+ ~vdev->host.slot || ~vdev->host.function)) {
+ error_setg(errp, "No provided host device");
+ error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
+#ifdef CONFIG_IOMMUFD
+ "or -device vfio-pci,fd=DEVICE_FD "
+#endif
+ "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
+ return;
}
+ vbasedev->sysfsdev =
+ g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x",
+ vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function);
+ }
+
+ if (!vfio_device_get_name(vbasedev, errp)) {
+ return;
+ }
+
+ /*
+ * Mediated devices *might* operate compatibly with discarding of RAM, but
+ * we cannot know for certain, it depends on whether the mdev vendor driver
+ * stays in sync with the active working set of the guest driver. Prevent
+ * the x-balloon-allowed option unless this is minimally an mdev device.
+ */
+ vbasedev->mdev = vfio_device_is_mdev(vbasedev);
+
+ trace_vfio_mdev(vbasedev->name, vbasedev->mdev);
+
+ if (vbasedev->ram_block_discard_allowed && !vbasedev->mdev) {
+ error_setg(errp, "x-balloon-allowed only potentially compatible "
+ "with mdev devices");
+ goto error;
+ }
+
+ if (!qemu_uuid_is_null(&vdev->vf_token)) {
+ qemu_uuid_unparse(&vdev->vf_token, uuid);
+ name = g_strdup_printf("%s vf_token=%s", vbasedev->name, uuid);
+ } else {
+ name = g_strdup(vbasedev->name);
+ }
+
+ if (!vfio_device_attach(name, vbasedev,
+ pci_device_iommu_address_space(pdev), errp)) {
+ goto error;
+ }
+
+ if (!vfio_pci_populate_device(vdev, errp)) {
+ goto error;
+ }
+
+ if (!vfio_pci_config_setup(vdev, errp)) {
+ goto error;
+ }
+
+ if (!vbasedev->mdev &&
+ !pci_device_set_iommu_device(pdev, vbasedev->hiod, errp)) {
+ error_prepend(errp, "Failed to set vIOMMU: ");
+ goto out_teardown;
+ }
+
+ if (!vfio_pci_add_capabilities(vdev, errp)) {
+ goto out_unset_idev;
+ }
+
+ if (!vfio_config_quirk_setup(vdev, errp)) {
+ goto out_unset_idev;
+ }
+
+ if (vdev->vga) {
+ vfio_vga_quirk_setup(vdev);
+ }
+
+ for (i = 0; i < PCI_ROM_SLOT; i++) {
+ vfio_bar_quirk_setup(vdev, i);
+ }
+
+ if (!vfio_pci_interrupt_setup(vdev, errp)) {
+ goto out_unset_idev;
}
if (vdev->display != ON_OFF_AUTO_OFF) {
@@ -3221,8 +3331,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
}
}
- vfio_register_err_notifier(vdev);
- vfio_register_req_notifier(vdev);
+ vfio_pci_register_err_notifier(vdev);
+ vfio_pci_register_req_notifier(vdev);
vfio_setup_resetfn_quirk(vdev);
return;
@@ -3243,33 +3353,22 @@ out_unset_idev:
pci_device_unset_iommu_device(pdev);
}
out_teardown:
- vfio_teardown_msi(vdev);
- vfio_bars_exit(vdev);
+ vfio_pci_teardown_msi(vdev);
+ vfio_pci_bars_exit(vdev);
error:
error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name);
}
static void vfio_instance_finalize(Object *obj)
{
- VFIOPCIDevice *vdev = VFIO_PCI(obj);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
- vfio_display_finalize(vdev);
- vfio_bars_finalize(vdev);
- g_free(vdev->emulated_config_bits);
- g_free(vdev->rom);
- /*
- * XXX Leaking igd_opregion is not an oversight, we can't remove the
- * fw_cfg entry therefore leaking this allocation seems like the safest
- * option.
- *
- * g_free(vdev->igd_opregion);
- */
vfio_pci_put_device(vdev);
}
static void vfio_exitfn(PCIDevice *pdev)
{
- VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
VFIODevice *vbasedev = &vdev->vbasedev;
vfio_unregister_req_notifier(vdev);
@@ -3282,9 +3381,9 @@ static void vfio_exitfn(PCIDevice *pdev)
if (vdev->intx.mmap_timer) {
timer_free(vdev->intx.mmap_timer);
}
- vfio_teardown_msi(vdev);
+ vfio_pci_teardown_msi(vdev);
vfio_pci_disable_rp_atomics(vdev);
- vfio_bars_exit(vdev);
+ vfio_pci_bars_exit(vdev);
vfio_migration_exit(vbasedev);
if (!vbasedev->mdev) {
pci_device_unset_iommu_device(pdev);
@@ -3293,7 +3392,12 @@ static void vfio_exitfn(PCIDevice *pdev)
static void vfio_pci_reset(DeviceState *dev)
{
- VFIOPCIDevice *vdev = VFIO_PCI(dev);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(dev);
+
+ /* Do not reset the device during qemu_system_reset prior to cpr load */
+ if (cpr_is_incoming()) {
+ return;
+ }
trace_vfio_pci_reset(vdev->vbasedev.name);
@@ -3333,7 +3437,7 @@ post_reset:
static void vfio_instance_init(Object *obj)
{
PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIOPCIDevice *vdev = VFIO_PCI(obj);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
VFIODevice *vbasedev = &vdev->vbasedev;
device_add_bootindex_property(obj, &vdev->bootindex,
@@ -3352,9 +3456,43 @@ static void vfio_instance_init(Object *obj)
/* QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command
* line, therefore, no need to wait to realize like other devices */
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
+
+ /*
+ * A device that is resuming for cpr is already configured, so do not
+ * reset it during qemu_system_reset prior to cpr load, else interrupts
+ * may be lost.
+ */
+ pci_dev->cap_present |= QEMU_PCI_SKIP_RESET_ON_CPR;
}
-static Property vfio_pci_dev_properties[] = {
+static void vfio_pci_base_dev_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "VFIO PCI base device";
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ pdc->exit = vfio_exitfn;
+ pdc->config_read = vfio_pci_read_config;
+ pdc->config_write = vfio_pci_write_config;
+}
+
+static const TypeInfo vfio_pci_base_dev_info = {
+ .name = TYPE_VFIO_PCI_BASE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VFIOPCIDevice),
+ .abstract = true,
+ .class_init = vfio_pci_base_dev_class_init,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { }
+ },
+};
+
+static PropertyInfo vfio_pci_migration_multifd_transfer_prop;
+
+static const Property vfio_pci_dev_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host),
DEFINE_PROP_UUID_NODEFAULT("vf-token", VFIOPCIDevice, vf_token),
DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev),
@@ -3375,9 +3513,17 @@ static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_BIT("x-req", VFIOPCIDevice, features,
VFIO_FEATURE_ENABLE_REQ_BIT, true),
DEFINE_PROP_BIT("x-igd-opregion", VFIOPCIDevice, features,
- VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false),
+ VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, true),
+ DEFINE_PROP_BIT("x-igd-lpc", VFIOPCIDevice, features,
+ VFIO_FEATURE_ENABLE_IGD_LPC_BIT, false),
+ DEFINE_PROP_ON_OFF_AUTO("x-igd-legacy-mode", VFIOPCIDevice,
+ igd_legacy_mode, ON_OFF_AUTO_AUTO),
DEFINE_PROP_ON_OFF_AUTO("enable-migration", VFIOPCIDevice,
vbasedev.enable_migration, ON_OFF_AUTO_AUTO),
+ DEFINE_PROP("x-migration-multifd-transfer", VFIOPCIDevice,
+ vbasedev.migration_multifd_transfer,
+ vfio_pci_migration_multifd_transfer_prop, OnOffAuto,
+ .set_default = true, .defval.i = ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("migration-events", VFIOPCIDevice,
vbasedev.migration_events, false),
DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false),
@@ -3403,67 +3549,187 @@ static Property vfio_pci_dev_properties[] = {
nv_gpudirect_clique,
qdev_prop_nv_gpudirect_clique, uint8_t),
DEFINE_PROP_OFF_AUTO_PCIBAR("x-msix-relocation", VFIOPCIDevice, msix_relo,
- OFF_AUTOPCIBAR_OFF),
+ OFF_AUTO_PCIBAR_OFF),
#ifdef CONFIG_IOMMUFD
DEFINE_PROP_LINK("iommufd", VFIOPCIDevice, vbasedev.iommufd,
TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *),
#endif
DEFINE_PROP_BOOL("skip-vsc-check", VFIOPCIDevice, skip_vsc_check, true),
- DEFINE_PROP_END_OF_LIST(),
};
#ifdef CONFIG_IOMMUFD
static void vfio_pci_set_fd(Object *obj, const char *str, Error **errp)
{
- vfio_device_set_fd(&VFIO_PCI(obj)->vbasedev, str, errp);
+ VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
+ vfio_device_set_fd(&vdev->vbasedev, str, errp);
}
#endif
-static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
+static void vfio_pci_dev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
- dc->reset = vfio_pci_reset;
+ device_class_set_legacy_reset(dc, vfio_pci_reset);
device_class_set_props(dc, vfio_pci_dev_properties);
#ifdef CONFIG_IOMMUFD
object_class_property_add_str(klass, "fd", NULL, vfio_pci_set_fd);
#endif
+ dc->vmsd = &vfio_cpr_pci_vmstate;
dc->desc = "VFIO-based PCI device assignment";
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- pdc->realize = vfio_realize;
- pdc->exit = vfio_exitfn;
- pdc->config_read = vfio_pci_read_config;
- pdc->config_write = vfio_pci_write_config;
+ pdc->realize = vfio_pci_realize;
+
+ object_class_property_set_description(klass, /* 1.3 */
+ "host",
+ "Host PCI address [domain:]<bus:slot.function> of assigned device");
+ object_class_property_set_description(klass, /* 1.3 */
+ "x-intx-mmap-timeout-ms",
+ "When EOI is not provided by KVM/QEMU, wait time "
+ "(milliseconds) to re-enable device direct access "
+ "after INTx (DEBUG)");
+ object_class_property_set_description(klass, /* 1.5 */
+ "x-vga",
+ "Expose VGA address spaces for device");
+ object_class_property_set_description(klass, /* 2.3 */
+ "x-req",
+ "Disable device request notification support (DEBUG)");
+ object_class_property_set_description(klass, /* 2.4 and 2.5 */
+ "x-no-mmap",
+ "Disable MMAP for device. Allows to trace MMIO "
+ "accesses (DEBUG)");
+ object_class_property_set_description(klass, /* 2.5 */
+ "x-no-kvm-intx",
+ "Disable direct VFIO->KVM INTx injection. Allows to "
+ "trace INTx interrupts (DEBUG)");
+ object_class_property_set_description(klass, /* 2.5 */
+ "x-no-kvm-msi",
+ "Disable direct VFIO->KVM MSI injection. Allows to "
+ "trace MSI interrupts (DEBUG)");
+ object_class_property_set_description(klass, /* 2.5 */
+ "x-no-kvm-msix",
+ "Disable direct VFIO->KVM MSIx injection. Allows to "
+ "trace MSIx interrupts (DEBUG)");
+ object_class_property_set_description(klass, /* 2.5 */
+ "x-pci-vendor-id",
+ "Override PCI Vendor ID with provided value (DEBUG)");
+ object_class_property_set_description(klass, /* 2.5 */
+ "x-pci-device-id",
+ "Override PCI device ID with provided value (DEBUG)");
+ object_class_property_set_description(klass, /* 2.5 */
+ "x-pci-sub-vendor-id",
+ "Override PCI Subsystem Vendor ID with provided value "
+ "(DEBUG)");
+ object_class_property_set_description(klass, /* 2.5 */
+ "x-pci-sub-device-id",
+ "Override PCI Subsystem Device ID with provided value "
+ "(DEBUG)");
+ object_class_property_set_description(klass, /* 2.6 */
+ "sysfsdev",
+ "Host sysfs path of assigned device");
+ object_class_property_set_description(klass, /* 2.7 */
+ "x-igd-opregion",
+ "Expose host IGD OpRegion to guest");
+ object_class_property_set_description(klass, /* 2.7 (See c4c45e943e51) */
+ "x-igd-gms",
+ "Override IGD data stolen memory size (32MiB units)");
+ object_class_property_set_description(klass, /* 2.11 */
+ "x-nv-gpudirect-clique",
+ "Add NVIDIA GPUDirect capability indicating P2P DMA "
+ "clique for device [0-15]");
+ object_class_property_set_description(klass, /* 2.12 */
+ "x-no-geforce-quirks",
+ "Disable GeForce quirks (for NVIDIA Quadro/GRID/Tesla). "
+ "Improves performance");
+ object_class_property_set_description(klass, /* 2.12 */
+ "display",
+ "Enable display support for device, ex. vGPU");
+ object_class_property_set_description(klass, /* 2.12 */
+ "x-msix-relocation",
+ "Specify MSI-X MMIO relocation to the end of specified "
+ "existing BAR or new BAR to avoid virtualization overhead "
+ "due to adjacent device registers");
+ object_class_property_set_description(klass, /* 3.0 */
+ "x-no-kvm-ioeventfd",
+ "Disable registration of ioeventfds with KVM (DEBUG)");
+ object_class_property_set_description(klass, /* 3.0 */
+ "x-no-vfio-ioeventfd",
+ "Disable linking of KVM ioeventfds to VFIO ioeventfds "
+ "(DEBUG)");
+ object_class_property_set_description(klass, /* 3.1 */
+ "x-balloon-allowed",
+ "Override allowing ballooning with device (DEBUG, DANGER)");
+ object_class_property_set_description(klass, /* 3.2 */
+ "xres",
+ "Set X display resolution the vGPU should use");
+ object_class_property_set_description(klass, /* 3.2 */
+ "yres",
+ "Set Y display resolution the vGPU should use");
+ object_class_property_set_description(klass, /* 5.2 */
+ "x-pre-copy-dirty-page-tracking",
+ "Disable dirty pages tracking during iterative phase "
+ "(DEBUG)");
+ object_class_property_set_description(klass, /* 5.2, 8.0 non-experimetal */
+ "enable-migration",
+ "Enale device migration. Also requires a host VFIO PCI "
+ "variant or mdev driver with migration support enabled");
+ object_class_property_set_description(klass, /* 8.1 */
+ "vf-token",
+ "Specify UUID VF token. Required for VF when PF is owned "
+ "by another VFIO driver");
+#ifdef CONFIG_IOMMUFD
+ object_class_property_set_description(klass, /* 9.0 */
+ "iommufd",
+ "Set host IOMMUFD backend device");
+#endif
+ object_class_property_set_description(klass, /* 9.1 */
+ "x-device-dirty-page-tracking",
+ "Disable device dirty page tracking and use "
+ "container-based dirty page tracking");
+ object_class_property_set_description(klass, /* 9.1 */
+ "migration-events",
+ "Emit VFIO migration QAPI event when a VFIO device "
+ "changes its migration state. For management applications");
+ object_class_property_set_description(klass, /* 9.1 */
+ "skip-vsc-check",
+ "Skip config space check for Vendor Specific Capability. "
+ "Setting to false will enforce strict checking of VSC content "
+ "(DEBUG)");
+ object_class_property_set_description(klass, /* 10.0 */
+ "x-migration-multifd-transfer",
+ "Transfer this device state via "
+ "multifd channels when live migrating it");
}
static const TypeInfo vfio_pci_dev_info = {
.name = TYPE_VFIO_PCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(VFIOPCIDevice),
+ .parent = TYPE_VFIO_PCI_BASE,
.class_init = vfio_pci_dev_class_init,
.instance_init = vfio_instance_init,
.instance_finalize = vfio_instance_finalize,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- { }
- },
};
-static Property vfio_pci_dev_nohotplug_properties[] = {
+static const Property vfio_pci_dev_nohotplug_properties[] = {
DEFINE_PROP_BOOL("ramfb", VFIOPCIDevice, enable_ramfb, false),
DEFINE_PROP_ON_OFF_AUTO("x-ramfb-migrate", VFIOPCIDevice, ramfb_migrate,
ON_OFF_AUTO_AUTO),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass, void *data)
+static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, vfio_pci_dev_nohotplug_properties);
dc->hotpluggable = false;
+
+ object_class_property_set_description(klass, /* 3.1 */
+ "ramfb",
+ "Enable ramfb to provide pre-boot graphics for devices "
+ "enabling display option");
+ object_class_property_set_description(klass, /* 8.2 */
+ "x-ramfb-migrate",
+ "Override default migration support for ramfb support "
+ "(DEBUG)");
}
static const TypeInfo vfio_pci_nohotplug_dev_info = {
@@ -3475,6 +3741,18 @@ static const TypeInfo vfio_pci_nohotplug_dev_info = {
static void register_vfio_pci_dev_type(void)
{
+ /*
+ * Ordinary ON_OFF_AUTO property isn't runtime-mutable, but source VM can
+ * run for a long time before being migrated so it is desirable to have a
+ * fallback mechanism to the old way of transferring VFIO device state if
+ * it turns to be necessary.
+ * The following makes this type of property have the same mutability level
+ * as ordinary migration parameters.
+ */
+ vfio_pci_migration_multifd_transfer_prop = qdev_prop_on_off_auto;
+ vfio_pci_migration_multifd_transfer_prop.realized_set_allowed = true;
+
+ type_register_static(&vfio_pci_base_dev_info);
type_register_static(&vfio_pci_dev_info);
type_register_static(&vfio_pci_nohotplug_dev_info);
}
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index bf67df2..5ba7330 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -12,14 +12,16 @@
#ifndef HW_VFIO_VFIO_PCI_H
#define HW_VFIO_VFIO_PCI_H
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/pci/pci_device.h"
-#include "hw/vfio/vfio-common.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/vfio/vfio-region.h"
#include "qemu/event_notifier.h"
#include "qemu/queue.h"
#include "qemu/timer.h"
#include "qom/object.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
+#include "vfio-display.h"
#define PCI_ANY_ID (~0)
@@ -114,10 +116,19 @@ typedef struct VFIOMSIXInfo {
uint32_t pba_offset;
unsigned long *pending;
bool noresize;
+ MemoryRegion *pba_region;
} VFIOMSIXInfo;
+/*
+ * TYPE_VFIO_PCI_BASE is an abstract type used to share code
+ * between VFIO implementations that use a kernel driver
+ * with those that use user sockets.
+ */
+#define TYPE_VFIO_PCI_BASE "vfio-pci-base"
+OBJECT_DECLARE_SIMPLE_TYPE(VFIOPCIDevice, VFIO_PCI_BASE)
+
#define TYPE_VFIO_PCI "vfio-pci"
-OBJECT_DECLARE_SIMPLE_TYPE(VFIOPCIDevice, VFIO_PCI)
+/* TYPE_VFIO_PCI shares struct VFIOPCIDevice. */
struct VFIOPCIDevice {
PCIDevice pdev;
@@ -154,13 +165,16 @@ struct VFIOPCIDevice {
#define VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT 2
#define VFIO_FEATURE_ENABLE_IGD_OPREGION \
(1 << VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT)
+#define VFIO_FEATURE_ENABLE_IGD_LPC_BIT 3
+#define VFIO_FEATURE_ENABLE_IGD_LPC \
+ (1 << VFIO_FEATURE_ENABLE_IGD_LPC_BIT)
OnOffAuto display;
uint32_t display_xres;
uint32_t display_yres;
int32_t bootindex;
+ OnOffAuto igd_legacy_mode;
uint32_t igd_gms;
OffAutoPCIBAR msix_relo;
- uint8_t pm_cap;
uint8_t nv_gpudirect_clique;
bool pci_aer;
bool req_enabled;
@@ -197,6 +211,14 @@ static inline bool vfio_is_vga(VFIOPCIDevice *vdev)
return class == PCI_CLASS_DISPLAY_VGA;
}
+/* MSI/MSI-X/INTx */
+void vfio_pci_vector_init(VFIOPCIDevice *vdev, int nr);
+void vfio_pci_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
+ int vector_n, bool msix);
+void vfio_pci_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev);
+void vfio_pci_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev);
+bool vfio_pci_intx_enable(VFIOPCIDevice *vdev, Error **errp);
+
uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
void vfio_pci_write_config(PCIDevice *pdev,
uint32_t addr, uint32_t val, int len);
@@ -205,6 +227,7 @@ uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size);
void vfio_vga_write(void *opaque, hwaddr addr, uint64_t data, unsigned size);
bool vfio_opt_rom_in_denylist(VFIOPCIDevice *vdev);
+bool vfio_config_quirk_setup(VFIOPCIDevice *vdev, Error **errp);
void vfio_vga_quirk_setup(VFIOPCIDevice *vdev);
void vfio_vga_quirk_exit(VFIOPCIDevice *vdev);
void vfio_vga_quirk_finalize(VFIOPCIDevice *vdev);
@@ -215,7 +238,8 @@ void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev);
bool vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp);
void vfio_quirk_reset(VFIOPCIDevice *vdev);
VFIOQuirk *vfio_quirk_alloc(int nr_mem);
-void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr);
+void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr);
+bool vfio_probe_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp);
extern const PropertyInfo qdev_prop_nv_gpudirect_clique;
@@ -227,14 +251,21 @@ int vfio_pci_get_pci_hot_reset_info(VFIOPCIDevice *vdev,
bool vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp);
-bool vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
- struct vfio_region_info *info,
- Error **errp);
-
void vfio_display_reset(VFIOPCIDevice *vdev);
bool vfio_display_probe(VFIOPCIDevice *vdev, Error **errp);
void vfio_display_finalize(VFIOPCIDevice *vdev);
extern const VMStateDescription vfio_display_vmstate;
+void vfio_pci_bars_exit(VFIOPCIDevice *vdev);
+bool vfio_pci_add_capabilities(VFIOPCIDevice *vdev, Error **errp);
+bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp);
+bool vfio_pci_interrupt_setup(VFIOPCIDevice *vdev, Error **errp);
+void vfio_pci_intx_eoi(VFIODevice *vbasedev);
+void vfio_pci_put_device(VFIOPCIDevice *vdev);
+bool vfio_pci_populate_device(VFIOPCIDevice *vdev, Error **errp);
+void vfio_pci_register_err_notifier(VFIOPCIDevice *vdev);
+void vfio_pci_register_req_notifier(VFIOPCIDevice *vdev);
+void vfio_pci_teardown_msi(VFIOPCIDevice *vdev);
+
#endif /* HW_VFIO_VFIO_PCI_H */
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index a85c199..9a21f2e 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -21,22 +21,23 @@
#include <linux/vfio.h>
#include "hw/vfio/vfio-platform.h"
-#include "sysemu/iommufd.h"
+#include "system/iommufd.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
#include "qemu/lockable.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/range.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
+#include "system/memory.h"
+#include "system/address-spaces.h"
#include "qemu/queue.h"
#include "hw/sysbus.h"
#include "trace.h"
#include "hw/irq.h"
#include "hw/platform-bus.h"
#include "hw/qdev-properties.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
+#include "hw/vfio/vfio-region.h"
/*
* Functions used whatever the injection method
@@ -118,8 +119,8 @@ static int vfio_set_trigger_eventfd(VFIOINTp *intp,
qemu_set_fd_handler(fd, (IOHandler *)handler, NULL, intp);
- if (!vfio_set_irq_signaling(vbasedev, intp->pin, 0,
- VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
+ if (!vfio_device_irq_set_signaling(vbasedev, intp->pin, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vbasedev->name);
qemu_set_fd_handler(fd, NULL, NULL, NULL);
return -EINVAL;
@@ -300,7 +301,7 @@ static void vfio_platform_eoi(VFIODevice *vbasedev)
if (vfio_irq_is_automasked(intp)) {
/* unmasks the physical level-sensitive IRQ */
- vfio_unmask_single_irqindex(vbasedev, intp->pin);
+ vfio_device_irq_unmask(vbasedev, intp->pin);
}
/* a single IRQ can be active at a time */
@@ -356,8 +357,8 @@ static int vfio_set_resample_eventfd(VFIOINTp *intp)
Error *err = NULL;
qemu_set_fd_handler(fd, NULL, NULL, NULL);
- if (!vfio_set_irq_signaling(vbasedev, intp->pin, 0,
- VFIO_IRQ_SET_ACTION_UNMASK, fd, &err)) {
+ if (!vfio_device_irq_set_signaling(vbasedev, intp->pin, 0,
+ VFIO_IRQ_SET_ACTION_UNMASK, fd, &err)) {
error_reportf_err(err, VFIO_MSG_PREFIX, vbasedev->name);
return -EINVAL;
}
@@ -418,7 +419,6 @@ fail_vfio:
abort();
fail_irqfd:
vfio_start_eventfd_injection(sbdev, irq);
- return;
}
/* VFIO skeleton */
@@ -474,10 +474,10 @@ static bool vfio_populate_device(VFIODevice *vbasedev, Error **errp)
QSIMPLEQ_INIT(&vdev->pending_intp_queue);
for (i = 0; i < vbasedev->num_irqs; i++) {
- struct vfio_irq_info irq = { .argsz = sizeof(irq) };
+ struct vfio_irq_info irq;
+
+ ret = vfio_device_get_irq_info(vbasedev, i, &irq);
- irq.index = i;
- ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
if (ret) {
error_setg_errno(errp, -ret, "failed to get device irq info");
goto irq_err;
@@ -546,7 +546,7 @@ static bool vfio_base_device_init(VFIODevice *vbasedev, Error **errp)
return false;
}
- if (!vfio_attach_device(vbasedev->name, vbasedev,
+ if (!vfio_device_attach(vbasedev->name, vbasedev,
&address_space_memory, errp)) {
return false;
}
@@ -555,7 +555,7 @@ static bool vfio_base_device_init(VFIODevice *vbasedev, Error **errp)
return true;
}
- vfio_detach_device(vbasedev);
+ vfio_device_detach(vbasedev);
return false;
}
@@ -575,6 +575,7 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
VFIODevice *vbasedev = &vdev->vbasedev;
int i;
+ warn_report("-device vfio-platform is deprecated");
qemu_mutex_init(&vdev->intp_mutex);
trace_vfio_platform_realize(vbasedev->sysfsdev ?
@@ -629,7 +630,7 @@ static const VMStateDescription vfio_platform_vmstate = {
.unmigratable = 1,
};
-static Property vfio_platform_dev_properties[] = {
+static const Property vfio_platform_dev_properties[] = {
DEFINE_PROP_STRING("host", VFIOPlatformDevice, vbasedev.name),
DEFINE_PROP_STRING("sysfsdev", VFIOPlatformDevice, vbasedev.sysfsdev),
DEFINE_PROP_BOOL("x-no-mmap", VFIOPlatformDevice, vbasedev.no_mmap, false),
@@ -640,7 +641,6 @@ static Property vfio_platform_dev_properties[] = {
DEFINE_PROP_LINK("iommufd", VFIOPlatformDevice, vbasedev.iommufd,
TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *),
#endif
- DEFINE_PROP_END_OF_LIST(),
};
static void vfio_platform_instance_init(Object *obj)
@@ -659,7 +659,7 @@ static void vfio_platform_set_fd(Object *obj, const char *str, Error **errp)
}
#endif
-static void vfio_platform_class_init(ObjectClass *klass, void *data)
+static void vfio_platform_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
@@ -673,13 +673,35 @@ static void vfio_platform_class_init(ObjectClass *klass, void *data)
dc->desc = "VFIO-based platform device assignment";
sbc->connect_irq_notifier = vfio_start_irqfd_injection;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- /* Supported by TYPE_VIRT_MACHINE */
- dc->user_creatable = true;
+
+ object_class_property_set_description(klass, /* 2.4 */
+ "host",
+ "Host device name of assigned device");
+ object_class_property_set_description(klass, /* 2.4 and 2.5 */
+ "x-no-mmap",
+ "Disable MMAP for device. Allows to trace MMIO "
+ "accesses (DEBUG)");
+ object_class_property_set_description(klass, /* 2.4 */
+ "mmap-timeout-ms",
+ "When EOI is not provided by KVM/QEMU, wait time "
+ "(milliseconds) to re-enable device direct access "
+ "after level interrupt (DEBUG)");
+ object_class_property_set_description(klass, /* 2.4 */
+ "x-irqfd",
+ "Allow disabling irqfd support (DEBUG)");
+ object_class_property_set_description(klass, /* 2.6 */
+ "sysfsdev",
+ "Host sysfs path of assigned device");
+#ifdef CONFIG_IOMMUFD
+ object_class_property_set_description(klass, /* 9.0 */
+ "iommufd",
+ "Set host IOMMUFD backend device");
+#endif
}
static const TypeInfo vfio_platform_dev_info = {
.name = TYPE_VFIO_PLATFORM,
- .parent = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
.instance_size = sizeof(VFIOPlatformDevice),
.instance_init = vfio_platform_instance_init,
.class_init = vfio_platform_class_init,
diff --git a/hw/vfio/region.c b/hw/vfio/region.c
new file mode 100644
index 0000000..d04c57d
--- /dev/null
+++ b/hw/vfio/region.c
@@ -0,0 +1,403 @@
+/*
+ * VFIO regions
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Based on qemu-kvm device-assignment:
+ * Adapted for KVM by Qumranet.
+ * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
+ */
+
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+
+#include "hw/vfio/vfio-region.h"
+#include "hw/vfio/vfio-device.h"
+#include "hw/hw.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "monitor/monitor.h"
+#include "vfio-helpers.h"
+
+/*
+ * IO Port/MMIO - Beware of the endians, VFIO is always little endian
+ */
+void vfio_region_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIORegion *region = opaque;
+ VFIODevice *vbasedev = region->vbasedev;
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+ int ret;
+
+ switch (size) {
+ case 1:
+ buf.byte = data;
+ break;
+ case 2:
+ buf.word = cpu_to_le16(data);
+ break;
+ case 4:
+ buf.dword = cpu_to_le32(data);
+ break;
+ case 8:
+ buf.qword = cpu_to_le64(data);
+ break;
+ default:
+ hw_error("vfio: unsupported write size, %u bytes", size);
+ break;
+ }
+
+ ret = vbasedev->io_ops->region_write(vbasedev, region->nr,
+ addr, size, &buf, region->post_wr);
+ if (ret != size) {
+ error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64
+ ",%d) failed: %s",
+ __func__, vbasedev->name, region->nr,
+ addr, data, size, strwriteerror(ret));
+ }
+
+ trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size);
+
+ /*
+ * A read or write to a BAR always signals an INTx EOI. This will
+ * do nothing if not pending (including not in INTx mode). We assume
+ * that a BAR access is in response to an interrupt and that BAR
+ * accesses will service the interrupt. Unfortunately, we don't know
+ * which access will service the interrupt, so we're potentially
+ * getting quite a few host interrupts per guest interrupt.
+ */
+ vbasedev->ops->vfio_eoi(vbasedev);
+}
+
+uint64_t vfio_region_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIORegion *region = opaque;
+ VFIODevice *vbasedev = region->vbasedev;
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+ uint64_t data = 0;
+ int ret;
+
+ ret = vbasedev->io_ops->region_read(vbasedev, region->nr, addr, size, &buf);
+ if (ret != size) {
+ error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %s",
+ __func__, vbasedev->name, region->nr,
+ addr, size, strreaderror(ret));
+ return (uint64_t)-1;
+ }
+ switch (size) {
+ case 1:
+ data = buf.byte;
+ break;
+ case 2:
+ data = le16_to_cpu(buf.word);
+ break;
+ case 4:
+ data = le32_to_cpu(buf.dword);
+ break;
+ case 8:
+ data = le64_to_cpu(buf.qword);
+ break;
+ default:
+ hw_error("vfio: unsupported read size, %u bytes", size);
+ break;
+ }
+
+ trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data);
+
+ /* Same as write above */
+ vbasedev->ops->vfio_eoi(vbasedev);
+
+ return data;
+}
+
+static const MemoryRegionOps vfio_region_ops = {
+ .read = vfio_region_read,
+ .write = vfio_region_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
+static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
+ struct vfio_region_info *info)
+{
+ struct vfio_info_cap_header *hdr;
+ struct vfio_region_info_cap_sparse_mmap *sparse;
+ int i, j;
+
+ hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP);
+ if (!hdr) {
+ return -ENODEV;
+ }
+
+ sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header);
+
+ trace_vfio_region_sparse_mmap_header(region->vbasedev->name,
+ region->nr, sparse->nr_areas);
+
+ region->mmaps = g_new0(VFIOMmap, sparse->nr_areas);
+
+ for (i = 0, j = 0; i < sparse->nr_areas; i++) {
+ if (sparse->areas[i].size) {
+ trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset,
+ sparse->areas[i].offset +
+ sparse->areas[i].size - 1);
+ region->mmaps[j].offset = sparse->areas[i].offset;
+ region->mmaps[j].size = sparse->areas[i].size;
+ j++;
+ }
+ }
+
+ region->nr_mmaps = j;
+ region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap));
+
+ return 0;
+}
+
+int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region,
+ int index, const char *name)
+{
+ struct vfio_region_info *info = NULL;
+ int ret;
+
+ ret = vfio_device_get_region_info(vbasedev, index, &info);
+ if (ret) {
+ return ret;
+ }
+
+ region->vbasedev = vbasedev;
+ region->flags = info->flags;
+ region->size = info->size;
+ region->fd_offset = info->offset;
+ region->nr = index;
+ region->post_wr = false;
+
+ if (region->size) {
+ region->mem = g_new0(MemoryRegion, 1);
+ memory_region_init_io(region->mem, obj, &vfio_region_ops,
+ region, name, region->size);
+
+ if (!vbasedev->no_mmap &&
+ region->flags & VFIO_REGION_INFO_FLAG_MMAP) {
+
+ ret = vfio_setup_region_sparse_mmaps(region, info);
+
+ if (ret) {
+ region->nr_mmaps = 1;
+ region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
+ region->mmaps[0].offset = 0;
+ region->mmaps[0].size = region->size;
+ }
+ }
+ }
+
+ trace_vfio_region_setup(vbasedev->name, index, name,
+ region->flags, region->fd_offset, region->size);
+ return 0;
+}
+
+static void vfio_subregion_unmap(VFIORegion *region, int index)
+{
+ trace_vfio_region_unmap(memory_region_name(&region->mmaps[index].mem),
+ region->mmaps[index].offset,
+ region->mmaps[index].offset +
+ region->mmaps[index].size - 1);
+ memory_region_del_subregion(region->mem, &region->mmaps[index].mem);
+ munmap(region->mmaps[index].mmap, region->mmaps[index].size);
+ object_unparent(OBJECT(&region->mmaps[index].mem));
+ region->mmaps[index].mmap = NULL;
+}
+
+int vfio_region_mmap(VFIORegion *region)
+{
+ int i, ret, prot = 0;
+ char *name;
+ int fd;
+
+ if (!region->mem) {
+ return 0;
+ }
+
+ prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0;
+ prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
+
+ for (i = 0; i < region->nr_mmaps; i++) {
+ size_t align = MIN(1ULL << ctz64(region->mmaps[i].size), 1 * GiB);
+ void *map_base, *map_align;
+
+ /*
+ * Align the mmap for more efficient mapping in the kernel. Ideally
+ * we'd know the PMD and PUD mapping sizes to use as discrete alignment
+ * intervals, but we don't. As of Linux v6.12, the largest PUD size
+ * supporting huge pfnmap is 1GiB (ARCH_SUPPORTS_PUD_PFNMAP is only set
+ * on x86_64). Align by power-of-two size, capped at 1GiB.
+ *
+ * NB. qemu_memalign() and friends actually allocate memory, whereas
+ * the region size here can exceed host memory, therefore we manually
+ * create an oversized anonymous mapping and clean it up for alignment.
+ */
+ map_base = mmap(0, region->mmaps[i].size + align, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (map_base == MAP_FAILED) {
+ ret = -errno;
+ goto no_mmap;
+ }
+
+ fd = vfio_device_get_region_fd(region->vbasedev, region->nr);
+
+ map_align = (void *)ROUND_UP((uintptr_t)map_base, (uintptr_t)align);
+ munmap(map_base, map_align - map_base);
+ munmap(map_align + region->mmaps[i].size,
+ align - (map_align - map_base));
+
+ region->mmaps[i].mmap = mmap(map_align, region->mmaps[i].size, prot,
+ MAP_SHARED | MAP_FIXED, fd,
+ region->fd_offset +
+ region->mmaps[i].offset);
+ if (region->mmaps[i].mmap == MAP_FAILED) {
+ ret = -errno;
+ goto no_mmap;
+ }
+
+ name = g_strdup_printf("%s mmaps[%d]",
+ memory_region_name(region->mem), i);
+ memory_region_init_ram_device_ptr(&region->mmaps[i].mem,
+ memory_region_owner(region->mem),
+ name, region->mmaps[i].size,
+ region->mmaps[i].mmap);
+ g_free(name);
+ memory_region_add_subregion(region->mem, region->mmaps[i].offset,
+ &region->mmaps[i].mem);
+
+ trace_vfio_region_mmap(memory_region_name(&region->mmaps[i].mem),
+ region->mmaps[i].offset,
+ region->mmaps[i].offset +
+ region->mmaps[i].size - 1);
+ }
+
+ return 0;
+
+no_mmap:
+ trace_vfio_region_mmap_fault(memory_region_name(region->mem), i,
+ region->fd_offset + region->mmaps[i].offset,
+ region->fd_offset + region->mmaps[i].offset +
+ region->mmaps[i].size - 1, ret);
+
+ region->mmaps[i].mmap = NULL;
+
+ for (i--; i >= 0; i--) {
+ vfio_subregion_unmap(region, i);
+ }
+
+ return ret;
+}
+
+void vfio_region_unmap(VFIORegion *region)
+{
+ int i;
+
+ if (!region->mem) {
+ return;
+ }
+
+ for (i = 0; i < region->nr_mmaps; i++) {
+ if (region->mmaps[i].mmap) {
+ vfio_subregion_unmap(region, i);
+ }
+ }
+}
+
+void vfio_region_exit(VFIORegion *region)
+{
+ int i;
+
+ if (!region->mem) {
+ return;
+ }
+
+ for (i = 0; i < region->nr_mmaps; i++) {
+ if (region->mmaps[i].mmap) {
+ memory_region_del_subregion(region->mem, &region->mmaps[i].mem);
+ }
+ }
+
+ trace_vfio_region_exit(region->vbasedev->name, region->nr);
+}
+
+void vfio_region_finalize(VFIORegion *region)
+{
+ int i;
+
+ if (!region->mem) {
+ return;
+ }
+
+ for (i = 0; i < region->nr_mmaps; i++) {
+ if (region->mmaps[i].mmap) {
+ munmap(region->mmaps[i].mmap, region->mmaps[i].size);
+ object_unparent(OBJECT(&region->mmaps[i].mem));
+ }
+ }
+
+ object_unparent(OBJECT(region->mem));
+
+ g_free(region->mem);
+ g_free(region->mmaps);
+
+ trace_vfio_region_finalize(region->vbasedev->name, region->nr);
+
+ region->mem = NULL;
+ region->mmaps = NULL;
+ region->nr_mmaps = 0;
+ region->size = 0;
+ region->flags = 0;
+ region->nr = 0;
+}
+
+void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled)
+{
+ int i;
+
+ if (!region->mem) {
+ return;
+ }
+
+ for (i = 0; i < region->nr_mmaps; i++) {
+ if (region->mmaps[i].mmap) {
+ memory_region_set_enabled(&region->mmaps[i].mem, enabled);
+ }
+ }
+
+ trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem),
+ enabled);
+}
diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index 018bd20..564b70e 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -11,23 +11,30 @@
#include "qemu/osdep.h"
#include <sys/ioctl.h>
#include <linux/vfio.h>
-#ifdef CONFIG_KVM
-#include <linux/kvm.h>
-#endif
-#include "sysemu/kvm.h"
-#include "exec/address-spaces.h"
+#include "system/kvm.h"
+#include "system/hostmem.h"
+#include "system/address-spaces.h"
-#include "hw/vfio/vfio-common.h"
+#include "hw/vfio/vfio-container.h"
#include "hw/hw.h"
-#include "exec/ram_addr.h"
+#include "system/ram_addr.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "trace.h"
+#include "vfio-helpers.h"
+
+typedef struct VFIOHostDMAWindow {
+ hwaddr min_iova;
+ hwaddr max_iova;
+ uint64_t iova_pgsizes;
+ QLIST_ENTRY(VFIOHostDMAWindow) hostwin_next;
+} VFIOHostDMAWindow;
typedef struct VFIOSpaprContainer {
VFIOContainer container;
MemoryListener prereg_listener;
QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list;
+ unsigned int levels;
} VFIOSpaprContainer;
OBJECT_DECLARE_SIMPLE_TYPE(VFIOSpaprContainer, VFIO_IOMMU_SPAPR);
@@ -232,15 +239,17 @@ static int vfio_spapr_remove_window(VFIOContainer *container,
return 0;
}
-static int vfio_spapr_create_window(VFIOContainer *container,
+static bool vfio_spapr_create_window(VFIOContainer *container,
MemoryRegionSection *section,
- hwaddr *pgsize)
+ hwaddr *pgsize, Error **errp)
{
int ret = 0;
VFIOContainerBase *bcontainer = &container->bcontainer;
+ VFIOSpaprContainer *scontainer = container_of(container, VFIOSpaprContainer,
+ container);
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr), pgmask;
- unsigned entries, bits_total, bits_per_level, max_levels;
+ unsigned entries, bits_total, bits_per_level, max_levels, ddw_levels;
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
long rampagesize = qemu_minrampagesize();
@@ -254,11 +263,11 @@ static int vfio_spapr_create_window(VFIOContainer *container,
pgmask = bcontainer->pgsizes & (pagesize | (pagesize - 1));
pagesize = pgmask ? (1ULL << (63 - clz64(pgmask))) : 0;
if (!pagesize) {
- error_report("Host doesn't support page size 0x%"PRIx64
- ", the supported mask is 0x%lx",
- memory_region_iommu_get_min_page_size(iommu_mr),
- bcontainer->pgsizes);
- return -EINVAL;
+ error_setg_errno(errp, EINVAL, "Host doesn't support page size 0x%"PRIx64
+ ", the supported mask is 0x%lx",
+ memory_region_iommu_get_min_page_size(iommu_mr),
+ bcontainer->pgsizes);
+ return false;
}
/*
@@ -293,28 +302,41 @@ static int vfio_spapr_create_window(VFIOContainer *container,
*/
bits_per_level = ctz64(qemu_real_host_page_size()) + 8;
create.levels = bits_total / bits_per_level;
- if (bits_total % bits_per_level) {
- ++create.levels;
- }
- max_levels = (64 - create.page_shift) / ctz64(qemu_real_host_page_size());
- for ( ; create.levels <= max_levels; ++create.levels) {
- ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
- if (!ret) {
- break;
+
+ ddw_levels = scontainer->levels;
+ if (ddw_levels > 1) {
+ if (bits_total % bits_per_level) {
+ ++create.levels;
+ }
+ max_levels = (64 - create.page_shift) / ctz64(qemu_real_host_page_size());
+ for ( ; create.levels <= max_levels; ++create.levels) {
+ ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
+ if (!ret) {
+ break;
+ }
}
+ } else { /* ddw_levels == 1 */
+ if (create.levels > ddw_levels) {
+ error_setg_errno(errp, EINVAL, "Host doesn't support multi-level TCE tables"
+ ". Use larger IO page size. Supported mask is 0x%lx",
+ bcontainer->pgsizes);
+ return false;
+ }
+ ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
}
+
if (ret) {
- error_report("Failed to create a window, ret = %d (%m)", ret);
- return -errno;
+ error_setg_errno(errp, errno, "Failed to create a window, ret = %d", ret);
+ return false;
}
if (create.start_addr != section->offset_within_address_space) {
vfio_spapr_remove_window(container, create.start_addr);
- error_report("Host doesn't support DMA window at %"HWADDR_PRIx", must be %"PRIx64,
- section->offset_within_address_space,
- (uint64_t)create.start_addr);
- return -EINVAL;
+ error_setg_errno(errp, EINVAL, "Host doesn't support DMA window at %"HWADDR_PRIx
+ ", must be %"PRIx64, section->offset_within_address_space,
+ (uint64_t)create.start_addr);
+ return false;
}
trace_vfio_spapr_create_window(create.page_shift,
create.levels,
@@ -322,7 +344,7 @@ static int vfio_spapr_create_window(VFIOContainer *container,
create.start_addr);
*pgsize = pagesize;
- return 0;
+ return true;
}
static bool
@@ -379,9 +401,8 @@ vfio_spapr_container_add_section_window(VFIOContainerBase *bcontainer,
}
}
- ret = vfio_spapr_create_window(container, section, &pgsize);
- if (ret) {
- error_setg_errno(errp, -ret, "Failed to create SPAPR window");
+ ret = vfio_spapr_create_window(container, section, &pgsize, errp);
+ if (!ret) {
return false;
}
@@ -504,6 +525,8 @@ static bool vfio_spapr_container_setup(VFIOContainerBase *bcontainer,
goto listener_unregister_exit;
}
+ scontainer->levels = info.ddw.levels;
+
if (v2) {
bcontainer->pgsizes = info.ddw.pgsizes;
/*
@@ -536,7 +559,7 @@ listener_unregister_exit:
return false;
}
-static void vfio_iommu_spapr_class_init(ObjectClass *klass, void *data)
+static void vfio_iommu_spapr_class_init(ObjectClass *klass, const void *data)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index 98bd4dc..e1728c4 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -1,8 +1,10 @@
# See docs/devel/tracing.rst for syntax documentation.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
# pci.c
vfio_intx_interrupt(const char *name, char line) " (%s) Pin %c"
-vfio_intx_eoi(const char *name) " (%s) EOI"
+vfio_pci_intx_eoi(const char *name) " (%s) EOI"
vfio_intx_enable_kvm(const char *name) " (%s) KVM INTx accel enabled"
vfio_intx_disable_kvm(const char *name) " (%s) KVM INTx accel disabled"
vfio_intx_update(const char *name, int new_irq, int target_irq) " (%s) IRQ moved %d -> %d"
@@ -27,7 +29,7 @@ vfio_vga_read(uint64_t addr, int size, uint64_t data) " (0x%"PRIx64", %d) = 0x%"
vfio_pci_read_config(const char *name, int addr, int len, int val) " (%s, @0x%x, len=0x%x) 0x%x"
vfio_pci_write_config(const char *name, int addr, int val, int len) " (%s, @0x%x, 0x%x, len=0x%x)"
vfio_msi_setup(const char *name, int pos) "%s PCI MSI CAP @0x%x"
-vfio_msix_early_setup(const char *name, int pos, int table_bar, int offset, int entries, bool noresize) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d, noresize %d"
+vfio_msix_early_setup(const char *name, int pos, int table_bar, uint64_t offset, int entries, bool noresize) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%"PRIx64", entries %d, noresize %d"
vfio_check_pcie_flr(const char *name) "%s Supports FLR via PCIe cap"
vfio_check_pm_reset(const char *name) "%s Supports PM reset"
vfio_check_af_flr(const char *name) "%s Supports FLR via AF cap"
@@ -35,10 +37,8 @@ vfio_pci_hot_reset(const char *name, const char *type) " (%s) %s"
vfio_pci_hot_reset_has_dep_devices(const char *name) "%s: hot reset dependent devices:"
vfio_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int group_id) "\t%04x:%02x:%02x.%x group %d"
vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: %s"
-vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device '%s' config: size: 0x%lx, offset: 0x%lx, flags: 0x%lx"
-vfio_populate_device_get_irq_info_failure(const char *errstr) "VFIO_DEVICE_GET_IRQ_INFO failure: %s"
-vfio_attach_device(const char *name, int group_id) " (%s) group %d"
-vfio_detach_device(const char *name, int group_id) " (%s) group %d"
+vfio_pci_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device '%s' config: size: 0x%lx, offset: 0x%lx, flags: 0x%lx"
+vfio_pci_populate_device_get_irq_info_failure(const char *errstr) "VFIO_DEVICE_GET_IRQ_INFO failure: %s"
vfio_mdev(const char *name, bool is_mdev) " (%s) is_mdev %d"
vfio_add_ext_cap_dropped(const char *name, uint16_t cap, uint16_t offset) "%s 0x%x@0x%x"
vfio_pci_reset(const char *name) " (%s)"
@@ -89,9 +89,7 @@ vfio_pci_igd_bdsm_enabled(const char *name, int size) "%s %dMB"
vfio_pci_igd_host_bridge_enabled(const char *name) "%s"
vfio_pci_igd_lpc_bridge_enabled(const char *name) "%s"
-# common.c
-vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)"
-vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64
+# listener.c
vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "iommu %s @ 0x%"PRIx64" - 0x%"PRIx64
vfio_listener_region_skip(const char *name, uint64_t start, uint64_t end) "SKIPPING %s 0x%"PRIx64" - 0x%"PRIx64
vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d"
@@ -103,10 +101,21 @@ vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t si
vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64
vfio_device_dirty_tracking_update(uint64_t start, uint64_t end, uint64_t min, uint64_t max) "section 0x%"PRIx64" - 0x%"PRIx64" -> update [0x%"PRIx64" - 0x%"PRIx64"]"
vfio_device_dirty_tracking_start(int nr_ranges, uint64_t min32, uint64_t max32, uint64_t min64, uint64_t max64, uint64_t minpci, uint64_t maxpci) "nr_ranges %d 32:[0x%"PRIx64" - 0x%"PRIx64"], 64:[0x%"PRIx64" - 0x%"PRIx64"], pci64:[0x%"PRIx64" - 0x%"PRIx64"]"
-vfio_disconnect_container(int fd) "close container->fd=%d"
-vfio_put_group(int fd) "close group->fd=%d"
-vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u"
-vfio_put_base_device(int fd) "close vdev->fd=%d"
+vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64
+
+# container-base.c
+vfio_container_query_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64
+
+# container.c
+vfio_container_disconnect(int fd) "close container->fd=%d"
+vfio_group_put(int fd) "close group->fd=%d"
+vfio_device_get(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u"
+vfio_device_put(int fd) "close vdev->fd=%d"
+vfio_legacy_dma_unmap_overflow_workaround(void) ""
+
+# region.c
+vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)"
+vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64
vfio_region_setup(const char *dev, int index, const char *name, unsigned long flags, unsigned long offset, unsigned long size) "Device %s, region %d \"%s\", flags: 0x%lx, offset: 0x%lx, size: 0x%lx"
vfio_region_mmap_fault(const char *name, int index, unsigned long offset, unsigned long size, int fault) "Region %s mmaps[%d], [0x%lx - 0x%lx], fault: %d"
vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Region %s [0x%lx - 0x%lx]"
@@ -116,10 +125,6 @@ vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps e
vfio_region_unmap(const char *name, unsigned long offset, unsigned long end) "Region %s unmap [0x%lx - 0x%lx]"
vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries"
vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]"
-vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x"
-vfio_legacy_dma_unmap_overflow_workaround(void) ""
-vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64
-vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64
# platform.c
vfio_platform_realize(char *name, char *compat) "vfio device %s, compat = %s"
@@ -148,22 +153,36 @@ vfio_display_edid_update(uint32_t prefx, uint32_t prefy) "%ux%u"
vfio_display_edid_write_error(void) ""
# migration.c
+vfio_load_bufs_thread_start(const char *name) " (%s)"
+vfio_load_bufs_thread_end(const char *name) " (%s)"
vfio_load_cleanup(const char *name) " (%s)"
-vfio_load_device_config_state(const char *name) " (%s)"
+vfio_load_device_config_state_start(const char *name) " (%s)"
+vfio_load_device_config_state_end(const char *name) " (%s)"
vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64
-vfio_load_state_device_data(const char *name, uint64_t data_size, int ret) " (%s) size 0x%"PRIx64" ret %d"
+vfio_load_state_device_data(const char *name, uint64_t data_size, int ret) " (%s) size %"PRIu64" ret %d"
+vfio_load_state_device_buffer_incoming(const char *name, uint32_t idx) " (%s) idx %"PRIu32
+vfio_load_state_device_buffer_start(const char *name) " (%s)"
+vfio_load_state_device_buffer_starved(const char *name, uint32_t idx) " (%s) idx %"PRIu32
+vfio_load_state_device_buffer_load_start(const char *name, uint32_t idx) " (%s) idx %"PRIu32
+vfio_load_state_device_buffer_load_end(const char *name, uint32_t idx) " (%s) idx %"PRIu32
+vfio_load_state_device_buffer_end(const char *name) " (%s)"
vfio_migration_realize(const char *name) " (%s)"
vfio_migration_set_device_state(const char *name, const char *state) " (%s) state %s"
vfio_migration_set_state(const char *name, const char *new_state, const char *recover_state) " (%s) new state %s, recover state %s"
vfio_migration_state_notifier(const char *name, int state) " (%s) state %d"
vfio_save_block(const char *name, int data_size) " (%s) data_size %d"
+vfio_save_block_precopy_empty_hit(const char *name) " (%s)"
vfio_save_cleanup(const char *name) " (%s)"
vfio_save_complete_precopy(const char *name, int ret) " (%s) ret %d"
+vfio_save_complete_precopy_start(const char *name) " (%s)"
+vfio_save_complete_precopy_thread_start(const char *name, const char *idstr, uint32_t instance_id) " (%s) idstr %s instance %"PRIu32
+vfio_save_complete_precopy_thread_end(const char *name, int ret) " (%s) ret %d"
vfio_save_device_config_state(const char *name) " (%s)"
-vfio_save_iterate(const char *name, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy initial size 0x%"PRIx64" precopy dirty size 0x%"PRIx64
-vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size 0x%"PRIx64
-vfio_state_pending_estimate(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" precopy initial size 0x%"PRIx64" precopy dirty size 0x%"PRIx64
-vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" stopcopy size 0x%"PRIx64" precopy initial size 0x%"PRIx64" precopy dirty size 0x%"PRIx64
+vfio_save_iterate(const char *name, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy initial size %"PRIu64" precopy dirty size %"PRIu64
+vfio_save_iterate_start(const char *name) " (%s)"
+vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size %"PRIu64
+vfio_state_pending_estimate(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64
+vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" stopcopy size %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64
vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
vfio_vmstate_change_prepare(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
@@ -177,3 +196,9 @@ iommufd_cdev_fail_attach_existing_container(const char *msg) " %s"
iommufd_cdev_alloc_ioas(int iommufd, int ioas_id) " [iommufd=%d] new IOMMUFD container with ioasid=%d"
iommufd_cdev_device_info(char *name, int devfd, int num_irqs, int num_regions, int flags) " %s (%d) num_irqs=%d num_regions=%d flags=%d"
iommufd_cdev_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int dev_id) "\t%04x:%02x:%02x.%x devid %d"
+
+# device.c
+vfio_device_get_region_info_type(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x"
+vfio_device_reset_handler(void) ""
+vfio_device_attach(const char *name, int group_id) " (%s) group %d"
+vfio_device_detach(const char *name, int group_id) " (%s) group %d"
diff --git a/hw/vfio/trace.h b/hw/vfio/trace.h
index 5a343aa..b34b61d 100644
--- a/hw/vfio/trace.h
+++ b/hw/vfio/trace.h
@@ -1 +1,4 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "trace/trace-hw_vfio.h"
diff --git a/hw/vfio/vfio-display.h b/hw/vfio/vfio-display.h
new file mode 100644
index 0000000..2606c34
--- /dev/null
+++ b/hw/vfio/vfio-display.h
@@ -0,0 +1,42 @@
+/*
+ * VFIO display
+ *
+ * Copyright Red Hat, Inc. 2025
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VFIO_VFIO_DISPLAY_H
+#define HW_VFIO_VFIO_DISPLAY_H
+
+#include "ui/console.h"
+#include "hw/display/ramfb.h"
+#include "hw/vfio/vfio-region.h"
+
+typedef struct VFIODMABuf {
+ QemuDmaBuf *buf;
+ uint32_t pos_x, pos_y, pos_updates;
+ uint32_t hot_x, hot_y, hot_updates;
+ int dmabuf_id;
+ QTAILQ_ENTRY(VFIODMABuf) next;
+} VFIODMABuf;
+
+typedef struct VFIODisplay {
+ QemuConsole *con;
+ RAMFBState *ramfb;
+ struct vfio_region_info *edid_info;
+ struct vfio_region_gfx_edid *edid_regs;
+ uint8_t *edid_blob;
+ QEMUTimer *edid_link_timer;
+ struct {
+ VFIORegion buffer;
+ DisplaySurface *surface;
+ } region;
+ struct {
+ QTAILQ_HEAD(, VFIODMABuf) bufs;
+ VFIODMABuf *primary;
+ VFIODMABuf *cursor;
+ } dmabuf;
+} VFIODisplay;
+
+#endif /* HW_VFIO_VFIO_DISPLAY_H */
diff --git a/hw/vfio/vfio-helpers.h b/hw/vfio/vfio-helpers.h
new file mode 100644
index 0000000..54a327f
--- /dev/null
+++ b/hw/vfio/vfio-helpers.h
@@ -0,0 +1,35 @@
+/*
+ * VFIO helpers
+ *
+ * Copyright Red Hat, Inc. 2025
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VFIO_VFIO_HELPERS_H
+#define HW_VFIO_VFIO_HELPERS_H
+
+#ifdef CONFIG_LINUX
+#include <linux/vfio.h>
+
+extern int vfio_kvm_device_fd;
+
+struct vfio_info_cap_header *
+vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id);
+struct vfio_info_cap_header *
+vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id);
+struct vfio_info_cap_header *
+vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id);
+struct vfio_info_cap_header *
+vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id);
+bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
+ unsigned int *avail);
+#endif
+
+int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size);
+struct vfio_device_info *vfio_get_device_info(int fd);
+
+int vfio_kvm_device_add_fd(int fd, Error **errp);
+int vfio_kvm_device_del_fd(int fd, Error **errp);
+
+#endif /* HW_VFIO_VFIO_HELPERS_H */
diff --git a/hw/vfio/vfio-iommufd.h b/hw/vfio/vfio-iommufd.h
new file mode 100644
index 0000000..07ea0f4
--- /dev/null
+++ b/hw/vfio/vfio-iommufd.h
@@ -0,0 +1,34 @@
+/*
+ * VFIO iommufd
+ *
+ * Copyright Red Hat, Inc. 2025
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VFIO_VFIO_IOMMUFD_H
+#define HW_VFIO_VFIO_IOMMUFD_H
+
+#include "hw/vfio/vfio-container-base.h"
+
+typedef struct VFIODevice VFIODevice;
+
+typedef struct VFIOIOASHwpt {
+ uint32_t hwpt_id;
+ uint32_t hwpt_flags;
+ QLIST_HEAD(, VFIODevice) device_list;
+ QLIST_ENTRY(VFIOIOASHwpt) next;
+} VFIOIOASHwpt;
+
+typedef struct IOMMUFDBackend IOMMUFDBackend;
+
+typedef struct VFIOIOMMUFDContainer {
+ VFIOContainerBase bcontainer;
+ IOMMUFDBackend *be;
+ uint32_t ioas_id;
+ QLIST_HEAD(, VFIOIOASHwpt) hwpt_list;
+} VFIOIOMMUFDContainer;
+
+OBJECT_DECLARE_SIMPLE_TYPE(VFIOIOMMUFDContainer, VFIO_IOMMU_IOMMUFD);
+
+#endif /* HW_VFIO_VFIO_IOMMUFD_H */
diff --git a/hw/vfio/vfio-listener.h b/hw/vfio/vfio-listener.h
new file mode 100644
index 0000000..eb69ddd
--- /dev/null
+++ b/hw/vfio/vfio-listener.h
@@ -0,0 +1,15 @@
+/*
+ * VFIO MemoryListener services
+ *
+ * Copyright Red Hat, Inc. 2025
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VFIO_VFIO_LISTENER_H
+#define HW_VFIO_VFIO_LISTENER_H
+
+bool vfio_listener_register(VFIOContainerBase *bcontainer, Error **errp);
+void vfio_listener_unregister(VFIOContainerBase *bcontainer);
+
+#endif /* HW_VFIO_VFIO_LISTENER_H */
diff --git a/hw/vfio/vfio-migration-internal.h b/hw/vfio/vfio-migration-internal.h
new file mode 100644
index 0000000..a8b456b
--- /dev/null
+++ b/hw/vfio/vfio-migration-internal.h
@@ -0,0 +1,74 @@
+/*
+ * VFIO migration
+ *
+ * Copyright Red Hat, Inc. 2025
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_VFIO_VFIO_MIGRATION_INTERNAL_H
+#define HW_VFIO_VFIO_MIGRATION_INTERNAL_H
+
+#ifdef CONFIG_LINUX
+#include <linux/vfio.h>
+#endif
+
+#include "qemu/typedefs.h"
+#include "qemu/notify.h"
+
+/*
+ * Flags to be used as unique delimiters for VFIO devices in the migration
+ * stream. These flags are composed as:
+ * 0xffffffff => MSB 32-bit all 1s
+ * 0xef10 => Magic ID, represents emulated (virtual) function IO
+ * 0x0000 => 16-bits reserved for flags
+ *
+ * The beginning of state information is marked by _DEV_CONFIG_STATE,
+ * _DEV_SETUP_STATE, or _DEV_DATA_STATE, respectively. The end of a
+ * certain state information is marked by _END_OF_STATE.
+ */
+#define VFIO_MIG_FLAG_END_OF_STATE (0xffffffffef100001ULL)
+#define VFIO_MIG_FLAG_DEV_CONFIG_STATE (0xffffffffef100002ULL)
+#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL)
+#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL)
+#define VFIO_MIG_FLAG_DEV_INIT_DATA_SENT (0xffffffffef100005ULL)
+
+typedef struct VFIODevice VFIODevice;
+typedef struct VFIOMultifd VFIOMultifd;
+
+typedef struct VFIOMigration {
+ struct VFIODevice *vbasedev;
+ VMChangeStateEntry *vm_state;
+ NotifierWithReturn migration_state;
+ uint32_t device_state;
+ int data_fd;
+ void *data_buffer;
+ size_t data_buffer_size;
+ uint64_t mig_flags;
+ uint64_t precopy_init_size;
+ uint64_t precopy_dirty_size;
+ bool multifd_transfer;
+ VFIOMultifd *multifd;
+ bool initial_data_sent;
+
+ bool event_save_iterate_started;
+ bool event_precopy_empty_hit;
+} VFIOMigration;
+
+bool vfio_migration_realize(VFIODevice *vbasedev, Error **errp);
+void vfio_migration_exit(VFIODevice *vbasedev);
+bool vfio_device_state_is_running(VFIODevice *vbasedev);
+bool vfio_device_state_is_precopy(VFIODevice *vbasedev);
+int vfio_save_device_config_state(QEMUFile *f, void *opaque, Error **errp);
+int vfio_load_device_config_state(QEMUFile *f, void *opaque);
+
+#ifdef CONFIG_LINUX
+int vfio_migration_set_state(VFIODevice *vbasedev,
+ enum vfio_device_mig_state new_state,
+ enum vfio_device_mig_state recover_state,
+ Error **errp);
+#endif
+
+void vfio_migration_add_bytes_transferred(unsigned long val);
+
+#endif /* HW_VFIO_VFIO_MIGRATION_INTERNAL_H */
diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
index aa63ff7..7648a2d 100644
--- a/hw/virtio/Kconfig
+++ b/hw/virtio/Kconfig
@@ -6,6 +6,10 @@ config VIRTIO_RNG
default y
depends on VIRTIO
+config VIRTIO_NSM
+ bool
+ depends on LIBCBOR && VIRTIO
+
config VIRTIO_IOMMU
bool
default y
@@ -16,6 +20,7 @@ config VIRTIO_PCI
default y if PCI_DEVICES
depends on PCI
select VIRTIO
+ select VIRTIO_MD_SUPPORTED
config VIRTIO_MMIO
bool
@@ -24,6 +29,7 @@ config VIRTIO_MMIO
config VIRTIO_CCW
bool
select VIRTIO
+ select VIRTIO_MD_SUPPORTED
config VIRTIO_BALLOON
bool
@@ -35,10 +41,17 @@ config VIRTIO_CRYPTO
default y
depends on VIRTIO
+# not all virtio transports support memory devices; if none does,
+# no need to include the code
+config VIRTIO_MD_SUPPORTED
+ bool
+
config VIRTIO_MD
bool
+ depends on VIRTIO_MD_SUPPORTED
select MEM_DEVICE
+# selected by the board if it has the required support code
config VIRTIO_PMEM_SUPPORTED
bool
@@ -46,9 +59,11 @@ config VIRTIO_PMEM
bool
default y
depends on VIRTIO
+ depends on VIRTIO_MD_SUPPORTED
depends on VIRTIO_PMEM_SUPPORTED
select VIRTIO_MD
+# selected by the board if it has the required support code
config VIRTIO_MEM_SUPPORTED
bool
@@ -57,6 +72,7 @@ config VIRTIO_MEM
default y
depends on VIRTIO
depends on LINUX
+ depends on VIRTIO_MD_SUPPORTED
depends on VIRTIO_MEM_SUPPORTED
select VIRTIO_MD
@@ -109,4 +125,4 @@ config VHOST_USER_SND
config VHOST_USER_SCMI
bool
default y
- depends on VIRTIO && VHOST_USER
+ depends on VIRTIO && VHOST_USER && ARM
diff --git a/hw/virtio/cbor-helpers.c b/hw/virtio/cbor-helpers.c
new file mode 100644
index 0000000..49f55df
--- /dev/null
+++ b/hw/virtio/cbor-helpers.c
@@ -0,0 +1,321 @@
+/*
+ * QEMU CBOR helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "hw/virtio/cbor-helpers.h"
+
+bool qemu_cbor_map_add(cbor_item_t *map, cbor_item_t *key, cbor_item_t *value)
+{
+ bool success = false;
+ struct cbor_pair pair = (struct cbor_pair) {
+ .key = cbor_move(key),
+ .value = cbor_move(value)
+ };
+
+ success = cbor_map_add(map, pair);
+ if (!success) {
+ cbor_incref(pair.key);
+ cbor_incref(pair.value);
+ }
+
+ return success;
+}
+
+bool qemu_cbor_array_push(cbor_item_t *array, cbor_item_t *value)
+{
+ bool success = false;
+
+ success = cbor_array_push(array, cbor_move(value));
+ if (!success) {
+ cbor_incref(value);
+ }
+
+ return success;
+}
+
+bool qemu_cbor_add_bool_to_map(cbor_item_t *map, const char *key, bool value)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_build_bool(value);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_uint8_to_map(cbor_item_t *map, const char *key,
+ uint8_t value)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_build_uint8(value);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_map_to_map(cbor_item_t *map, const char *key,
+ size_t nested_map_size,
+ cbor_item_t **nested_map)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_new_definite_map(nested_map_size);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+ *nested_map = value_cbor;
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_bytestring_to_map(cbor_item_t *map, const char *key,
+ uint8_t *arr, size_t len)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_build_bytestring(arr, len);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_null_to_map(cbor_item_t *map, const char *key)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_new_null();
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_string_to_map(cbor_item_t *map, const char *key,
+ const char *value)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_build_string(value);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_uint8_array_to_map(cbor_item_t *map, const char *key,
+ uint8_t *arr, size_t len)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_new_definite_array(len);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+
+ for (int i = 0; i < len; ++i) {
+ cbor_item_t *tmp = cbor_build_uint8(arr[i]);
+ if (!tmp) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_array_push(value_cbor, tmp)) {
+ cbor_decref(&tmp);
+ goto cleanup;
+ }
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_uint8_key_bytestring_to_map(cbor_item_t *map, uint8_t key,
+ uint8_t *buf, size_t len)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_uint8(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_build_bytestring(buf, len);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+bool qemu_cbor_add_uint64_to_map(cbor_item_t *map, const char *key,
+ uint64_t value)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+
+ key_cbor = cbor_build_string(key);
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_build_uint64(value);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
diff --git a/hw/virtio/iothread-vq-mapping.c b/hw/virtio/iothread-vq-mapping.c
new file mode 100644
index 0000000..15909eb
--- /dev/null
+++ b/hw/virtio/iothread-vq-mapping.c
@@ -0,0 +1,131 @@
+/*
+ * IOThread Virtqueue Mapping
+ *
+ * Copyright Red Hat, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include "qemu/osdep.h"
+#include "system/iothread.h"
+#include "hw/virtio/iothread-vq-mapping.h"
+
+static bool
+iothread_vq_mapping_validate(IOThreadVirtQueueMappingList *list, uint16_t
+ num_queues, Error **errp)
+{
+ g_autofree unsigned long *vqs = bitmap_new(num_queues);
+ g_autoptr(GHashTable) iothreads =
+ g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (IOThreadVirtQueueMappingList *node = list; node; node = node->next) {
+ const char *name = node->value->iothread;
+ uint16List *vq;
+
+ if (!iothread_by_id(name)) {
+ error_setg(errp, "IOThread \"%s\" object does not exist", name);
+ return false;
+ }
+
+ if (!g_hash_table_add(iothreads, (gpointer)name)) {
+ error_setg(errp,
+ "duplicate IOThread name \"%s\" in iothread-vq-mapping",
+ name);
+ return false;
+ }
+
+ if (node != list) {
+ if (!!node->value->vqs != !!list->value->vqs) {
+ error_setg(errp, "either all items in iothread-vq-mapping "
+ "must have vqs or none of them must have it");
+ return false;
+ }
+ }
+
+ for (vq = node->value->vqs; vq; vq = vq->next) {
+ if (vq->value >= num_queues) {
+ error_setg(errp, "vq index %u for IOThread \"%s\" must be "
+ "less than num_queues %u in iothread-vq-mapping",
+ vq->value, name, num_queues);
+ return false;
+ }
+
+ if (test_and_set_bit(vq->value, vqs)) {
+ error_setg(errp, "cannot assign vq %u to IOThread \"%s\" "
+ "because it is already assigned", vq->value, name);
+ return false;
+ }
+ }
+ }
+
+ if (list->value->vqs) {
+ for (uint16_t i = 0; i < num_queues; i++) {
+ if (!test_bit(i, vqs)) {
+ error_setg(errp,
+ "missing vq %u IOThread assignment in iothread-vq-mapping",
+ i);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool iothread_vq_mapping_apply(
+ IOThreadVirtQueueMappingList *list,
+ AioContext **vq_aio_context,
+ uint16_t num_queues,
+ Error **errp)
+{
+ IOThreadVirtQueueMappingList *node;
+ size_t num_iothreads = 0;
+ size_t cur_iothread = 0;
+
+ if (!iothread_vq_mapping_validate(list, num_queues, errp)) {
+ return false;
+ }
+
+ for (node = list; node; node = node->next) {
+ num_iothreads++;
+ }
+
+ for (node = list; node; node = node->next) {
+ IOThread *iothread = iothread_by_id(node->value->iothread);
+ AioContext *ctx = iothread_get_aio_context(iothread);
+
+ /* Released in virtio_blk_vq_aio_context_cleanup() */
+ object_ref(OBJECT(iothread));
+
+ if (node->value->vqs) {
+ uint16List *vq;
+
+ /* Explicit vq:IOThread assignment */
+ for (vq = node->value->vqs; vq; vq = vq->next) {
+ assert(vq->value < num_queues);
+ vq_aio_context[vq->value] = ctx;
+ }
+ } else {
+ /* Round-robin vq:IOThread assignment */
+ for (unsigned i = cur_iothread; i < num_queues;
+ i += num_iothreads) {
+ vq_aio_context[i] = ctx;
+ }
+ }
+
+ cur_iothread++;
+ }
+
+ return true;
+}
+
+void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list)
+{
+ IOThreadVirtQueueMappingList *node;
+
+ for (node = list; node; node = node->next) {
+ IOThread *iothread = iothread_by_id(node->value->iothread);
+ object_unref(OBJECT(iothread));
+ }
+}
+
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 621fc65..164f6fd 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -1,5 +1,6 @@
system_virtio_ss = ss.source_set()
system_virtio_ss.add(files('virtio-bus.c'))
+system_virtio_ss.add(files('iothread-vq-mapping.c'))
system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c'))
system_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c'))
system_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c'))
@@ -54,6 +55,7 @@ specific_virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c
specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c'))
specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c'))
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c'))
+specific_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('virtio-nsm.c', 'cbor-helpers.c'), libcbor])
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c'))
specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c'))
specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SCMI'], if_true: files('vhost-user-scmi-pci.c'))
@@ -70,6 +72,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto-pc
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng-pci.c'))
+virtio_pci_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('virtio-nsm-pci.c', 'cbor-helpers.c'), libcbor])
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-9p-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: files('virtio-scsi-pci.c'))
@@ -87,7 +90,8 @@ specific_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss)
system_ss.add_all(when: 'CONFIG_VIRTIO', if_true: system_virtio_ss)
system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c'))
system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c'))
-system_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-md-stubs.c'))
+system_ss.add(when: ['CONFIG_VIRTIO_MD', 'CONFIG_VIRTIO_PCI'],
+ if_false: files('virtio-md-stubs.c'))
system_ss.add(files('virtio-hmp-cmds.c'))
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 04e36ae..76f0d45 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -108,7 +108,7 @@ virtio_pci_notify_write(uint64_t addr, uint64_t val, unsigned int size) "0x%" PR
virtio_pci_notify_write_pio(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)"
# hw/virtio/virtio-iommu.c
-virtio_iommu_device_reset(void) "reset!"
+virtio_iommu_device_reset_exit(void) "reset!"
virtio_iommu_system_reset(void) "system reset!"
virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
virtio_iommu_device_status(uint8_t status) "driver status = %d"
diff --git a/hw/virtio/vdpa-dev-pci.c b/hw/virtio/vdpa-dev-pci.c
index 5446e6b..3068112 100644
--- a/hw/virtio/vdpa-dev-pci.c
+++ b/hw/virtio/vdpa-dev-pci.c
@@ -48,10 +48,6 @@ static void vhost_vdpa_device_pci_instance_init(Object *obj)
"bootindex");
}
-static Property vhost_vdpa_device_pci_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
static int vhost_vdpa_device_pci_post_init(VhostVdpaDevice *v, Error **errp)
{
VhostVdpaDevicePCI *dev = container_of(v, VhostVdpaDevicePCI, vdev);
@@ -74,13 +70,13 @@ vhost_vdpa_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(DEVICE(&dev->vdev), BUS(&vpci_dev->bus), errp);
}
-static void vhost_vdpa_device_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_vdpa_device_pci_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- device_class_set_props(dc, vhost_vdpa_device_pci_properties);
k->realize = vhost_vdpa_device_pci_realize;
}
diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c
index 64b96b226c..d1da40a 100644
--- a/hw/virtio/vdpa-dev.c
+++ b/hw/virtio/vdpa-dev.c
@@ -26,8 +26,8 @@
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/vdpa-dev.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/runstate.h"
static void
vhost_vdpa_device_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
@@ -312,7 +312,7 @@ static void vhost_vdpa_device_stop(VirtIODevice *vdev)
vhost_dev_disable_notifiers(&s->dev, vdev);
}
-static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status)
+static int vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status)
{
VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
bool should_start = virtio_device_started(vdev, status);
@@ -324,7 +324,7 @@ static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status)
}
if (s->started == should_start) {
- return;
+ return 0;
}
if (should_start) {
@@ -335,12 +335,12 @@ static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status)
} else {
vhost_vdpa_device_stop(vdev);
}
+ return 0;
}
-static Property vhost_vdpa_device_properties[] = {
+static const Property vhost_vdpa_device_properties[] = {
DEFINE_PROP_STRING("vhostdev", VhostVdpaDevice, vhostdev),
DEFINE_PROP_UINT16("queue-size", VhostVdpaDevice, queue_size, 0),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_vhost_vdpa_device = {
@@ -354,7 +354,7 @@ static const VMStateDescription vmstate_vhost_vdpa_device = {
},
};
-static void vhost_vdpa_device_class_init(ObjectClass *klass, void *data)
+static void vhost_vdpa_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c
index 3d03395..fa4147b 100644
--- a/hw/virtio/vhost-iova-tree.c
+++ b/hw/virtio/vhost-iova-tree.c
@@ -28,12 +28,18 @@ struct VhostIOVATree {
/* IOVA address to qemu memory maps. */
IOVATree *iova_taddr_map;
+
+ /* Allocated IOVA addresses */
+ IOVATree *iova_map;
+
+ /* GPA->IOVA address memory maps */
+ IOVATree *gpa_iova_map;
};
/**
- * Create a new IOVA tree
+ * Create a new VhostIOVATree
*
- * Returns the new IOVA tree
+ * Returns the new VhostIOVATree.
*/
VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last)
{
@@ -44,25 +50,29 @@ VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last)
tree->iova_last = iova_last;
tree->iova_taddr_map = iova_tree_new();
+ tree->iova_map = iova_tree_new();
+ tree->gpa_iova_map = gpa_tree_new();
return tree;
}
/**
- * Delete an iova tree
+ * Delete a VhostIOVATree
*/
void vhost_iova_tree_delete(VhostIOVATree *iova_tree)
{
iova_tree_destroy(iova_tree->iova_taddr_map);
+ iova_tree_destroy(iova_tree->iova_map);
+ iova_tree_destroy(iova_tree->gpa_iova_map);
g_free(iova_tree);
}
/**
* Find the IOVA address stored from a memory address
*
- * @tree: The iova tree
+ * @tree: The VhostIOVATree
* @map: The map with the memory address
*
- * Return the stored mapping, or NULL if not found.
+ * Returns the stored IOVA->HVA mapping, or NULL if not found.
*/
const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree,
const DMAMap *map)
@@ -71,40 +81,111 @@ const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree,
}
/**
- * Allocate a new mapping
+ * Allocate a new IOVA range and add the mapping to the IOVA->HVA tree
*
- * @tree: The iova tree
- * @map: The iova map
+ * @tree: The VhostIOVATree
+ * @map: The IOVA mapping
+ * @taddr: The translated address (HVA)
*
* Returns:
* - IOVA_OK if the map fits in the container
* - IOVA_ERR_INVALID if the map does not make sense (like size overflow)
* - IOVA_ERR_NOMEM if tree cannot allocate more space.
*
- * It returns assignated iova in map->iova if return value is VHOST_DMA_MAP_OK.
+ * It returns an assigned IOVA in map->iova if the return value is IOVA_OK.
*/
-int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map)
+int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map, hwaddr taddr)
{
+ int ret;
+
/* Some vhost devices do not like addr 0. Skip first page */
hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size();
- if (map->translated_addr + map->size < map->translated_addr ||
- map->perm == IOMMU_NONE) {
+ if (taddr + map->size < taddr || map->perm == IOMMU_NONE) {
return IOVA_ERR_INVALID;
}
- /* Allocate a node in IOVA address */
- return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first,
- tree->iova_last);
+ /* Allocate a node in the IOVA-only tree */
+ ret = iova_tree_alloc_map(tree->iova_map, map, iova_first, tree->iova_last);
+ if (unlikely(ret != IOVA_OK)) {
+ return ret;
+ }
+
+ /* Insert a node in the IOVA->HVA tree */
+ map->translated_addr = taddr;
+ return iova_tree_insert(tree->iova_taddr_map, map);
}
/**
- * Remove existing mappings from iova tree
+ * Remove existing mappings from the IOVA-only and IOVA->HVA trees
*
- * @iova_tree: The vhost iova tree
+ * @iova_tree: The VhostIOVATree
* @map: The map to remove
*/
void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map)
{
iova_tree_remove(iova_tree->iova_taddr_map, map);
+ iova_tree_remove(iova_tree->iova_map, map);
+}
+
+/**
+ * Find the IOVA address stored from a guest memory address (GPA)
+ *
+ * @tree: The VhostIOVATree
+ * @map: The map with the guest memory address
+ *
+ * Returns the stored GPA->IOVA mapping, or NULL if not found.
+ */
+const DMAMap *vhost_iova_tree_find_gpa(const VhostIOVATree *tree,
+ const DMAMap *map)
+{
+ return iova_tree_find_iova(tree->gpa_iova_map, map);
+}
+
+/**
+ * Allocate a new IOVA range and add the mapping to the GPA->IOVA tree
+ *
+ * @tree: The VhostIOVATree
+ * @map: The IOVA mapping
+ * @taddr: The translated address (GPA)
+ *
+ * Returns:
+ * - IOVA_OK if the map fits both containers
+ * - IOVA_ERR_INVALID if the map does not make sense (like size overflow)
+ * - IOVA_ERR_NOMEM if the IOVA-only tree cannot allocate more space
+ *
+ * It returns an assigned IOVA in map->iova if the return value is IOVA_OK.
+ */
+int vhost_iova_tree_map_alloc_gpa(VhostIOVATree *tree, DMAMap *map, hwaddr taddr)
+{
+ int ret;
+
+ /* Some vhost devices don't like addr 0. Skip first page */
+ hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size();
+
+ if (taddr + map->size < taddr || map->perm == IOMMU_NONE) {
+ return IOVA_ERR_INVALID;
+ }
+
+ /* Allocate a node in the IOVA-only tree */
+ ret = iova_tree_alloc_map(tree->iova_map, map, iova_first, tree->iova_last);
+ if (unlikely(ret != IOVA_OK)) {
+ return ret;
+ }
+
+ /* Insert a node in the GPA->IOVA tree */
+ map->translated_addr = taddr;
+ return gpa_tree_insert(tree->gpa_iova_map, map);
+}
+
+/**
+ * Remove existing mappings from the IOVA-only and GPA->IOVA trees
+ *
+ * @tree: The VhostIOVATree
+ * @map: The map to remove
+ */
+void vhost_iova_tree_remove_gpa(VhostIOVATree *iova_tree, DMAMap map)
+{
+ iova_tree_remove(iova_tree->gpa_iova_map, map);
+ iova_tree_remove(iova_tree->iova_map, map);
}
diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h
index 4adfd79..08f63b6 100644
--- a/hw/virtio/vhost-iova-tree.h
+++ b/hw/virtio/vhost-iova-tree.h
@@ -11,7 +11,7 @@
#define HW_VIRTIO_VHOST_IOVA_TREE_H
#include "qemu/iova-tree.h"
-#include "exec/memory.h"
+#include "system/memory.h"
typedef struct VhostIOVATree VhostIOVATree;
@@ -21,7 +21,13 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete);
const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree,
const DMAMap *map);
-int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map);
+int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map,
+ hwaddr taddr);
void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map);
+const DMAMap *vhost_iova_tree_find_gpa(const VhostIOVATree *iova_tree,
+ const DMAMap *map);
+int vhost_iova_tree_map_alloc_gpa(VhostIOVATree *iova_tree, DMAMap *map,
+ hwaddr taddr);
+void vhost_iova_tree_remove_gpa(VhostIOVATree *iova_tree, DMAMap map);
#endif
diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c
index 08980bc..7399ace 100644
--- a/hw/virtio/vhost-scsi-pci.c
+++ b/hw/virtio/vhost-scsi-pci.c
@@ -38,10 +38,9 @@ struct VHostSCSIPCI {
VHostSCSI vdev;
};
-static Property vhost_scsi_pci_properties[] = {
+static const Property vhost_scsi_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -62,7 +61,7 @@ static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_scsi_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
index fc5f408..2481d49 100644
--- a/hw/virtio/vhost-shadow-virtqueue.c
+++ b/hw/virtio/vhost-shadow-virtqueue.c
@@ -78,24 +78,39 @@ uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
* @vaddr: Translated IOVA addresses
* @iovec: Source qemu's VA addresses
* @num: Length of iovec and minimum length of vaddr
+ * @gpas: Descriptors' GPAs, if backed by guest memory
*/
static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq,
hwaddr *addrs, const struct iovec *iovec,
- size_t num)
+ size_t num, const hwaddr *gpas)
{
if (num == 0) {
return true;
}
for (size_t i = 0; i < num; ++i) {
- DMAMap needle = {
- .translated_addr = (hwaddr)(uintptr_t)iovec[i].iov_base,
- .size = iovec[i].iov_len,
- };
Int128 needle_last, map_last;
size_t off;
+ const DMAMap *map;
+ DMAMap needle;
+
+ /* Check if the descriptor is backed by guest memory */
+ if (gpas) {
+ /* Search the GPA->IOVA tree */
+ needle = (DMAMap) {
+ .translated_addr = gpas[i],
+ .size = iovec[i].iov_len,
+ };
+ map = vhost_iova_tree_find_gpa(svq->iova_tree, &needle);
+ } else {
+ /* Search the IOVA->HVA tree */
+ needle = (DMAMap) {
+ .translated_addr = (hwaddr)(uintptr_t)iovec[i].iov_base,
+ .size = iovec[i].iov_len,
+ };
+ map = vhost_iova_tree_find_iova(svq->iova_tree, &needle);
+ }
- const DMAMap *map = vhost_iova_tree_find_iova(svq->iova_tree, &needle);
/*
* Map cannot be NULL since iova map contains all guest space and
* qemu already has a physical address mapped
@@ -130,6 +145,7 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq,
* @sg: Cache for hwaddr
* @iovec: The iovec from the guest
* @num: iovec length
+ * @addr: Descriptors' GPAs, if backed by guest memory
* @more_descs: True if more descriptors come in the chain
* @write: True if they are writeable descriptors
*
@@ -137,7 +153,8 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq,
*/
static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
const struct iovec *iovec, size_t num,
- bool more_descs, bool write)
+ const hwaddr *addr, bool more_descs,
+ bool write)
{
uint16_t i = svq->free_head, last = svq->free_head;
unsigned n;
@@ -149,7 +166,7 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
return true;
}
- ok = vhost_svq_translate_addr(svq, sg, iovec, num);
+ ok = vhost_svq_translate_addr(svq, sg, iovec, num, addr);
if (unlikely(!ok)) {
return false;
}
@@ -165,17 +182,18 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
descs[i].len = cpu_to_le32(iovec[n].iov_len);
last = i;
- i = cpu_to_le16(svq->desc_next[i]);
+ i = svq->desc_next[i];
}
- svq->free_head = le16_to_cpu(svq->desc_next[last]);
+ svq->free_head = svq->desc_next[last];
return true;
}
static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
const struct iovec *out_sg, size_t out_num,
+ const hwaddr *out_addr,
const struct iovec *in_sg, size_t in_num,
- unsigned *head)
+ const hwaddr *in_addr, unsigned *head)
{
unsigned avail_idx;
vring_avail_t *avail = svq->vring.avail;
@@ -191,13 +209,14 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
return false;
}
- ok = vhost_svq_vring_write_descs(svq, sgs, out_sg, out_num, in_num > 0,
- false);
+ ok = vhost_svq_vring_write_descs(svq, sgs, out_sg, out_num, out_addr,
+ in_num > 0, false);
if (unlikely(!ok)) {
return false;
}
- ok = vhost_svq_vring_write_descs(svq, sgs, in_sg, in_num, false, true);
+ ok = vhost_svq_vring_write_descs(svq, sgs, in_sg, in_num, in_addr, false,
+ true);
if (unlikely(!ok)) {
return false;
}
@@ -228,10 +247,12 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq)
smp_mb();
if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
- uint16_t avail_event = *(uint16_t *)(&svq->vring.used->ring[svq->vring.num]);
+ uint16_t avail_event = le16_to_cpu(
+ *(uint16_t *)(&svq->vring.used->ring[svq->vring.num]));
needs_kick = vring_need_event(avail_event, svq->shadow_avail_idx, svq->shadow_avail_idx - 1);
} else {
- needs_kick = !(svq->vring.used->flags & VRING_USED_F_NO_NOTIFY);
+ needs_kick =
+ !(svq->vring.used->flags & cpu_to_le16(VRING_USED_F_NO_NOTIFY));
}
if (!needs_kick) {
@@ -247,8 +268,9 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq)
* Return -EINVAL if element is invalid, -ENOSPC if dev queue is full
*/
int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
- size_t out_num, const struct iovec *in_sg, size_t in_num,
- VirtQueueElement *elem)
+ size_t out_num, const hwaddr *out_addr,
+ const struct iovec *in_sg, size_t in_num,
+ const hwaddr *in_addr, VirtQueueElement *elem)
{
unsigned qemu_head;
unsigned ndescs = in_num + out_num;
@@ -258,7 +280,8 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
return -ENOSPC;
}
- ok = vhost_svq_add_split(svq, out_sg, out_num, in_sg, in_num, &qemu_head);
+ ok = vhost_svq_add_split(svq, out_sg, out_num, out_addr, in_sg, in_num,
+ in_addr, &qemu_head);
if (unlikely(!ok)) {
return -EINVAL;
}
@@ -274,8 +297,8 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
static int vhost_svq_add_element(VhostShadowVirtqueue *svq,
VirtQueueElement *elem)
{
- return vhost_svq_add(svq, elem->out_sg, elem->out_num, elem->in_sg,
- elem->in_num, elem);
+ return vhost_svq_add(svq, elem->out_sg, elem->out_num, elem->out_addr,
+ elem->in_sg, elem->in_num, elem->in_addr, elem);
}
/**
@@ -365,7 +388,7 @@ static bool vhost_svq_more_used(VhostShadowVirtqueue *svq)
return true;
}
- svq->shadow_used_idx = cpu_to_le16(*(volatile uint16_t *)used_idx);
+ svq->shadow_used_idx = le16_to_cpu(*(volatile uint16_t *)used_idx);
return svq->last_used_idx != svq->shadow_used_idx;
}
@@ -383,7 +406,7 @@ static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq)
{
if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
uint16_t *used_event = (uint16_t *)&svq->vring.avail->ring[svq->vring.num];
- *used_event = svq->shadow_used_idx;
+ *used_event = cpu_to_le16(svq->shadow_used_idx);
} else {
svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
}
@@ -408,12 +431,13 @@ static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq,
uint16_t num, uint16_t i)
{
for (uint16_t j = 0; j < (num - 1); ++j) {
- i = le16_to_cpu(svq->desc_next[i]);
+ i = svq->desc_next[i];
}
return i;
}
+G_GNUC_WARN_UNUSED_RESULT
static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
uint32_t *len)
{
@@ -526,10 +550,11 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq,
size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num)
{
size_t len = 0;
- uint32_t r;
while (num--) {
+ g_autofree VirtQueueElement *elem = NULL;
int64_t start_us = g_get_monotonic_time();
+ uint32_t r = 0;
do {
if (vhost_svq_more_used(svq)) {
@@ -541,7 +566,7 @@ size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num)
}
} while (true);
- vhost_svq_get_buf(svq, &r);
+ elem = vhost_svq_get_buf(svq, &r);
len += r;
}
@@ -681,7 +706,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
svq->desc_state = g_new0(SVQDescState, svq->vring.num);
svq->desc_next = g_new0(uint16_t, svq->vring.num);
for (unsigned i = 0; i < svq->vring.num - 1; i++) {
- svq->desc_next[i] = cpu_to_le16(i + 1);
+ svq->desc_next[i] = i + 1;
}
}
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
index 19c842a..9c27373 100644
--- a/hw/virtio/vhost-shadow-virtqueue.h
+++ b/hw/virtio/vhost-shadow-virtqueue.h
@@ -118,8 +118,9 @@ uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq);
void vhost_svq_push_elem(VhostShadowVirtqueue *svq,
const VirtQueueElement *elem, uint32_t len);
int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
- size_t out_num, const struct iovec *in_sg, size_t in_num,
- VirtQueueElement *elem);
+ size_t out_num, const hwaddr *out_addr,
+ const struct iovec *in_sg, size_t in_num,
+ const hwaddr *in_addr, VirtQueueElement *elem);
size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num);
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
diff --git a/hw/virtio/vhost-user-base.c b/hw/virtio/vhost-user-base.c
index 2bc3423..ff67a02 100644
--- a/hw/virtio/vhost-user-base.c
+++ b/hw/virtio/vhost-user-base.c
@@ -66,7 +66,7 @@ err_host_notifiers:
vhost_dev_disable_notifiers(&vub->vhost_dev, vdev);
}
-static void vub_stop(VirtIODevice *vdev)
+static int vub_stop(VirtIODevice *vdev)
{
VHostUserBase *vub = VHOST_USER_BASE(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@@ -74,34 +74,39 @@ static void vub_stop(VirtIODevice *vdev)
int ret;
if (!k->set_guest_notifiers) {
- return;
+ return 0;
}
- vhost_dev_stop(&vub->vhost_dev, vdev, true);
+ ret = vhost_dev_stop(&vub->vhost_dev, vdev, true);
- ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false);
- if (ret < 0) {
+ if (k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false) < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
- return;
+ return -1;
}
vhost_dev_disable_notifiers(&vub->vhost_dev, vdev);
+ return ret;
}
-static void vub_set_status(VirtIODevice *vdev, uint8_t status)
+static int vub_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserBase *vub = VHOST_USER_BASE(vdev);
bool should_start = virtio_device_should_start(vdev, status);
if (vhost_dev_is_started(&vub->vhost_dev) == should_start) {
- return;
+ return 0;
}
if (should_start) {
vub_start(vdev);
} else {
- vub_stop(vdev);
+ int ret;
+ ret = vub_stop(vdev);
+ if (ret < 0) {
+ return ret;
+ }
}
+ return 0;
}
/*
@@ -348,7 +353,7 @@ static void vub_device_unrealize(DeviceState *dev)
do_vhost_user_cleanup(vdev, vub);
}
-static void vub_class_init(ObjectClass *klass, void *data)
+static void vub_class_init(ObjectClass *klass, const void *data)
{
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c
index eef8641..904369f 100644
--- a/hw/virtio/vhost-user-blk-pci.c
+++ b/hw/virtio/vhost-user-blk-pci.c
@@ -43,11 +43,10 @@ struct VHostUserBlkPCI {
VHostUserBlk vdev;
};
-static Property vhost_user_blk_pci_properties[] = {
+static const Property vhost_user_blk_pci_properties[] = {
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -66,7 +65,7 @@ static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_blk_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-device-pci.c b/hw/virtio/vhost-user-device-pci.c
index efaf55d..f10bac8 100644
--- a/hw/virtio/vhost-user-device-pci.c
+++ b/hw/virtio/vhost-user-device-pci.c
@@ -31,7 +31,8 @@ static void vhost_user_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_device_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_device_pci_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-device.c b/hw/virtio/vhost-user-device.c
index 67aa934..3939bdf 100644
--- a/hw/virtio/vhost-user-device.c
+++ b/hw/virtio/vhost-user-device.c
@@ -29,16 +29,15 @@ static const VMStateDescription vud_vmstate = {
.unmigratable = 1,
};
-static Property vud_properties[] = {
+static const Property vud_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
DEFINE_PROP_UINT16("virtio-id", VHostUserBase, virtio_id, 0),
DEFINE_PROP_UINT32("vq_size", VHostUserBase, vq_size, 64),
DEFINE_PROP_UINT32("num_vqs", VHostUserBase, num_vqs, 1),
DEFINE_PROP_UINT32("config_size", VHostUserBase, config_size, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vud_class_init(ObjectClass *klass, void *data)
+static void vud_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c
index 6829b8b..1490c11 100644
--- a/hw/virtio/vhost-user-fs-pci.c
+++ b/hw/virtio/vhost-user-fs-pci.c
@@ -29,10 +29,9 @@ typedef struct VHostUserFSPCI VHostUserFSPCI;
DECLARE_INSTANCE_CHECKER(VHostUserFSPCI, VHOST_USER_FS_PCI,
TYPE_VHOST_USER_FS_PCI)
-static Property vhost_user_fs_pci_properties[] = {
+static const Property vhost_user_fs_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_fs_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -48,7 +47,7 @@ static void vhost_user_fs_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_fs_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_fs_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
index 32ee7f4..e77c69e 100644
--- a/hw/virtio/vhost-user-fs.c
+++ b/hw/virtio/vhost-user-fs.c
@@ -23,7 +23,7 @@
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user-fs.h"
#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static const int user_feature_bits[] = {
VIRTIO_F_VERSION_1,
@@ -100,7 +100,7 @@ err_host_notifiers:
vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
}
-static void vuf_stop(VirtIODevice *vdev)
+static int vuf_stop(VirtIODevice *vdev)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@@ -108,34 +108,39 @@ static void vuf_stop(VirtIODevice *vdev)
int ret;
if (!k->set_guest_notifiers) {
- return;
+ return 0;
}
- vhost_dev_stop(&fs->vhost_dev, vdev, true);
+ ret = vhost_dev_stop(&fs->vhost_dev, vdev, true);
- ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false);
- if (ret < 0) {
+ if (k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false) < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
- return;
+ return -1;
}
vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
+ return ret;
}
-static void vuf_set_status(VirtIODevice *vdev, uint8_t status)
+static int vuf_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
bool should_start = virtio_device_should_start(vdev, status);
if (vhost_dev_is_started(&fs->vhost_dev) == should_start) {
- return;
+ return 0;
}
if (should_start) {
vuf_start(vdev);
} else {
- vuf_stop(vdev);
+ int ret;
+ ret = vuf_stop(vdev);
+ if (ret < 0) {
+ return ret;
+ }
}
+ return 0;
}
static uint64_t vuf_get_features(VirtIODevice *vdev,
@@ -267,7 +272,6 @@ err_virtio:
g_free(fs->req_vqs);
virtio_cleanup(vdev);
g_free(fs->vhost_dev.vqs);
- return;
}
static void vuf_device_unrealize(DeviceState *dev)
@@ -403,13 +407,12 @@ static const VMStateDescription vuf_backend_vmstate = {
},
};
-static Property vuf_properties[] = {
+static const Property vuf_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserFS, conf.chardev),
DEFINE_PROP_STRING("tag", VHostUserFS, conf.tag),
DEFINE_PROP_UINT16("num-request-queues", VHostUserFS,
conf.num_request_queues, 1),
DEFINE_PROP_UINT16("queue-size", VHostUserFS, conf.queue_size, 128),
- DEFINE_PROP_END_OF_LIST(),
};
static void vuf_instance_init(Object *obj)
@@ -420,7 +423,7 @@ static void vuf_instance_init(Object *obj)
"/filesystem@0", DEVICE(obj));
}
-static void vuf_class_init(ObjectClass *klass, void *data)
+static void vuf_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-gpio-pci.c b/hw/virtio/vhost-user-gpio-pci.c
index b3028a2..9b165b5 100644
--- a/hw/virtio/vhost-user-gpio-pci.c
+++ b/hw/virtio/vhost-user-gpio-pci.c
@@ -32,7 +32,7 @@ static void vhost_user_gpio_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_gpio_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_gpio_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-gpio.c b/hw/virtio/vhost-user-gpio.c
index 9f37c25..a7fd49b 100644
--- a/hw/virtio/vhost-user-gpio.c
+++ b/hw/virtio/vhost-user-gpio.c
@@ -14,9 +14,8 @@
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_gpio.h"
-static Property vgpio_properties[] = {
+static const Property vgpio_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
- DEFINE_PROP_END_OF_LIST(),
};
static void vgpio_realize(DeviceState *dev, Error **errp)
@@ -37,7 +36,7 @@ static const VMStateDescription vu_gpio_vmstate = {
.unmigratable = 1,
};
-static void vu_gpio_class_init(ObjectClass *klass, void *data)
+static void vu_gpio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-i2c-pci.c b/hw/virtio/vhost-user-i2c-pci.c
index 00ac109..692cd66 100644
--- a/hw/virtio/vhost-user-i2c-pci.c
+++ b/hw/virtio/vhost-user-i2c-pci.c
@@ -32,7 +32,7 @@ static void vhost_user_i2c_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_i2c_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_i2c_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
index a464f5e..ae007fe 100644
--- a/hw/virtio/vhost-user-i2c.c
+++ b/hw/virtio/vhost-user-i2c.c
@@ -14,9 +14,8 @@
#include "qemu/error-report.h"
#include "standard-headers/linux/virtio_ids.h"
-static Property vi2c_properties[] = {
+static const Property vi2c_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
- DEFINE_PROP_END_OF_LIST(),
};
static void vi2c_realize(DeviceState *dev, Error **errp)
@@ -37,7 +36,7 @@ static const VMStateDescription vu_i2c_vmstate = {
.unmigratable = 1,
};
-static void vu_i2c_class_init(ObjectClass *klass, void *data)
+static void vu_i2c_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-input.c b/hw/virtio/vhost-user-input.c
index bedec04..5cfc5bb 100644
--- a/hw/virtio/vhost-user-input.c
+++ b/hw/virtio/vhost-user-input.c
@@ -7,9 +7,8 @@
#include "qemu/osdep.h"
#include "hw/virtio/virtio-input.h"
-static Property vinput_properties[] = {
+static const Property vinput_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
- DEFINE_PROP_END_OF_LIST(),
};
static void vinput_realize(DeviceState *dev, Error **errp)
@@ -31,7 +30,7 @@ static const VMStateDescription vmstate_vhost_input = {
.unmigratable = 1,
};
-static void vhost_input_class_init(ObjectClass *klass, void *data)
+static void vhost_input_class_init(ObjectClass *klass, const void *data)
{
VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-rng-pci.c b/hw/virtio/vhost-user-rng-pci.c
index f649354..9f45fc6 100644
--- a/hw/virtio/vhost-user-rng-pci.c
+++ b/hw/virtio/vhost-user-rng-pci.c
@@ -23,10 +23,9 @@ typedef struct VHostUserRNGPCI VHostUserRNGPCI;
DECLARE_INSTANCE_CHECKER(VHostUserRNGPCI, VHOST_USER_RNG_PCI,
TYPE_VHOST_USER_RNG_PCI)
-static Property vhost_user_rng_pci_properties[] = {
+static const Property vhost_user_rng_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -41,7 +40,7 @@ static void vhost_user_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_rng_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_rng_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c
index 01879c8..61dadcd 100644
--- a/hw/virtio/vhost-user-rng.c
+++ b/hw/virtio/vhost-user-rng.c
@@ -20,9 +20,8 @@ static const VMStateDescription vu_rng_vmstate = {
.unmigratable = 1,
};
-static Property vrng_properties[] = {
+static const Property vrng_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
- DEFINE_PROP_END_OF_LIST(),
};
static void vu_rng_base_realize(DeviceState *dev, Error **errp)
@@ -38,7 +37,7 @@ static void vu_rng_base_realize(DeviceState *dev, Error **errp)
vubs->parent_realize(dev, errp);
}
-static void vu_rng_class_init(ObjectClass *klass, void *data)
+static void vu_rng_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-scmi-pci.c b/hw/virtio/vhost-user-scmi-pci.c
index 7f53af7..0ab56a5 100644
--- a/hw/virtio/vhost-user-scmi-pci.c
+++ b/hw/virtio/vhost-user-scmi-pci.c
@@ -31,7 +31,7 @@ static void vhost_user_scmi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_scmi_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_scmi_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-scmi.c b/hw/virtio/vhost-user-scmi.c
index 300847e..f9264c4 100644
--- a/hw/virtio/vhost-user-scmi.c
+++ b/hw/virtio/vhost-user-scmi.c
@@ -83,7 +83,7 @@ err_host_notifiers:
return ret;
}
-static void vu_scmi_stop(VirtIODevice *vdev)
+static int vu_scmi_stop(VirtIODevice *vdev)
{
VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@@ -93,41 +93,46 @@ static void vu_scmi_stop(VirtIODevice *vdev)
/* vhost_dev_is_started() check in the callers is not fully reliable. */
if (!scmi->started_vu) {
- return;
+ return 0;
}
scmi->started_vu = false;
if (!k->set_guest_notifiers) {
- return;
+ return 0;
}
- vhost_dev_stop(vhost_dev, vdev, true);
+ ret = vhost_dev_stop(vhost_dev, vdev, true);
- ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false);
- if (ret < 0) {
+ if (k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false) < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
- return;
+ return -1;
}
vhost_dev_disable_notifiers(vhost_dev, vdev);
+ return ret;
}
-static void vu_scmi_set_status(VirtIODevice *vdev, uint8_t status)
+static int vu_scmi_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev);
bool should_start = virtio_device_should_start(vdev, status);
if (!scmi->connected) {
- return;
+ return -1;
}
if (vhost_dev_is_started(&scmi->vhost_dev) == should_start) {
- return;
+ return 0;
}
if (should_start) {
vu_scmi_start(vdev);
} else {
- vu_scmi_stop(vdev);
+ int ret;
+ ret = vu_scmi_stop(vdev);
+ if (ret < 0) {
+ return ret;
+ }
}
+ return 0;
}
static uint64_t vu_scmi_get_features(VirtIODevice *vdev, uint64_t features,
@@ -258,8 +263,6 @@ static void vu_scmi_device_realize(DeviceState *dev, Error **errp)
qemu_chr_fe_set_handlers(&scmi->chardev, NULL, NULL, vu_scmi_event, NULL,
dev, NULL, true);
-
- return;
}
static void vu_scmi_device_unrealize(DeviceState *dev)
@@ -277,12 +280,11 @@ static const VMStateDescription vu_scmi_vmstate = {
.unmigratable = 1,
};
-static Property vu_scmi_properties[] = {
+static const Property vu_scmi_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserSCMI, chardev),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vu_scmi_class_init(ObjectClass *klass, void *data)
+static void vu_scmi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c
index 75882e3..994e51a 100644
--- a/hw/virtio/vhost-user-scsi-pci.c
+++ b/hw/virtio/vhost-user-scsi-pci.c
@@ -29,7 +29,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/loader.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "hw/virtio/virtio-pci.h"
#include "qom/object.h"
@@ -44,10 +44,9 @@ struct VHostUserSCSIPCI {
VHostUserSCSI vdev;
};
-static Property vhost_user_scsi_pci_properties[] = {
+static const Property vhost_user_scsi_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -68,7 +67,7 @@ static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_scsi_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-snd-pci.c b/hw/virtio/vhost-user-snd-pci.c
index d61cfda..f5015fb 100644
--- a/hw/virtio/vhost-user-snd-pci.c
+++ b/hw/virtio/vhost-user-snd-pci.c
@@ -23,10 +23,6 @@ typedef struct VHostUserSoundPCI VHostUserSoundPCI;
DECLARE_INSTANCE_CHECKER(VHostUserSoundPCI, VHOST_USER_SND_PCI,
TYPE_VHOST_USER_SND_PCI)
-static Property vhost_user_snd_pci_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void vhost_user_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VHostUserSoundPCI *dev = VHOST_USER_SND_PCI(vpci_dev);
@@ -37,14 +33,13 @@ static void vhost_user_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_snd_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_snd_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
k->realize = vhost_user_snd_pci_realize;
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- device_class_set_props(dc, vhost_user_snd_pci_properties);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
pcidev_k->revision = 0x00;
diff --git a/hw/virtio/vhost-user-snd.c b/hw/virtio/vhost-user-snd.c
index 9a21754..732411c 100644
--- a/hw/virtio/vhost-user-snd.c
+++ b/hw/virtio/vhost-user-snd.c
@@ -16,30 +16,45 @@
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_snd.h"
+static const VirtIOFeature feature_sizes[] = {
+ {.flags = 1ULL << VIRTIO_SND_F_CTLS,
+ .end = endof(struct virtio_snd_config, controls)},
+ {}
+};
+
+static const VirtIOConfigSizeParams cfg_size_params = {
+ .min_size = endof(struct virtio_snd_config, chmaps),
+ .max_size = sizeof(struct virtio_snd_config),
+ .feature_sizes = feature_sizes
+};
+
static const VMStateDescription vu_snd_vmstate = {
.name = "vhost-user-snd",
.unmigratable = 1,
};
-static Property vsnd_properties[] = {
+static const Property vsnd_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
- DEFINE_PROP_END_OF_LIST(),
+ DEFINE_PROP_BIT64("controls", VHostUserBase,
+ parent_obj.host_features, VIRTIO_SND_F_CTLS, false),
};
static void vu_snd_base_realize(DeviceState *dev, Error **errp)
{
VHostUserBase *vub = VHOST_USER_BASE(dev);
VHostUserBaseClass *vubs = VHOST_USER_BASE_GET_CLASS(dev);
+ VirtIODevice *vdev = &vub->parent_obj;
vub->virtio_id = VIRTIO_ID_SOUND;
vub->num_vqs = 4;
- vub->config_size = sizeof(struct virtio_snd_config);
+ vub->config_size = virtio_get_config_size(&cfg_size_params,
+ vdev->host_features);
vub->vq_size = 64;
vubs->parent_realize(dev, errp);
}
-static void vu_snd_class_init(ObjectClass *klass, void *data)
+static void vu_snd_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c
index e5a86e8..adb877b 100644
--- a/hw/virtio/vhost-user-vsock-pci.c
+++ b/hw/virtio/vhost-user-vsock-pci.c
@@ -31,9 +31,8 @@ struct VHostUserVSockPCI {
/* vhost-user-vsock-pci */
-static Property vhost_user_vsock_pci_properties[] = {
+static const Property vhost_user_vsock_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -47,7 +46,8 @@ static void vhost_user_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_user_vsock_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_user_vsock_pci_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c
index da3b0e0..993c287 100644
--- a/hw/virtio/vhost-user-vsock.c
+++ b/hw/virtio/vhost-user-vsock.c
@@ -54,23 +54,28 @@ const VhostDevConfigOps vsock_ops = {
.vhost_dev_config_notifier = vuv_handle_config_change,
};
-static void vuv_set_status(VirtIODevice *vdev, uint8_t status)
+static int vuv_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
bool should_start = virtio_device_should_start(vdev, status);
+ int ret;
if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) {
- return;
+ return 0;
}
if (should_start) {
- int ret = vhost_vsock_common_start(vdev);
+ ret = vhost_vsock_common_start(vdev);
if (ret < 0) {
- return;
+ return ret;
}
} else {
- vhost_vsock_common_stop(vdev);
+ ret = vhost_vsock_common_stop(vdev);
+ if (ret < 0) {
+ return ret;
+ }
}
+ return 0;
}
static uint64_t vuv_get_features(VirtIODevice *vdev,
@@ -128,7 +133,6 @@ err_vhost_dev:
err_virtio:
vhost_vsock_common_unrealize(vdev);
vhost_user_cleanup(&vsock->vhost_user);
- return;
}
static void vuv_device_unrealize(DeviceState *dev)
@@ -148,12 +152,11 @@ static void vuv_device_unrealize(DeviceState *dev)
}
-static Property vuv_properties[] = {
+static const Property vuv_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vuv_class_init(ObjectClass *klass, void *data)
+static void vuv_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 00561da..1e1d6b0 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -19,16 +19,16 @@
#include "hw/virtio/virtio-net.h"
#include "chardev/char-fe.h"
#include "io/channel-socket.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/uuid.h"
#include "qemu/sockets.h"
-#include "sysemu/runstate.h"
-#include "sysemu/cryptodev.h"
+#include "system/runstate.h"
+#include "system/cryptodev.h"
#include "migration/postcopy-ram.h"
#include "trace.h"
-#include "exec/ramblock.h"
+#include "system/ramblock.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -654,8 +654,6 @@ static void scrub_shadow_regions(struct vhost_dev *dev,
}
*nr_rem_reg = rm_idx;
*nr_add_reg = add_idx;
-
- return;
}
static int send_remove_regions(struct vhost_dev *dev,
@@ -1185,9 +1183,16 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev,
static void vhost_user_host_notifier_free(VhostUserHostNotifier *n)
{
- assert(n && n->unmap_addr);
- munmap(n->unmap_addr, qemu_real_host_page_size());
- n->unmap_addr = NULL;
+ if (n->unmap_addr) {
+ munmap(n->unmap_addr, qemu_real_host_page_size());
+ n->unmap_addr = NULL;
+ }
+ if (n->destroy) {
+ memory_region_transaction_begin();
+ object_unparent(OBJECT(&n->mr));
+ memory_region_transaction_commit();
+ g_free(n);
+ }
}
/*
@@ -1195,17 +1200,28 @@ static void vhost_user_host_notifier_free(VhostUserHostNotifier *n)
* under rcu.
*/
static void vhost_user_host_notifier_remove(VhostUserHostNotifier *n,
- VirtIODevice *vdev)
+ VirtIODevice *vdev, bool destroy)
{
+ /*
+ * if destroy == false and n->addr == NULL, we have nothing to do.
+ * so, just return.
+ */
+ if (!n || (!destroy && !n->addr)) {
+ return;
+ }
+
if (n->addr) {
if (vdev) {
+ memory_region_transaction_begin();
virtio_queue_set_host_notifier_mr(vdev, n->idx, &n->mr, false);
+ memory_region_transaction_commit();
}
assert(!n->unmap_addr);
n->unmap_addr = n->addr;
n->addr = NULL;
- call_rcu(n, vhost_user_host_notifier_free, rcu);
}
+ n->destroy = destroy;
+ call_rcu(n, vhost_user_host_notifier_free, rcu);
}
static int vhost_user_set_vring_base(struct vhost_dev *dev,
@@ -1279,9 +1295,7 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
struct vhost_user *u = dev->opaque;
VhostUserHostNotifier *n = fetch_notifier(u->user, ring->index);
- if (n) {
- vhost_user_host_notifier_remove(n, dev->vdev);
- }
+ vhost_user_host_notifier_remove(n, dev->vdev, false);
ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
@@ -1562,7 +1576,7 @@ static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev,
* new mapped address.
*/
n = fetch_or_create_notifier(user, queue_idx);
- vhost_user_host_notifier_remove(n, vdev);
+ vhost_user_host_notifier_remove(n, vdev, false);
if (area->u64 & VHOST_USER_VRING_NOFD_MASK) {
return 0;
@@ -1607,9 +1621,14 @@ vhost_user_backend_handle_shared_object_add(struct vhost_dev *dev,
QemuUUID uuid;
memcpy(uuid.data, object->uuid, sizeof(object->uuid));
- return virtio_add_vhost_device(&uuid, dev);
+ return !virtio_add_vhost_device(&uuid, dev);
}
+/*
+ * Handle VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE backend requests.
+ *
+ * Return: 0 on success, 1 on error.
+ */
static int
vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
VhostUserShared *object)
@@ -1623,16 +1642,16 @@ vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
struct vhost_dev *owner = virtio_lookup_vhost_device(&uuid);
if (dev != owner) {
/* Not allowed to remove non-owned entries */
- return 0;
+ return 1;
}
break;
}
default:
/* Not allowed to remove non-owned entries */
- return 0;
+ return 1;
}
- return virtio_remove_resource(&uuid);
+ return !virtio_remove_resource(&uuid);
}
static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
@@ -2736,15 +2755,7 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev,
static void vhost_user_state_destroy(gpointer data)
{
VhostUserHostNotifier *n = (VhostUserHostNotifier *) data;
- if (n) {
- vhost_user_host_notifier_remove(n, NULL);
- object_unparent(OBJECT(&n->mr));
- /*
- * We can't free until vhost_user_host_notifier_remove has
- * done it's thing so schedule the free with RCU.
- */
- g_free_rcu(n, rcu);
- }
+ vhost_user_host_notifier_remove(n, NULL, true);
}
bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)
@@ -2765,9 +2776,7 @@ void vhost_user_cleanup(VhostUserState *user)
if (!user->chr) {
return;
}
- memory_region_transaction_begin();
user->notifiers = (GPtrArray *) g_ptr_array_free(user->notifiers, true);
- memory_region_transaction_commit();
user->chr = NULL;
}
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index 3cdaa12..7061b6e 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -20,7 +20,7 @@
#include "hw/virtio/virtio-net.h"
#include "hw/virtio/vhost-shadow-virtqueue.h"
#include "hw/virtio/vhost-vdpa.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "migration/blocker.h"
#include "qemu/cutils.h"
#include "qemu/main-loop.h"
@@ -209,6 +209,8 @@ static void vhost_vdpa_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
int ret;
Int128 llend;
Error *local_err = NULL;
+ MemoryRegion *mr;
+ hwaddr xlat;
if (iotlb->target_as != &address_space_memory) {
error_report("Wrong target AS \"%s\", only system memory is allowed",
@@ -228,11 +230,14 @@ static void vhost_vdpa_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
bool read_only;
- if (!memory_get_xlat_addr(iotlb, &vaddr, NULL, &read_only, NULL,
- &local_err)) {
+ mr = memory_translate_iotlb(iotlb, &xlat, &local_err);
+ if (!mr) {
error_report_err(local_err);
return;
}
+ vaddr = memory_region_get_ram_ptr(mr) + xlat;
+ read_only = !(iotlb->perm & IOMMU_WO) || mr->readonly;
+
ret = vhost_vdpa_dma_map(s, VHOST_VDPA_GUEST_PA_ASID, iova,
iotlb->addr_mask + 1, vaddr, read_only);
if (ret) {
@@ -288,8 +293,6 @@ static void vhost_vdpa_iommu_region_add(MemoryListener *listener,
QLIST_INSERT_HEAD(&s->iommu_list, iommu, iommu_next);
memory_region_iommu_replay(iommu->iommu_mr, &iommu->n);
-
- return;
}
static void vhost_vdpa_iommu_region_del(MemoryListener *listener,
@@ -360,14 +363,20 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
llsize = int128_sub(llend, int128_make64(iova));
if (s->shadow_data) {
int r;
+ hwaddr gpa = section->offset_within_address_space;
- mem_region.translated_addr = (hwaddr)(uintptr_t)vaddr,
mem_region.size = int128_get64(llsize) - 1,
mem_region.perm = IOMMU_ACCESS_FLAG(true, section->readonly),
- r = vhost_iova_tree_map_alloc(s->iova_tree, &mem_region);
+ r = vhost_iova_tree_map_alloc_gpa(s->iova_tree, &mem_region, gpa);
if (unlikely(r != IOVA_OK)) {
error_report("Can't allocate a mapping (%d)", r);
+
+ if (mem_region.translated_addr == gpa) {
+ error_report("Insertion to GPA->IOVA tree failed");
+ /* Remove the mapping from the IOVA-only tree */
+ goto fail_map;
+ }
goto fail;
}
@@ -386,7 +395,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
fail_map:
if (s->shadow_data) {
- vhost_iova_tree_remove(s->iova_tree, mem_region);
+ vhost_iova_tree_remove_gpa(s->iova_tree, mem_region);
}
fail:
@@ -440,21 +449,18 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
if (s->shadow_data) {
const DMAMap *result;
- const void *vaddr = memory_region_get_ram_ptr(section->mr) +
- section->offset_within_region +
- (iova - section->offset_within_address_space);
DMAMap mem_region = {
- .translated_addr = (hwaddr)(uintptr_t)vaddr,
+ .translated_addr = section->offset_within_address_space,
.size = int128_get64(llsize) - 1,
};
- result = vhost_iova_tree_find_iova(s->iova_tree, &mem_region);
+ result = vhost_iova_tree_find_gpa(s->iova_tree, &mem_region);
if (!result) {
/* The memory listener map wasn't mapped */
return;
}
iova = result->iova;
- vhost_iova_tree_remove(s->iova_tree, *result);
+ vhost_iova_tree_remove_gpa(s->iova_tree, *result);
}
vhost_vdpa_iotlb_batch_begin_once(s);
/*
@@ -593,6 +599,36 @@ static void vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v)
v->shadow_vqs = g_steal_pointer(&shadow_vqs);
}
+static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev)
+{
+ struct vhost_vdpa *v = dev->opaque;
+
+ uint64_t features;
+ uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 |
+ 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH |
+ 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID |
+ 0x1ULL << VHOST_BACKEND_F_SUSPEND;
+ int r;
+
+ if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) {
+ return -EFAULT;
+ }
+
+ features &= f;
+
+ if (vhost_vdpa_first_dev(dev)) {
+ r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features);
+ if (r) {
+ return -EFAULT;
+ }
+ }
+
+ dev->backend_cap = features;
+ v->shared->backend_cap = features;
+
+ return 0;
+}
+
static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
{
struct vhost_vdpa *v = opaque;
@@ -602,7 +638,12 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
v->dev = dev;
dev->opaque = opaque ;
- v->shared->listener = vhost_vdpa_memory_listener;
+
+ ret = vhost_vdpa_set_backend_cap(dev);
+ if (unlikely(ret != 0)) {
+ return ret;
+ }
+
vhost_vdpa_init_svq(dev, v);
error_propagate(&dev->migration_blocker, v->migration_blocker);
@@ -638,6 +679,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER);
+ v->shared->listener = vhost_vdpa_memory_listener;
return 0;
}
@@ -840,36 +882,6 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev,
return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
}
-static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev)
-{
- struct vhost_vdpa *v = dev->opaque;
-
- uint64_t features;
- uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 |
- 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH |
- 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID |
- 0x1ULL << VHOST_BACKEND_F_SUSPEND;
- int r;
-
- if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) {
- return -EFAULT;
- }
-
- features &= f;
-
- if (vhost_vdpa_first_dev(dev)) {
- r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features);
- if (r) {
- return -EFAULT;
- }
- }
-
- dev->backend_cap = features;
- v->shared->backend_cap = features;
-
- return 0;
-}
-
static int vhost_vdpa_get_device_id(struct vhost_dev *dev,
uint32_t *device_id)
{
@@ -887,8 +899,14 @@ static int vhost_vdpa_reset_device(struct vhost_dev *dev)
ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status);
trace_vhost_vdpa_reset_device(dev);
+ if (ret) {
+ return ret;
+ }
+
+ memory_listener_unregister(&v->shared->listener);
+ v->shared->listener_registered = false;
v->suspended = false;
- return ret;
+ return 0;
}
static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx)
@@ -1142,16 +1160,23 @@ static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
*
* @v: Vhost-vdpa device
* @needle: The area to search iova
+ * @taddr: The translated address (HVA)
* @errorp: Error pointer
*/
static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle,
- Error **errp)
+ hwaddr taddr, Error **errp)
{
int r;
- r = vhost_iova_tree_map_alloc(v->shared->iova_tree, needle);
+ r = vhost_iova_tree_map_alloc(v->shared->iova_tree, needle, taddr);
if (unlikely(r != IOVA_OK)) {
error_setg(errp, "Cannot allocate iova (%d)", r);
+
+ if (needle->translated_addr == taddr) {
+ error_append_hint(errp, "Insertion to IOVA->HVA tree failed");
+ /* Remove the mapping from the IOVA-only tree */
+ vhost_iova_tree_remove(v->shared->iova_tree, *needle);
+ }
return false;
}
@@ -1192,11 +1217,11 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
vhost_svq_get_vring_addr(svq, &svq_addr);
driver_region = (DMAMap) {
- .translated_addr = svq_addr.desc_user_addr,
.size = driver_size - 1,
.perm = IOMMU_RO,
};
- ok = vhost_vdpa_svq_map_ring(v, &driver_region, errp);
+ ok = vhost_vdpa_svq_map_ring(v, &driver_region, svq_addr.desc_user_addr,
+ errp);
if (unlikely(!ok)) {
error_prepend(errp, "Cannot create vq driver region: ");
return false;
@@ -1206,11 +1231,11 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
addr->avail_user_addr = driver_region.iova + avail_offset;
device_region = (DMAMap) {
- .translated_addr = svq_addr.used_user_addr,
.size = device_size - 1,
.perm = IOMMU_RW,
};
- ok = vhost_vdpa_svq_map_ring(v, &device_region, errp);
+ ok = vhost_vdpa_svq_map_ring(v, &device_region, svq_addr.used_user_addr,
+ errp);
if (unlikely(!ok)) {
error_prepend(errp, "Cannot create vq device region: ");
vhost_vdpa_svq_unmap_ring(v, driver_region.translated_addr);
@@ -1365,7 +1390,15 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
"IOMMU and try again");
return -1;
}
- memory_listener_register(&v->shared->listener, dev->vdev->dma_as);
+ if (v->shared->listener_registered &&
+ dev->vdev->dma_as != v->shared->listener.address_space) {
+ memory_listener_unregister(&v->shared->listener);
+ v->shared->listener_registered = false;
+ }
+ if (!v->shared->listener_registered) {
+ memory_listener_register(&v->shared->listener, dev->vdev->dma_as);
+ v->shared->listener_registered = true;
+ }
return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
}
@@ -1375,8 +1408,6 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
static void vhost_vdpa_reset_status(struct vhost_dev *dev)
{
- struct vhost_vdpa *v = dev->opaque;
-
if (!vhost_vdpa_last_dev(dev)) {
return;
}
@@ -1384,7 +1415,6 @@ static void vhost_vdpa_reset_status(struct vhost_dev *dev)
vhost_vdpa_reset_device(dev);
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER);
- memory_listener_unregister(&v->shared->listener);
}
static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base,
@@ -1518,12 +1548,27 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev,
static int vhost_vdpa_set_owner(struct vhost_dev *dev)
{
+ int r;
+ struct vhost_vdpa *v;
+
if (!vhost_vdpa_first_dev(dev)) {
return 0;
}
trace_vhost_vdpa_set_owner(dev);
- return vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL);
+ r = vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL);
+ if (unlikely(r < 0)) {
+ return r;
+ }
+
+ /*
+ * Being optimistic and listening address space memory. If the device
+ * uses vIOMMU, it is changed at vhost_vdpa_dev_start.
+ */
+ v = dev->opaque;
+ memory_listener_register(&v->shared->listener, &address_space_memory);
+ v->shared->listener_registered = true;
+ return 0;
}
static int vhost_vdpa_vq_get_addr(struct vhost_dev *dev,
@@ -1555,7 +1600,6 @@ const VhostOps vdpa_ops = {
.vhost_set_vring_kick = vhost_vdpa_set_vring_kick,
.vhost_set_vring_call = vhost_vdpa_set_vring_call,
.vhost_get_features = vhost_vdpa_get_features,
- .vhost_set_backend_cap = vhost_vdpa_set_backend_cap,
.vhost_set_owner = vhost_vdpa_set_owner,
.vhost_set_vring_endian = NULL,
.vhost_backend_memslots_limit = vhost_vdpa_memslots_limit,
diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
index fd88df2..c6c44d8 100644
--- a/hw/virtio/vhost-vsock-common.c
+++ b/hw/virtio/vhost-vsock-common.c
@@ -95,7 +95,7 @@ err_host_notifiers:
return ret;
}
-void vhost_vsock_common_stop(VirtIODevice *vdev)
+int vhost_vsock_common_stop(VirtIODevice *vdev)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@@ -103,18 +103,18 @@ void vhost_vsock_common_stop(VirtIODevice *vdev)
int ret;
if (!k->set_guest_notifiers) {
- return;
+ return 0;
}
- vhost_dev_stop(&vvc->vhost_dev, vdev, true);
+ ret = vhost_dev_stop(&vvc->vhost_dev, vdev, true);
- ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false);
- if (ret < 0) {
+ if (k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false) < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
- return;
+ return -1;
}
vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev);
+ return ret;
}
@@ -285,13 +285,12 @@ static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev)
return &vvc->vhost_dev;
}
-static Property vhost_vsock_common_properties[] = {
+static const Property vhost_vsock_common_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket,
ON_OFF_AUTO_AUTO),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vhost_vsock_common_class_init(ObjectClass *klass, void *data)
+static void vhost_vsock_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c
index 9f34414..0022a71 100644
--- a/hw/virtio/vhost-vsock-pci.c
+++ b/hw/virtio/vhost-vsock-pci.c
@@ -35,9 +35,8 @@ struct VHostVSockPCI {
/* vhost-vsock-pci */
-static Property vhost_vsock_pci_properties[] = {
+static const Property vhost_vsock_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_PROP_END_OF_LIST(),
};
static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -57,7 +56,7 @@ static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data)
+static void vhost_vsock_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c
index 3d4a5a9..6e40888 100644
--- a/hw/virtio/vhost-vsock.c
+++ b/hw/virtio/vhost-vsock.c
@@ -67,37 +67,38 @@ static int vhost_vsock_set_running(VirtIODevice *vdev, int start)
}
-static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status)
+static int vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
bool should_start = virtio_device_should_start(vdev, status);
int ret;
if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) {
- return;
+ return 0;
}
if (should_start) {
ret = vhost_vsock_common_start(vdev);
if (ret < 0) {
- return;
+ return 0;
}
ret = vhost_vsock_set_running(vdev, 1);
if (ret < 0) {
vhost_vsock_common_stop(vdev);
error_report("Error starting vhost vsock: %d", -ret);
- return;
+ return 0;
}
} else {
ret = vhost_vsock_set_running(vdev, 0);
if (ret < 0) {
error_report("vhost vsock set running failed: %d", ret);
- return;
+ return 0;
}
vhost_vsock_common_stop(vdev);
}
+ return 0;
}
static uint64_t vhost_vsock_get_features(VirtIODevice *vdev,
@@ -205,13 +206,12 @@ static void vhost_vsock_device_unrealize(DeviceState *dev)
vhost_vsock_common_unrealize(vdev);
}
-static Property vhost_vsock_properties[] = {
+static const Property vhost_vsock_properties[] = {
DEFINE_PROP_UINT64("guest-cid", VHostVSock, conf.guest_cid, 0),
DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vhost_vsock_class_init(ObjectClass *klass, void *data)
+static void vhost_vsock_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 06fc717..fc43853 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -26,7 +26,7 @@
#include "hw/mem/memory-device.h"
#include "migration/blocker.h"
#include "migration/qemu-file-types.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "trace.h"
/* enabled until disconnected backend stabilizes */
@@ -732,7 +732,6 @@ out:
memory_region_unref(old_sections[n_old_sections].mr);
}
g_free(old_sections);
- return;
}
/* Adds the section data to the tmp_section structure.
@@ -1368,10 +1367,10 @@ fail_alloc_desc:
return r;
}
-void vhost_virtqueue_stop(struct vhost_dev *dev,
- struct VirtIODevice *vdev,
- struct vhost_virtqueue *vq,
- unsigned idx)
+int vhost_virtqueue_stop(struct vhost_dev *dev,
+ struct VirtIODevice *vdev,
+ struct vhost_virtqueue *vq,
+ unsigned idx)
{
int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
struct vhost_vring_state state = {
@@ -1381,7 +1380,7 @@ void vhost_virtqueue_stop(struct vhost_dev *dev,
if (virtio_queue_get_desc_addr(vdev, idx) == 0) {
/* Don't stop the virtqueue which might have not been started */
- return;
+ return 0;
}
r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
@@ -1412,6 +1411,7 @@ void vhost_virtqueue_stop(struct vhost_dev *dev,
0, virtio_queue_get_avail_size(vdev, idx));
vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx),
0, virtio_queue_get_desc_size(vdev, idx));
+ return r;
}
static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev,
@@ -1682,9 +1682,9 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
memset(hdev, 0, sizeof(struct vhost_dev));
}
-static void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
- VirtIODevice *vdev,
- unsigned int nvqs)
+void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
+ VirtIODevice *vdev,
+ unsigned int nvqs)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
int i, r;
@@ -1930,62 +1930,6 @@ void vhost_dev_free_inflight(struct vhost_inflight *inflight)
}
}
-static int vhost_dev_resize_inflight(struct vhost_inflight *inflight,
- uint64_t new_size)
-{
- Error *err = NULL;
- int fd = -1;
- void *addr = qemu_memfd_alloc("vhost-inflight", new_size,
- F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL,
- &fd, &err);
-
- if (err) {
- error_report_err(err);
- return -ENOMEM;
- }
-
- vhost_dev_free_inflight(inflight);
- inflight->offset = 0;
- inflight->addr = addr;
- inflight->fd = fd;
- inflight->size = new_size;
-
- return 0;
-}
-
-void vhost_dev_save_inflight(struct vhost_inflight *inflight, QEMUFile *f)
-{
- if (inflight->addr) {
- qemu_put_be64(f, inflight->size);
- qemu_put_be16(f, inflight->queue_size);
- qemu_put_buffer(f, inflight->addr, inflight->size);
- } else {
- qemu_put_be64(f, 0);
- }
-}
-
-int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f)
-{
- uint64_t size;
-
- size = qemu_get_be64(f);
- if (!size) {
- return 0;
- }
-
- if (inflight->size != size) {
- int ret = vhost_dev_resize_inflight(inflight, size);
- if (ret < 0) {
- return ret;
- }
- }
- inflight->queue_size = qemu_get_be16(f);
-
- qemu_get_buffer(f, inflight->addr, size);
-
- return 0;
-}
-
int vhost_dev_prepare_inflight(struct vhost_dev *hdev, VirtIODevice *vdev)
{
int r;
@@ -2151,11 +2095,22 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
* vhost-kernel code requires for this.*/
for (i = 0; i < hdev->nvqs; ++i) {
struct vhost_virtqueue *vq = hdev->vqs + i;
- vhost_device_iotlb_miss(hdev, vq->used_phys, true);
+ r = vhost_device_iotlb_miss(hdev, vq->used_phys, true);
+ if (r) {
+ goto fail_iotlb;
+ }
}
}
vhost_start_config_intr(hdev);
return 0;
+fail_iotlb:
+ if (vhost_dev_has_iommu(hdev) &&
+ hdev->vhost_ops->vhost_set_iotlb_callback) {
+ hdev->vhost_ops->vhost_set_iotlb_callback(hdev, false);
+ }
+ if (hdev->vhost_ops->vhost_dev_start) {
+ hdev->vhost_ops->vhost_dev_start(hdev, false);
+ }
fail_start:
if (vrings) {
vhost_dev_set_vring_enable(hdev, false);
@@ -2181,9 +2136,10 @@ fail_features:
}
/* Host notifiers must be enabled at this point. */
-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
+int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
{
int i;
+ int rc = 0;
/* should only be called after backend is connected */
assert(hdev->vhost_ops);
@@ -2202,10 +2158,10 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
vhost_dev_set_vring_enable(hdev, false);
}
for (i = 0; i < hdev->nvqs; ++i) {
- vhost_virtqueue_stop(hdev,
- vdev,
- hdev->vqs + i,
- hdev->vq_index + i);
+ rc |= vhost_virtqueue_stop(hdev,
+ vdev,
+ hdev->vqs + i,
+ hdev->vq_index + i);
}
if (hdev->vhost_ops->vhost_reset_status) {
hdev->vhost_ops->vhost_reset_status(hdev);
@@ -2222,6 +2178,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
hdev->started = false;
vdev->vhost_started = false;
hdev->vdev = NULL;
+ return rc;
}
int vhost_net_set_backend(struct vhost_dev *hdev,
diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c
index 94c14f0..594742f 100644
--- a/hw/virtio/virtio-9p-pci.c
+++ b/hw/virtio/virtio-9p-pci.c
@@ -43,14 +43,13 @@ static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static Property virtio_9p_pci_properties[] = {
+static const Property virtio_9p_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_9p_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/virtio/virtio-acpi.c b/hw/virtio/virtio-acpi.c
index 230a669..85becef 100644
--- a/hw/virtio/virtio-acpi.c
+++ b/hw/virtio/virtio-acpi.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* virtio ACPI Support
*
diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c
index ce2645b..96e88b6 100644
--- a/hw/virtio/virtio-balloon-pci.c
+++ b/hw/virtio/virtio-balloon-pci.c
@@ -35,16 +35,27 @@ struct VirtIOBalloonPCI {
VirtIOBalloon vdev;
};
+static const Property virtio_balloon_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+};
+
static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = 2;
+ }
+
vpci_dev->class_code = PCI_CLASS_OTHERS;
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_balloon_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
@@ -55,6 +66,7 @@ static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS;
+ device_class_set_props(dc, virtio_balloon_properties);
}
static void virtio_balloon_pci_instance_init(Object *obj)
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 609e39a..db787d0 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -22,16 +22,16 @@
#include "hw/mem/pc-dimm.h"
#include "hw/qdev-properties.h"
#include "hw/boards.h"
-#include "sysemu/balloon.h"
+#include "system/balloon.h"
#include "hw/virtio/virtio-balloon.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "qapi/error.h"
#include "qapi/qapi-events-machine.h"
#include "qapi/visitor.h"
#include "trace.h"
#include "qemu/error-report.h"
#include "migration/misc.h"
-
+#include "system/reset.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
@@ -167,19 +167,33 @@ static void balloon_deflate_page(VirtIOBalloon *balloon,
}
}
+/*
+ * All stats upto VIRTIO_BALLOON_S_NR /must/ have a
+ * non-NULL name declared here, since these are used
+ * as keys for populating the QDict with stats
+ */
static const char *balloon_stat_names[] = {
[VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in",
[VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out",
[VIRTIO_BALLOON_S_MAJFLT] = "stat-major-faults",
[VIRTIO_BALLOON_S_MINFLT] = "stat-minor-faults",
[VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory",
+
[VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory",
[VIRTIO_BALLOON_S_AVAIL] = "stat-available-memory",
[VIRTIO_BALLOON_S_CACHES] = "stat-disk-caches",
[VIRTIO_BALLOON_S_HTLB_PGALLOC] = "stat-htlb-pgalloc",
[VIRTIO_BALLOON_S_HTLB_PGFAIL] = "stat-htlb-pgfail",
- [VIRTIO_BALLOON_S_NR] = NULL
+
+ [VIRTIO_BALLOON_S_OOM_KILL] = "stat-oom-kills",
+ [VIRTIO_BALLOON_S_ALLOC_STALL] = "stat-alloc-stalls",
+ [VIRTIO_BALLOON_S_ASYNC_SCAN] = "stat-async-scans",
+ [VIRTIO_BALLOON_S_DIRECT_SCAN] = "stat-direct-scans",
+ [VIRTIO_BALLOON_S_ASYNC_RECLAIM] = "stat-async-reclaims",
+
+ [VIRTIO_BALLOON_S_DIRECT_RECLAIM] = "stat-direct-reclaims",
};
+G_STATIC_ASSERT(G_N_ELEMENTS(balloon_stat_names) == VIRTIO_BALLOON_S_NR);
/*
* reset_stats - Mark all items in the stats array as unset
@@ -896,6 +910,8 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
}
reset_stats(s);
+ s->stats_last_update = 0;
+ qemu_register_resettable(OBJECT(dev));
}
static void virtio_balloon_device_unrealize(DeviceState *dev)
@@ -903,6 +919,7 @@ static void virtio_balloon_device_unrealize(DeviceState *dev)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOBalloon *s = VIRTIO_BALLOON(dev);
+ qemu_unregister_resettable(OBJECT(dev));
if (s->free_page_bh) {
qemu_bh_delete(s->free_page_bh);
object_unref(OBJECT(s->iothread));
@@ -941,7 +958,7 @@ static void virtio_balloon_device_reset(VirtIODevice *vdev)
s->poison_val = 0;
}
-static void virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status)
+static int virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status)
{
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
@@ -971,6 +988,28 @@ static void virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status)
qemu_mutex_unlock(&s->free_page_lock);
}
}
+ return 0;
+}
+
+static ResettableState *virtio_balloon_get_reset_state(Object *obj)
+{
+ VirtIOBalloon *s = VIRTIO_BALLOON(obj);
+ return &s->reset_state;
+}
+
+static void virtio_balloon_reset_enter(Object *obj, ResetType type)
+{
+ VirtIOBalloon *s = VIRTIO_BALLOON(obj);
+
+ /*
+ * When waking up from standby/suspend-to-ram, do not reset stats.
+ */
+ if (type == RESET_TYPE_WAKEUP) {
+ return;
+ }
+
+ reset_stats(s);
+ s->stats_last_update = 0;
}
static void virtio_balloon_instance_init(Object *obj)
@@ -1001,7 +1040,7 @@ static const VMStateDescription vmstate_virtio_balloon = {
},
};
-static Property virtio_balloon_properties[] = {
+static const Property virtio_balloon_properties[] = {
DEFINE_PROP_BIT("deflate-on-oom", VirtIOBalloon, host_features,
VIRTIO_BALLOON_F_DEFLATE_ON_OOM, false),
DEFINE_PROP_BIT("free-page-hint", VirtIOBalloon, host_features,
@@ -1018,13 +1057,13 @@ static Property virtio_balloon_properties[] = {
qemu_4_0_config_size, false),
DEFINE_PROP_LINK("iothread", VirtIOBalloon, iothread, TYPE_IOTHREAD,
IOThread *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_balloon_class_init(ObjectClass *klass, void *data)
+static void virtio_balloon_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
device_class_set_props(dc, virtio_balloon_properties);
dc->vmsd = &vmstate_virtio_balloon;
@@ -1037,6 +1076,9 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data)
vdc->get_features = virtio_balloon_get_features;
vdc->set_status = virtio_balloon_set_status;
vdc->vmsd = &vmstate_virtio_balloon_device;
+
+ rc->get_state = virtio_balloon_get_reset_state;
+ rc->phases.enter = virtio_balloon_reset_enter;
}
static const TypeInfo virtio_balloon_info = {
diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c
index 9743bee..fd33bbd 100644
--- a/hw/virtio/virtio-blk-pci.c
+++ b/hw/virtio/virtio-blk-pci.c
@@ -38,13 +38,12 @@ struct VirtIOBlkPCI {
VirtIOBlock vdev;
};
-static Property virtio_blk_pci_properties[] = {
+static const Property virtio_blk_pci_properties[] = {
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -64,7 +63,7 @@ static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_blk_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index 896feb3..11adfbf 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -28,7 +28,7 @@
#include "qapi/error.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
/* #define DEBUG_VIRTIO_BUS */
@@ -348,7 +348,7 @@ bool virtio_bus_device_iommu_enabled(VirtIODevice *vdev)
return klass->iommu_enabled(qbus->parent);
}
-static void virtio_bus_class_init(ObjectClass *klass, void *data)
+static void virtio_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *bus_class = BUS_CLASS(klass);
bus_class->get_dev_path = virtio_bus_get_dev_path;
diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index 0783dc2..868abc0 100644
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -37,11 +37,10 @@ struct VirtIOCryptoPCI {
VirtIOCrypto vdev;
};
-static Property virtio_crypto_pci_properties[] = {
+static const Property virtio_crypto_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -60,7 +59,7 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
}
}
-static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_crypto_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index 5034768..517f208 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -22,7 +22,7 @@
#include "hw/virtio/virtio-crypto.h"
#include "hw/qdev-properties.h"
#include "standard-headers/linux/virtio_ids.h"
-#include "sysemu/cryptodev-vhost.h"
+#include "system/cryptodev-vhost.h"
#define VIRTIO_CRYPTO_VM_VERSION 1
@@ -461,7 +461,7 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq,
req->in_iov = NULL;
req->in_num = 0;
req->in_len = 0;
- req->flags = QCRYPTODEV_BACKEND_ALG__MAX;
+ req->flags = QCRYPTODEV_BACKEND_ALGO_TYPE__MAX;
memset(&req->op_info, 0x00, sizeof(req->op_info));
}
@@ -471,7 +471,7 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
return;
}
- if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) {
+ if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
size_t max_len;
CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
@@ -486,7 +486,7 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
memset(op_info, 0, sizeof(*op_info) + max_len);
g_free(op_info);
}
- } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
if (op_info) {
g_free(op_info->src);
@@ -571,10 +571,10 @@ static void virtio_crypto_req_complete(void *opaque, int ret)
VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
uint8_t status = -ret;
- if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) {
+ if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
virtio_crypto_sym_input_data_helper(vdev, req, status,
req->op_info.u.sym_op_info);
- } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
virtio_crypto_akcipher_input_data_helper(vdev, req, status,
req->op_info.u.asym_op_info);
}
@@ -884,7 +884,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
switch (opcode) {
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
case VIRTIO_CRYPTO_CIPHER_DECRYPT:
- op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_SYM;
+ op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALGO_TYPE_SYM;
ret = virtio_crypto_handle_sym_req(vcrypto,
&req.u.sym_req, op_info,
out_iov, out_num);
@@ -894,7 +894,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
case VIRTIO_CRYPTO_AKCIPHER_SIGN:
case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
- op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_ASYM;
+ op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM;
ret = virtio_crypto_handle_asym_req(vcrypto,
&req.u.akcipher_req, op_info,
out_iov, out_num);
@@ -1008,19 +1008,19 @@ static uint32_t virtio_crypto_init_services(uint32_t qservices)
{
uint32_t vservices = 0;
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_CIPHER)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_CIPHER);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_HASH)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_HASH)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_HASH);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_MAC)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_MAC)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_MAC);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AEAD)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_AEAD)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AEAD);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_AKCIPHER)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AKCIPHER);
}
@@ -1128,10 +1128,9 @@ static const VMStateDescription vmstate_virtio_crypto = {
},
};
-static Property virtio_crypto_properties[] = {
+static const Property virtio_crypto_properties[] = {
DEFINE_PROP_LINK("cryptodev", VirtIOCrypto, conf.cryptodev,
TYPE_CRYPTODEV_BACKEND, CryptoDevBackend *),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config)
@@ -1198,11 +1197,12 @@ static void virtio_crypto_vhost_status(VirtIOCrypto *c, uint8_t status)
}
}
-static void virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status)
+static int virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status)
{
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
virtio_crypto_vhost_status(vcrypto, status);
+ return 0;
}
static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx,
@@ -1247,13 +1247,25 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx)
static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev)
{
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
- CryptoDevBackend *b = vcrypto->cryptodev;
- CryptoDevBackendClient *cc = b->conf.peers.ccs[0];
- CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0);
+ CryptoDevBackend *b;
+ CryptoDevBackendClient *cc;
+ CryptoDevBackendVhost *vhost_crypto;
+
+ b = vcrypto->cryptodev;
+ if (!b) {
+ return NULL;
+ }
+
+ cc = b->conf.peers.ccs[0];
+ vhost_crypto = cryptodev_get_vhost(cc, b, 0);
+ if (!vhost_crypto) {
+ return NULL;
+ }
+
return &vhost_crypto->dev;
}
-static void virtio_crypto_class_init(ObjectClass *klass, void *data)
+static void virtio_crypto_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/virtio-hmp-cmds.c b/hw/virtio/virtio-hmp-cmds.c
index 477c97d..7d8677b 100644
--- a/hw/virtio/virtio-hmp-cmds.c
+++ b/hw/virtio/virtio-hmp-cmds.c
@@ -9,7 +9,7 @@
#include "monitor/hmp.h"
#include "monitor/monitor.h"
#include "qapi/qapi-commands-virtio.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
static void hmp_virtio_dump_protocols(Monitor *mon,
diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c
index a53edf4..3be5358 100644
--- a/hw/virtio/virtio-input-pci.c
+++ b/hw/virtio/virtio-input-pci.c
@@ -37,9 +37,8 @@ struct VirtIOInputHIDPCI {
VirtIOInputHID vdev;
};
-static Property virtio_input_pci_properties[] = {
+static const Property virtio_input_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -51,7 +50,7 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_input_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
@@ -64,7 +63,8 @@ static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
}
-static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass,
+ const void *data)
{
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
@@ -72,7 +72,7 @@ static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
}
static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c
index cbdfe4c..8123c6f 100644
--- a/hw/virtio/virtio-iommu-pci.c
+++ b/hw/virtio/virtio-iommu-pci.c
@@ -34,12 +34,11 @@ struct VirtIOIOMMUPCI {
VirtIOIOMMU vdev;
};
-static Property virtio_iommu_pci_properties[] = {
+static const Property virtio_iommu_pci_properties[] = {
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_PROP_ARRAY("reserved-regions", VirtIOIOMMUPCI,
vdev.nr_prop_resv_regions, vdev.prop_resv_regions,
qdev_prop_reserved_region, ReservedRegion),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -74,7 +73,7 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void virtio_iommu_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_iommu_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 59ef4fb..3500f1b 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -25,9 +25,9 @@
#include "exec/target_page.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio.h"
-#include "sysemu/kvm.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
+#include "system/kvm.h"
+#include "system/reset.h"
+#include "system/system.h"
#include "qemu/reserved-region.h"
#include "qemu/units.h"
#include "qapi/error.h"
@@ -1504,11 +1504,11 @@ static void virtio_iommu_device_unrealize(DeviceState *dev)
virtio_cleanup(vdev);
}
-static void virtio_iommu_device_reset(VirtIODevice *vdev)
+static void virtio_iommu_device_reset_exit(Object *obj, ResetType type)
{
- VirtIOIOMMU *s = VIRTIO_IOMMU(vdev);
+ VirtIOIOMMU *s = VIRTIO_IOMMU(obj);
- trace_virtio_iommu_device_reset();
+ trace_virtio_iommu_device_reset_exit();
if (s->domains) {
g_tree_destroy(s->domains);
@@ -1522,9 +1522,10 @@ static void virtio_iommu_device_reset(VirtIODevice *vdev)
NULL, NULL, virtio_iommu_put_endpoint);
}
-static void virtio_iommu_set_status(VirtIODevice *vdev, uint8_t status)
+static int virtio_iommu_set_status(VirtIODevice *vdev, uint8_t status)
{
trace_virtio_iommu_device_status(status);
+ return 0;
}
static void virtio_iommu_instance_init(Object *obj)
@@ -1655,20 +1656,20 @@ static const VMStateDescription vmstate_virtio_iommu = {
},
};
-static Property virtio_iommu_properties[] = {
+static const Property virtio_iommu_properties[] = {
DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus,
TYPE_PCI_BUS, PCIBus *),
DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true),
DEFINE_PROP_GRANULE_MODE("granule", VirtIOIOMMU, granule_mode,
GRANULE_MODE_HOST),
DEFINE_PROP_UINT8("aw-bits", VirtIOIOMMU, aw_bits, 64),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_iommu_class_init(ObjectClass *klass, void *data)
+static void virtio_iommu_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
device_class_set_props(dc, virtio_iommu_properties);
dc->vmsd = &vmstate_virtio_iommu;
@@ -1676,7 +1677,12 @@ static void virtio_iommu_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
vdc->realize = virtio_iommu_device_realize;
vdc->unrealize = virtio_iommu_device_unrealize;
- vdc->reset = virtio_iommu_device_reset;
+
+ /*
+ * Use 'exit' reset phase to make sure all DMA requests
+ * have been quiesced during 'enter' or 'hold' phase
+ */
+ rc->phases.exit = virtio_iommu_device_reset_exit;
vdc->get_config = virtio_iommu_get_config;
vdc->set_config = virtio_iommu_set_config;
vdc->get_features = virtio_iommu_get_features;
@@ -1685,7 +1691,7 @@ static void virtio_iommu_class_init(ObjectClass *klass, void *data)
}
static void virtio_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
+ const void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
diff --git a/hw/virtio/virtio-md-pci.c b/hw/virtio/virtio-md-pci.c
index 9ec5067..9278b32 100644
--- a/hw/virtio/virtio-md-pci.c
+++ b/hw/virtio/virtio-md-pci.c
@@ -138,7 +138,7 @@ static const TypeInfo virtio_md_pci_info = {
.instance_size = sizeof(VirtIOMDPCI),
.class_size = sizeof(VirtIOMDPCIClass),
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_MEMORY_DEVICE },
{ }
},
diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c
index 1b4e9a3..f592eb1 100644
--- a/hw/virtio/virtio-mem-pci.c
+++ b/hw/virtio/virtio-mem-pci.c
@@ -22,6 +22,10 @@ static void virtio_mem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
VirtIOMEMPCI *mem_pci = VIRTIO_MEM_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&mem_pci->vdev);
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = 2;
+ }
+
virtio_pci_force_virtio_1(vpci_dev);
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
@@ -152,7 +156,14 @@ static void virtio_mem_pci_set_requested_size(Object *obj, Visitor *v,
object_property_set(OBJECT(&pci_mem->vdev), name, v, errp);
}
-static void virtio_mem_pci_class_init(ObjectClass *klass, void *data)
+static const Property virtio_mem_pci_class_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+};
+
+static void virtio_mem_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
@@ -164,6 +175,7 @@ static void virtio_mem_pci_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS;
+ device_class_set_props(dc, virtio_mem_pci_class_properties);
mdc->get_addr = virtio_mem_pci_get_addr;
mdc->set_addr = virtio_mem_pci_set_addr;
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index ef64bf1..c46f6f9 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -15,20 +15,20 @@
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/units.h"
-#include "sysemu/numa.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/numa.h"
+#include "system/system.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-mem.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#include "exec/ram_addr.h"
+#include "system/ram_addr.h"
#include "migration/misc.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
-#include CONFIG_DEVICES
+#include "hw/acpi/acpi.h"
#include "trace.h"
static const VMStateDescription vmstate_virtio_mem_device_early;
@@ -61,6 +61,8 @@ static uint32_t virtio_mem_default_thp_size(void)
} else if (qemu_real_host_page_size() == 64 * KiB) {
default_thp_size = 512 * MiB;
}
+#elif defined(__s390x__)
+ default_thp_size = 1 * MiB;
#endif
return default_thp_size;
@@ -88,6 +90,7 @@ static uint32_t virtio_mem_default_thp_size(void)
static uint32_t thp_size;
#define HPAGE_PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
+#define HPAGE_PATH "/sys/kernel/mm/transparent_hugepage/"
static uint32_t virtio_mem_thp_size(void)
{
gchar *content = NULL;
@@ -98,6 +101,12 @@ static uint32_t virtio_mem_thp_size(void)
return thp_size;
}
+ /* No THP -> no restrictions. */
+ if (!g_file_test(HPAGE_PATH, G_FILE_TEST_EXISTS)) {
+ thp_size = VIRTIO_MEM_MIN_BLOCK_SIZE;
+ return thp_size;
+ }
+
/*
* Try to probe the actual THP size, fallback to (sane but eventually
* incorrect) default sizes.
@@ -161,7 +170,7 @@ static bool virtio_mem_has_shared_zeropage(RAMBlock *rb)
* necessary (as the section size can change). But it's more likely that the
* section size will rather get smaller and not bigger over time.
*/
-#if defined(TARGET_X86_64) || defined(TARGET_I386)
+#if defined(TARGET_X86_64) || defined(TARGET_I386) || defined(TARGET_S390X)
#define VIRTIO_MEM_USABLE_EXTENT (2 * (128 * MiB))
#elif defined(TARGET_ARM)
#define VIRTIO_MEM_USABLE_EXTENT (2 * (512 * MiB))
@@ -181,7 +190,7 @@ static bool virtio_mem_is_busy(void)
* after plugging them) until we're running on the destination (as we didn't
* migrate these blocks when they were unplugged).
*/
- return migration_in_incoming_postcopy() || !migration_is_idle();
+ return migration_in_incoming_postcopy() || migration_is_running();
}
typedef int (*virtio_mem_range_cb)(VirtIOMEM *vmem, void *arg,
@@ -235,28 +244,6 @@ static int virtio_mem_for_each_plugged_range(VirtIOMEM *vmem, void *arg,
return ret;
}
-/*
- * Adjust the memory section to cover the intersection with the given range.
- *
- * Returns false if the intersection is empty, otherwise returns true.
- */
-static bool virtio_mem_intersect_memory_section(MemoryRegionSection *s,
- uint64_t offset, uint64_t size)
-{
- uint64_t start = MAX(s->offset_within_region, offset);
- uint64_t end = MIN(s->offset_within_region + int128_get64(s->size),
- offset + size);
-
- if (end <= start) {
- return false;
- }
-
- s->offset_within_address_space += start - s->offset_within_region;
- s->offset_within_region = start;
- s->size = int128_make64(end - start);
- return true;
-}
-
typedef int (*virtio_mem_section_cb)(MemoryRegionSection *s, void *arg);
static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem,
@@ -278,7 +265,7 @@ static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem,
first_bit + 1) - 1;
size = (last_bit - first_bit + 1) * vmem->block_size;
- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) {
+ if (!memory_region_section_intersect_range(&tmp, offset, size)) {
break;
}
ret = cb(&tmp, arg);
@@ -310,7 +297,7 @@ static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem,
first_bit + 1) - 1;
size = (last_bit - first_bit + 1) * vmem->block_size;
- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) {
+ if (!memory_region_section_intersect_range(&tmp, offset, size)) {
break;
}
ret = cb(&tmp, arg);
@@ -346,7 +333,7 @@ static void virtio_mem_notify_unplug(VirtIOMEM *vmem, uint64_t offset,
QLIST_FOREACH(rdl, &vmem->rdl_list, next) {
MemoryRegionSection tmp = *rdl->section;
- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) {
+ if (!memory_region_section_intersect_range(&tmp, offset, size)) {
continue;
}
rdl->notify_discard(rdl, &tmp);
@@ -362,7 +349,7 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset,
QLIST_FOREACH(rdl, &vmem->rdl_list, next) {
MemoryRegionSection tmp = *rdl->section;
- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) {
+ if (!memory_region_section_intersect_range(&tmp, offset, size)) {
continue;
}
ret = rdl->notify_populate(rdl, &tmp);
@@ -379,7 +366,7 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset,
if (rdl2 == rdl) {
break;
}
- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) {
+ if (!memory_region_section_intersect_range(&tmp, offset, size)) {
continue;
}
rdl2->notify_discard(rdl2, &tmp);
@@ -874,15 +861,16 @@ static uint64_t virtio_mem_get_features(VirtIODevice *vdev, uint64_t features,
MachineState *ms = MACHINE(qdev_get_machine());
VirtIOMEM *vmem = VIRTIO_MEM(vdev);
- if (ms->numa_state) {
-#if defined(CONFIG_ACPI)
+ if (ms->numa_state && acpi_builtin()) {
virtio_add_feature(&features, VIRTIO_MEM_F_ACPI_PXM);
-#endif
}
assert(vmem->unplugged_inaccessible != ON_OFF_AUTO_AUTO);
if (vmem->unplugged_inaccessible == ON_OFF_AUTO_ON) {
virtio_add_feature(&features, VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE);
}
+ if (qemu_wakeup_suspend_enabled()) {
+ virtio_add_feature(&features, VIRTIO_MEM_F_PERSISTENT_SUSPEND);
+ }
return features;
}
@@ -895,18 +883,6 @@ static int virtio_mem_validate_features(VirtIODevice *vdev)
return 0;
}
-static void virtio_mem_system_reset(void *opaque)
-{
- VirtIOMEM *vmem = VIRTIO_MEM(opaque);
-
- /*
- * During usual resets, we will unplug all memory and shrink the usable
- * region size. This is, however, not possible in all scenarios. Then,
- * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL).
- */
- virtio_mem_unplug_all(vmem);
-}
-
static void virtio_mem_prepare_mr(VirtIOMEM *vmem)
{
const uint64_t region_size = memory_region_size(&vmem->memdev->mr);
@@ -958,6 +934,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
VirtIOMEM *vmem = VIRTIO_MEM(dev);
uint64_t page_size;
RAMBlock *rb;
+ Object *obj;
int ret;
if (!vmem->memdev) {
@@ -990,7 +967,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
return;
}
- if (enable_mlock) {
+ if (should_mlock(mlock_state)) {
error_setg(errp, "Incompatible with mlock");
return;
}
@@ -1071,6 +1048,17 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
}
/*
+ * Set ourselves as RamDiscardManager before the plug handler maps the
+ * memory region and exposes it via an address space.
+ */
+ if (memory_region_set_ram_discard_manager(&vmem->memdev->mr,
+ RAM_DISCARD_MANAGER(vmem))) {
+ error_setg(errp, "Failed to set RamDiscardManager");
+ ram_block_coordinated_discard_require(false);
+ return;
+ }
+
+ /*
* We don't know at this point whether shared RAM is migrated using
* QEMU or migrated using the file content. "x-ignore-shared" will be
* configured after realizing the device. So in case we have an
@@ -1084,6 +1072,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
ret = ram_block_discard_range(rb, 0, qemu_ram_get_used_length(rb));
if (ret) {
error_setg_errno(errp, -ret, "Unexpected error discarding RAM");
+ memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL);
ram_block_coordinated_discard_require(false);
return;
}
@@ -1123,14 +1112,28 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
vmstate_register_any(VMSTATE_IF(vmem),
&vmstate_virtio_mem_device_early, vmem);
}
- qemu_register_reset(virtio_mem_system_reset, vmem);
/*
- * Set ourselves as RamDiscardManager before the plug handler maps the
- * memory region and exposes it via an address space.
+ * We only want to unplug all memory to start with a clean slate when
+ * it is safe for the guest -- during system resets that call
+ * qemu_devices_reset().
+ *
+ * We'll filter out selected qemu_devices_reset() calls used for other
+ * purposes, like resetting all devices during wakeup from suspend on
+ * x86 based on the reset type passed to qemu_devices_reset().
+ *
+ * Unplugging all memory during simple device resets can result in the VM
+ * unexpectedly losing RAM, corrupting VM state.
+ *
+ * Simple device resets (or resets triggered by getting a parent device
+ * reset) must not change the state of plugged memory blocks. Therefore,
+ * we need a dedicated reset object that only gets called during
+ * qemu_devices_reset().
*/
- memory_region_set_ram_discard_manager(&vmem->memdev->mr,
- RAM_DISCARD_MANAGER(vmem));
+ obj = object_new(TYPE_VIRTIO_MEM_SYSTEM_RESET);
+ vmem->system_reset = VIRTIO_MEM_SYSTEM_RESET(obj);
+ vmem->system_reset->vmem = vmem;
+ qemu_register_resettable(obj);
}
static void virtio_mem_device_unrealize(DeviceState *dev)
@@ -1138,12 +1141,9 @@ static void virtio_mem_device_unrealize(DeviceState *dev)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOMEM *vmem = VIRTIO_MEM(dev);
- /*
- * The unplug handler unmapped the memory region, it cannot be
- * found via an address space anymore. Unset ourselves.
- */
- memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL);
- qemu_unregister_reset(virtio_mem_system_reset, vmem);
+ qemu_unregister_resettable(OBJECT(vmem->system_reset));
+ object_unref(OBJECT(vmem->system_reset));
+
if (vmem->early_migration) {
vmstate_unregister(VMSTATE_IF(vmem), &vmstate_virtio_mem_device_early,
vmem);
@@ -1153,6 +1153,11 @@ static void virtio_mem_device_unrealize(DeviceState *dev)
virtio_del_queue(vdev, 0);
virtio_cleanup(vdev);
g_free(vmem->bitmap);
+ /*
+ * The unplug handler unmapped the memory region, it cannot be
+ * found via an address space anymore. Unset ourselves.
+ */
+ memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL);
ram_block_coordinated_discard_require(false);
}
@@ -1682,7 +1687,7 @@ static void virtio_mem_instance_finalize(Object *obj)
vmem->mr = NULL;
}
-static Property virtio_mem_properties[] = {
+static const Property virtio_mem_properties[] = {
DEFINE_PROP_UINT64(VIRTIO_MEM_ADDR_PROP, VirtIOMEM, addr, 0),
DEFINE_PROP_UINT32(VIRTIO_MEM_NODE_PROP, VirtIOMEM, node, 0),
DEFINE_PROP_BOOL(VIRTIO_MEM_PREALLOC_PROP, VirtIOMEM, prealloc, false),
@@ -1696,7 +1701,6 @@ static Property virtio_mem_properties[] = {
early_migration, true),
DEFINE_PROP_BOOL(VIRTIO_MEM_DYNAMIC_MEMSLOTS_PROP, VirtIOMEM,
dynamic_memslots, false),
- DEFINE_PROP_END_OF_LIST(),
};
static uint64_t virtio_mem_rdm_get_min_granularity(const RamDiscardManager *rdm,
@@ -1728,7 +1732,7 @@ static bool virtio_mem_rdm_is_populated(const RamDiscardManager *rdm,
}
struct VirtIOMEMReplayData {
- void *fn;
+ ReplayRamDiscardState fn;
void *opaque;
};
@@ -1736,12 +1740,12 @@ static int virtio_mem_rdm_replay_populated_cb(MemoryRegionSection *s, void *arg)
{
struct VirtIOMEMReplayData *data = arg;
- return ((ReplayRamPopulate)data->fn)(s, data->opaque);
+ return data->fn(s, data->opaque);
}
static int virtio_mem_rdm_replay_populated(const RamDiscardManager *rdm,
MemoryRegionSection *s,
- ReplayRamPopulate replay_fn,
+ ReplayRamDiscardState replay_fn,
void *opaque)
{
const VirtIOMEM *vmem = VIRTIO_MEM(rdm);
@@ -1760,14 +1764,13 @@ static int virtio_mem_rdm_replay_discarded_cb(MemoryRegionSection *s,
{
struct VirtIOMEMReplayData *data = arg;
- ((ReplayRamDiscard)data->fn)(s, data->opaque);
- return 0;
+ return data->fn(s, data->opaque);
}
-static void virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm,
- MemoryRegionSection *s,
- ReplayRamDiscard replay_fn,
- void *opaque)
+static int virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm,
+ MemoryRegionSection *s,
+ ReplayRamDiscardState replay_fn,
+ void *opaque)
{
const VirtIOMEM *vmem = VIRTIO_MEM(rdm);
struct VirtIOMEMReplayData data = {
@@ -1776,8 +1779,8 @@ static void virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm,
};
g_assert(s->mr == &vmem->memdev->mr);
- virtio_mem_for_each_unplugged_section(vmem, s, &data,
- virtio_mem_rdm_replay_discarded_cb);
+ return virtio_mem_for_each_unplugged_section(vmem, s, &data,
+ virtio_mem_rdm_replay_discarded_cb);
}
static void virtio_mem_rdm_register_listener(RamDiscardManager *rdm,
@@ -1843,7 +1846,7 @@ static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp)
}
}
-static void virtio_mem_class_init(ObjectClass *klass, void *data)
+static void virtio_mem_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -1885,7 +1888,7 @@ static const TypeInfo virtio_mem_info = {
.instance_finalize = virtio_mem_instance_finalize,
.class_init = virtio_mem_class_init,
.class_size = sizeof(VirtIOMEMClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_RAM_DISCARD_MANAGER },
{ }
},
@@ -1897,3 +1900,49 @@ static void virtio_register_types(void)
}
type_init(virtio_register_types)
+
+OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(VirtioMemSystemReset, virtio_mem_system_reset, VIRTIO_MEM_SYSTEM_RESET, OBJECT, { TYPE_RESETTABLE_INTERFACE }, { })
+
+static void virtio_mem_system_reset_init(Object *obj)
+{
+}
+
+static void virtio_mem_system_reset_finalize(Object *obj)
+{
+}
+
+static ResettableState *virtio_mem_system_reset_get_state(Object *obj)
+{
+ VirtioMemSystemReset *vmem_reset = VIRTIO_MEM_SYSTEM_RESET(obj);
+
+ return &vmem_reset->reset_state;
+}
+
+static void virtio_mem_system_reset_hold(Object *obj, ResetType type)
+{
+ VirtioMemSystemReset *vmem_reset = VIRTIO_MEM_SYSTEM_RESET(obj);
+ VirtIOMEM *vmem = vmem_reset->vmem;
+
+ /*
+ * When waking up from standby/suspend-to-ram, do not unplug any memory.
+ */
+ if (type == RESET_TYPE_WAKEUP) {
+ return;
+ }
+
+ /*
+ * During usual resets, we will unplug all memory and shrink the usable
+ * region size. This is, however, not possible in all scenarios. Then,
+ * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL).
+ */
+ virtio_mem_unplug_all(vmem);
+}
+
+static void virtio_mem_system_reset_class_init(ObjectClass *klass,
+ const void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->get_state = virtio_mem_system_reset_get_state;
+ rc->phases.hold = virtio_mem_system_reset_hold;
+}
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 320428a..532c671 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -28,8 +28,8 @@
#include "migration/qemu-file-types.h"
#include "qemu/host-utils.h"
#include "qemu/module.h"
-#include "sysemu/kvm.h"
-#include "sysemu/replay.h"
+#include "system/kvm.h"
+#include "system/replay.h"
#include "hw/virtio/virtio-mmio.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
@@ -751,13 +751,12 @@ static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
/* virtio-mmio device */
-static Property virtio_mmio_properties[] = {
+static const Property virtio_mmio_properties[] = {
DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
format_transport_address, true),
DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true),
DEFINE_PROP_BIT("ioeventfd", VirtIOMMIOProxy, flags,
VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
@@ -785,12 +784,12 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
sysbus_init_mmio(sbd, &proxy->iomem);
}
-static void virtio_mmio_class_init(ObjectClass *klass, void *data)
+static void virtio_mmio_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = virtio_mmio_realizefn;
- dc->reset = virtio_mmio_reset;
+ device_class_set_legacy_reset(dc, virtio_mmio_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
device_class_set_props(dc, virtio_mmio_properties);
}
@@ -856,7 +855,7 @@ static void virtio_mmio_vmstate_change(DeviceState *d, bool running)
}
}
-static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
+static void virtio_mmio_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *bus_class = BUS_CLASS(klass);
VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c
index e03543a..f857a84 100644
--- a/hw/virtio/virtio-net-pci.c
+++ b/hw/virtio/virtio-net-pci.c
@@ -38,12 +38,11 @@ struct VirtIONetPCI {
VirtIONet vdev;
};
-static Property virtio_net_properties[] = {
+static const Property virtio_net_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -64,7 +63,7 @@ static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_net_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -75,6 +74,7 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
k->revision = VIRTIO_PCI_ABI_VERSION;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ k->sriov_vf_user_creatable = true;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
device_class_set_props(dc, virtio_net_properties);
vpciklass->realize = virtio_net_pci_realize;
diff --git a/hw/virtio/virtio-nsm-pci.c b/hw/virtio/virtio-nsm-pci.c
new file mode 100644
index 0000000..ec24396
--- /dev/null
+++ b/hw/virtio/virtio-nsm-pci.c
@@ -0,0 +1,73 @@
+/*
+ * AWS Nitro Secure Module (NSM) device
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/virtio/virtio-pci.h"
+#include "hw/virtio/virtio-nsm.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "qom/object.h"
+
+typedef struct VirtIONsmPCI VirtIONsmPCI;
+
+#define TYPE_VIRTIO_NSM_PCI "virtio-nsm-pci-base"
+DECLARE_INSTANCE_CHECKER(VirtIONsmPCI, VIRTIO_NSM_PCI,
+ TYPE_VIRTIO_NSM_PCI)
+
+struct VirtIONsmPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIONSM vdev;
+};
+
+static void virtio_nsm_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIONsmPCI *vnsm = VIRTIO_NSM_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&vnsm->vdev);
+
+ virtio_pci_force_virtio_1(vpci_dev);
+
+ if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) {
+ return;
+ }
+}
+
+static void virtio_nsm_pci_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+
+ k->realize = virtio_nsm_pci_realize;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static void virtio_nsm_initfn(Object *obj)
+{
+ VirtIONsmPCI *dev = VIRTIO_NSM_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_NSM);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_nsm_pci_info = {
+ .base_name = TYPE_VIRTIO_NSM_PCI,
+ .generic_name = "virtio-nsm-pci",
+ .instance_size = sizeof(VirtIONsmPCI),
+ .instance_init = virtio_nsm_initfn,
+ .class_init = virtio_nsm_pci_class_init,
+};
+
+static void virtio_nsm_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_nsm_pci_info);
+}
+
+type_init(virtio_nsm_pci_register)
diff --git a/hw/virtio/virtio-nsm.c b/hw/virtio/virtio-nsm.c
new file mode 100644
index 0000000..3bf5e70
--- /dev/null
+++ b/hw/virtio/virtio-nsm.c
@@ -0,0 +1,1737 @@
+/*
+ * AWS Nitro Secure Module (NSM) device
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/iov.h"
+#include "qemu/guest-random.h"
+#include "qapi/error.h"
+
+#include "crypto/hash.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-nsm.h"
+#include "hw/virtio/cbor-helpers.h"
+#include "standard-headers/linux/virtio_ids.h"
+
+#define NSM_REQUEST_MAX_SIZE 0x1000
+#define NSM_RESPONSE_BUF_SIZE 0x3000
+#define NSM_RND_BUF_SIZE 256
+
+enum NSMResponseTypes {
+ NSM_SUCCESS = 0,
+ NSM_INVALID_ARGUMENT = 1,
+ NSM_INVALID_INDEX = 2,
+ NSM_READONLY_INDEX = 3,
+ NSM_INVALID_OPERATION = 4,
+ NSM_BUFFER_TOO_SMALL = 5,
+ NSM_INPUT_TOO_LARGE = 6,
+ NSM_INTERNAL_ERROR = 7,
+};
+
+static const char *error_string(enum NSMResponseTypes type)
+{
+ const char *str;
+ switch (type) {
+ case NSM_INVALID_ARGUMENT:
+ str = "InvalidArgument";
+ break;
+ case NSM_INVALID_INDEX:
+ str = "InvalidIndex";
+ break;
+ case NSM_READONLY_INDEX:
+ str = "ReadOnlyIndex";
+ break;
+ case NSM_INVALID_OPERATION:
+ str = "InvalidOperation";
+ break;
+ case NSM_BUFFER_TOO_SMALL:
+ str = "BufferTooSmall";
+ break;
+ case NSM_INPUT_TOO_LARGE:
+ str = "InputTooLarge";
+ break;
+ default:
+ str = "InternalError";
+ break;
+ }
+
+ return str;
+}
+
+/*
+ * Error response structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("Error"),
+ * value = String(error_name)
+ * }
+ * }
+ *
+ * where error_name can be one of the following:
+ * InvalidArgument
+ * InvalidIndex
+ * InvalidResponse
+ * ReadOnlyIndex
+ * InvalidOperation
+ * BufferTooSmall
+ * InputTooLarge
+ * InternalError
+ */
+
+static bool error_response(struct iovec *response, enum NSMResponseTypes error,
+ Error **errp)
+{
+ cbor_item_t *root;
+ size_t len;
+ bool r = false;
+
+ root = cbor_new_definite_map(1);
+ if (!root) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_string_to_map(root, "Error", error_string(error))) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ error_setg(errp, "Response buffer is small for %s response",
+ error_string(error));
+ goto out;
+ }
+ response->iov_len = len;
+ r = true;
+
+ out:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+
+ err:
+ error_setg(errp, "Failed to initialize %s response", error_string(error));
+ goto out;
+}
+
+/*
+ * GetRandom response structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("GetRandom"),
+ * value = Map(1) {
+ * key = String("random"),
+ * value = Byte_String()
+ * }
+ * }
+ * }
+ */
+static bool handle_get_random(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp)
+{
+ cbor_item_t *root, *nested_map;
+ size_t len;
+ uint8_t rnd[NSM_RND_BUF_SIZE];
+ bool r = false;
+
+ root = cbor_new_definite_map(1);
+ if (!root) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_map_to_map(root, "GetRandom", 1, &nested_map)) {
+ goto err;
+ }
+
+ qemu_guest_getrandom_nofail(rnd, NSM_RND_BUF_SIZE);
+
+ if (!qemu_cbor_add_bytestring_to_map(nested_map, "random", rnd,
+ NSM_RND_BUF_SIZE)) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ response->iov_len = len;
+ r = true;
+
+ out:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+
+ err:
+ error_setg(errp, "Failed to initialize GetRandom response");
+ goto out;
+}
+
+/*
+ * DescribeNSM response structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("DescribeNSM"),
+ * value = Map(7) {
+ * key = String("digest"),
+ * value = String("SHA384"),
+ * key = String("max_pcrs"),
+ * value = Uint8(32),
+ * key = String("module_id"),
+ * value = String("i-1234-enc5678"),
+ * key = String("locked_pcrs"),
+ * value = Array<Uint8>(),
+ * key = String("version_major"),
+ * value = Uint8(1),
+ * key = String("version_minor"),
+ * value = Uint8(0),
+ * key = String("version_patch"),
+ * value = Uint8(0)
+ * }
+ * }
+ * }
+ */
+static bool handle_describe_nsm(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp)
+{
+ cbor_item_t *root, *nested_map;
+ uint16_t locked_pcrs_cnt = 0;
+ uint8_t locked_pcrs_ind[NSM_MAX_PCRS];
+ size_t len;
+ bool r = false;
+
+ root = cbor_new_definite_map(1);
+ if (!root) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_map_to_map(root, "DescribeNSM", 7, &nested_map)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_string_to_map(nested_map, "digest", vnsm->digest)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_uint8_to_map(nested_map, "max_pcrs", vnsm->max_pcrs)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_string_to_map(nested_map, "module_id",
+ vnsm->module_id)) {
+ goto err;
+ }
+
+ for (uint8_t i = 0; i < NSM_MAX_PCRS; ++i) {
+ if (vnsm->pcrs[i].locked) {
+ locked_pcrs_ind[locked_pcrs_cnt++] = i;
+ }
+ }
+ if (!qemu_cbor_add_uint8_array_to_map(nested_map, "locked_pcrs",
+ locked_pcrs_ind, locked_pcrs_cnt)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_uint8_to_map(nested_map, "version_major",
+ vnsm->version_major)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_uint8_to_map(nested_map, "version_minor",
+ vnsm->version_minor)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_uint8_to_map(nested_map, "version_patch",
+ vnsm->version_patch)) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ response->iov_len = len;
+ r = true;
+
+ out:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+
+ err:
+ error_setg(errp, "Failed to initialize DescribeNSM response");
+ goto out;
+}
+
+/*
+ * DescribePCR request structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("DescribePCR"),
+ * value = Map(1) {
+ * key = String("index"),
+ * value = Uint8(pcr)
+ * }
+ * }
+ * }
+ */
+typedef struct NSMDescribePCRReq {
+ uint8_t index;
+} NSMDescribePCRReq;
+
+static enum NSMResponseTypes get_nsm_describe_pcr_req(
+ uint8_t *req, size_t len,
+ NSMDescribePCRReq *nsm_req)
+{
+ size_t size;
+ uint8_t *str;
+ struct cbor_pair *pair;
+ cbor_item_t *item = NULL;
+ struct cbor_load_result result;
+ enum NSMResponseTypes r = NSM_INVALID_OPERATION;
+
+ item = cbor_load(req, len, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(item);
+ if (!cbor_isa_map(pair->value)) {
+ goto cleanup;
+ }
+ size = cbor_map_size(pair->value);
+ if (size < 1) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(pair->value);
+ for (int i = 0; i < size; ++i) {
+ if (!cbor_isa_string(pair[i].key)) {
+ continue;
+ }
+
+ str = cbor_string_handle(pair[i].key);
+ if (str && cbor_string_length(pair[i].key) == 5 &&
+ memcmp(str, "index", 5) == 0) {
+ if (!cbor_isa_uint(pair[i].value) ||
+ cbor_int_get_width(pair[i].value) != CBOR_INT_8) {
+ break;
+ }
+
+ nsm_req->index = cbor_get_uint8(pair[i].value);
+ r = NSM_SUCCESS;
+ break;
+ }
+ }
+
+ cleanup:
+ if (item) {
+ cbor_decref(&item);
+ }
+ return r;
+}
+
+/*
+ * DescribePCR response structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("DescribePCR"),
+ * value = Map(2) {
+ * key = String("data"),
+ * value = Byte_String(),
+ * key = String("lock"),
+ * value = Bool()
+ * }
+ * }
+ * }
+ */
+static bool handle_describe_pcr(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp)
+{
+ cbor_item_t *root = NULL;
+ cbor_item_t *nested_map;
+ size_t len;
+ NSMDescribePCRReq nsm_req;
+ enum NSMResponseTypes type;
+ struct PCRInfo *pcr;
+ bool r = false;
+
+ type = get_nsm_describe_pcr_req(request->iov_base, request->iov_len,
+ &nsm_req);
+ if (type != NSM_SUCCESS) {
+ if (error_response(response, type, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+ if (nsm_req.index >= vnsm->max_pcrs) {
+ if (error_response(response, NSM_INVALID_INDEX, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+ pcr = &(vnsm->pcrs[nsm_req.index]);
+
+ root = cbor_new_definite_map(1);
+ if (!root) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_map_to_map(root, "DescribePCR", 2, &nested_map)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_bytestring_to_map(nested_map, "data", pcr->data,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_bool_to_map(nested_map, "lock", pcr->locked)) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ response->iov_len = len;
+ r = true;
+
+ out:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+
+ err:
+ error_setg(errp, "Failed to initialize DescribePCR response");
+ goto out;
+}
+
+/*
+ * ExtendPCR request structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("ExtendPCR"),
+ * value = Map(2) {
+ * key = String("index"),
+ * value = Uint8(pcr),
+ * key = String("data"),
+ * value = Byte_String(data) || String(data),
+ * }
+ * }
+ * }
+ */
+typedef struct NSMExtendPCRReq {
+ uint8_t index;
+ uint16_t data_len;
+ uint8_t data[NSM_REQUEST_MAX_SIZE];
+} NSMExtendPCRReq;
+
+static enum NSMResponseTypes get_nsm_extend_pcr_req(uint8_t *req, size_t len,
+ NSMExtendPCRReq *nsm_req)
+{
+ cbor_item_t *item = NULL;
+ size_t size ;
+ uint8_t *str;
+ bool index_found = false;
+ bool data_found = false;
+ struct cbor_pair *pair;
+ struct cbor_load_result result;
+ enum NSMResponseTypes r = NSM_INVALID_OPERATION;
+
+ item = cbor_load(req, len, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(item);
+ if (!cbor_isa_map(pair->value)) {
+ goto cleanup;
+ }
+ size = cbor_map_size(pair->value);
+ if (size < 2) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(pair->value);
+ for (int i = 0; i < size; ++i) {
+ if (!cbor_isa_string(pair[i].key)) {
+ continue;
+ }
+ str = cbor_string_handle(pair[i].key);
+ if (!str) {
+ continue;
+ }
+
+ if (cbor_string_length(pair[i].key) == 5 &&
+ memcmp(str, "index", 5) == 0) {
+ if (!cbor_isa_uint(pair[i].value) ||
+ cbor_int_get_width(pair[i].value) != CBOR_INT_8) {
+ goto cleanup;
+ }
+ nsm_req->index = cbor_get_uint8(pair[i].value);
+ index_found = true;
+ continue;
+ }
+
+ if (cbor_string_length(pair[i].key) == 4 &&
+ memcmp(str, "data", 4) == 0) {
+ if (cbor_isa_bytestring(pair[i].value)) {
+ str = cbor_bytestring_handle(pair[i].value);
+ if (!str) {
+ goto cleanup;
+ }
+ nsm_req->data_len = cbor_bytestring_length(pair[i].value);
+ } else if (cbor_isa_string(pair[i].value)) {
+ str = cbor_string_handle(pair[i].value);
+ if (!str) {
+ goto cleanup;
+ }
+ nsm_req->data_len = cbor_string_length(pair[i].value);
+ } else {
+ goto cleanup;
+ }
+ /*
+ * nsm_req->data_len will be smaller than NSM_REQUEST_MAX_SIZE as
+ * we already check for the max request size before processing
+ * any request. So it's safe to copy.
+ */
+ memcpy(nsm_req->data, str, nsm_req->data_len);
+ data_found = true;
+ continue;
+ }
+ }
+
+ if (index_found && data_found) {
+ r = NSM_SUCCESS;
+ }
+
+ cleanup:
+ if (item) {
+ cbor_decref(&item);
+ }
+ return r;
+}
+
+/*
+ * ExtendPCR response structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("ExtendPCR"),
+ * value = Map(1) {
+ * key = String("data"),
+ * value = Byte_String()
+ * }
+ * }
+ * }
+ */
+static bool handle_extend_pcr(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp)
+{
+ cbor_item_t *root = NULL;
+ cbor_item_t *nested_map;
+ size_t len;
+ struct PCRInfo *pcr;
+ enum NSMResponseTypes type;
+ bool r = false;
+ g_autofree NSMExtendPCRReq *nsm_req = g_malloc(sizeof(NSMExtendPCRReq));
+
+ type = get_nsm_extend_pcr_req(request->iov_base, request->iov_len,
+ nsm_req);
+ if (type != NSM_SUCCESS) {
+ if (error_response(response, type, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+ if (nsm_req->index >= vnsm->max_pcrs) {
+ if (error_response(response, NSM_INVALID_INDEX, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ pcr = &(vnsm->pcrs[nsm_req->index]);
+
+ if (pcr->locked) {
+ if (error_response(response, NSM_READONLY_INDEX, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ if (!vnsm->extend_pcr(vnsm, nsm_req->index, nsm_req->data,
+ nsm_req->data_len)) {
+ if (error_response(response, NSM_INTERNAL_ERROR, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ root = cbor_new_definite_map(1);
+ if (!root) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_map_to_map(root, "ExtendPCR", 1, &nested_map)) {
+ goto err;
+ }
+
+ if (!qemu_cbor_add_bytestring_to_map(nested_map, "data", pcr->data,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384)) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ if (error_response(response, NSM_BUFFER_TOO_SMALL, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ response->iov_len = len;
+ r = true;
+
+ out:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+
+ err:
+ error_setg(errp, "Failed to initialize DescribePCR response");
+ goto out;
+}
+
+/*
+ * LockPCR request structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("LockPCR"),
+ * value = Map(1) {
+ * key = String("index"),
+ * value = Uint8(pcr)
+ * }
+ * }
+ * }
+ */
+typedef struct NSMLockPCRReq {
+ uint8_t index;
+} NSMLockPCRReq;
+
+static enum NSMResponseTypes get_nsm_lock_pcr_req(uint8_t *req, size_t len,
+ NSMLockPCRReq *nsm_req)
+{
+ cbor_item_t *item = NULL;
+ size_t size;
+ uint8_t *str;
+ struct cbor_pair *pair;
+ struct cbor_load_result result;
+ enum NSMResponseTypes r = NSM_INVALID_OPERATION;
+
+ item = cbor_load(req, len, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(item);
+ if (!cbor_isa_map(pair->value)) {
+ goto cleanup;
+ }
+ size = cbor_map_size(pair->value);
+ if (size < 1) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(pair->value);
+ for (int i = 0; i < size; ++i) {
+ if (!cbor_isa_string(pair[i].key)) {
+ continue;
+ }
+ str = cbor_string_handle(pair[i].key);
+ if (str && cbor_string_length(pair[i].key) == 5 &&
+ memcmp(str, "index", 5) == 0) {
+ if (!cbor_isa_uint(pair[i].value) ||
+ cbor_int_get_width(pair[i].value) != CBOR_INT_8) {
+ break;
+ }
+
+ nsm_req->index = cbor_get_uint8(pair[i].value);
+ r = NSM_SUCCESS;
+ break;
+ }
+ }
+
+ cleanup:
+ if (item) {
+ cbor_decref(&item);
+ }
+ return r;
+}
+
+/*
+ * LockPCR success response structure:
+ * {
+ * String("LockPCR")
+ * }
+ */
+static bool handle_lock_pcr(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp)
+{
+ cbor_item_t *root = NULL;
+ size_t len;
+ NSMLockPCRReq nsm_req;
+ enum NSMResponseTypes type;
+ struct PCRInfo *pcr;
+ bool r = false;
+
+ type = get_nsm_lock_pcr_req(request->iov_base, request->iov_len, &nsm_req);
+ if (type != NSM_SUCCESS) {
+ if (error_response(response, type, errp)) {
+ r = true;
+ }
+ goto cleanup;
+ }
+ if (nsm_req.index >= vnsm->max_pcrs) {
+ if (error_response(response, NSM_INVALID_INDEX, errp)) {
+ r = true;
+ }
+ goto cleanup;
+ }
+
+ pcr = &(vnsm->pcrs[nsm_req.index]);
+
+ if (pcr->locked) {
+ if (error_response(response, NSM_READONLY_INDEX, errp)) {
+ r = true;
+ }
+ goto cleanup;
+ }
+
+ pcr->locked = true;
+
+ root = cbor_build_string("LockPCR");
+ if (!root) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ if (error_response(response, NSM_BUFFER_TOO_SMALL, errp)) {
+ r = true;
+ }
+ goto cleanup;
+ }
+
+ response->iov_len = len;
+ r = true;
+ goto cleanup;
+
+ err:
+ error_setg(errp, "Failed to initialize LockPCR response");
+
+ cleanup:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+}
+
+/*
+ * LockPCRs request structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("LockPCRs"),
+ * value = Map(1) {
+ * key = String("range"),
+ * value = Uint8(pcr)
+ * }
+ * }
+ * }
+ */
+typedef struct NSMLockPCRsReq {
+ uint16_t range;
+} NSMLockPCRsReq;
+
+static enum NSMResponseTypes get_nsm_lock_pcrs_req(uint8_t *req, size_t len,
+ NSMLockPCRsReq *nsm_req)
+{
+ cbor_item_t *item = NULL;
+ size_t size;
+ uint8_t *str;
+ struct cbor_pair *pair;
+ struct cbor_load_result result;
+ enum NSMResponseTypes r = NSM_INVALID_OPERATION;
+
+ item = cbor_load(req, len, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(item);
+ if (!cbor_isa_map(pair->value)) {
+ goto cleanup;
+ }
+ size = cbor_map_size(pair->value);
+ if (size < 1) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(pair->value);
+ for (int i = 0; i < size; ++i) {
+ if (!cbor_isa_string(pair[i].key)) {
+ continue;
+ }
+ str = cbor_string_handle(pair[i].key);
+ if (str && cbor_string_length(pair[i].key) == 5 &&
+ memcmp(str, "range", 5) == 0) {
+ if (!cbor_isa_uint(pair[i].value) ||
+ cbor_int_get_width(pair[i].value) != CBOR_INT_8) {
+ break;
+ }
+
+ nsm_req->range = cbor_get_uint8(pair[i].value);
+ r = NSM_SUCCESS;
+ break;
+ }
+ }
+
+ cleanup:
+ if (item) {
+ cbor_decref(&item);
+ }
+ return r;
+}
+
+/*
+ * LockPCRs success response structure:
+ * {
+ * String("LockPCRs")
+ * }
+ */
+static bool handle_lock_pcrs(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp)
+{
+ cbor_item_t *root = NULL;
+ size_t len;
+ NSMLockPCRsReq nsm_req;
+ enum NSMResponseTypes type;
+ bool r = false;
+
+ type = get_nsm_lock_pcrs_req(request->iov_base, request->iov_len, &nsm_req);
+ if (type != NSM_SUCCESS) {
+ if (error_response(response, type, errp)) {
+ r = true;
+ }
+ goto cleanup;
+ }
+ if (nsm_req.range > vnsm->max_pcrs) {
+ if (error_response(response, NSM_INVALID_INDEX, errp)) {
+ r = true;
+ }
+ goto cleanup;
+ }
+
+ for (int i = 0; i < nsm_req.range; ++i) {
+ vnsm->pcrs[i].locked = true;
+ }
+
+ root = cbor_build_string("LockPCRs");
+ if (!root) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ if (error_response(response, NSM_BUFFER_TOO_SMALL, errp)) {
+ r = true;
+ }
+ goto cleanup;
+ }
+
+ response->iov_len = len;
+ r = true;
+ goto cleanup;
+
+ err:
+ error_setg(errp, "Failed to initialize response");
+
+ cleanup:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+}
+
+/*
+ * Attestation request structure:
+ *
+ * Map(1) {
+ * key = String("Attestation"),
+ * value = Map(3) {
+ * key = String("user_data"),
+ * value = Byte_String() || null, // Optional
+ * key = String("nonce"),
+ * value = Byte_String() || null, // Optional
+ * key = String("public_key"),
+ * value = Byte_String() || null, // Optional
+ * }
+ * }
+ * }
+ */
+
+struct AttestationProperty {
+ bool is_null; /* True if property is not present in map or is null */
+ uint16_t len;
+ uint8_t buf[NSM_REQUEST_MAX_SIZE];
+};
+
+typedef struct NSMAttestationReq {
+ struct AttestationProperty public_key;
+ struct AttestationProperty user_data;
+ struct AttestationProperty nonce;
+} NSMAttestationReq;
+
+static bool fill_attestation_property(struct AttestationProperty *prop,
+ cbor_item_t *value)
+{
+ uint8_t *str;
+ bool ret = false;
+
+ if (cbor_is_null(value)) {
+ prop->is_null = true;
+ ret = true;
+ goto out;
+ } else if (cbor_isa_bytestring(value)) {
+ str = cbor_bytestring_handle(value);
+ if (!str) {
+ goto out;
+ }
+ prop->len = cbor_bytestring_length(value);
+ } else if (cbor_isa_string(value)) {
+ str = cbor_string_handle(value);
+ if (!str) {
+ goto out;
+ }
+ prop->len = cbor_string_length(value);
+ } else {
+ goto out;
+ }
+
+ /*
+ * prop->len will be smaller than NSM_REQUEST_MAX_SIZE as we
+ * already check for the max request size before processing
+ * any request. So it's safe to copy.
+ */
+ memcpy(prop->buf, str, prop->len);
+ prop->is_null = false;
+ ret = true;
+
+ out:
+ return ret;
+}
+
+static enum NSMResponseTypes get_nsm_attestation_req(uint8_t *req, size_t len,
+ NSMAttestationReq *nsm_req)
+{
+ cbor_item_t *item = NULL;
+ size_t size;
+ uint8_t *str;
+ struct cbor_pair *pair;
+ struct cbor_load_result result;
+ enum NSMResponseTypes r = NSM_INVALID_OPERATION;
+
+ nsm_req->public_key.is_null = true;
+ nsm_req->user_data.is_null = true;
+ nsm_req->nonce.is_null = true;
+
+ item = cbor_load(req, len, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(item);
+ if (!cbor_isa_map(pair->value)) {
+ goto cleanup;
+ }
+ size = cbor_map_size(pair->value);
+ if (size == 0) {
+ r = NSM_SUCCESS;
+ goto cleanup;
+ }
+
+ pair = cbor_map_handle(pair->value);
+ for (int i = 0; i < size; ++i) {
+ if (!cbor_isa_string(pair[i].key)) {
+ continue;
+ }
+
+ str = cbor_string_handle(pair[i].key);
+ if (!str) {
+ continue;
+ }
+
+ if (cbor_string_length(pair[i].key) == 10 &&
+ memcmp(str, "public_key", 10) == 0) {
+ if (!fill_attestation_property(&(nsm_req->public_key),
+ pair[i].value)) {
+ goto cleanup;
+ }
+ continue;
+ }
+
+ if (cbor_string_length(pair[i].key) == 9 &&
+ memcmp(str, "user_data", 9) == 0) {
+ if (!fill_attestation_property(&(nsm_req->user_data),
+ pair[i].value)) {
+ goto cleanup;
+ }
+ continue;
+ }
+
+ if (cbor_string_length(pair[i].key) == 5 &&
+ memcmp(str, "nonce", 5) == 0) {
+ if (!fill_attestation_property(&(nsm_req->nonce), pair[i].value)) {
+ goto cleanup;
+ }
+ continue;
+ }
+ }
+
+ r = NSM_SUCCESS;
+
+ cleanup:
+ if (item) {
+ cbor_decref(&item);
+ }
+ return r;
+}
+
+static bool add_protected_header_to_cose(cbor_item_t *cose)
+{
+ cbor_item_t *map = NULL;
+ cbor_item_t *key = NULL;
+ cbor_item_t *value = NULL;
+ cbor_item_t *bs = NULL;
+ size_t len;
+ bool r = false;
+ size_t buf_len = 4096;
+ g_autofree uint8_t *buf = g_malloc(buf_len);
+
+ map = cbor_new_definite_map(1);
+ if (!map) {
+ goto cleanup;
+ }
+ key = cbor_build_uint8(1);
+ if (!key) {
+ goto cleanup;
+ }
+ value = cbor_new_int8();
+ if (!value) {
+ goto cleanup;
+ }
+ cbor_mark_negint(value);
+ /* we don't actually sign the data, so we use -1 as the 'alg' value */
+ cbor_set_uint8(value, 0);
+
+ if (!qemu_cbor_map_add(map, key, value)) {
+ goto cleanup;
+ }
+
+ len = cbor_serialize(map, buf, buf_len);
+ if (len == 0) {
+ goto cleanup_map;
+ }
+
+ bs = cbor_build_bytestring(buf, len);
+ if (!bs) {
+ goto cleanup_map;
+ }
+ if (!qemu_cbor_array_push(cose, bs)) {
+ cbor_decref(&bs);
+ goto cleanup_map;
+ }
+ r = true;
+ goto cleanup_map;
+
+ cleanup:
+ if (key) {
+ cbor_decref(&key);
+ }
+ if (value) {
+ cbor_decref(&value);
+ }
+
+ cleanup_map:
+ if (map) {
+ cbor_decref(&map);
+ }
+ return r;
+}
+
+static bool add_unprotected_header_to_cose(cbor_item_t *cose)
+{
+ cbor_item_t *map = cbor_new_definite_map(0);
+ if (!map) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_array_push(cose, map)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (map) {
+ cbor_decref(&map);
+ }
+ return false;
+}
+
+static bool add_ca_bundle_to_payload(cbor_item_t *map)
+{
+ cbor_item_t *key_cbor = NULL;
+ cbor_item_t *value_cbor = NULL;
+ cbor_item_t *bs = NULL;
+ uint8_t zero[64] = {0};
+
+ key_cbor = cbor_build_string("cabundle");
+ if (!key_cbor) {
+ goto cleanup;
+ }
+ value_cbor = cbor_new_definite_array(1);
+ if (!value_cbor) {
+ goto cleanup;
+ }
+ bs = cbor_build_bytestring(zero, 64);
+ if (!bs) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_array_push(value_cbor, bs)) {
+ cbor_decref(&bs);
+ goto cleanup;
+ }
+ if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (key_cbor) {
+ cbor_decref(&key_cbor);
+ }
+ if (value_cbor) {
+ cbor_decref(&value_cbor);
+ }
+ return false;
+}
+
+static bool add_payload_to_cose(cbor_item_t *cose, VirtIONSM *vnsm,
+ NSMAttestationReq *req)
+{
+ cbor_item_t *root = NULL;
+ cbor_item_t *nested_map;
+ cbor_item_t *bs = NULL;
+ size_t locked_cnt;
+ uint8_t ind[NSM_MAX_PCRS];
+ size_t payload_map_size = 9;
+ size_t len;
+ struct PCRInfo *pcr;
+ uint8_t zero[64] = {0};
+ bool r = false;
+ size_t buf_len = 16384;
+ g_autofree uint8_t *buf = g_malloc(buf_len);
+
+ root = cbor_new_definite_map(payload_map_size);
+ if (!root) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_add_string_to_map(root, "module_id", vnsm->module_id)) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_add_string_to_map(root, "digest", vnsm->digest)) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_add_uint64_to_map(root, "timestamp",
+ (uint64_t) time(NULL) * 1000)) {
+ goto cleanup;
+ }
+
+ locked_cnt = 0;
+ for (uint8_t i = 0; i < NSM_MAX_PCRS; ++i) {
+ if (vnsm->pcrs[i].locked) {
+ ind[locked_cnt++] = i;
+ }
+ }
+ if (!qemu_cbor_add_map_to_map(root, "pcrs", locked_cnt, &nested_map)) {
+ goto cleanup;
+ }
+ for (uint8_t i = 0; i < locked_cnt; ++i) {
+ pcr = &(vnsm->pcrs[ind[i]]);
+ if (!qemu_cbor_add_uint8_key_bytestring_to_map(
+ nested_map, ind[i],
+ pcr->data,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384)) {
+ goto cleanup;
+ }
+ }
+ if (!qemu_cbor_add_bytestring_to_map(root, "certificate", zero, 64)) {
+ goto cleanup;
+ }
+ if (!add_ca_bundle_to_payload(root)) {
+ goto cleanup;
+ }
+
+ if (req->public_key.is_null) {
+ if (!qemu_cbor_add_null_to_map(root, "public_key")) {
+ goto cleanup;
+ }
+ } else if (!qemu_cbor_add_bytestring_to_map(root, "public_key",
+ req->public_key.buf,
+ req->public_key.len)) {
+ goto cleanup;
+ }
+
+ if (req->user_data.is_null) {
+ if (!qemu_cbor_add_null_to_map(root, "user_data")) {
+ goto cleanup;
+ }
+ } else if (!qemu_cbor_add_bytestring_to_map(root, "user_data",
+ req->user_data.buf,
+ req->user_data.len)) {
+ goto cleanup;
+ }
+
+ if (req->nonce.is_null) {
+ if (!qemu_cbor_add_null_to_map(root, "nonce")) {
+ goto cleanup;
+ }
+ } else if (!qemu_cbor_add_bytestring_to_map(root, "nonce",
+ req->nonce.buf,
+ req->nonce.len)) {
+ goto cleanup;
+ }
+
+ len = cbor_serialize(root, buf, buf_len);
+ if (len == 0) {
+ goto cleanup;
+ }
+
+ bs = cbor_build_bytestring(buf, len);
+ if (!bs) {
+ goto cleanup;
+ }
+ if (!qemu_cbor_array_push(cose, bs)) {
+ cbor_decref(&bs);
+ goto cleanup;
+ }
+
+ r = true;
+
+ cleanup:
+ if (root) {
+ cbor_decref(&root);
+ }
+ return r;
+}
+
+static bool add_signature_to_cose(cbor_item_t *cose)
+{
+ cbor_item_t *bs = NULL;
+ uint8_t zero[64] = {0};
+
+ /* we don't actually sign the data, so we just put 64 zero bytes */
+ bs = cbor_build_bytestring(zero, 64);
+ if (!bs) {
+ goto cleanup;
+ }
+
+ if (!qemu_cbor_array_push(cose, bs)) {
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (bs) {
+ cbor_decref(&bs);
+ }
+ return false;
+}
+
+/*
+ * Attestation response structure:
+ *
+ * {
+ * Map(1) {
+ * key = String("Attestation"),
+ * value = Map(1) {
+ * key = String("document"),
+ * value = Byte_String()
+ * }
+ * }
+ * }
+ *
+ * The document is a serialized COSE sign1 blob of the structure:
+ * {
+ * Array(4) {
+ * [0] { ByteString() }, // serialized protected header
+ * [1] { Map(0) }, // 0 length map
+ * [2] { ByteString() }, // serialized payload
+ * [3] { ByteString() }, // signature
+ * }
+ * }
+ *
+ * where [0] protected header is a serialized CBOR blob of the structure:
+ * {
+ * Map(1) {
+ * key = Uint8(1) // alg
+ * value = NegativeInt8() // Signing algorithm
+ * }
+ * }
+ *
+ * [2] payload is serialized CBOR blob of the structure:
+ * {
+ * Map(9) {
+ * [0] { key = String("module_id"), value = String(module_id) },
+ * [1] { key = String("digest"), value = String("SHA384") },
+ * [2] {
+ * key = String("timestamp"),
+ * value = Uint64(unix epoch of when document was created)
+ * },
+ * [3] {
+ * key = String("pcrs"),
+ * value = Map(locked_pcr_cnt) {
+ * key = Uint8(pcr_index),
+ * value = ByteString(pcr_data)
+ * },
+ * },
+ * [4] {
+ * key = String("certificate"),
+ * value = ByteString(Signing certificate)
+ * },
+ * [5] { key = String("cabundle"), value = Array(N) { ByteString()... } },
+ * [6] { key = String("public_key"), value = ByteString() || null },
+ * [7] { key = String("user_data"), value = ByteString() || null},
+ * [8] { key = String("nonce"), value = ByteString() || null},
+ * }
+ * }
+ */
+static bool handle_attestation(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp)
+{
+ cbor_item_t *root = NULL;
+ cbor_item_t *cose = NULL;
+ cbor_item_t *nested_map;
+ size_t len;
+ enum NSMResponseTypes type;
+ bool r = false;
+ size_t buf_len = 16384;
+ g_autofree uint8_t *buf = g_malloc(buf_len);
+ g_autofree NSMAttestationReq *nsm_req = g_malloc(sizeof(NSMAttestationReq));
+
+ nsm_req->public_key.is_null = true;
+ nsm_req->user_data.is_null = true;
+ nsm_req->nonce.is_null = true;
+
+ type = get_nsm_attestation_req(request->iov_base, request->iov_len,
+ nsm_req);
+ if (type != NSM_SUCCESS) {
+ if (error_response(response, type, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ cose = cbor_new_definite_array(4);
+ if (!cose) {
+ goto err;
+ }
+ if (!add_protected_header_to_cose(cose)) {
+ goto err;
+ }
+ if (!add_unprotected_header_to_cose(cose)) {
+ goto err;
+ }
+ if (!add_payload_to_cose(cose, vnsm, nsm_req)) {
+ goto err;
+ }
+ if (!add_signature_to_cose(cose)) {
+ goto err;
+ }
+
+ len = cbor_serialize(cose, buf, buf_len);
+ if (len == 0) {
+ goto err;
+ }
+
+ root = cbor_new_definite_map(1);
+ if (!root) {
+ goto err;
+ }
+ if (!qemu_cbor_add_map_to_map(root, "Attestation", 1, &nested_map)) {
+ goto err;
+ }
+ if (!qemu_cbor_add_bytestring_to_map(nested_map, "document", buf, len)) {
+ goto err;
+ }
+
+ len = cbor_serialize(root, response->iov_base, response->iov_len);
+ if (len == 0) {
+ if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) {
+ r = true;
+ }
+ goto out;
+ }
+
+ response->iov_len = len;
+ r = true;
+
+ out:
+ if (root) {
+ cbor_decref(&root);
+ }
+ if (cose) {
+ cbor_decref(&cose);
+ }
+ return r;
+
+ err:
+ error_setg(errp, "Failed to initialize Attestation response");
+ goto out;
+}
+
+enum CBOR_ROOT_TYPE {
+ CBOR_ROOT_TYPE_STRING = 0,
+ CBOR_ROOT_TYPE_MAP = 1,
+};
+
+struct nsm_cmd {
+ char name[16];
+ /*
+ * There are 2 types of request
+ * 1) String(); "GetRandom", "DescribeNSM"
+ * 2) Map(1) { key: String(), value: ... }
+ */
+ enum CBOR_ROOT_TYPE root_type;
+ bool (*response_fn)(VirtIONSM *vnsm, struct iovec *request,
+ struct iovec *response, Error **errp);
+};
+
+const struct nsm_cmd nsm_cmds[] = {
+ { "GetRandom", CBOR_ROOT_TYPE_STRING, handle_get_random },
+ { "DescribeNSM", CBOR_ROOT_TYPE_STRING, handle_describe_nsm },
+ { "DescribePCR", CBOR_ROOT_TYPE_MAP, handle_describe_pcr },
+ { "ExtendPCR", CBOR_ROOT_TYPE_MAP, handle_extend_pcr },
+ { "LockPCR", CBOR_ROOT_TYPE_MAP, handle_lock_pcr },
+ { "LockPCRs", CBOR_ROOT_TYPE_MAP, handle_lock_pcrs },
+ { "Attestation", CBOR_ROOT_TYPE_MAP, handle_attestation },
+};
+
+static const struct nsm_cmd *get_nsm_request_cmd(uint8_t *buf, size_t len)
+{
+ size_t size;
+ uint8_t *req;
+ enum CBOR_ROOT_TYPE root_type;
+ struct cbor_load_result result;
+ cbor_item_t *item = cbor_load(buf, len, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ goto cleanup;
+ }
+
+ if (cbor_isa_string(item)) {
+ size = cbor_string_length(item);
+ req = cbor_string_handle(item);
+ root_type = CBOR_ROOT_TYPE_STRING;
+ } else if (cbor_isa_map(item) && cbor_map_size(item) == 1) {
+ struct cbor_pair *handle = cbor_map_handle(item);
+ if (cbor_isa_string(handle->key)) {
+ size = cbor_string_length(handle->key);
+ req = cbor_string_handle(handle->key);
+ root_type = CBOR_ROOT_TYPE_MAP;
+ } else {
+ goto cleanup;
+ }
+ } else {
+ goto cleanup;
+ }
+
+ if (size == 0 || req == NULL) {
+ goto cleanup;
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(nsm_cmds); ++i) {
+ if (nsm_cmds[i].root_type == root_type &&
+ strlen(nsm_cmds[i].name) == size &&
+ memcmp(nsm_cmds[i].name, req, size) == 0) {
+ cbor_decref(&item);
+ return &nsm_cmds[i];
+ }
+ }
+
+ cleanup:
+ if (item) {
+ cbor_decref(&item);
+ }
+ return NULL;
+}
+
+static bool get_nsm_request_response(VirtIONSM *vnsm, struct iovec *req,
+ struct iovec *resp, Error **errp)
+{
+ const struct nsm_cmd *cmd;
+
+ if (req->iov_len > NSM_REQUEST_MAX_SIZE) {
+ if (error_response(resp, NSM_INPUT_TOO_LARGE, errp)) {
+ return true;
+ }
+ error_setg(errp, "Failed to initialize InputTooLarge response");
+ return false;
+ }
+
+ cmd = get_nsm_request_cmd(req->iov_base, req->iov_len);
+
+ if (cmd == NULL) {
+ if (error_response(resp, NSM_INVALID_OPERATION, errp)) {
+ return true;
+ }
+ error_setg(errp, "Failed to initialize InvalidOperation response");
+ return false;
+ }
+
+ return cmd->response_fn(vnsm, req, resp, errp);
+}
+
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+ g_autofree VirtQueueElement *out_elem = NULL;
+ g_autofree VirtQueueElement *in_elem = NULL;
+ VirtIONSM *vnsm = VIRTIO_NSM(vdev);
+ Error *err = NULL;
+ size_t sz;
+ struct iovec req = {.iov_base = NULL, .iov_len = 0};
+ struct iovec res = {.iov_base = NULL, .iov_len = 0};
+
+ out_elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!out_elem) {
+ /* nothing in virtqueue */
+ return;
+ }
+
+ sz = iov_size(out_elem->out_sg, out_elem->out_num);
+ if (sz == 0) {
+ virtio_error(vdev, "Expected non-zero sized request buffer in "
+ "virtqueue");
+ goto cleanup;
+ }
+
+ in_elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!in_elem) {
+ virtio_error(vdev, "Expected response buffer after request buffer "
+ "in virtqueue");
+ goto cleanup;
+ }
+ if (iov_size(in_elem->in_sg, in_elem->in_num) != NSM_RESPONSE_BUF_SIZE) {
+ virtio_error(vdev, "Expected response buffer of length 0x3000");
+ goto cleanup;
+ }
+
+ req.iov_base = g_malloc(sz);
+ req.iov_len = iov_to_buf(out_elem->out_sg, out_elem->out_num, 0,
+ req.iov_base, sz);
+ if (req.iov_len != sz) {
+ virtio_error(vdev, "Failed to copy request buffer");
+ goto cleanup;
+ }
+
+ res.iov_base = g_malloc(NSM_RESPONSE_BUF_SIZE);
+ res.iov_len = NSM_RESPONSE_BUF_SIZE;
+
+ if (!get_nsm_request_response(vnsm, &req, &res, &err)) {
+ error_report_err(err);
+ virtio_error(vdev, "Failed to get NSM request response");
+ goto cleanup;
+ }
+
+ sz = iov_from_buf(in_elem->in_sg, in_elem->in_num, 0, res.iov_base,
+ res.iov_len);
+ if (sz != res.iov_len) {
+ virtio_error(vdev, "Failed to copy response buffer");
+ goto cleanup;
+ }
+
+ g_free(req.iov_base);
+ g_free(res.iov_base);
+ virtqueue_push(vq, out_elem, 0);
+ virtqueue_push(vq, in_elem, sz);
+ virtio_notify(vdev, vq);
+ return;
+
+ cleanup:
+ g_free(req.iov_base);
+ g_free(res.iov_base);
+ if (out_elem) {
+ virtqueue_detach_element(vq, out_elem, 0);
+ }
+ if (in_elem) {
+ virtqueue_detach_element(vq, in_elem, 0);
+ }
+}
+
+static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp)
+{
+ return f;
+}
+
+static bool extend_pcr(VirtIONSM *vnsm, int ind, uint8_t *data, uint16_t len)
+{
+ Error *err = NULL;
+ struct PCRInfo *pcr = &(vnsm->pcrs[ind]);
+ size_t digest_len = QCRYPTO_HASH_DIGEST_LEN_SHA384;
+ uint8_t result[QCRYPTO_HASH_DIGEST_LEN_SHA384];
+ uint8_t *ptr = result;
+ struct iovec iov[2] = {
+ { .iov_base = pcr->data, .iov_len = QCRYPTO_HASH_DIGEST_LEN_SHA384 },
+ { .iov_base = data, .iov_len = len },
+ };
+
+ if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA384, iov, 2, &ptr, &digest_len,
+ &err) < 0) {
+ return false;
+ }
+
+ memcpy(pcr->data, result, QCRYPTO_HASH_DIGEST_LEN_SHA384);
+ return true;
+}
+
+static void lock_pcr(VirtIONSM *vnsm, int ind)
+{
+ vnsm->pcrs[ind].locked = true;
+}
+
+static void virtio_nsm_device_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIONSM *vnsm = VIRTIO_NSM(dev);
+
+ vnsm->max_pcrs = NSM_MAX_PCRS;
+ vnsm->digest = (char *) "SHA384";
+ if (vnsm->module_id == NULL) {
+ vnsm->module_id = (char *) "i-234-enc5678";
+ }
+ vnsm->version_major = 1;
+ vnsm->version_minor = 0;
+ vnsm->version_patch = 0;
+ vnsm->extend_pcr = extend_pcr;
+ vnsm->lock_pcr = lock_pcr;
+
+ virtio_init(vdev, VIRTIO_ID_NITRO_SEC_MOD, 0);
+
+ vnsm->vq = virtio_add_queue(vdev, 2, handle_input);
+}
+
+static void virtio_nsm_device_unrealize(DeviceState *dev)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ virtio_del_queue(vdev, 0);
+ virtio_cleanup(vdev);
+}
+
+static const VMStateDescription vmstate_pcr_info_entry = {
+ .name = "pcr_info_entry",
+ .minimum_version_id = 1,
+ .version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BOOL(locked, struct PCRInfo),
+ VMSTATE_UINT8_ARRAY(data, struct PCRInfo,
+ QCRYPTO_HASH_DIGEST_LEN_SHA384),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_virtio_nsm_device = {
+ .name = "virtio-nsm-device",
+ .minimum_version_id = 1,
+ .version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(pcrs, VirtIONSM, NSM_MAX_PCRS, 1,
+ vmstate_pcr_info_entry, struct PCRInfo),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_virtio_nsm = {
+ .name = "virtio-nsm",
+ .minimum_version_id = 1,
+ .version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_VIRTIO_DEVICE,
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const Property virtio_nsm_properties[] = {
+ DEFINE_PROP_STRING("module-id", VirtIONSM, module_id),
+};
+
+static void virtio_nsm_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+ device_class_set_props(dc, virtio_nsm_properties);
+ dc->vmsd = &vmstate_virtio_nsm;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ vdc->realize = virtio_nsm_device_realize;
+ vdc->unrealize = virtio_nsm_device_unrealize;
+ vdc->get_features = get_features;
+ vdc->vmsd = &vmstate_virtio_nsm_device;
+}
+
+static const TypeInfo virtio_nsm_info = {
+ .name = TYPE_VIRTIO_NSM,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIONSM),
+ .class_init = virtio_nsm_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_nsm_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 524b63e..fba2372 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -33,12 +33,12 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/loader.h"
-#include "sysemu/kvm.h"
+#include "system/kvm.h"
#include "hw/virtio/virtio-pci.h"
#include "qemu/range.h"
#include "hw/virtio/virtio-bus.h"
#include "qapi/visitor.h"
-#include "sysemu/replay.h"
+#include "system/replay.h"
#include "trace.h"
#define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
@@ -146,9 +146,7 @@ static const VMStateDescription vmstate_virtio_pci = {
static bool virtio_pci_has_extra_state(DeviceState *d)
{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-
- return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA;
+ return true;
}
static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f)
@@ -615,8 +613,12 @@ static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy,
reg = &proxy->regs[i];
if (*off >= reg->offset &&
*off + len <= reg->offset + reg->size) {
- *off -= reg->offset;
- return &reg->mr;
+ MemoryRegionSection mrs = memory_region_find(&reg->mr,
+ *off - reg->offset, len);
+ assert(mrs.mr);
+ *off = mrs.offset_within_region;
+ memory_region_unref(mrs.mr);
+ return mrs.mr;
}
}
@@ -1211,7 +1213,12 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
static bool virtio_pci_query_guest_notifiers(DeviceState *d)
{
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- return msix_enabled(&proxy->pci_dev);
+
+ if (msix_enabled(&proxy->pci_dev)) {
+ return true;
+ } else {
+ return pci_irq_disabled(&proxy->pci_dev);
+ }
}
static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
@@ -1958,6 +1965,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
uint8_t *config;
uint32_t size;
VirtIODevice *vdev = virtio_bus_get_device(bus);
+ int16_t res;
/*
* Virtio capabilities present without
@@ -2053,6 +2061,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (modern_pio) {
memory_region_init(&proxy->io_bar, OBJECT(proxy),
"virtio-pci-io", 0x4);
+ address_space_init(&proxy->modern_cfg_io_as, &proxy->io_bar,
+ "virtio-pci-cfg-io-as");
pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar_idx,
PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar);
@@ -2103,6 +2113,18 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar_idx,
PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar);
}
+
+ if (pci_is_vf(&proxy->pci_dev)) {
+ pcie_ari_init(&proxy->pci_dev, proxy->last_pcie_cap_offset);
+ proxy->last_pcie_cap_offset += PCI_ARI_SIZEOF;
+ } else {
+ res = pcie_sriov_pf_init_from_user_created_vfs(
+ &proxy->pci_dev, proxy->last_pcie_cap_offset, errp);
+ if (res > 0) {
+ proxy->last_pcie_cap_offset += res;
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV);
+ }
+ }
}
static void virtio_pci_device_unplugged(DeviceState *d)
@@ -2176,6 +2198,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
/* PCI BAR regions must be powers of 2 */
pow2ceil(proxy->notify.offset + proxy->notify.size));
+ address_space_init(&proxy->modern_cfg_mem_as, &proxy->modern_bar,
+ "virtio-pci-cfg-mem-as");
+
if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
@@ -2190,19 +2215,16 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
if (pcie_port && pci_is_express(pci_dev)) {
int pos;
- uint16_t last_pcie_cap_offset = PCI_CONFIG_SPACE_SIZE;
+ proxy->last_pcie_cap_offset = PCI_CONFIG_SPACE_SIZE;
pos = pcie_endpoint_cap_init(pci_dev, 0);
assert(pos > 0);
- pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0,
- PCI_PM_SIZEOF, errp);
+ pos = pci_pm_init(pci_dev, 0, errp);
if (pos < 0) {
return;
}
- pci_dev->exp.pm_cap = pos;
-
/*
* Indicates that this function complies with revision 1.2 of the
* PCI Power Management Interface Specification.
@@ -2210,9 +2232,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3);
if (proxy->flags & VIRTIO_PCI_FLAG_AER) {
- pcie_aer_init(pci_dev, PCI_ERR_VER, last_pcie_cap_offset,
+ pcie_aer_init(pci_dev, PCI_ERR_VER, proxy->last_pcie_cap_offset,
PCI_ERR_SIZEOF, NULL);
- last_pcie_cap_offset += PCI_ERR_SIZEOF;
+ proxy->last_pcie_cap_offset += PCI_ERR_SIZEOF;
}
if (proxy->flags & VIRTIO_PCI_FLAG_INIT_DEVERR) {
@@ -2237,9 +2259,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
}
if (proxy->flags & VIRTIO_PCI_FLAG_ATS) {
- pcie_ats_init(pci_dev, last_pcie_cap_offset,
+ pcie_ats_init(pci_dev, proxy->last_pcie_cap_offset,
proxy->flags & VIRTIO_PCI_FLAG_ATS_PAGE_ALIGNED);
- last_pcie_cap_offset += PCI_EXT_CAP_ATS_SIZEOF;
+ proxy->last_pcie_cap_offset += PCI_EXT_CAP_ATS_SIZEOF;
}
if (proxy->flags & VIRTIO_PCI_FLAG_INIT_FLR) {
@@ -2265,12 +2287,18 @@ static void virtio_pci_exit(PCIDevice *pci_dev)
VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
bool pcie_port = pci_bus_is_express(pci_get_bus(pci_dev)) &&
!pci_bus_is_root(pci_get_bus(pci_dev));
+ bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
+ pcie_sriov_pf_exit(&proxy->pci_dev);
msix_uninit_exclusive_bar(pci_dev);
if (proxy->flags & VIRTIO_PCI_FLAG_AER && pcie_port &&
pci_is_express(pci_dev)) {
pcie_aer_exit(pci_dev);
}
+ address_space_destroy(&proxy->modern_cfg_mem_as);
+ if (modern_pio) {
+ address_space_destroy(&proxy->modern_cfg_io_as);
+ }
}
static void virtio_pci_reset(DeviceState *qdev)
@@ -2296,11 +2324,11 @@ static bool virtio_pci_no_soft_reset(PCIDevice *dev)
{
uint16_t pmcsr;
- if (!pci_is_express(dev) || !dev->exp.pm_cap) {
+ if (!pci_is_express(dev) || !(dev->cap_present & QEMU_PCI_CAP_PM)) {
return false;
}
- pmcsr = pci_get_word(dev->config + dev->exp.pm_cap + PCI_PM_CTRL);
+ pmcsr = pci_get_word(dev->config + dev->pm_cap + PCI_PM_CTRL);
/*
* When No_Soft_Reset bit is set and the device
@@ -2329,21 +2357,17 @@ static void virtio_pci_bus_reset_hold(Object *obj, ResetType type)
if (proxy->flags & VIRTIO_PCI_FLAG_INIT_PM) {
pci_word_test_and_clear_mask(
- dev->config + dev->exp.pm_cap + PCI_PM_CTRL,
+ dev->config + dev->pm_cap + PCI_PM_CTRL,
PCI_PM_CTRL_STATE_MASK);
}
}
}
-static Property virtio_pci_properties[] = {
+static const Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
- DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false),
- DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false),
DEFINE_PROP_BIT("page-per-vq", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false),
DEFINE_PROP_BOOL("x-ignore-backend-features", VirtIOPCIProxy,
@@ -2364,7 +2388,6 @@ static Property virtio_pci_properties[] = {
VIRTIO_PCI_FLAG_INIT_FLR_BIT, true),
DEFINE_PROP_BIT("aer", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_AER_BIT, false),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp)
@@ -2373,15 +2396,22 @@ static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp)
VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
PCIDevice *pci_dev = &proxy->pci_dev;
- if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) &&
- virtio_pci_modern(proxy)) {
+ if (virtio_pci_modern(proxy)) {
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
vpciklass->parent_dc_realize(qdev, errp);
}
-static void virtio_pci_class_init(ObjectClass *klass, void *data)
+static int virtio_pci_sync_config(DeviceState *dev, Error **errp)
+{
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(dev);
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+
+ return qdev_sync_config(DEVICE(vdev), errp);
+}
+
+static void virtio_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -2397,6 +2427,7 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data)
device_class_set_parent_realize(dc, virtio_pci_dc_realize,
&vpciklass->parent_dc_realize);
rc->phases.hold = virtio_pci_bus_reset_hold;
+ dc->sync_config = virtio_pci_sync_config;
}
static const TypeInfo virtio_pci_info = {
@@ -2408,14 +2439,13 @@ static const TypeInfo virtio_pci_info = {
.abstract = true,
};
-static Property virtio_pci_generic_properties[] = {
+static const Property virtio_pci_generic_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_pci_base_class_init(ObjectClass *klass, void *data)
+static void virtio_pci_base_class_init(ObjectClass *klass, const void *data)
{
const VirtioPCIDeviceTypeInfo *t = data;
if (t->class_init) {
@@ -2423,7 +2453,7 @@ static void virtio_pci_base_class_init(ObjectClass *klass, void *data)
}
}
-static void virtio_pci_generic_class_init(ObjectClass *klass, void *data)
+static void virtio_pci_generic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2463,7 +2493,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
.name = t->generic_name,
.parent = base_type_info.name,
.class_init = virtio_pci_generic_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
@@ -2479,18 +2509,18 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
generic_type_info.parent = base_name;
generic_type_info.class_init = virtio_pci_base_class_init;
- generic_type_info.class_data = (void *)t;
+ generic_type_info.class_data = t;
assert(!t->non_transitional_name);
assert(!t->transitional_name);
} else {
base_type_info.class_init = virtio_pci_base_class_init;
- base_type_info.class_data = (void *)t;
+ base_type_info.class_data = t;
}
- type_register(&base_type_info);
+ type_register_static(&base_type_info);
if (generic_type_info.name) {
- type_register(&generic_type_info);
+ type_register_static(&generic_type_info);
}
if (t->non_transitional_name) {
@@ -2498,13 +2528,13 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
.name = t->non_transitional_name,
.parent = base_type_info.name,
.instance_init = virtio_pci_non_transitional_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
- type_register(&non_transitional_type_info);
+ type_register_static(&non_transitional_type_info);
}
if (t->transitional_name) {
@@ -2512,7 +2542,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
.name = t->transitional_name,
.parent = base_type_info.name,
.instance_init = virtio_pci_transitional_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
/*
* Transitional virtio devices work only as Conventional PCI
* devices because they require PIO ports.
@@ -2521,7 +2551,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
{ }
},
};
- type_register(&transitional_type_info);
+ type_register_static(&transitional_type_info);
}
g_free(base_name);
}
@@ -2568,7 +2598,7 @@ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
qbus_init(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev, virtio_bus_name);
}
-static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
+static void virtio_pci_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *bus_class = BUS_CLASS(klass);
VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
diff --git a/hw/virtio/virtio-pmem-pci.c b/hw/virtio/virtio-pmem-pci.c
index cfe7f3b..babd91c 100644
--- a/hw/virtio/virtio-pmem-pci.c
+++ b/hw/virtio/virtio-pmem-pci.c
@@ -80,7 +80,7 @@ static void virtio_pmem_pci_fill_device_info(const MemoryDeviceState *md,
info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM;
}
-static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_pmem_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
index c3512c2..3416ea1 100644
--- a/hw/virtio/virtio-pmem.c
+++ b/hw/virtio/virtio-pmem.c
@@ -21,7 +21,7 @@
#include "hw/virtio/virtio-access.h"
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_pmem.h"
-#include "sysemu/hostmem.h"
+#include "system/hostmem.h"
#include "block/aio.h"
#include "block/thread-pool.h"
#include "trace.h"
@@ -155,14 +155,13 @@ static MemoryRegion *virtio_pmem_get_memory_region(VirtIOPMEM *pmem,
return &pmem->memdev->mr;
}
-static Property virtio_pmem_properties[] = {
+static const Property virtio_pmem_properties[] = {
DEFINE_PROP_UINT64(VIRTIO_PMEM_ADDR_PROP, VirtIOPMEM, start, 0),
DEFINE_PROP_LINK(VIRTIO_PMEM_MEMDEV_PROP, VirtIOPMEM, memdev,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_pmem_class_init(ObjectClass *klass, void *data)
+static void virtio_pmem_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
index 1dd96ed..3b6377c 100644
--- a/hw/virtio/virtio-qmp.c
+++ b/hw/virtio/virtio-qmp.c
@@ -15,8 +15,8 @@
#include "qapi/error.h"
#include "qapi/qapi-commands-virtio.h"
#include "qapi/qapi-commands-qom.h"
-#include "qapi/qmp/qobject.h"
-#include "qapi/qmp/qjson.h"
+#include "qobject/qobject.h"
+#include "qobject/qjson.h"
#include "hw/virtio/vhost-user.h"
#include "standard-headers/linux/virtio_ids.h"
@@ -121,6 +121,12 @@ static const qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_STATUS, \
"VHOST_USER_PROTOCOL_F_STATUS: Querying and notifying back-end "
"device status supported"),
+ FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_SHARED_OBJECT, \
+ "VHOST_USER_PROTOCOL_F_SHARED_OBJECT: Backend shared object "
+ "supported"),
+ FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_DEVICE_STATE, \
+ "VHOST_USER_PROTOCOL_F_DEVICE_STATE: Backend device state transfer "
+ "supported"),
{ -1, "" }
};
@@ -450,6 +456,9 @@ static const qmp_virtio_feature_map_t virtio_mem_feature_map[] = {
FEATURE_ENTRY(VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, \
"VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE: Unplugged memory cannot be "
"accessed"),
+ FEATURE_ENTRY(VIRTIO_MEM_F_PERSISTENT_SUSPEND, \
+ "VIRTIO_MEM_F_PERSISTENT_SUSPND: Plugged memory will remain "
+ "plugged when suspending+resuming"),
{ -1, "" }
};
#endif
diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c
index 6e76f8b..39b6003 100644
--- a/hw/virtio/virtio-rng-pci.c
+++ b/hw/virtio/virtio-rng-pci.c
@@ -32,12 +32,11 @@ struct VirtIORngPCI {
VirtIORNG vdev;
};
-static Property virtio_rng_properties[] = {
+static const Property virtio_rng_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -54,7 +53,7 @@ static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
}
}
-static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_rng_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index 7cf31da..3df5d25 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -17,8 +17,8 @@
#include "hw/virtio/virtio.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio-rng.h"
-#include "sysemu/rng.h"
-#include "sysemu/runstate.h"
+#include "system/rng.h"
+#include "system/runstate.h"
#include "qom/object_interfaces.h"
#include "trace.h"
@@ -159,17 +159,18 @@ static void check_rate_limit(void *opaque)
vrng->activate_timer = true;
}
-static void virtio_rng_set_status(VirtIODevice *vdev, uint8_t status)
+static int virtio_rng_set_status(VirtIODevice *vdev, uint8_t status)
{
VirtIORNG *vrng = VIRTIO_RNG(vdev);
if (!vdev->vm_running) {
- return;
+ return 0;
}
vdev->status = status;
/* Something changed, try to process buffers */
virtio_rng_process(vrng);
+ return 0;
}
static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
@@ -249,7 +250,7 @@ static const VMStateDescription vmstate_virtio_rng = {
},
};
-static Property virtio_rng_properties[] = {
+static const Property virtio_rng_properties[] = {
/* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If
* you have an entropy source capable of generating more entropy than this
* and you can pass it through via virtio-rng, then hats off to you. Until
@@ -258,10 +259,9 @@ static Property virtio_rng_properties[] = {
DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16),
DEFINE_PROP_LINK("rng", VirtIORNG, conf.rng, TYPE_RNG_BACKEND, RngBackend *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_rng_class_init(ObjectClass *klass, void *data)
+static void virtio_rng_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c
index e8e3442..af87759 100644
--- a/hw/virtio/virtio-scsi-pci.c
+++ b/hw/virtio/virtio-scsi-pci.c
@@ -35,12 +35,11 @@ struct VirtIOSCSIPCI {
VirtIOSCSI vdev;
};
-static Property virtio_scsi_pci_properties[] = {
+static const Property virtio_scsi_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
};
static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
@@ -73,7 +72,7 @@ static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_scsi_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c
index cea31ad..3f212ff 100644
--- a/hw/virtio/virtio-serial-pci.c
+++ b/hw/virtio/virtio-serial-pci.c
@@ -69,15 +69,14 @@ static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
-static Property virtio_serial_pci_properties[] = {
+static const Property virtio_serial_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_serial_pci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 9e10cbc..82a285a 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -30,8 +30,8 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio-access.h"
-#include "sysemu/dma.h"
-#include "sysemu/runstate.h"
+#include "system/dma.h"
+#include "system/runstate.h"
#include "virtio-qmp.h"
#include "standard-headers/linux/virtio_ids.h"
@@ -205,6 +205,15 @@ static const char *virtio_id_to_name(uint16_t device_id)
return name;
}
+static void virtio_check_indirect_feature(VirtIODevice *vdev)
+{
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Device %s: indirect_desc was not negotiated!\n",
+ vdev->name);
+ }
+}
+
/* Called within call_rcu(). */
static void virtio_free_region_cache(VRingMemoryRegionCaches *caches)
{
@@ -1680,8 +1689,8 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz)
VirtIODevice *vdev = vq->vdev;
VirtQueueElement *elem = NULL;
unsigned out_num, in_num, elem_entries;
- hwaddr addr[VIRTQUEUE_MAX_SIZE];
- struct iovec iov[VIRTQUEUE_MAX_SIZE];
+ hwaddr QEMU_UNINITIALIZED addr[VIRTQUEUE_MAX_SIZE];
+ struct iovec QEMU_UNINITIALIZED iov[VIRTQUEUE_MAX_SIZE];
VRingDesc desc;
int rc;
@@ -1733,6 +1742,7 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz)
virtio_error(vdev, "Invalid size for indirect buffer table");
goto done;
}
+ virtio_check_indirect_feature(vdev);
/* loop over the indirect descriptor table */
len = address_space_cache_init(&indirect_desc_cache, vdev->dma_as,
@@ -1826,8 +1836,8 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz)
VirtIODevice *vdev = vq->vdev;
VirtQueueElement *elem = NULL;
unsigned out_num, in_num, elem_entries;
- hwaddr addr[VIRTQUEUE_MAX_SIZE];
- struct iovec iov[VIRTQUEUE_MAX_SIZE];
+ hwaddr QEMU_UNINITIALIZED addr[VIRTQUEUE_MAX_SIZE];
+ struct iovec QEMU_UNINITIALIZED iov[VIRTQUEUE_MAX_SIZE];
VRingPackedDesc desc;
uint16_t id;
int rc;
@@ -1870,6 +1880,7 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz)
virtio_error(vdev, "Invalid size for indirect buffer table");
goto done;
}
+ virtio_check_indirect_feature(vdev);
/* loop over the indirect descriptor table */
len = address_space_cache_init(&indirect_desc_cache, vdev->dma_as,
@@ -2221,12 +2232,12 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
trace_virtio_set_status(vdev, val);
+ int ret = 0;
if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) &&
val & VIRTIO_CONFIG_S_FEATURES_OK) {
- int ret = virtio_validate_features(vdev);
-
+ ret = virtio_validate_features(vdev);
if (ret) {
return ret;
}
@@ -2239,16 +2250,20 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val)
}
if (k->set_status) {
- k->set_status(vdev, val);
+ ret = k->set_status(vdev, val);
+ if (ret) {
+ qemu_log("set %s status to %d failed, old status: %d\n",
+ vdev->name, val, vdev->status);
+ }
}
vdev->status = val;
- return 0;
+ return ret;
}
static enum virtio_device_endian virtio_default_endian(void)
{
- if (target_words_bigendian()) {
+ if (target_big_endian()) {
return VIRTIO_DEVICE_ENDIAN_BIG;
} else {
return VIRTIO_DEVICE_ENDIAN_LITTLE;
@@ -2316,45 +2331,6 @@ void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
}
}
-void virtio_reset(void *opaque)
-{
- VirtIODevice *vdev = opaque;
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- int i;
-
- virtio_set_status(vdev, 0);
- if (current_cpu) {
- /* Guest initiated reset */
- vdev->device_endian = virtio_current_cpu_endian();
- } else {
- /* System reset */
- vdev->device_endian = virtio_default_endian();
- }
-
- if (vdev->vhost_started && k->get_vhost) {
- vhost_reset_device(k->get_vhost(vdev));
- }
-
- if (k->reset) {
- k->reset(vdev);
- }
-
- vdev->start_on_kick = false;
- vdev->started = false;
- vdev->broken = false;
- vdev->guest_features = 0;
- vdev->queue_sel = 0;
- vdev->status = 0;
- vdev->disabled = false;
- qatomic_set(&vdev->isr, 0);
- vdev->config_vector = VIRTIO_NO_VECTOR;
- virtio_notify_vector(vdev, vdev->config_vector);
-
- for(i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- __virtio_queue_reset(vdev, i);
- }
-}
-
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
{
if (!vdev->vq[n].vring.num) {
@@ -3165,6 +3141,49 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val)
return ret;
}
+void virtio_reset(void *opaque)
+{
+ VirtIODevice *vdev = opaque;
+ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+ int i;
+
+ virtio_set_status(vdev, 0);
+ if (current_cpu) {
+ /* Guest initiated reset */
+ vdev->device_endian = virtio_current_cpu_endian();
+ } else {
+ /* System reset */
+ vdev->device_endian = virtio_default_endian();
+ }
+
+ if (k->get_vhost) {
+ struct vhost_dev *hdev = k->get_vhost(vdev);
+ /* Only reset when vhost back-end is connected */
+ if (hdev && hdev->vhost_ops) {
+ vhost_reset_device(hdev);
+ }
+ }
+
+ if (k->reset) {
+ k->reset(vdev);
+ }
+
+ vdev->start_on_kick = false;
+ vdev->started = false;
+ vdev->broken = false;
+ virtio_set_features_nocheck(vdev, 0);
+ vdev->queue_sel = 0;
+ vdev->status = 0;
+ vdev->disabled = false;
+ qatomic_set(&vdev->isr, 0);
+ vdev->config_vector = VIRTIO_NO_VECTOR;
+ virtio_notify_vector(vdev, vdev->config_vector);
+
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ __virtio_queue_reset(vdev, i);
+ }
+}
+
static void virtio_device_check_notification_compatibility(VirtIODevice *vdev,
Error **errp)
{
@@ -3251,6 +3270,13 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
config_len--;
}
+ if (vdc->pre_load_queues) {
+ ret = vdc->pre_load_queues(vdev);
+ if (ret) {
+ return ret;
+ }
+ }
+
num = qemu_get_be32(f);
if (num > VIRTIO_QUEUE_MAX) {
@@ -3408,7 +3434,7 @@ void virtio_cleanup(VirtIODevice *vdev)
qemu_del_vm_change_state_handler(vdev->vmstate);
}
-static void virtio_vmstate_change(void *opaque, bool running, RunState state)
+static int virtio_vmstate_change(void *opaque, bool running, RunState state)
{
VirtIODevice *vdev = opaque;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
@@ -3425,8 +3451,12 @@ static void virtio_vmstate_change(void *opaque, bool running, RunState state)
}
if (!backend_run) {
- virtio_set_status(vdev, vdev->status);
+ int ret = virtio_set_status(vdev, vdev->status);
+ if (ret) {
+ return ret;
+ }
}
+ return 0;
}
void virtio_instance_init_common(Object *proxy_obj, void *data,
@@ -3478,7 +3508,7 @@ void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size)
vdev->config = NULL;
}
vdev->vmstate = qdev_add_vm_change_state_handler(DEVICE(vdev),
- virtio_vmstate_change, vdev);
+ NULL, virtio_vmstate_change, vdev);
vdev->device_endian = virtio_default_endian();
vdev->use_guest_notifier_mask = true;
}
@@ -3637,7 +3667,6 @@ static void virtio_queue_packed_restore_last_avail_idx(VirtIODevice *vdev,
int n)
{
/* We don't have a reference like avail idx in shared memory */
- return;
}
static void virtio_queue_split_restore_last_avail_idx(VirtIODevice *vdev,
@@ -3662,10 +3691,9 @@ void virtio_queue_restore_last_avail_idx(VirtIODevice *vdev, int n)
static void virtio_queue_packed_update_used_idx(VirtIODevice *vdev, int n)
{
/* used idx was updated through set_last_avail_idx() */
- return;
}
-static void virtio_split_packed_update_used_idx(VirtIODevice *vdev, int n)
+static void virtio_queue_split_update_used_idx(VirtIODevice *vdev, int n)
{
RCU_READ_LOCK_GUARD();
if (vdev->vq[n].vring.desc) {
@@ -3678,7 +3706,7 @@ void virtio_queue_update_used_idx(VirtIODevice *vdev, int n)
if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
return virtio_queue_packed_update_used_idx(vdev, n);
} else {
- return virtio_split_packed_update_used_idx(vdev, n);
+ return virtio_queue_split_update_used_idx(vdev, n);
}
}
@@ -4001,13 +4029,12 @@ static void virtio_device_instance_finalize(Object *obj)
g_free(vdev->vector_queues);
}
-static Property virtio_properties[] = {
+static const Property virtio_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features),
DEFINE_PROP_BOOL("use-started", VirtIODevice, use_started, true),
DEFINE_PROP_BOOL("use-disabled-flag", VirtIODevice, use_disabled_flag, true),
DEFINE_PROP_BOOL("x-disable-legacy-check", VirtIODevice,
disable_legacy_check, false),
- DEFINE_PROP_END_OF_LIST(),
};
static int virtio_device_start_ioeventfd_impl(VirtIODevice *vdev)
@@ -4130,7 +4157,7 @@ void virtio_device_release_ioeventfd(VirtIODevice *vdev)
virtio_bus_release_ioeventfd(vbus);
}
-static void virtio_device_class_init(ObjectClass *klass, void *data)
+static void virtio_device_class_init(ObjectClass *klass, const void *data)
{
/* Set the default value here. */
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
new file mode 100644
index 0000000..2382b29
--- /dev/null
+++ b/hw/vmapple/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config VMAPPLE_AES
+ bool
+
+config VMAPPLE_BDIF
+ bool
+
+config VMAPPLE_CFG
+ bool
+
+config VMAPPLE_VIRTIO_BLK
+ bool
+
+config VMAPPLE
+ bool
+ depends on ARM
+ depends on HVF
+ default y if ARM
+ imply PCI_DEVICES
+ select ARM_GICV3
+ select PLATFORM_BUS
+ select PCI_EXPRESS
+ select PCI_EXPRESS_GENERIC_BRIDGE
+ select PL011 # UART
+ select PL031 # RTC
+ select PL061 # GPIO
+ select GPIO_PWR
+ select PVPANIC_MMIO
+ select VMAPPLE_AES
+ select VMAPPLE_BDIF
+ select VMAPPLE_CFG
+ select MAC_PVG_MMIO
+ select VMAPPLE_VIRTIO_BLK
diff --git a/hw/vmapple/aes.c b/hw/vmapple/aes.c
new file mode 100644
index 0000000..a4853a9
--- /dev/null
+++ b/hw/vmapple/aes.c
@@ -0,0 +1,581 @@
+/*
+ * QEMU Apple AES device emulation
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "trace.h"
+#include "crypto/hash.h"
+#include "crypto/aes.h"
+#include "crypto/cipher.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "hw/vmapple/vmapple.h"
+#include "migration/vmstate.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "system/dma.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(AESState, APPLE_AES)
+
+#define MAX_FIFO_SIZE 9
+
+#define CMD_KEY 0x1
+#define CMD_KEY_CONTEXT_SHIFT 27
+#define CMD_KEY_CONTEXT_MASK (0x1 << CMD_KEY_CONTEXT_SHIFT)
+#define CMD_KEY_SELECT_MAX_IDX 0x7
+#define CMD_KEY_SELECT_SHIFT 24
+#define CMD_KEY_SELECT_MASK (CMD_KEY_SELECT_MAX_IDX << CMD_KEY_SELECT_SHIFT)
+#define CMD_KEY_KEY_LEN_NUM 4u
+#define CMD_KEY_KEY_LEN_SHIFT 22
+#define CMD_KEY_KEY_LEN_MASK ((CMD_KEY_KEY_LEN_NUM - 1u) << CMD_KEY_KEY_LEN_SHIFT)
+#define CMD_KEY_ENCRYPT_SHIFT 20
+#define CMD_KEY_ENCRYPT_MASK (0x1 << CMD_KEY_ENCRYPT_SHIFT)
+#define CMD_KEY_BLOCK_MODE_SHIFT 16
+#define CMD_KEY_BLOCK_MODE_MASK (0x3 << CMD_KEY_BLOCK_MODE_SHIFT)
+#define CMD_IV 0x2
+#define CMD_IV_CONTEXT_SHIFT 26
+#define CMD_IV_CONTEXT_MASK (0x3 << CMD_KEY_CONTEXT_SHIFT)
+#define CMD_DSB 0x3
+#define CMD_SKG 0x4
+#define CMD_DATA 0x5
+#define CMD_DATA_KEY_CTX_SHIFT 27
+#define CMD_DATA_KEY_CTX_MASK (0x1 << CMD_DATA_KEY_CTX_SHIFT)
+#define CMD_DATA_IV_CTX_SHIFT 25
+#define CMD_DATA_IV_CTX_MASK (0x3 << CMD_DATA_IV_CTX_SHIFT)
+#define CMD_DATA_LEN_MASK 0xffffff
+#define CMD_STORE_IV 0x6
+#define CMD_STORE_IV_ADDR_MASK 0xffffff
+#define CMD_WRITE_REG 0x7
+#define CMD_FLAG 0x8
+#define CMD_FLAG_STOP_MASK BIT(26)
+#define CMD_FLAG_RAISE_IRQ_MASK BIT(27)
+#define CMD_FLAG_INFO_MASK 0xff
+#define CMD_MAX 0x10
+
+#define CMD_SHIFT 28
+
+#define REG_STATUS 0xc
+#define REG_STATUS_DMA_READ_RUNNING BIT(0)
+#define REG_STATUS_DMA_READ_PENDING BIT(1)
+#define REG_STATUS_DMA_WRITE_RUNNING BIT(2)
+#define REG_STATUS_DMA_WRITE_PENDING BIT(3)
+#define REG_STATUS_BUSY BIT(4)
+#define REG_STATUS_EXECUTING BIT(5)
+#define REG_STATUS_READY BIT(6)
+#define REG_STATUS_TEXT_DPA_SEEDED BIT(7)
+#define REG_STATUS_UNWRAP_DPA_SEEDED BIT(8)
+
+#define REG_IRQ_STATUS 0x18
+#define REG_IRQ_STATUS_INVALID_CMD BIT(2)
+#define REG_IRQ_STATUS_FLAG BIT(5)
+#define REG_IRQ_ENABLE 0x1c
+#define REG_WATERMARK 0x20
+#define REG_Q_STATUS 0x24
+#define REG_FLAG_INFO 0x30
+#define REG_FIFO 0x200
+
+static const uint32_t key_lens[CMD_KEY_KEY_LEN_NUM] = {
+ [0] = 16,
+ [1] = 24,
+ [2] = 32,
+ [3] = 64,
+};
+
+typedef struct Key {
+ uint32_t key_len;
+ uint8_t key[32];
+} Key;
+
+typedef struct IV {
+ uint32_t iv[4];
+} IV;
+
+static Key builtin_keys[CMD_KEY_SELECT_MAX_IDX + 1] = {
+ [1] = {
+ .key_len = 32,
+ .key = { 0x1 },
+ },
+ [2] = {
+ .key_len = 32,
+ .key = { 0x2 },
+ },
+ [3] = {
+ .key_len = 32,
+ .key = { 0x3 },
+ }
+};
+
+struct AESState {
+ SysBusDevice parent_obj;
+
+ qemu_irq irq;
+ MemoryRegion iomem1;
+ MemoryRegion iomem2;
+ AddressSpace *as;
+
+ uint32_t status;
+ uint32_t q_status;
+ uint32_t irq_status;
+ uint32_t irq_enable;
+ uint32_t watermark;
+ uint32_t flag_info;
+ uint32_t fifo[MAX_FIFO_SIZE];
+ uint32_t fifo_idx;
+ Key key[2];
+ IV iv[4];
+ bool is_encrypt;
+ QCryptoCipherMode block_mode;
+};
+
+static void aes_update_irq(AESState *s)
+{
+ qemu_set_irq(s->irq, !!(s->irq_status & s->irq_enable));
+}
+
+static uint64_t aes1_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AESState *s = opaque;
+ uint64_t res = 0;
+
+ switch (offset) {
+ case REG_STATUS:
+ res = s->status;
+ break;
+ case REG_IRQ_STATUS:
+ res = s->irq_status;
+ break;
+ case REG_IRQ_ENABLE:
+ res = s->irq_enable;
+ break;
+ case REG_WATERMARK:
+ res = s->watermark;
+ break;
+ case REG_Q_STATUS:
+ res = s->q_status;
+ break;
+ case REG_FLAG_INFO:
+ res = s->flag_info;
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: Unknown AES MMIO offset %" PRIx64 "\n",
+ __func__, offset);
+ break;
+ }
+
+ trace_aes_read(offset, res);
+
+ return res;
+}
+
+static void fifo_append(AESState *s, uint64_t val)
+{
+ if (s->fifo_idx == MAX_FIFO_SIZE) {
+ /* Exceeded the FIFO. Bail out */
+ return;
+ }
+
+ s->fifo[s->fifo_idx++] = val;
+}
+
+static bool has_payload(AESState *s, uint32_t elems)
+{
+ return s->fifo_idx >= elems + 1;
+}
+
+static bool cmd_key(AESState *s)
+{
+ uint32_t cmd = s->fifo[0];
+ uint32_t key_select = (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_SHIFT;
+ uint32_t ctxt = (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIFT;
+ uint32_t key_len;
+
+ switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) {
+ case 0:
+ s->block_mode = QCRYPTO_CIPHER_MODE_ECB;
+ break;
+ case 1:
+ s->block_mode = QCRYPTO_CIPHER_MODE_CBC;
+ break;
+ default:
+ return false;
+ }
+
+ s->is_encrypt = cmd & CMD_KEY_ENCRYPT_MASK;
+ key_len = key_lens[(cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_SHIFT];
+
+ if (key_select) {
+ trace_aes_cmd_key_select_builtin(ctxt, key_select,
+ s->is_encrypt ? "en" : "de",
+ QCryptoCipherMode_str(s->block_mode));
+ s->key[ctxt] = builtin_keys[key_select];
+ } else {
+ trace_aes_cmd_key_select_new(ctxt, key_len,
+ s->is_encrypt ? "en" : "de",
+ QCryptoCipherMode_str(s->block_mode));
+ if (key_len > sizeof(s->key[ctxt].key)) {
+ return false;
+ }
+ if (!has_payload(s, key_len / sizeof(uint32_t))) {
+ /* wait for payload */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+ return false;
+ }
+ memcpy(&s->key[ctxt].key, &s->fifo[1], key_len);
+ s->key[ctxt].key_len = key_len;
+ }
+
+ return true;
+}
+
+static bool cmd_iv(AESState *s)
+{
+ uint32_t cmd = s->fifo[0];
+ uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
+
+ if (!has_payload(s, 4)) {
+ /* wait for payload */
+ return false;
+ }
+ memcpy(&s->iv[ctxt].iv, &s->fifo[1], sizeof(s->iv[ctxt].iv));
+ trace_aes_cmd_iv(ctxt, s->fifo[1], s->fifo[2], s->fifo[3], s->fifo[4]);
+
+ return true;
+}
+
+static void dump_data(const char *desc, const void *p, size_t len)
+{
+ static const size_t MAX_LEN = 0x1000;
+ char hex[MAX_LEN * 2 + 1] = "";
+
+ if (len > MAX_LEN) {
+ return;
+ }
+
+ qemu_hexdump_to_buffer(hex, sizeof(hex), p, len);
+ trace_aes_dump_data(desc, hex);
+}
+
+static bool cmd_data(AESState *s)
+{
+ uint32_t cmd = s->fifo[0];
+ uint32_t ctxt_iv = 0;
+ uint32_t ctxt_key = (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CTX_SHIFT;
+ uint32_t len = cmd & CMD_DATA_LEN_MASK;
+ uint64_t src_addr = s->fifo[2];
+ uint64_t dst_addr = s->fifo[3];
+ QCryptoCipherAlgo alg;
+ g_autoptr(QCryptoCipher) cipher = NULL;
+ g_autoptr(GByteArray) src = NULL;
+ g_autoptr(GByteArray) dst = NULL;
+ MemTxResult r;
+
+ src_addr |= ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL;
+ dst_addr |= ((uint64_t)s->fifo[1] << 32) & 0xffff00000000ULL;
+
+ trace_aes_cmd_data(ctxt_key, ctxt_iv, src_addr, dst_addr, len);
+
+ if (!has_payload(s, 3)) {
+ /* wait for payload */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+ return false;
+ }
+
+ if (ctxt_key >= ARRAY_SIZE(s->key) ||
+ ctxt_iv >= ARRAY_SIZE(s->iv)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key or iv\n", __func__);
+ return false;
+ }
+
+ src = g_byte_array_sized_new(len);
+ g_byte_array_set_size(src, len);
+ dst = g_byte_array_sized_new(len);
+ g_byte_array_set_size(dst, len);
+
+ r = dma_memory_read(s->as, src_addr, src->data, len, MEMTXATTRS_UNSPECIFIED);
+ if (r != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA read of %"PRIu32" bytes "
+ "from 0x%"PRIx64" failed. (r=%d)\n",
+ __func__, len, src_addr, r);
+ return false;
+ }
+
+ dump_data("cmd_data(): src_data=", src->data, len);
+
+ switch (s->key[ctxt_key].key_len) {
+ case 128 / 8:
+ alg = QCRYPTO_CIPHER_ALGO_AES_128;
+ break;
+ case 192 / 8:
+ alg = QCRYPTO_CIPHER_ALGO_AES_192;
+ break;
+ case 256 / 8:
+ alg = QCRYPTO_CIPHER_ALGO_AES_256;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key length\n", __func__);
+ return false;
+ }
+ cipher = qcrypto_cipher_new(alg, s->block_mode,
+ s->key[ctxt_key].key,
+ s->key[ctxt_key].key_len, NULL);
+ if (!cipher) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to create cipher object\n",
+ __func__);
+ return false;
+ }
+ if (s->block_mode != QCRYPTO_CIPHER_MODE_ECB) {
+ if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv,
+ sizeof(s->iv[ctxt_iv].iv), NULL) != 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to set IV\n", __func__);
+ return false;
+ }
+ }
+ if (s->is_encrypt) {
+ if (qcrypto_cipher_encrypt(cipher, src->data, dst->data, len, NULL) != 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Encryption failed\n", __func__);
+ return false;
+ }
+ } else {
+ if (qcrypto_cipher_decrypt(cipher, src->data, dst->data, len, NULL) != 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Decryption failed\n", __func__);
+ return false;
+ }
+ }
+
+ dump_data("cmd_data(): dst_data=", dst->data, len);
+ r = dma_memory_write(s->as, dst_addr, dst->data, len, MEMTXATTRS_UNSPECIFIED);
+ if (r != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA write of %"PRIu32" bytes "
+ "to 0x%"PRIx64" failed. (r=%d)\n",
+ __func__, len, src_addr, r);
+ return false;
+ }
+
+ return true;
+}
+
+static bool cmd_store_iv(AESState *s)
+{
+ uint32_t cmd = s->fifo[0];
+ uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
+ uint64_t addr = s->fifo[1];
+ MemTxResult dma_result;
+
+ if (!has_payload(s, 1)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
+ return false;
+ }
+
+ if (ctxt >= ARRAY_SIZE(s->iv)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid context. ctxt = %u, allowed: 0..%zu\n",
+ __func__, ctxt, ARRAY_SIZE(s->iv) - 1);
+ return false;
+ }
+
+ addr |= ((uint64_t)cmd << 32) & 0xff00000000ULL;
+ dma_result = dma_memory_write(&address_space_memory, addr,
+ &s->iv[ctxt].iv, sizeof(s->iv[ctxt].iv),
+ MEMTXATTRS_UNSPECIFIED);
+
+ trace_aes_cmd_store_iv(ctxt, addr, s->iv[ctxt].iv[0], s->iv[ctxt].iv[1],
+ s->iv[ctxt].iv[2], s->iv[ctxt].iv[3]);
+
+ return dma_result == MEMTX_OK;
+}
+
+static bool cmd_flag(AESState *s)
+{
+ uint32_t cmd = s->fifo[0];
+ uint32_t raise_irq = cmd & CMD_FLAG_RAISE_IRQ_MASK;
+
+ /* We always process data when it's coming in, so fire an IRQ immediately */
+ if (raise_irq) {
+ s->irq_status |= REG_IRQ_STATUS_FLAG;
+ }
+
+ s->flag_info = cmd & CMD_FLAG_INFO_MASK;
+
+ trace_aes_cmd_flag(!!raise_irq, s->flag_info);
+
+ return true;
+}
+
+static void fifo_process(AESState *s)
+{
+ uint32_t cmd = s->fifo[0] >> CMD_SHIFT;
+ bool success = false;
+
+ if (!s->fifo_idx) {
+ return;
+ }
+
+ switch (cmd) {
+ case CMD_KEY:
+ success = cmd_key(s);
+ break;
+ case CMD_IV:
+ success = cmd_iv(s);
+ break;
+ case CMD_DATA:
+ success = cmd_data(s);
+ break;
+ case CMD_STORE_IV:
+ success = cmd_store_iv(s);
+ break;
+ case CMD_FLAG:
+ success = cmd_flag(s);
+ break;
+ default:
+ s->irq_status |= REG_IRQ_STATUS_INVALID_CMD;
+ break;
+ }
+
+ if (success) {
+ s->fifo_idx = 0;
+ }
+
+ trace_aes_fifo_process(cmd, success);
+}
+
+static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
+{
+ AESState *s = opaque;
+
+ trace_aes_write(offset, val);
+
+ switch (offset) {
+ case REG_IRQ_STATUS:
+ s->irq_status &= ~val;
+ break;
+ case REG_IRQ_ENABLE:
+ s->irq_enable = val;
+ break;
+ case REG_FIFO:
+ fifo_append(s, val);
+ fifo_process(s);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Unknown AES MMIO offset %"PRIx64", data %"PRIx64"\n",
+ __func__, offset, val);
+ return;
+ }
+
+ aes_update_irq(s);
+}
+
+static const MemoryRegionOps aes1_ops = {
+ .read = aes1_read,
+ .write = aes1_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint64_t res = 0;
+
+ switch (offset) {
+ case 0:
+ res = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Unknown AES MMIO 2 offset %"PRIx64"\n",
+ __func__, offset);
+ break;
+ }
+
+ trace_aes_2_read(offset, res);
+
+ return res;
+}
+
+static void aes2_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
+{
+ trace_aes_2_write(offset, val);
+
+ switch (offset) {
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Unknown AES MMIO 2 offset %"PRIx64", data %"PRIx64"\n",
+ __func__, offset, val);
+ return;
+ }
+}
+
+static const MemoryRegionOps aes2_ops = {
+ .read = aes2_read,
+ .write = aes2_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void aes_reset(Object *obj, ResetType type)
+{
+ AESState *s = APPLE_AES(obj);
+
+ s->status = 0x3f80;
+ s->q_status = 2;
+ s->irq_status = 0;
+ s->irq_enable = 0;
+ s->watermark = 0;
+}
+
+static void aes_init(Object *obj)
+{
+ AESState *s = APPLE_AES(obj);
+
+ memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_APPLE_AES, 0x4000);
+ memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_APPLE_AES, 0x4000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem1);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem2);
+ sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
+ s->as = &address_space_memory;
+}
+
+static void aes_class_init(ObjectClass *klass, const void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = aes_reset;
+}
+
+static const TypeInfo aes_info = {
+ .name = TYPE_APPLE_AES,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AESState),
+ .class_init = aes_class_init,
+ .instance_init = aes_init,
+};
+
+static void aes_register_types(void)
+{
+ type_register_static(&aes_info);
+}
+
+type_init(aes_register_types)
diff --git a/hw/vmapple/bdif.c b/hw/vmapple/bdif.c
new file mode 100644
index 0000000..5ccd374
--- /dev/null
+++ b/hw/vmapple/bdif.c
@@ -0,0 +1,274 @@
+/*
+ * VMApple Backdoor Interface
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "trace.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/sysbus.h"
+#include "hw/block/block.h"
+#include "qapi/error.h"
+#include "system/block-backend.h"
+#include "system/dma.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleBdifState, VMAPPLE_BDIF)
+
+struct VMAppleBdifState {
+ SysBusDevice parent_obj;
+
+ BlockBackend *aux;
+ BlockBackend *root;
+ MemoryRegion mmio;
+};
+
+#define VMAPPLE_BDIF_SIZE 0x00200000
+
+#define REG_DEVID_MASK 0xffff0000
+#define DEVID_ROOT 0x00000000
+#define DEVID_AUX 0x00010000
+#define DEVID_USB 0x00100000
+
+#define REG_STATUS 0x0
+#define REG_STATUS_ACTIVE BIT(0)
+#define REG_CFG 0x4
+#define REG_CFG_ACTIVE BIT(1)
+#define REG_UNK1 0x8
+#define REG_BUSY 0x10
+#define REG_BUSY_READY BIT(0)
+#define REG_UNK2 0x400
+#define REG_CMD 0x408
+#define REG_NEXT_DEVICE 0x420
+#define REG_UNK3 0x434
+
+typedef struct VblkSector {
+ uint32_t pad;
+ uint32_t pad2;
+ uint32_t sector;
+ uint32_t pad3;
+} VblkSector;
+
+typedef struct VblkReqCmd {
+ uint64_t addr;
+ uint32_t len;
+ uint32_t flags;
+} VblkReqCmd;
+
+typedef struct VblkReq {
+ VblkReqCmd sector;
+ VblkReqCmd data;
+ VblkReqCmd retval;
+} VblkReq;
+
+#define VBLK_DATA_FLAGS_READ 0x00030001
+#define VBLK_DATA_FLAGS_WRITE 0x00010001
+
+#define VBLK_RET_SUCCESS 0
+#define VBLK_RET_FAILED 1
+
+static uint64_t bdif_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint64_t ret = -1;
+ uint64_t devid = offset & REG_DEVID_MASK;
+
+ switch (offset & ~REG_DEVID_MASK) {
+ case REG_STATUS:
+ ret = REG_STATUS_ACTIVE;
+ break;
+ case REG_CFG:
+ ret = REG_CFG_ACTIVE;
+ break;
+ case REG_UNK1:
+ ret = 0x420;
+ break;
+ case REG_BUSY:
+ ret = REG_BUSY_READY;
+ break;
+ case REG_UNK2:
+ ret = 0x1;
+ break;
+ case REG_UNK3:
+ ret = 0x0;
+ break;
+ case REG_NEXT_DEVICE:
+ switch (devid) {
+ case DEVID_ROOT:
+ ret = 0x8000000;
+ break;
+ case DEVID_AUX:
+ ret = 0x10000;
+ break;
+ }
+ break;
+ }
+
+ trace_bdif_read(offset, size, ret);
+ return ret;
+}
+
+static void le2cpu_sector(VblkSector *sector)
+{
+ sector->sector = le32_to_cpu(sector->sector);
+}
+
+static void le2cpu_reqcmd(VblkReqCmd *cmd)
+{
+ cmd->addr = le64_to_cpu(cmd->addr);
+ cmd->len = le32_to_cpu(cmd->len);
+ cmd->flags = le32_to_cpu(cmd->flags);
+}
+
+static void le2cpu_req(VblkReq *req)
+{
+ le2cpu_reqcmd(&req->sector);
+ le2cpu_reqcmd(&req->data);
+ le2cpu_reqcmd(&req->retval);
+}
+
+static void vblk_cmd(uint64_t devid, BlockBackend *blk, uint64_t gp_addr,
+ uint64_t static_off)
+{
+ VblkReq req;
+ VblkSector sector;
+ uint64_t off = 0;
+ g_autofree char *buf = NULL;
+ uint8_t ret = VBLK_RET_FAILED;
+ int r;
+ MemTxResult dma_result;
+
+ dma_result = dma_memory_read(&address_space_memory, gp_addr,
+ &req, sizeof(req), MEMTXATTRS_UNSPECIFIED);
+ if (dma_result != MEMTX_OK) {
+ goto out;
+ }
+
+ le2cpu_req(&req);
+
+ if (req.sector.len != sizeof(sector)) {
+ goto out;
+ }
+
+ /* Read the vblk command */
+ dma_result = dma_memory_read(&address_space_memory, req.sector.addr,
+ &sector, sizeof(sector),
+ MEMTXATTRS_UNSPECIFIED);
+ if (dma_result != MEMTX_OK) {
+ goto out;
+ }
+ le2cpu_sector(&sector);
+
+ off = sector.sector * 512ULL + static_off;
+
+ /* Sanity check that we're not allocating bogus sizes */
+ if (req.data.len > 128 * MiB) {
+ goto out;
+ }
+
+ buf = g_malloc0(req.data.len);
+ switch (req.data.flags) {
+ case VBLK_DATA_FLAGS_READ:
+ r = blk_pread(blk, off, req.data.len, buf, 0);
+ trace_bdif_vblk_read(devid == DEVID_AUX ? "aux" : "root",
+ req.data.addr, off, req.data.len, r);
+ if (r < 0) {
+ goto out;
+ }
+ dma_result = dma_memory_write(&address_space_memory, req.data.addr, buf,
+ req.data.len, MEMTXATTRS_UNSPECIFIED);
+ if (dma_result == MEMTX_OK) {
+ ret = VBLK_RET_SUCCESS;
+ }
+ break;
+ case VBLK_DATA_FLAGS_WRITE:
+ /* Not needed, iBoot only reads */
+ break;
+ default:
+ break;
+ }
+
+out:
+ dma_memory_write(&address_space_memory, req.retval.addr, &ret, 1,
+ MEMTXATTRS_UNSPECIFIED);
+}
+
+static void bdif_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ VMAppleBdifState *s = opaque;
+ uint64_t devid = (offset & REG_DEVID_MASK);
+
+ trace_bdif_write(offset, size, value);
+
+ switch (offset & ~REG_DEVID_MASK) {
+ case REG_CMD:
+ switch (devid) {
+ case DEVID_ROOT:
+ vblk_cmd(devid, s->root, value, 0x0);
+ break;
+ case DEVID_AUX:
+ vblk_cmd(devid, s->aux, value, 0x0);
+ break;
+ }
+ break;
+ }
+}
+
+static const MemoryRegionOps bdif_ops = {
+ .read = bdif_read,
+ .write = bdif_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
+static void bdif_init(Object *obj)
+{
+ VMAppleBdifState *s = VMAPPLE_BDIF(obj);
+
+ memory_region_init_io(&s->mmio, obj, &bdif_ops, obj,
+ "VMApple Backdoor Interface", VMAPPLE_BDIF_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static const Property bdif_properties[] = {
+ DEFINE_PROP_DRIVE("aux", VMAppleBdifState, aux),
+ DEFINE_PROP_DRIVE("root", VMAppleBdifState, root),
+};
+
+static void bdif_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "VMApple Backdoor Interface";
+ device_class_set_props(dc, bdif_properties);
+}
+
+static const TypeInfo bdif_info = {
+ .name = TYPE_VMAPPLE_BDIF,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(VMAppleBdifState),
+ .instance_init = bdif_init,
+ .class_init = bdif_class_init,
+};
+
+static void bdif_register_types(void)
+{
+ type_register_static(&bdif_info);
+}
+
+type_init(bdif_register_types)
diff --git a/hw/vmapple/cfg.c b/hw/vmapple/cfg.c
new file mode 100644
index 0000000..3d58a29
--- /dev/null
+++ b/hw/vmapple/cfg.c
@@ -0,0 +1,195 @@
+/*
+ * VMApple Configuration Region
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "net/net.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleCfgState, VMAPPLE_CFG)
+
+#define VMAPPLE_CFG_SIZE 0x00010000
+
+typedef struct VMAppleCfg {
+ uint32_t version; /* 0x000 */
+ uint32_t nr_cpus; /* 0x004 */
+ uint32_t unk1; /* 0x008 */
+ uint32_t unk2; /* 0x00c */
+ uint32_t unk3; /* 0x010 */
+ uint32_t unk4; /* 0x014 */
+ uint64_t ecid; /* 0x018 */
+ uint64_t ram_size; /* 0x020 */
+ uint32_t run_installer1; /* 0x028 */
+ uint32_t unk5; /* 0x02c */
+ uint32_t unk6; /* 0x030 */
+ uint32_t run_installer2; /* 0x034 */
+ uint32_t rnd; /* 0x038 */
+ uint32_t unk7; /* 0x03c */
+ MACAddr mac_en0; /* 0x040 */
+ uint8_t pad1[2];
+ MACAddr mac_en1; /* 0x048 */
+ uint8_t pad2[2];
+ MACAddr mac_wifi0; /* 0x050 */
+ uint8_t pad3[2];
+ MACAddr mac_bt0; /* 0x058 */
+ uint8_t pad4[2];
+ uint8_t reserved[0xa0]; /* 0x060 */
+ uint32_t cpu_ids[0x80]; /* 0x100 */
+ uint8_t scratch[0x200]; /* 0x180 */
+ char serial[32]; /* 0x380 */
+ char unk8[32]; /* 0x3a0 */
+ char model[32]; /* 0x3c0 */
+ uint8_t unk9[32]; /* 0x3e0 */
+ uint32_t unk10; /* 0x400 */
+ char soc_name[32]; /* 0x404 */
+} VMAppleCfg;
+
+struct VMAppleCfgState {
+ SysBusDevice parent_obj;
+ VMAppleCfg cfg;
+
+ MemoryRegion mem;
+ char *serial;
+ char *model;
+ char *soc_name;
+};
+
+static void vmapple_cfg_reset(Object *obj, ResetType type)
+{
+ VMAppleCfgState *s = VMAPPLE_CFG(obj);
+ VMAppleCfg *cfg;
+
+ cfg = memory_region_get_ram_ptr(&s->mem);
+ memset(cfg, 0, VMAPPLE_CFG_SIZE);
+ *cfg = s->cfg;
+}
+
+static bool set_fixlen_property_or_error(char *restrict dst,
+ const char *restrict src,
+ size_t dst_size, Error **errp,
+ const char *property_name)
+{
+ ERRP_GUARD();
+ size_t len;
+
+ len = g_strlcpy(dst, src, dst_size);
+ if (len < dst_size) { /* len does not count nul terminator */
+ return true;
+ }
+
+ error_setg(errp, "Provided value too long for property '%s'", property_name);
+ error_append_hint(errp, "length (%zu) exceeds maximum of %zu\n",
+ len, dst_size - 1);
+ return false;
+}
+
+#define set_fixlen_property_or_return(dst_array, src, errp, property_name) \
+ do { \
+ if (!set_fixlen_property_or_error((dst_array), (src), \
+ ARRAY_SIZE(dst_array), \
+ (errp), (property_name))) { \
+ return; \
+ } \
+ } while (0)
+
+static void vmapple_cfg_realize(DeviceState *dev, Error **errp)
+{
+ VMAppleCfgState *s = VMAPPLE_CFG(dev);
+ uint32_t i;
+
+ if (!s->serial) {
+ s->serial = g_strdup("1234");
+ }
+ if (!s->model) {
+ s->model = g_strdup("VM0001");
+ }
+ if (!s->soc_name) {
+ s->soc_name = g_strdup("Apple M1 (Virtual)");
+ }
+
+ set_fixlen_property_or_return(s->cfg.serial, s->serial, errp, "serial");
+ set_fixlen_property_or_return(s->cfg.model, s->model, errp, "model");
+ set_fixlen_property_or_return(s->cfg.soc_name, s->soc_name, errp, "soc_name");
+ set_fixlen_property_or_return(s->cfg.unk8, "D/A", errp, "unk8");
+ s->cfg.version = 2;
+ s->cfg.unk1 = 1;
+ s->cfg.unk2 = 1;
+ s->cfg.unk3 = 0x20;
+ s->cfg.unk4 = 0;
+ s->cfg.unk5 = 1;
+ s->cfg.unk6 = 1;
+ s->cfg.unk7 = 0;
+ s->cfg.unk10 = 1;
+
+ if (s->cfg.nr_cpus > ARRAY_SIZE(s->cfg.cpu_ids)) {
+ error_setg(errp,
+ "Failed to create %u CPUs, vmapple machine supports %zu max",
+ s->cfg.nr_cpus, ARRAY_SIZE(s->cfg.cpu_ids));
+ return;
+ }
+ for (i = 0; i < s->cfg.nr_cpus; i++) {
+ s->cfg.cpu_ids[i] = i;
+ }
+}
+
+static void vmapple_cfg_init(Object *obj)
+{
+ VMAppleCfgState *s = VMAPPLE_CFG(obj);
+
+ memory_region_init_ram(&s->mem, obj, "VMApple Config", VMAPPLE_CFG_SIZE,
+ &error_fatal);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mem);
+}
+
+static const Property vmapple_cfg_properties[] = {
+ DEFINE_PROP_UINT32("nr-cpus", VMAppleCfgState, cfg.nr_cpus, 1),
+ DEFINE_PROP_UINT64("ecid", VMAppleCfgState, cfg.ecid, 0),
+ DEFINE_PROP_UINT64("ram-size", VMAppleCfgState, cfg.ram_size, 0),
+ DEFINE_PROP_UINT32("run_installer1", VMAppleCfgState, cfg.run_installer1, 0),
+ DEFINE_PROP_UINT32("run_installer2", VMAppleCfgState, cfg.run_installer2, 0),
+ DEFINE_PROP_UINT32("rnd", VMAppleCfgState, cfg.rnd, 0),
+ DEFINE_PROP_MACADDR("mac-en0", VMAppleCfgState, cfg.mac_en0),
+ DEFINE_PROP_MACADDR("mac-en1", VMAppleCfgState, cfg.mac_en1),
+ DEFINE_PROP_MACADDR("mac-wifi0", VMAppleCfgState, cfg.mac_wifi0),
+ DEFINE_PROP_MACADDR("mac-bt0", VMAppleCfgState, cfg.mac_bt0),
+ DEFINE_PROP_STRING("serial", VMAppleCfgState, serial),
+ DEFINE_PROP_STRING("model", VMAppleCfgState, model),
+ DEFINE_PROP_STRING("soc_name", VMAppleCfgState, soc_name),
+};
+
+static void vmapple_cfg_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = vmapple_cfg_realize;
+ dc->desc = "VMApple Configuration Region";
+ device_class_set_props(dc, vmapple_cfg_properties);
+ rc->phases.hold = vmapple_cfg_reset;
+}
+
+static const TypeInfo vmapple_cfg_info = {
+ .name = TYPE_VMAPPLE_CFG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(VMAppleCfgState),
+ .instance_init = vmapple_cfg_init,
+ .class_init = vmapple_cfg_class_init,
+};
+
+static void vmapple_cfg_register_types(void)
+{
+ type_register_static(&vmapple_cfg_info);
+}
+
+type_init(vmapple_cfg_register_types)
diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
new file mode 100644
index 0000000..23bc4c9
--- /dev/null
+++ b/hw/vmapple/meson.build
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_BDIF', if_true: files('bdif.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_CFG', if_true: files('cfg.c'))
+system_ss.add(when: 'CONFIG_VMAPPLE_VIRTIO_BLK', if_true: files('virtio-blk.c'))
+specific_ss.add(when: 'CONFIG_VMAPPLE', if_true: files('vmapple.c'))
diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
new file mode 100644
index 0000000..93380ed
--- /dev/null
+++ b/hw/vmapple/trace-events
@@ -0,0 +1,21 @@
+# See docs/devel/tracing.rst for syntax documentation.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# aes.c
+aes_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
+aes_cmd_key_select_builtin(uint32_t ctx, uint32_t key_id, const char *direction, const char *cipher) "[%d] Selecting builtin key %d to %scrypt with %s"
+aes_cmd_key_select_new(uint32_t ctx, uint32_t key_len, const char *direction, const char *cipher) "[%d] Selecting new key size=%d to %scrypt with %s"
+aes_cmd_iv(uint32_t ctx, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] 0x%08x 0x%08x 0x%08x 0x%08x"
+aes_cmd_data(uint32_t key, uint32_t iv, uint64_t src, uint64_t dst, uint32_t len) "[key=%d iv=%d] src=0x%"PRIx64" dst=0x%"PRIx64" len=0x%x"
+aes_cmd_store_iv(uint32_t ctx, uint64_t addr, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] addr=0x%"PRIx64"x -> 0x%08x 0x%08x 0x%08x 0x%08x"
+aes_cmd_flag(uint32_t raise, uint32_t flag_info) "raise=%d flag_info=0x%x"
+aes_fifo_process(uint32_t cmd, bool success) "cmd=%d success=%d"
+aes_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
+aes_2_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
+aes_2_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
+aes_dump_data(const char *desc, const char *hex) "%s%s"
+
+# bdif.c
+bdif_read(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64
+bdif_write(uint64_t offset, uint32_t size, uint64_t value) "offset=0x%"PRIx64" size=0x%x value=0x%"PRIx64
+bdif_vblk_read(const char *dev, uint64_t addr, uint64_t offset, uint32_t len, int r) "dev=%s addr=0x%"PRIx64" off=0x%"PRIx64" size=0x%x r=%d"
diff --git a/hw/vmapple/trace.h b/hw/vmapple/trace.h
new file mode 100644
index 0000000..d099d5e
--- /dev/null
+++ b/hw/vmapple/trace.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "trace/trace-hw_vmapple.h"
diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c
new file mode 100644
index 0000000..532b564
--- /dev/null
+++ b/hw/vmapple/virtio-blk.c
@@ -0,0 +1,205 @@
+/*
+ * VMApple specific VirtIO Block implementation
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * VMApple uses almost standard VirtIO Block, but with a few key differences:
+ *
+ * - Different PCI device/vendor ID
+ * - An additional "type" identifier to differentiate AUX and Root volumes
+ * - An additional BARRIER command
+ */
+
+#include "qemu/osdep.h"
+#include "hw/vmapple/vmapple.h"
+#include "hw/virtio/virtio-blk.h"
+#include "hw/virtio/virtio-pci.h"
+#include "qemu/bswap.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+
+#define TYPE_VMAPPLE_VIRTIO_BLK "vmapple-virtio-blk"
+OBJECT_DECLARE_TYPE(VMAppleVirtIOBlk, VMAppleVirtIOBlkClass, VMAPPLE_VIRTIO_BLK)
+
+typedef struct VMAppleVirtIOBlkClass {
+ VirtIOBlkClass parent;
+
+ void (*get_config)(VirtIODevice *vdev, uint8_t *config);
+} VMAppleVirtIOBlkClass;
+
+typedef struct VMAppleVirtIOBlk {
+ VirtIOBlock parent_obj;
+
+ uint32_t apple_type;
+} VMAppleVirtIOBlk;
+
+/*
+ * vmapple-virtio-blk-pci: This extends VirtioPCIProxy.
+ */
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleVirtIOBlkPCI, VMAPPLE_VIRTIO_BLK_PCI)
+
+#define VIRTIO_BLK_T_APPLE_BARRIER 0x10000
+
+static bool vmapple_virtio_blk_handle_unknown_request(VirtIOBlockReq *req,
+ MultiReqBuffer *mrb,
+ uint32_t type)
+{
+ switch (type) {
+ case VIRTIO_BLK_T_APPLE_BARRIER:
+ qemu_log_mask(LOG_UNIMP, "%s: Barrier requests are currently no-ops\n",
+ __func__);
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+ g_free(req);
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * VMApple virtio-blk uses the same config format as normal virtio, with one
+ * exception: It adds an "apple type" specififer at the same location that
+ * the spec reserves for max_secure_erase_sectors. Let's hook into the
+ * get_config code path here, run it as usual and then patch in the apple type.
+ */
+static void vmapple_virtio_blk_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+ VMAppleVirtIOBlk *dev = VMAPPLE_VIRTIO_BLK(vdev);
+ VMAppleVirtIOBlkClass *vvbk = VMAPPLE_VIRTIO_BLK_GET_CLASS(dev);
+ struct virtio_blk_config *blkcfg = (struct virtio_blk_config *)config;
+
+ vvbk->get_config(vdev, config);
+
+ g_assert(dev->parent_obj.config_size >= endof(struct virtio_blk_config, zoned));
+
+ /* Apple abuses the field for max_secure_erase_sectors as type id */
+ stl_he_p(&blkcfg->max_secure_erase_sectors, dev->apple_type);
+}
+
+static void vmapple_virtio_blk_class_init(ObjectClass *klass, const void *data)
+{
+ VirtIOBlkClass *vbk = VIRTIO_BLK_CLASS(klass);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ VMAppleVirtIOBlkClass *vvbk = VMAPPLE_VIRTIO_BLK_CLASS(klass);
+
+ vbk->handle_unknown_request = vmapple_virtio_blk_handle_unknown_request;
+ vvbk->get_config = vdc->get_config;
+ vdc->get_config = vmapple_virtio_blk_get_config;
+}
+
+static const TypeInfo vmapple_virtio_blk_info = {
+ .name = TYPE_VMAPPLE_VIRTIO_BLK,
+ .parent = TYPE_VIRTIO_BLK,
+ .instance_size = sizeof(VMAppleVirtIOBlk),
+ .class_size = sizeof(VMAppleVirtIOBlkClass),
+ .class_init = vmapple_virtio_blk_class_init,
+};
+
+/* PCI Devices */
+
+struct VMAppleVirtIOBlkPCI {
+ VirtIOPCIProxy parent_obj;
+
+ VMAppleVirtIOBlk vdev;
+ VMAppleVirtioBlkVariant variant;
+};
+
+static const Property vmapple_virtio_blk_pci_properties[] = {
+ DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_VMAPPLE_VIRTIO_BLK_VARIANT("variant", VMAppleVirtIOBlkPCI, variant,
+ VM_APPLE_VIRTIO_BLK_VARIANT_UNSPECIFIED),
+};
+
+static void vmapple_virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ ERRP_GUARD();
+ VMAppleVirtIOBlkPCI *dev = VMAPPLE_VIRTIO_BLK_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtIOBlkConf *conf = &dev->vdev.parent_obj.conf;
+
+ if (dev->variant == VM_APPLE_VIRTIO_BLK_VARIANT_UNSPECIFIED) {
+ error_setg(errp, "vmapple virtio block device variant unspecified");
+ error_append_hint(errp,
+ "Variant property must be set to 'aux' or 'root'.\n"
+ "Use a regular virtio-blk-pci device instead when "
+ "neither is applicaple.\n");
+ return;
+ }
+
+ if (conf->num_queues == VIRTIO_BLK_AUTO_NUM_QUEUES) {
+ conf->num_queues = virtio_pci_optimal_num_queues(0);
+ }
+
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = conf->num_queues + 1;
+ }
+
+ /*
+ * We don't support zones, but we need the additional config space size.
+ * Let's just expose the feature so the rest of the virtio-blk logic
+ * allocates enough space for us. The guest will ignore zones anyway.
+ */
+ virtio_add_feature(&dev->vdev.parent_obj.host_features, VIRTIO_BLK_F_ZONED);
+ /* Propagate the apple type down to the virtio-blk device */
+ dev->vdev.apple_type = dev->variant;
+ /* and spawn the virtio-blk device */
+ qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
+
+ /*
+ * The virtio-pci machinery adjusts its vendor/device ID based on whether
+ * we support modern or legacy virtio. Let's patch it back to the Apple
+ * identifiers here.
+ */
+ pci_config_set_vendor_id(vpci_dev->pci_dev.config, PCI_VENDOR_ID_APPLE);
+ pci_config_set_device_id(vpci_dev->pci_dev.config,
+ PCI_DEVICE_ID_APPLE_VIRTIO_BLK);
+}
+
+static void vmapple_virtio_blk_pci_class_init(ObjectClass *klass,
+ const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ device_class_set_props(dc, vmapple_virtio_blk_pci_properties);
+ k->realize = vmapple_virtio_blk_pci_realize;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_APPLE;
+ pcidev_k->device_id = PCI_DEVICE_ID_APPLE_VIRTIO_BLK;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void vmapple_virtio_blk_pci_instance_init(Object *obj)
+{
+ VMAppleVirtIOBlkPCI *dev = VMAPPLE_VIRTIO_BLK_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VMAPPLE_VIRTIO_BLK);
+}
+
+static const VirtioPCIDeviceTypeInfo vmapple_virtio_blk_pci_info = {
+ .generic_name = TYPE_VMAPPLE_VIRTIO_BLK_PCI,
+ .instance_size = sizeof(VMAppleVirtIOBlkPCI),
+ .instance_init = vmapple_virtio_blk_pci_instance_init,
+ .class_init = vmapple_virtio_blk_pci_class_init,
+};
+
+static void vmapple_virtio_blk_register_types(void)
+{
+ type_register_static(&vmapple_virtio_blk_info);
+ virtio_pci_types_register(&vmapple_virtio_blk_pci_info);
+}
+
+type_init(vmapple_virtio_blk_register_types)
diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c
new file mode 100644
index 0000000..16e6110
--- /dev/null
+++ b/hw/vmapple/vmapple.c
@@ -0,0 +1,618 @@
+/*
+ * VMApple machine emulation
+ *
+ * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * VMApple is the device model that the macOS built-in hypervisor called
+ * "Virtualization.framework" exposes to Apple Silicon macOS guests. The
+ * machine model in this file implements the same device model in QEMU, but
+ * does not use any code from Virtualization.Framework.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/datadir.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include "qemu/help-texts.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
+#include "qemu/units.h"
+#include "monitor/qdev.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "hw/loader.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "hw/usb.h"
+#include "hw/arm/boot.h"
+#include "hw/arm/primecell.h"
+#include "hw/char/pl011.h"
+#include "hw/intc/arm_gic.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "hw/misc/pvpanic.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/usb/hcd-xhci-pci.h"
+#include "hw/virtio/virtio-pci.h"
+#include "hw/vmapple/vmapple.h"
+#include "net/net.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "qapi/qapi-visit-common.h"
+#include "qobject/qlist.h"
+#include "standard-headers/linux/input.h"
+#include "system/hvf.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/system.h"
+
+struct VMAppleMachineState {
+ MachineState parent;
+
+ Notifier machine_done;
+ struct arm_boot_info bootinfo;
+ const MemMapEntry *memmap;
+ const int *irqmap;
+ DeviceState *gic;
+ DeviceState *cfg;
+ DeviceState *pvpanic;
+ Notifier powerdown_notifier;
+ PCIBus *bus;
+ MemoryRegion fw_mr;
+ MemoryRegion ecam_alias;
+ uint64_t uuid;
+};
+
+#define TYPE_VMAPPLE_MACHINE MACHINE_TYPE_NAME("vmapple")
+OBJECT_DECLARE_SIMPLE_TYPE(VMAppleMachineState, VMAPPLE_MACHINE)
+
+/* Number of external interrupt lines to configure the GIC with */
+#define NUM_IRQS 256
+
+enum {
+ VMAPPLE_FIRMWARE,
+ VMAPPLE_CONFIG,
+ VMAPPLE_MEM,
+ VMAPPLE_GIC_DIST,
+ VMAPPLE_GIC_REDIST,
+ VMAPPLE_UART,
+ VMAPPLE_RTC,
+ VMAPPLE_PCIE,
+ VMAPPLE_PCIE_MMIO,
+ VMAPPLE_PCIE_ECAM,
+ VMAPPLE_GPIO,
+ VMAPPLE_PVPANIC,
+ VMAPPLE_APV_GFX,
+ VMAPPLE_APV_IOSFC,
+ VMAPPLE_AES_1,
+ VMAPPLE_AES_2,
+ VMAPPLE_BDOOR,
+ VMAPPLE_MEMMAP_LAST,
+};
+
+static const MemMapEntry memmap[] = {
+ [VMAPPLE_FIRMWARE] = { 0x00100000, 0x00100000 },
+ [VMAPPLE_CONFIG] = { 0x00400000, 0x00010000 },
+
+ [VMAPPLE_GIC_DIST] = { 0x10000000, 0x00010000 },
+ [VMAPPLE_GIC_REDIST] = { 0x10010000, 0x00400000 },
+
+ [VMAPPLE_UART] = { 0x20010000, 0x00010000 },
+ [VMAPPLE_RTC] = { 0x20050000, 0x00001000 },
+ [VMAPPLE_GPIO] = { 0x20060000, 0x00001000 },
+ [VMAPPLE_PVPANIC] = { 0x20070000, 0x00000002 },
+ [VMAPPLE_BDOOR] = { 0x30000000, 0x00200000 },
+ [VMAPPLE_APV_GFX] = { 0x30200000, 0x00010000 },
+ [VMAPPLE_APV_IOSFC] = { 0x30210000, 0x00010000 },
+ [VMAPPLE_AES_1] = { 0x30220000, 0x00004000 },
+ [VMAPPLE_AES_2] = { 0x30230000, 0x00004000 },
+ [VMAPPLE_PCIE_ECAM] = { 0x40000000, 0x10000000 },
+ [VMAPPLE_PCIE_MMIO] = { 0x50000000, 0x1fff0000 },
+
+ /* Actual RAM size depends on configuration */
+ [VMAPPLE_MEM] = { 0x70000000ULL, GiB},
+};
+
+static const int irqmap[] = {
+ [VMAPPLE_UART] = 1,
+ [VMAPPLE_RTC] = 2,
+ [VMAPPLE_GPIO] = 0x5,
+ [VMAPPLE_APV_IOSFC] = 0x10,
+ [VMAPPLE_APV_GFX] = 0x11,
+ [VMAPPLE_AES_1] = 0x12,
+ [VMAPPLE_PCIE] = 0x20,
+};
+
+#define GPEX_NUM_IRQS 16
+
+static void create_bdif(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+ DeviceState *bdif;
+ SysBusDevice *bdif_sb;
+ DriveInfo *di_aux = drive_get(IF_PFLASH, 0, 0);
+ DriveInfo *di_root = drive_get(IF_PFLASH, 0, 1);
+
+ if (!di_aux) {
+ error_report("No AUX device. Please specify one as pflash drive.");
+ exit(1);
+ }
+
+ if (!di_root) {
+ /* Fall back to the first IF_VIRTIO device as root device */
+ di_root = drive_get(IF_VIRTIO, 0, 0);
+ }
+
+ if (!di_root) {
+ error_report("No root device. Please specify one as virtio drive.");
+ exit(1);
+ }
+
+ /* PV backdoor device */
+ bdif = qdev_new(TYPE_VMAPPLE_BDIF);
+ bdif_sb = SYS_BUS_DEVICE(bdif);
+ sysbus_mmio_map(bdif_sb, 0, vms->memmap[VMAPPLE_BDOOR].base);
+
+ qdev_prop_set_drive(DEVICE(bdif), "aux", blk_by_legacy_dinfo(di_aux));
+ qdev_prop_set_drive(DEVICE(bdif), "root", blk_by_legacy_dinfo(di_root));
+
+ sysbus_realize_and_unref(bdif_sb, &error_fatal);
+}
+
+static void create_pvpanic(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+ SysBusDevice *pvpanic;
+
+ vms->pvpanic = qdev_new(TYPE_PVPANIC_MMIO_DEVICE);
+ pvpanic = SYS_BUS_DEVICE(vms->pvpanic);
+ sysbus_mmio_map(pvpanic, 0, vms->memmap[VMAPPLE_PVPANIC].base);
+
+ sysbus_realize_and_unref(pvpanic, &error_fatal);
+}
+
+static bool create_cfg(VMAppleMachineState *vms, MemoryRegion *mem,
+ Error **errp)
+{
+ ERRP_GUARD();
+ SysBusDevice *cfg;
+ MachineState *machine = MACHINE(vms);
+ uint32_t rnd = 1;
+
+ vms->cfg = qdev_new(TYPE_VMAPPLE_CFG);
+ cfg = SYS_BUS_DEVICE(vms->cfg);
+ sysbus_mmio_map(cfg, 0, vms->memmap[VMAPPLE_CONFIG].base);
+
+ qemu_guest_getrandom_nofail(&rnd, sizeof(rnd));
+
+ qdev_prop_set_uint32(vms->cfg, "nr-cpus", machine->smp.cpus);
+ qdev_prop_set_uint64(vms->cfg, "ecid", vms->uuid);
+ qdev_prop_set_uint64(vms->cfg, "ram-size", machine->ram_size);
+ qdev_prop_set_uint32(vms->cfg, "rnd", rnd);
+
+ if (!sysbus_realize_and_unref(cfg, errp)) {
+ error_prepend(errp, "Error creating vmapple cfg device: ");
+ return false;
+ }
+
+ return true;
+}
+
+static void create_gfx(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+ int irq_gfx = vms->irqmap[VMAPPLE_APV_GFX];
+ int irq_iosfc = vms->irqmap[VMAPPLE_APV_IOSFC];
+ SysBusDevice *gfx;
+
+ gfx = SYS_BUS_DEVICE(qdev_new("apple-gfx-mmio"));
+ sysbus_mmio_map(gfx, 0, vms->memmap[VMAPPLE_APV_GFX].base);
+ sysbus_mmio_map(gfx, 1, vms->memmap[VMAPPLE_APV_IOSFC].base);
+ sysbus_connect_irq(gfx, 0, qdev_get_gpio_in(vms->gic, irq_gfx));
+ sysbus_connect_irq(gfx, 1, qdev_get_gpio_in(vms->gic, irq_iosfc));
+ sysbus_realize_and_unref(gfx, &error_fatal);
+}
+
+static void create_aes(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+ int irq = vms->irqmap[VMAPPLE_AES_1];
+ SysBusDevice *aes;
+
+ aes = SYS_BUS_DEVICE(qdev_new(TYPE_APPLE_AES));
+ sysbus_mmio_map(aes, 0, vms->memmap[VMAPPLE_AES_1].base);
+ sysbus_mmio_map(aes, 1, vms->memmap[VMAPPLE_AES_2].base);
+ sysbus_connect_irq(aes, 0, qdev_get_gpio_in(vms->gic, irq));
+ sysbus_realize_and_unref(aes, &error_fatal);
+}
+
+static int arm_gic_ppi_index(int cpu_nr, int ppi_index)
+{
+ return NUM_IRQS + cpu_nr * GIC_INTERNAL + ppi_index;
+}
+
+static void create_gic(VMAppleMachineState *vms, MemoryRegion *mem)
+{
+ MachineState *ms = MACHINE(vms);
+ /* We create a standalone GIC */
+ SysBusDevice *gicbusdev;
+ QList *redist_region_count;
+ int i;
+ unsigned int smp_cpus = ms->smp.cpus;
+
+ vms->gic = qdev_new(gicv3_class_name());
+ qdev_prop_set_uint32(vms->gic, "revision", 3);
+ qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
+ /*
+ * Note that the num-irq property counts both internal and external
+ * interrupts; there are always 32 of the former (mandated by GIC spec).
+ */
+ qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
+
+ uint32_t redist0_capacity =
+ vms->memmap[VMAPPLE_GIC_REDIST].size / GICV3_REDIST_SIZE;
+ uint32_t redist0_count = MIN(smp_cpus, redist0_capacity);
+
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, redist0_count);
+ qdev_prop_set_array(vms->gic, "redist-region-count", redist_region_count);
+
+ gicbusdev = SYS_BUS_DEVICE(vms->gic);
+ sysbus_realize_and_unref(gicbusdev, &error_fatal);
+ sysbus_mmio_map(gicbusdev, 0, vms->memmap[VMAPPLE_GIC_DIST].base);
+ sysbus_mmio_map(gicbusdev, 1, vms->memmap[VMAPPLE_GIC_REDIST].base);
+
+ /*
+ * 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.
+ */
+ for (i = 0; i < smp_cpus; i++) {
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+
+ /* Map the virt timer to PPI 27 */
+ qdev_connect_gpio_out(cpudev, GTIMER_VIRT,
+ qdev_get_gpio_in(vms->gic,
+ arm_gic_ppi_index(i, 27)));
+
+ /* Map the GIC IRQ and FIQ lines to CPU */
+ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+ sysbus_connect_irq(gicbusdev, i + smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ }
+}
+
+static void create_uart(const VMAppleMachineState *vms, int uart,
+ MemoryRegion *mem, Chardev *chr)
+{
+ hwaddr base = vms->memmap[uart].base;
+ int irq = vms->irqmap[uart];
+ DeviceState *dev = qdev_new(TYPE_PL011);
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
+
+ qdev_prop_set_chr(dev, "chardev", chr);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ memory_region_add_subregion(mem, base,
+ sysbus_mmio_get_region(s, 0));
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+}
+
+static void create_rtc(const VMAppleMachineState *vms)
+{
+ hwaddr base = vms->memmap[VMAPPLE_RTC].base;
+ int irq = vms->irqmap[VMAPPLE_RTC];
+
+ sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
+}
+
+static DeviceState *gpio_key_dev;
+static void vmapple_powerdown_req(Notifier *n, void *opaque)
+{
+ /* use gpio Pin 3 for power button event */
+ qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
+}
+
+static void create_gpio_devices(const VMAppleMachineState *vms, int gpio,
+ MemoryRegion *mem)
+{
+ DeviceState *pl061_dev;
+ hwaddr base = vms->memmap[gpio].base;
+ int irq = vms->irqmap[gpio];
+ SysBusDevice *s;
+
+ pl061_dev = qdev_new("pl061");
+ /* Pull lines down to 0 if not driven by the PL061 */
+ qdev_prop_set_uint32(pl061_dev, "pullups", 0);
+ qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff);
+ s = SYS_BUS_DEVICE(pl061_dev);
+ sysbus_realize_and_unref(s, &error_fatal);
+ memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+ gpio_key_dev = sysbus_create_simple("gpio-key", -1,
+ qdev_get_gpio_in(pl061_dev, 3));
+}
+
+static void vmapple_firmware_init(VMAppleMachineState *vms,
+ MemoryRegion *sysmem)
+{
+ hwaddr size = vms->memmap[VMAPPLE_FIRMWARE].size;
+ hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base;
+ const char *bios_name;
+ int image_size;
+ char *fname;
+
+ bios_name = MACHINE(vms)->firmware;
+ if (!bios_name) {
+ error_report("No firmware specified");
+ exit(1);
+ }
+
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (!fname) {
+ error_report("Could not find ROM image '%s'", bios_name);
+ exit(1);
+ }
+
+ memory_region_init_ram(&vms->fw_mr, NULL, "firmware", size, &error_fatal);
+ image_size = load_image_mr(fname, &vms->fw_mr);
+
+ g_free(fname);
+ if (image_size < 0) {
+ error_report("Could not load ROM image '%s'", bios_name);
+ exit(1);
+ }
+
+ memory_region_add_subregion(get_system_memory(), base, &vms->fw_mr);
+}
+
+static void create_pcie(VMAppleMachineState *vms)
+{
+ hwaddr base_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].base;
+ hwaddr size_mmio = vms->memmap[VMAPPLE_PCIE_MMIO].size;
+ hwaddr base_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].base;
+ hwaddr size_ecam = vms->memmap[VMAPPLE_PCIE_ECAM].size;
+ int irq = vms->irqmap[VMAPPLE_PCIE];
+ MemoryRegion *mmio_alias;
+ MemoryRegion *mmio_reg;
+ MemoryRegion *ecam_reg;
+ DeviceState *dev;
+ int i;
+ PCIHostState *pci;
+ DeviceState *usb_controller;
+ USBBus *usb_bus;
+
+ dev = qdev_new(TYPE_GPEX_HOST);
+ qdev_prop_set_uint32(dev, "num-irqs", GPEX_NUM_IRQS);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ /* Map only the first size_ecam bytes of ECAM space */
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_init_alias(&vms->ecam_alias, OBJECT(dev), "pcie-ecam",
+ ecam_reg, 0, size_ecam);
+ memory_region_add_subregion(get_system_memory(), base_ecam,
+ &vms->ecam_alias);
+
+ /*
+ * Map the MMIO window from [0x50000000-0x7fff0000] in PCI space into
+ * system address space at [0x50000000-0x7fff0000].
+ */
+ mmio_alias = g_new0(MemoryRegion, 1);
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg, base_mmio, size_mmio);
+ memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
+
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+ qdev_get_gpio_in(vms->gic, irq + i));
+ gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
+ }
+
+ pci = PCI_HOST_BRIDGE(dev);
+ vms->bus = pci->bus;
+ g_assert(vms->bus);
+
+ while ((dev = qemu_create_nic_device("virtio-net-pci", true, NULL))) {
+ qdev_realize_and_unref(dev, BUS(vms->bus), &error_fatal);
+ }
+
+ if (defaults_enabled()) {
+ usb_controller = qdev_new(TYPE_QEMU_XHCI);
+ qdev_realize_and_unref(usb_controller, BUS(pci->bus), &error_fatal);
+
+ usb_bus = USB_BUS(object_resolve_type_unambiguous(TYPE_USB_BUS,
+ &error_fatal));
+ usb_create_simple(usb_bus, "usb-kbd");
+ usb_create_simple(usb_bus, "usb-tablet");
+ }
+}
+
+static void vmapple_reset(void *opaque)
+{
+ VMAppleMachineState *vms = opaque;
+ hwaddr base = vms->memmap[VMAPPLE_FIRMWARE].base;
+
+ cpu_set_pc(first_cpu, base);
+}
+
+static void mach_vmapple_init(MachineState *machine)
+{
+ VMAppleMachineState *vms = VMAPPLE_MACHINE(machine);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ const CPUArchIdList *possible_cpus;
+ MemoryRegion *sysmem = get_system_memory();
+ int n;
+ unsigned int smp_cpus = machine->smp.cpus;
+ unsigned int max_cpus = machine->smp.max_cpus;
+
+ vms->memmap = memmap;
+ machine->usb = true;
+
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
+ assert(possible_cpus->len == max_cpus);
+ for (n = 0; n < possible_cpus->len; n++) {
+ Object *cpu;
+ CPUState *cs;
+
+ if (n >= smp_cpus) {
+ break;
+ }
+
+ cpu = object_new(possible_cpus->cpus[n].type);
+ object_property_set_int(cpu, "mp-affinity",
+ possible_cpus->cpus[n].arch_id, &error_fatal);
+
+ cs = CPU(cpu);
+ cs->cpu_index = n;
+
+ numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpu),
+ &error_fatal);
+
+ if (object_property_find(cpu, "has_el3")) {
+ object_property_set_bool(cpu, "has_el3", false, &error_fatal);
+ }
+ if (object_property_find(cpu, "has_el2")) {
+ object_property_set_bool(cpu, "has_el2", false, &error_fatal);
+ }
+ object_property_set_int(cpu, "psci-conduit", QEMU_PSCI_CONDUIT_HVC,
+ &error_fatal);
+
+ /* Secondary CPUs start in PSCI powered-down state */
+ if (n > 0) {
+ object_property_set_bool(cpu, "start-powered-off", true,
+ &error_fatal);
+ }
+
+ object_property_set_link(cpu, "memory", OBJECT(sysmem), &error_abort);
+ qdev_realize(DEVICE(cpu), NULL, &error_fatal);
+ object_unref(cpu);
+ }
+
+ memory_region_add_subregion(sysmem, vms->memmap[VMAPPLE_MEM].base,
+ machine->ram);
+
+ create_gic(vms, sysmem);
+ create_bdif(vms, sysmem);
+ create_pvpanic(vms, sysmem);
+ create_aes(vms, sysmem);
+ create_gfx(vms, sysmem);
+ create_uart(vms, VMAPPLE_UART, sysmem, serial_hd(0));
+ create_rtc(vms);
+ create_pcie(vms);
+
+ create_gpio_devices(vms, VMAPPLE_GPIO, sysmem);
+
+ vmapple_firmware_init(vms, sysmem);
+ create_cfg(vms, sysmem, &error_fatal);
+
+ /* connect powerdown request */
+ vms->powerdown_notifier.notify = vmapple_powerdown_req;
+ qemu_register_powerdown_notifier(&vms->powerdown_notifier);
+
+ vms->bootinfo.ram_size = machine->ram_size;
+ vms->bootinfo.board_id = -1;
+ vms->bootinfo.loader_start = vms->memmap[VMAPPLE_MEM].base;
+ vms->bootinfo.skip_dtb_autoload = true;
+ vms->bootinfo.firmware_loaded = true;
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
+
+ qemu_register_reset(vmapple_reset, vms);
+}
+
+static CpuInstanceProperties
+vmapple_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
+
+ assert(cpu_index < possible_cpus->len);
+ return possible_cpus->cpus[cpu_index].props;
+}
+
+
+static int64_t vmapple_get_default_cpu_node_id(const MachineState *ms, int idx)
+{
+ return idx % ms->numa_state->num_nodes;
+}
+
+static const CPUArchIdList *vmapple_possible_cpu_arch_ids(MachineState *ms)
+{
+ int n;
+ unsigned int max_cpus = ms->smp.max_cpus;
+
+ if (ms->possible_cpus) {
+ assert(ms->possible_cpus->len == max_cpus);
+ return ms->possible_cpus;
+ }
+
+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
+ sizeof(CPUArchId) * max_cpus);
+ ms->possible_cpus->len = max_cpus;
+ for (n = 0; n < ms->possible_cpus->len; n++) {
+ ms->possible_cpus->cpus[n].type = ms->cpu_type;
+ ms->possible_cpus->cpus[n].arch_id =
+ arm_build_mp_affinity(n, GICV3_TARGETLIST_BITS);
+ ms->possible_cpus->cpus[n].props.has_thread_id = true;
+ ms->possible_cpus->cpus[n].props.thread_id = n;
+ }
+ return ms->possible_cpus;
+}
+
+static GlobalProperty vmapple_compat_defaults[] = {
+ { TYPE_VIRTIO_PCI, "disable-legacy", "on" },
+ /*
+ * macOS XHCI driver attempts to schedule events onto even rings 1 & 2
+ * even when (as here) there is no MSI(-X) support. Disabling interrupter
+ * mapping in the XHCI controller works around the problem.
+ */
+ { TYPE_XHCI_PCI, "conditional-intr-mapping", "on" },
+};
+
+static void vmapple_machine_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->init = mach_vmapple_init;
+ mc->max_cpus = 32;
+ mc->block_default_type = IF_VIRTIO;
+ mc->no_cdrom = 1;
+ mc->pci_allow_0_address = true;
+ mc->minimum_page_bits = 12;
+ mc->possible_cpu_arch_ids = vmapple_possible_cpu_arch_ids;
+ mc->cpu_index_to_instance_props = vmapple_cpu_index_to_props;
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("host");
+ mc->get_default_cpu_node_id = vmapple_get_default_cpu_node_id;
+ mc->default_ram_id = "mach-vmapple.ram";
+ mc->desc = "Apple aarch64 Virtual Machine";
+
+ compat_props_add(mc->compat_props, vmapple_compat_defaults,
+ G_N_ELEMENTS(vmapple_compat_defaults));
+}
+
+static void vmapple_instance_init(Object *obj)
+{
+ VMAppleMachineState *vms = VMAPPLE_MACHINE(obj);
+
+ vms->irqmap = irqmap;
+
+ object_property_add_uint64_ptr(obj, "uuid", &vms->uuid,
+ OBJ_PROP_FLAG_READWRITE);
+ object_property_set_description(obj, "uuid", "Machine UUID (SDOM)");
+}
+
+static const TypeInfo vmapple_machine_info = {
+ .name = TYPE_VMAPPLE_MACHINE,
+ .parent = TYPE_MACHINE,
+ .instance_size = sizeof(VMAppleMachineState),
+ .class_init = vmapple_machine_class_init,
+ .instance_init = vmapple_instance_init,
+};
+
+static void machvmapple_machine_init(void)
+{
+ type_register_static(&vmapple_machine_info);
+}
+type_init(machvmapple_machine_init);
+
diff --git a/hw/watchdog/allwinner-wdt.c b/hw/watchdog/allwinner-wdt.c
index d35711c..8fcd776 100644
--- a/hw/watchdog/allwinner-wdt.c
+++ b/hw/watchdog/allwinner-wdt.c
@@ -28,7 +28,7 @@
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "hw/watchdog/allwinner-wdt.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "migration/vmstate.h"
/* WDT registers */
@@ -275,7 +275,7 @@ static void allwinner_wdt_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_wdt_ops = {
.read = allwinner_wdt_read,
.write = allwinner_wdt_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -348,7 +348,7 @@ static void allwinner_wdt_realize(DeviceState *dev, Error **errp)
ptimer_transaction_commit(s->timer);
}
-static void allwinner_wdt_class_init(ObjectClass *klass, void *data)
+static void allwinner_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -358,7 +358,7 @@ static void allwinner_wdt_class_init(ObjectClass *klass, void *data)
dc->vmsd = &allwinner_wdt_vmstate;
}
-static void allwinner_wdt_sun4i_class_init(ObjectClass *klass, void *data)
+static void allwinner_wdt_sun4i_class_init(ObjectClass *klass, const void *data)
{
AwWdtClass *awc = AW_WDT_CLASS(klass);
@@ -371,7 +371,7 @@ static void allwinner_wdt_sun4i_class_init(ObjectClass *klass, void *data)
awc->get_intv_value = allwinner_wdt_sun4i_get_intv_value;
}
-static void allwinner_wdt_sun6i_class_init(ObjectClass *klass, void *data)
+static void allwinner_wdt_sun6i_class_init(ObjectClass *klass, const void *data)
{
AwWdtClass *awc = AW_WDT_CLASS(klass);
diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
index 3091e5c..6a8d07c 100644
--- a/hw/watchdog/cmsdk-apb-watchdog.c
+++ b/hw/watchdog/cmsdk-apb-watchdog.c
@@ -12,8 +12,8 @@
/*
* This is a model of the "APB watchdog" which is part of the Cortex-M
* System Design Kit (CMSDK) and documented in the Cortex-M System
- * Design Kit Technical Reference Manual (ARM DDI0479C):
- * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
+ * Design Kit Technical Reference Manual (ARM DDI0479):
+ * https://developer.arm.com/documentation/ddi0479/
*
* We also support the variant of this device found in the TI
* Stellaris/Luminary boards and documented in:
@@ -25,7 +25,7 @@
#include "trace.h"
#include "qapi/error.h"
#include "qemu/module.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
@@ -196,16 +196,13 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
switch (offset) {
case A_WDOGLOAD:
- /*
- * Reset the load value and the current count, and make sure
- * we're counting.
- */
+ /* Reset the load value and the current count. */
ptimer_transaction_begin(s->timer);
ptimer_set_limit(s->timer, value, 1);
- ptimer_run(s->timer, 0);
ptimer_transaction_commit(s->timer);
break;
- case A_WDOGCONTROL:
+ case A_WDOGCONTROL: {
+ uint32_t prev_control = s->control;
if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) {
/*
* The Luminary version of this device ignores writes to
@@ -215,8 +212,25 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
break;
}
s->control = value & R_WDOGCONTROL_VALID_MASK;
+ if (R_WDOGCONTROL_INTEN_MASK & (s->control ^ prev_control)) {
+ ptimer_transaction_begin(s->timer);
+ if (R_WDOGCONTROL_INTEN_MASK & s->control) {
+ /*
+ * Set HIGH to enable the counter and the interrupt. Reloads
+ * the counter from the value in WDOGLOAD when the interrupt
+ * is enabled, after previously being disabled.
+ */
+ ptimer_set_count(s->timer, ptimer_get_limit(s->timer));
+ ptimer_run(s->timer, 0);
+ } else {
+ /* Or LOW to disable the counter and interrupt. */
+ ptimer_stop(s->timer);
+ }
+ ptimer_transaction_commit(s->timer);
+ }
cmsdk_apb_watchdog_update(s);
break;
+ }
case A_WDOGINTCLR:
s->intstatus = 0;
ptimer_transaction_begin(s->timer);
@@ -305,8 +319,14 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev)
s->resetstatus = 0;
/* Set the limit and the count */
ptimer_transaction_begin(s->timer);
+ /*
+ * We need to stop the ptimer before setting its limit reset value. If the
+ * order is the opposite when the code executes the stop after setting a new
+ * limit it may want to recalculate the count based on the current time (if
+ * the timer was currently running) and it won't get the proper reset value.
+ */
+ ptimer_stop(s->timer);
ptimer_set_limit(s->timer, 0xffffffff, 1);
- ptimer_run(s->timer, 0);
ptimer_transaction_commit(s->timer);
}
@@ -374,13 +394,13 @@ static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
}
};
-static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
+static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cmsdk_apb_watchdog_realize;
dc->vmsd = &cmsdk_apb_watchdog_vmstate;
- dc->reset = cmsdk_apb_watchdog_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_watchdog_reset);
}
static const TypeInfo cmsdk_apb_watchdog_info = {
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index d437535..ce84849 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -16,8 +16,8 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/reset.h"
-#include "sysemu/watchdog.h"
+#include "system/reset.h"
+#include "system/watchdog.h"
#include "hw/qdev-properties.h"
#include "hw/watchdog/sbsa_gwdt.h"
#include "qemu/timer.h"
@@ -174,7 +174,6 @@ static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :"
" 0x%x\n", (int)offset);
}
- return;
}
static void wdt_sbsa_gwdt_reset(DeviceState *dev)
@@ -262,7 +261,7 @@ static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
dev);
}
-static Property wdt_sbsa_gwdt_props[] = {
+static const Property wdt_sbsa_gwdt_props[] = {
/*
* Timer frequency in Hz. This must match the frequency used by
* the CPU's generic timer. Default 62.5Hz matches QEMU's legacy
@@ -270,15 +269,14 @@ static Property wdt_sbsa_gwdt_props[] = {
*/
DEFINE_PROP_UINT64("clock-frequency", struct SBSA_GWDTState, freq,
62500000),
- DEFINE_PROP_END_OF_LIST(),
};
-static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
+static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = wdt_sbsa_gwdt_realize;
- dc->reset = wdt_sbsa_gwdt_reset;
+ device_class_set_legacy_reset(dc, wdt_sbsa_gwdt_reset);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_sbsa_gwdt;
diff --git a/hw/watchdog/spapr_watchdog.c b/hw/watchdog/spapr_watchdog.c
index 2bb1d3c..5b3f50d 100644
--- a/hw/watchdog/spapr_watchdog.c
+++ b/hw/watchdog/spapr_watchdog.c
@@ -249,7 +249,7 @@ static void spapr_wdt_realize(DeviceState *dev, Error **errp)
&w->leave_others, OBJ_PROP_FLAG_READ);
}
-static void spapr_wdt_class_init(ObjectClass *oc, void *data)
+static void spapr_wdt_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c
index 9550461..0721373 100644
--- a/hw/watchdog/watchdog.c
+++ b/hw/watchdog/watchdog.c
@@ -26,8 +26,8 @@
#include "qapi/error.h"
#include "qapi/qapi-commands-run-state.h"
#include "qapi/qapi-events-run-state.h"
-#include "sysemu/runstate.h"
-#include "sysemu/watchdog.h"
+#include "system/runstate.h"
+#include "system/watchdog.h"
#include "hw/nmi.h"
#include "qemu/help_option.h"
#include "trace.h"
@@ -85,7 +85,7 @@ void watchdog_perform_action(void)
break;
default:
- assert(0);
+ g_assert_not_reached();
}
}
diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
index 75685c5..3022643 100644
--- a/hw/watchdog/wdt_aspeed.c
+++ b/hw/watchdog/wdt_aspeed.c
@@ -13,7 +13,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/timer.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "hw/watchdog/wdt_aspeed.h"
@@ -51,11 +51,20 @@
#define WDT_TIMEOUT_CLEAR (0x14 / 4)
#define WDT_RESTART_MAGIC 0x4755
+#define WDT_SW_RESET_ENABLE 0xAEEDF123
#define AST2600_SCU_RESET_CONTROL1 (0x40 / 4)
#define SCU_RESET_CONTROL1 (0x04 / 4)
#define SCU_RESET_SDRAM BIT(0)
+static bool aspeed_wdt_is_soc_reset_mode(const AspeedWDTState *s)
+{
+ uint32_t mode;
+
+ mode = extract32(s->regs[WDT_CTRL], 5, 2);
+ return (mode == WDT_CTRL_RESET_MODE_SOC);
+}
+
static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
{
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
@@ -199,19 +208,23 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
case WDT_TIMEOUT_STATUS:
case WDT_TIMEOUT_CLEAR:
case WDT_RESET_MASK2:
- case WDT_SW_RESET_CTRL:
case WDT_SW_RESET_MASK1:
case WDT_SW_RESET_MASK2:
qemu_log_mask(LOG_UNIMP,
"%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
+ case WDT_SW_RESET_CTRL:
+ if (aspeed_wdt_is_soc_reset_mode(s) &&
+ (data == WDT_SW_RESET_ENABLE)) {
+ watchdog_perform_action();
+ }
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
}
- return;
}
static const VMStateDescription vmstate_aspeed_wdt = {
@@ -278,7 +291,8 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
- /* FIXME: This setting should be derived from the SCU hw strapping
+ /*
+ * FIXME: This setting should be derived from the SCU hw strapping
* register SCU70
*/
s->pclk_freq = PCLK_HZ;
@@ -288,19 +302,18 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static Property aspeed_wdt_properties[] = {
+static const Property aspeed_wdt_properties[] = {
DEFINE_PROP_LINK("scu", AspeedWDTState, scu, TYPE_ASPEED_SCU,
AspeedSCUState *),
- DEFINE_PROP_END_OF_LIST(),
};
-static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
+static void aspeed_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "ASPEED Watchdog Controller";
dc->realize = aspeed_wdt_realize;
- dc->reset = aspeed_wdt_reset;
+ device_class_set_legacy_reset(dc, aspeed_wdt_reset);
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_aspeed_wdt;
device_class_set_props(dc, aspeed_wdt_properties);
@@ -316,7 +329,7 @@ static const TypeInfo aspeed_wdt_info = {
.abstract = true,
};
-static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data)
+static void aspeed_2400_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
@@ -353,7 +366,7 @@ static void aspeed_2500_wdt_reset_pulse(AspeedWDTState *s, uint32_t property)
}
}
-static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data)
+static void aspeed_2500_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
@@ -376,7 +389,7 @@ static const TypeInfo aspeed_2500_wdt_info = {
.class_init = aspeed_2500_wdt_class_init,
};
-static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data)
+static void aspeed_2600_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
@@ -399,7 +412,7 @@ static const TypeInfo aspeed_2600_wdt_info = {
.class_init = aspeed_2600_wdt_class_init,
};
-static void aspeed_1030_wdt_class_init(ObjectClass *klass, void *data)
+static void aspeed_1030_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
@@ -422,7 +435,7 @@ static const TypeInfo aspeed_1030_wdt_info = {
.class_init = aspeed_1030_wdt_class_init,
};
-static void aspeed_2700_wdt_class_init(ObjectClass *klass, void *data)
+static void aspeed_2700_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c
index 1b73b16..1275353 100644
--- a/hw/watchdog/wdt_diag288.c
+++ b/hw/watchdog/wdt_diag288.c
@@ -12,8 +12,8 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/reset.h"
-#include "sysemu/watchdog.h"
+#include "system/reset.h"
+#include "system/watchdog.h"
#include "qemu/timer.h"
#include "hw/watchdog/wdt_diag288.h"
#include "migration/vmstate.h"
@@ -108,14 +108,14 @@ static void wdt_diag288_unrealize(DeviceState *dev)
timer_free(diag288->timer);
}
-static void wdt_diag288_class_init(ObjectClass *klass, void *data)
+static void wdt_diag288_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
DIAG288Class *diag288 = DIAG288_CLASS(klass);
dc->realize = wdt_diag288_realize;
dc->unrealize = wdt_diag288_unrealize;
- dc->reset = wdt_diag288_reset;
+ device_class_set_legacy_reset(dc, wdt_diag288_reset);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_diag288;
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
index 8bce050..bb8a276 100644
--- a/hw/watchdog/wdt_i6300esb.c
+++ b/hw/watchdog/wdt_i6300esb.c
@@ -23,7 +23,7 @@
#include "qemu/module.h"
#include "qemu/timer.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "hw/pci/pci_device.h"
#include "migration/vmstate.h"
#include "qom/object.h"
@@ -457,7 +457,7 @@ static void i6300esb_exit(PCIDevice *dev)
timer_free(d->timer);
}
-static void i6300esb_class_init(ObjectClass *klass, void *data)
+static void i6300esb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -469,7 +469,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data)
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
k->class_id = PCI_CLASS_SYSTEM_OTHER;
- dc->reset = i6300esb_reset;
+ device_class_set_legacy_reset(dc, i6300esb_reset);
dc->vmsd = &vmstate_i6300esb;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->desc = "Intel 6300ESB";
@@ -480,7 +480,7 @@ static const TypeInfo i6300esb_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(I6300State),
.class_init = i6300esb_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c
index eea8da6..51a26a4 100644
--- a/hw/watchdog/wdt_ib700.c
+++ b/hw/watchdog/wdt_ib700.c
@@ -22,7 +22,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/timer.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "hw/isa/isa.h"
#include "migration/vmstate.h"
#include "qom/object.h"
@@ -128,12 +128,12 @@ static void wdt_ib700_reset(DeviceState *dev)
timer_del(s->timer);
}
-static void wdt_ib700_class_init(ObjectClass *klass, void *data)
+static void wdt_ib700_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = wdt_ib700_realize;
- dc->reset = wdt_ib700_reset;
+ device_class_set_legacy_reset(dc, wdt_ib700_reset);
dc->vmsd = &vmstate_ib700;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->desc = "iBASE 700";
diff --git a/hw/watchdog/wdt_imx2.c b/hw/watchdog/wdt_imx2.c
index 6452fc4..10151a1 100644
--- a/hw/watchdog/wdt_imx2.c
+++ b/hw/watchdog/wdt_imx2.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "qemu/module.h"
-#include "sysemu/watchdog.h"
+#include "system/watchdog.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
@@ -39,7 +39,6 @@ static void imx2_wdt_expired(void *opaque)
/* Perform watchdog action if watchdog is enabled */
if (s->wcr & IMX2_WDT_WCR_WDE) {
- s->wrsr = IMX2_WDT_WRSR_TOUT;
watchdog_perform_action();
}
}
@@ -282,19 +281,18 @@ static void imx2_wdt_realize(DeviceState *dev, Error **errp)
}
}
-static Property imx2_wdt_properties[] = {
+static const Property imx2_wdt_properties[] = {
DEFINE_PROP_BOOL("pretimeout-support", IMX2WdtState, pretimeout_support,
false),
- DEFINE_PROP_END_OF_LIST()
};
-static void imx2_wdt_class_init(ObjectClass *klass, void *data)
+static void imx2_wdt_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, imx2_wdt_properties);
dc->realize = imx2_wdt_realize;
- dc->reset = imx2_wdt_reset;
+ device_class_set_legacy_reset(dc, imx2_wdt_reset);
dc->vmsd = &vmstate_imx2_wdt;
dc->desc = "i.MX2 watchdog timer";
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
diff --git a/hw/xen/meson.build b/hw/xen/meson.build
index d887fa9..a1850e7 100644
--- a/hw/xen/meson.build
+++ b/hw/xen/meson.build
@@ -9,12 +9,16 @@ system_ss.add(when: ['CONFIG_XEN_BUS'], if_true: files(
system_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
'xen-operations.c',
+),
+if_false: files(
+ 'xen_stubs.c',
))
xen_specific_ss = ss.source_set()
xen_specific_ss.add(files(
'xen-mapcache.c',
'xen-hvm-common.c',
+ 'xen-pvh-common.c',
))
if have_xen_pci_passthrough
xen_specific_ss.add(files(
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
index d1b27f6..b67942d 100644
--- a/hw/xen/trace-events
+++ b/hw/xen/trace-events
@@ -38,7 +38,7 @@ xen_device_remove_watch(const char *type, char *name, const char *node, const ch
xs_node_create(const char *node) "%s"
xs_node_destroy(const char *node) "%s"
xs_node_vprintf(char *path, char *value) "%s %s"
-xs_node_vscanf(char *path, char *value) "%s %s"
+xs_node_read(const char *path, const char *value) "%s %s"
xs_node_watch(char *path) "%s"
xs_node_unwatch(char *path) "%s"
@@ -64,6 +64,10 @@ destroy_hvm_domain_cannot_acquire_handle(void) "Cannot acquire xenctrl handle"
destroy_hvm_domain_failed_action(const char *action, int sts, char *errno_s) "xc_domain_shutdown failed to issue %s, sts %d, %s"
destroy_hvm_domain_action(int xen_domid, const char *action) "Issued domain %d %s"
+# xen-pvh-common.c
+xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64
+xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64
+
# xen-mapcache.c
xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64
xen_remap_bucket(uint64_t index) "index 0x%"PRIx64
diff --git a/hw/xen/xen-bus-helper.c b/hw/xen/xen-bus-helper.c
index b2b2cc9..288fad4 100644
--- a/hw/xen/xen-bus-helper.c
+++ b/hw/xen/xen-bus-helper.c
@@ -105,25 +105,22 @@ int xs_node_vscanf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
{
- char *path, *value;
+ char *value;
int rc;
- path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
- g_strdup(key);
- value = qemu_xen_xs_read(h, tid, path, NULL);
-
- trace_xs_node_vscanf(path, value);
+ if (node && strlen(node) != 0) {
+ value = xs_node_read(h, tid, NULL, errp, "%s/%s", node, key);
+ } else {
+ value = xs_node_read(h, tid, NULL, errp, "%s", key);
+ }
if (value) {
rc = vsscanf(value, fmt, ap);
} else {
- error_setg_errno(errp, errno, "failed to read from '%s'",
- path);
rc = EOF;
}
free(value);
- g_free(path);
return rc;
}
@@ -142,6 +139,28 @@ int xs_node_scanf(struct qemu_xs_handle *h, xs_transaction_t tid,
return rc;
}
+char *xs_node_read(struct qemu_xs_handle *h, xs_transaction_t tid,
+ unsigned int *len, Error **errp,
+ const char *path_fmt, ...)
+{
+ char *path, *value;
+ va_list ap;
+
+ va_start(ap, path_fmt);
+ path = g_strdup_vprintf(path_fmt, ap);
+ va_end(ap);
+
+ value = qemu_xen_xs_read(h, tid, path, len);
+ trace_xs_node_read(path, value);
+ if (!value) {
+ error_setg_errno(errp, errno, "failed to read from '%s'", path);
+ }
+
+ g_free(path);
+
+ return value;
+}
+
struct qemu_xs_watch *xs_node_watch(struct qemu_xs_handle *h, const char *node,
const char *key, xs_watch_fn fn,
void *opaque, Error **errp)
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 95b207a..6bd2e54 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -18,8 +18,8 @@
#include "hw/xen/xen-bus-helper.h"
#include "monitor/monitor.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "sysemu/sysemu.h"
+#include "qobject/qdict.h"
+#include "system/system.h"
#include "net/net.h"
#include "trace.h"
@@ -156,8 +156,8 @@ again:
!strcmp(key[i], "hotplug-status"))
continue;
- if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms",
- &val) == 1) {
+ val = xs_node_read(xenbus->xsh, tid, NULL, NULL, "%s/%s", path, key[i]);
+ if (val) {
qdict_put_str(opts, key[i], val);
free(val);
}
@@ -353,10 +353,10 @@ static void xen_bus_realize(BusState *bus, Error **errp)
xs_node_watch(xenbus->xsh, node, key, xen_bus_backend_changed,
xenbus, &local_err);
if (local_err) {
- /* This need not be treated as a hard error so don't propagate */
- error_reportf_err(local_err,
- "failed to set up '%s' enumeration watch: ",
- type[i]);
+ warn_reportf_err(local_err,
+ "failed to set up '%s' enumeration watch: ",
+ type[i]);
+ local_err = NULL;
}
g_free(node);
@@ -380,7 +380,7 @@ static void xen_bus_unplug_request(HotplugHandler *hotplug,
xen_device_unplug(xendev, errp);
}
-static void xen_bus_class_init(ObjectClass *class, void *data)
+static void xen_bus_class_init(ObjectClass *class, const void *data)
{
BusClass *bus_class = BUS_CLASS(class);
HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
@@ -399,7 +399,7 @@ static const TypeInfo xen_bus_type_info = {
.instance_size = sizeof(XenBus),
.class_size = sizeof(XenBusClass),
.class_init = xen_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
},
@@ -650,6 +650,16 @@ int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
return rc;
}
+char *xen_device_frontend_read(XenDevice *xendev, const char *key)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+
+ g_assert(xenbus->xsh);
+
+ return xs_node_read(xenbus->xsh, XBT_NULL, NULL, NULL, "%s/%s",
+ xendev->frontend_path, key);
+}
+
static void xen_device_frontend_set_state(XenDevice *xendev,
enum xenbus_state state,
bool publish)
@@ -1092,13 +1102,12 @@ unrealize:
xen_device_unrealize(dev);
}
-static Property xen_device_props[] = {
+static const Property xen_device_props[] = {
DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
DOMID_INVALID),
- DEFINE_PROP_END_OF_LIST()
};
-static void xen_device_class_init(ObjectClass *class, void *data)
+static void xen_device_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index 3a9d6f9..78e0bc8 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -1,14 +1,21 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/error-report.h"
#include "qapi/error.h"
+#include "exec/target_long.h"
#include "exec/target_page.h"
#include "trace.h"
+#include "hw/hw.h"
#include "hw/pci/pci_host.h"
#include "hw/xen/xen-hvm-common.h"
#include "hw/xen/xen-bus.h"
#include "hw/boards.h"
#include "hw/xen/arch_hvm.h"
+#include "system/runstate.h"
+#include "system/system.h"
+#include "system/xen.h"
+#include "system/xen-mapcache.h"
MemoryRegion xen_memory, xen_grants;
@@ -667,6 +674,8 @@ static int xen_map_ioreq_server(XenIOState *state)
xen_pfn_t ioreq_pfn;
xen_pfn_t bufioreq_pfn;
evtchn_port_t bufioreq_evtchn;
+ unsigned long num_frames = 1;
+ unsigned long frame = 1;
int rc;
/*
@@ -675,65 +684,85 @@ static int xen_map_ioreq_server(XenIOState *state)
*/
QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_bufioreq != 0);
QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_ioreq(0) != 1);
+
+ if (state->has_bufioreq) {
+ frame = 0;
+ num_frames = 2;
+ }
state->fres = xenforeignmemory_map_resource(xen_fmem, xen_domid,
XENMEM_resource_ioreq_server,
- state->ioservid, 0, 2,
+ state->ioservid,
+ frame, num_frames,
&addr,
PROT_READ | PROT_WRITE, 0);
if (state->fres != NULL) {
trace_xen_map_resource_ioreq(state->ioservid, addr);
- state->buffered_io_page = addr;
- state->shared_page = addr + XC_PAGE_SIZE;
+ state->shared_page = addr;
+ if (state->has_bufioreq) {
+ state->buffered_io_page = addr;
+ state->shared_page = addr + XC_PAGE_SIZE;
+ }
} else if (errno != EOPNOTSUPP) {
error_report("failed to map ioreq server resources: error %d handle=%p",
errno, xen_xc);
return -1;
}
- rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
- (state->shared_page == NULL) ?
- &ioreq_pfn : NULL,
- (state->buffered_io_page == NULL) ?
- &bufioreq_pfn : NULL,
- &bufioreq_evtchn);
- if (rc < 0) {
- error_report("failed to get ioreq server info: error %d handle=%p",
- errno, xen_xc);
- return rc;
- }
+ /*
+ * If we fail to map the shared page with xenforeignmemory_map_resource()
+ * or if we're using buffered ioreqs, we need xen_get_ioreq_server_info()
+ * to provide the addresses to map the shared page and/or to get the
+ * event-channel port for buffered ioreqs.
+ */
+ if (state->shared_page == NULL || state->has_bufioreq) {
+ rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
+ (state->shared_page == NULL) ?
+ &ioreq_pfn : NULL,
+ (state->has_bufioreq &&
+ state->buffered_io_page == NULL) ?
+ &bufioreq_pfn : NULL,
+ &bufioreq_evtchn);
+ if (rc < 0) {
+ error_report("failed to get ioreq server info: error %d handle=%p",
+ errno, xen_xc);
+ return rc;
+ }
- if (state->shared_page == NULL) {
- trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
+ if (state->shared_page == NULL) {
+ trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
- state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ | PROT_WRITE,
- 1, &ioreq_pfn, NULL);
+ state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &ioreq_pfn, NULL);
+ }
if (state->shared_page == NULL) {
error_report("map shared IO page returned error %d handle=%p",
errno, xen_xc);
}
- }
- if (state->buffered_io_page == NULL) {
- trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
+ if (state->has_bufioreq && state->buffered_io_page == NULL) {
+ trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
- state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ | PROT_WRITE,
- 1, &bufioreq_pfn,
- NULL);
- if (state->buffered_io_page == NULL) {
- error_report("map buffered IO page returned error %d", errno);
- return -1;
+ state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &bufioreq_pfn,
+ NULL);
+ if (state->buffered_io_page == NULL) {
+ error_report("map buffered IO page returned error %d", errno);
+ return -1;
+ }
}
}
- if (state->shared_page == NULL || state->buffered_io_page == NULL) {
+ if (state->shared_page == NULL ||
+ (state->has_bufioreq && state->buffered_io_page == NULL)) {
return -1;
}
- trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
-
- state->bufioreq_remote_port = bufioreq_evtchn;
+ if (state->has_bufioreq) {
+ trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
+ state->bufioreq_remote_port = bufioreq_evtchn;
+ }
return 0;
}
@@ -830,14 +859,15 @@ static void xen_do_ioreq_register(XenIOState *state,
state->ioreq_local_port[i] = rc;
}
- rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
- state->bufioreq_remote_port);
- if (rc == -1) {
- error_report("buffered evtchn bind error %d", errno);
- goto err;
+ if (state->has_bufioreq) {
+ rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
+ state->bufioreq_remote_port);
+ if (rc == -1) {
+ error_report("buffered evtchn bind error %d", errno);
+ goto err;
+ }
+ state->bufioreq_local_port = rc;
}
- state->bufioreq_local_port = rc;
-
/* Init RAM management */
#ifdef XEN_COMPAT_PHYSMAP
xen_map_cache_init(xen_phys_offset_to_gaddr, state);
@@ -865,6 +895,7 @@ err:
}
void xen_register_ioreq(XenIOState *state, unsigned int max_cpus,
+ uint8_t handle_bufioreq,
const MemoryListener *xen_memory_listener)
{
int rc;
@@ -883,7 +914,8 @@ void xen_register_ioreq(XenIOState *state, unsigned int max_cpus,
goto err;
}
- rc = xen_create_ioreq_server(xen_domid, &state->ioservid);
+ state->has_bufioreq = handle_bufioreq != HVM_IOREQSRV_BUFIOREQ_OFF;
+ rc = xen_create_ioreq_server(xen_domid, handle_bufioreq, &state->ioservid);
if (!rc) {
xen_do_ioreq_register(state, max_cpus, xen_memory_listener);
} else {
diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c
index 5514184..5ed53f8 100644
--- a/hw/xen/xen-legacy-backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -147,24 +147,6 @@ void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
}
}
-int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
- bool to_domain,
- XenGrantCopySegment segs[],
- unsigned int nr_segs)
-{
- int rc;
-
- assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
-
- rc = qemu_xen_gnttab_grant_copy(xendev->gnttabdev, to_domain, xen_domid,
- segs, nr_segs, NULL);
- if (rc) {
- xen_pv_printf(xendev, 0, "xengnttab_grant_copy failed: %s\n",
- strerror(-rc));
- }
- return rc;
-}
-
/*
* get xen backend device, allocate a new one if it doesn't exist.
*/
@@ -181,7 +163,7 @@ static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom,
/* init new xendev */
xendev = g_malloc0(ops->size);
- object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND);
+ object_initialize(xendev, ops->size, TYPE_XENBACKEND);
OBJECT(xendev)->free = g_free;
qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev),
&error_fatal);
@@ -653,29 +635,22 @@ int xen_be_bind_evtchn(struct XenLegacyDevice *xendev)
}
-static Property xendev_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xendev_class_init(ObjectClass *klass, void *data)
+static void xendev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- device_class_set_props(dc, xendev_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- /* xen-backend devices can be plugged/unplugged dynamically */
- dc->user_creatable = true;
dc->bus_type = TYPE_XENSYSBUS;
}
static const TypeInfo xendev_type_info = {
.name = TYPE_XENBACKEND,
- .parent = TYPE_DEVICE,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
.class_init = xendev_class_init,
- .instance_size = sizeof(struct XenLegacyDevice),
+ .instance_size = sizeof(XenLegacyDevice),
};
-static void xen_sysbus_class_init(ObjectClass *klass, void *data)
+static void xen_sysbus_class_init(ObjectClass *klass, const void *data)
{
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
@@ -686,28 +661,15 @@ static const TypeInfo xensysbus_info = {
.name = TYPE_XENSYSBUS,
.parent = TYPE_BUS,
.class_init = xen_sysbus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
-static Property xen_sysdev_properties[] = {
- {/* end of property list */},
-};
-
-static void xen_sysdev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- device_class_set_props(dc, xen_sysdev_properties);
-}
-
static const TypeInfo xensysdev_info = {
.name = TYPE_XENSYSDEV,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .class_init = xen_sysdev_class_init,
};
static void xenbe_register_types(void)
diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
index 18ba7b1..e31d379 100644
--- a/hw/xen/xen-mapcache.c
+++ b/hw/xen/xen-mapcache.c
@@ -18,8 +18,8 @@
#include "hw/xen/xen_native.h"
#include "qemu/bitmap.h"
-#include "sysemu/runstate.h"
-#include "sysemu/xen-mapcache.h"
+#include "system/runstate.h"
+#include "system/xen-mapcache.h"
#include "trace.h"
#include <xenevtchn.h>
@@ -75,7 +75,8 @@ typedef struct MapCache {
} MapCache;
static MapCache *mapcache;
-static MapCache *mapcache_grants;
+static MapCache *mapcache_grants_ro;
+static MapCache *mapcache_grants_rw;
static xengnttab_handle *xen_region_gnttabdev;
static inline void mapcache_lock(MapCache *mc)
@@ -176,9 +177,12 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
* Grant mappings must use XC_PAGE_SIZE granularity since we can't
* map anything beyond the number of pages granted to us.
*/
- mapcache_grants = xen_map_cache_init_single(f, opaque,
- XC_PAGE_SHIFT,
- max_mcache_size);
+ mapcache_grants_ro = xen_map_cache_init_single(f, opaque,
+ XC_PAGE_SHIFT,
+ max_mcache_size);
+ mapcache_grants_rw = xen_map_cache_init_single(f, opaque,
+ XC_PAGE_SHIFT,
+ max_mcache_size);
setrlimit(RLIMIT_AS, &rlimit_as);
}
@@ -376,12 +380,12 @@ tryagain:
entry = &mc->entry[address_index % mc->nr_buckets];
- while (entry && (lock || entry->lock) && entry->vaddr_base &&
- (entry->paddr_index != address_index || entry->size != cache_size ||
+ while (entry && (!entry->vaddr_base ||
+ entry->paddr_index != address_index || entry->size != cache_size ||
!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping))) {
- if (!free_entry && !entry->lock) {
+ if (!free_entry && (!entry->lock || !entry->vaddr_base)) {
free_entry = entry;
free_pentry = pentry;
}
@@ -456,9 +460,13 @@ uint8_t *xen_map_cache(MemoryRegion *mr,
bool is_write)
{
bool grant = xen_mr_is_grants(mr);
- MapCache *mc = grant ? mapcache_grants : mapcache;
+ MapCache *mc = mapcache;
uint8_t *p;
+ if (grant) {
+ mc = is_write ? mapcache_grants_rw : mapcache_grants_ro;
+ }
+
if (grant && !lock) {
/*
* Grants are only supported via address_space_map(). Anything
@@ -523,7 +531,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
addr = xen_ram_addr_from_mapcache_single(mapcache, ptr);
if (addr == RAM_ADDR_INVALID) {
- addr = xen_ram_addr_from_mapcache_single(mapcache_grants, ptr);
+ addr = xen_ram_addr_from_mapcache_single(mapcache_grants_ro, ptr);
+ }
+ if (addr == RAM_ADDR_INVALID) {
+ addr = xen_ram_addr_from_mapcache_single(mapcache_grants_rw, ptr);
}
return addr;
@@ -626,7 +637,8 @@ static void xen_invalidate_map_cache_entry_single(MapCache *mc, uint8_t *buffer)
static void xen_invalidate_map_cache_entry_all(uint8_t *buffer)
{
xen_invalidate_map_cache_entry_single(mapcache, buffer);
- xen_invalidate_map_cache_entry_single(mapcache_grants, buffer);
+ xen_invalidate_map_cache_entry_single(mapcache_grants_ro, buffer);
+ xen_invalidate_map_cache_entry_single(mapcache_grants_rw, buffer);
}
static void xen_invalidate_map_cache_entry_bh(void *opaque)
@@ -700,7 +712,6 @@ void xen_invalidate_map_cache(void)
bdrv_drain_all();
xen_invalidate_map_cache_single(mapcache);
- xen_invalidate_map_cache_single(mapcache_grants);
}
static uint8_t *xen_replace_cache_entry_unlocked(MapCache *mc,
diff --git a/hw/xen/xen-pvh-common.c b/hw/xen/xen-pvh-common.c
new file mode 100644
index 0000000..b93ff80
--- /dev/null
+++ b/hw/xen/xen-pvh-common.c
@@ -0,0 +1,399 @@
+/*
+ * QEMU Xen PVH machine - common code.
+ *
+ * Copyright (c) 2024 Advanced Micro Devices, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "qapi/visitor.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "system/tpm.h"
+#include "system/tpm_backend.h"
+#include "system/runstate.h"
+#include "hw/xen/xen-pvh-common.h"
+#include "trace.h"
+
+static const MemoryListener xen_memory_listener = {
+ .region_add = xen_region_add,
+ .region_del = xen_region_del,
+ .log_start = NULL,
+ .log_stop = NULL,
+ .log_sync = NULL,
+ .log_global_start = NULL,
+ .log_global_stop = NULL,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
+};
+
+static void xen_pvh_init_ram(XenPVHMachineState *s,
+ MemoryRegion *sysmem)
+{
+ MachineState *ms = MACHINE(s);
+ ram_addr_t block_len, ram_size[2];
+
+ if (ms->ram_size <= s->cfg.ram_low.size) {
+ ram_size[0] = ms->ram_size;
+ ram_size[1] = 0;
+ block_len = s->cfg.ram_low.base + ram_size[0];
+ } else {
+ ram_size[0] = s->cfg.ram_low.size;
+ ram_size[1] = ms->ram_size - s->cfg.ram_low.size;
+ block_len = s->cfg.ram_high.base + ram_size[1];
+ }
+
+ memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len,
+ &error_fatal);
+
+ memory_region_init_alias(&s->ram.low, NULL, "xen.ram.lo", &xen_memory,
+ s->cfg.ram_low.base, ram_size[0]);
+ memory_region_add_subregion(sysmem, s->cfg.ram_low.base, &s->ram.low);
+ if (ram_size[1] > 0) {
+ memory_region_init_alias(&s->ram.high, NULL, "xen.ram.hi", &xen_memory,
+ s->cfg.ram_high.base, ram_size[1]);
+ memory_region_add_subregion(sysmem, s->cfg.ram_high.base, &s->ram.high);
+ }
+
+ /* Setup support for grants. */
+ memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
+ &error_fatal);
+ memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
+}
+
+static void xen_set_irq(void *opaque, int irq, int level)
+{
+ if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
+ error_report("xendevicemodel_set_irq_level failed");
+ }
+}
+
+static void xen_create_virtio_mmio_devices(XenPVHMachineState *s)
+{
+ int i;
+
+ /*
+ * We create the transports in reverse order. Since qbus_realize()
+ * prepends (not appends) new child buses, the decrementing loop below will
+ * create a list of virtio-mmio buses with increasing base addresses.
+ *
+ * When a -device option is processed from the command line,
+ * qbus_find_recursive() picks the next free virtio-mmio bus in forwards
+ * order.
+ *
+ * This is what the Xen tools expect.
+ */
+ for (i = s->cfg.virtio_mmio_num - 1; i >= 0; i--) {
+ hwaddr base = s->cfg.virtio_mmio.base + i * s->cfg.virtio_mmio.size;
+ qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL,
+ s->cfg.virtio_mmio_irq_base + i);
+
+ sysbus_create_simple("virtio-mmio", base, irq);
+
+ trace_xen_create_virtio_mmio_devices(i,
+ s->cfg.virtio_mmio_irq_base + i,
+ base);
+ }
+}
+
+#ifdef CONFIG_TPM
+static void xen_enable_tpm(XenPVHMachineState *s)
+{
+ Error *errp = NULL;
+ DeviceState *dev;
+ SysBusDevice *busdev;
+
+ TPMBackend *be = qemu_find_tpm_be("tpm0");
+ if (be == NULL) {
+ error_report("Couldn't find tmp0 backend");
+ return;
+ }
+ dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
+ object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp);
+ object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp);
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(busdev, &error_fatal);
+ sysbus_mmio_map(busdev, 0, s->cfg.tpm.base);
+
+ trace_xen_enable_tpm(s->cfg.tpm.base);
+}
+#endif
+
+/*
+ * We use the GPEX PCIe controller with its internal INTX PCI interrupt
+ * swizzling. This swizzling is emulated in QEMU and routes all INTX
+ * interrupts from endpoints down to only 4 INTX interrupts.
+ * See include/hw/pci/pci.h : pci_swizzle()
+ */
+static inline void xenpvh_gpex_init(XenPVHMachineState *s,
+ XenPVHMachineClass *xpc,
+ MemoryRegion *sysmem)
+{
+ MemoryRegion *ecam_reg;
+ MemoryRegion *mmio_reg;
+ DeviceState *dev;
+ int i;
+
+ object_initialize_child(OBJECT(s), "gpex", &s->pci.gpex,
+ TYPE_GPEX_HOST);
+ dev = DEVICE(&s->pci.gpex);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_add_subregion(sysmem, s->cfg.pci_ecam.base, ecam_reg);
+
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+
+ if (s->cfg.pci_mmio.size) {
+ memory_region_init_alias(&s->pci.mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg,
+ s->cfg.pci_mmio.base, s->cfg.pci_mmio.size);
+ memory_region_add_subregion(sysmem, s->cfg.pci_mmio.base,
+ &s->pci.mmio_alias);
+ }
+
+ if (s->cfg.pci_mmio_high.size) {
+ memory_region_init_alias(&s->pci.mmio_high_alias, OBJECT(dev),
+ "pcie-mmio-high",
+ mmio_reg, s->cfg.pci_mmio_high.base, s->cfg.pci_mmio_high.size);
+ memory_region_add_subregion(sysmem, s->cfg.pci_mmio_high.base,
+ &s->pci.mmio_high_alias);
+ }
+
+ /*
+ * PVH implementations with PCI enabled must provide set_pci_intx_irq()
+ * and optionally an implementation of set_pci_link_route().
+ */
+ assert(xpc->set_pci_intx_irq);
+
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ qemu_irq irq = qemu_allocate_irq(xpc->set_pci_intx_irq, s, i);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+ gpex_set_irq_num(GPEX_HOST(dev), i, s->cfg.pci_intx_irq_base + i);
+ if (xpc->set_pci_link_route) {
+ xpc->set_pci_link_route(i, s->cfg.pci_intx_irq_base + i);
+ }
+ }
+}
+
+static void xen_pvh_init(MachineState *ms)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(ms);
+ XenPVHMachineClass *xpc = XEN_PVH_MACHINE_GET_CLASS(s);
+ MemoryRegion *sysmem = get_system_memory();
+
+ if (ms->ram_size == 0) {
+ warn_report("%s: ram size not specified. QEMU machine started"
+ " without IOREQ (no emulated devices including virtio)",
+ MACHINE_CLASS(object_get_class(OBJECT(ms)))->desc);
+ return;
+ }
+
+ xen_pvh_init_ram(s, sysmem);
+ xen_register_ioreq(&s->ioreq, ms->smp.max_cpus,
+ xpc->handle_bufioreq,
+ &xen_memory_listener);
+
+ if (s->cfg.virtio_mmio_num) {
+ xen_create_virtio_mmio_devices(s);
+ }
+
+#ifdef CONFIG_TPM
+ if (xpc->has_tpm) {
+ if (s->cfg.tpm.base) {
+ xen_enable_tpm(s);
+ } else {
+ warn_report("tpm-base-addr is not set. TPM will not be enabled");
+ }
+ }
+#endif
+
+ /* Non-zero pci-ecam-size enables PCI. */
+ if (s->cfg.pci_ecam.size) {
+ if (s->cfg.pci_ecam.size != 256 * MiB) {
+ error_report("pci-ecam-size only supports values 0 or 0x10000000");
+ exit(EXIT_FAILURE);
+ }
+ if (!s->cfg.pci_intx_irq_base) {
+ error_report("PCI enabled but pci-intx-irq-base not set");
+ exit(EXIT_FAILURE);
+ }
+
+ xenpvh_gpex_init(s, xpc, sysmem);
+ }
+
+ /* Call the implementation specific init. */
+ if (xpc->init) {
+ xpc->init(ms);
+ }
+}
+
+#define XEN_PVH_PROP_MEMMAP_SETTER(n, f) \
+static void xen_pvh_set_ ## n ## _ ## f(Object *obj, Visitor *v, \
+ const char *name, void *opaque, \
+ Error **errp) \
+{ \
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \
+ uint64_t value; \
+ \
+ if (!visit_type_size(v, name, &value, errp)) { \
+ return; \
+ } \
+ xp->cfg.n.f = value; \
+}
+
+#define XEN_PVH_PROP_MEMMAP_GETTER(n, f) \
+static void xen_pvh_get_ ## n ## _ ## f(Object *obj, Visitor *v, \
+ const char *name, void *opaque, \
+ Error **errp) \
+{ \
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \
+ uint64_t value = xp->cfg.n.f; \
+ \
+ visit_type_uint64(v, name, &value, errp); \
+}
+
+#define XEN_PVH_PROP_MEMMAP_BASE(n) \
+ XEN_PVH_PROP_MEMMAP_SETTER(n, base) \
+ XEN_PVH_PROP_MEMMAP_GETTER(n, base) \
+
+#define XEN_PVH_PROP_MEMMAP_SIZE(n) \
+ XEN_PVH_PROP_MEMMAP_SETTER(n, size) \
+ XEN_PVH_PROP_MEMMAP_GETTER(n, size)
+
+#define XEN_PVH_PROP_MEMMAP(n) \
+ XEN_PVH_PROP_MEMMAP_BASE(n) \
+ XEN_PVH_PROP_MEMMAP_SIZE(n)
+
+XEN_PVH_PROP_MEMMAP(ram_low)
+XEN_PVH_PROP_MEMMAP(ram_high)
+/* TPM only has a base-addr option. */
+XEN_PVH_PROP_MEMMAP_BASE(tpm)
+XEN_PVH_PROP_MEMMAP(virtio_mmio)
+XEN_PVH_PROP_MEMMAP(pci_ecam)
+XEN_PVH_PROP_MEMMAP(pci_mmio)
+XEN_PVH_PROP_MEMMAP(pci_mmio_high)
+
+static void xen_pvh_set_pci_intx_irq_base(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ xp->cfg.pci_intx_irq_base = value;
+}
+
+static void xen_pvh_get_pci_intx_irq_base(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
+ uint32_t value = xp->cfg.pci_intx_irq_base;
+
+ visit_type_uint32(v, name, &value, errp);
+}
+
+void xen_pvh_class_setup_common_props(XenPVHMachineClass *xpc)
+{
+ ObjectClass *oc = OBJECT_CLASS(xpc);
+ MachineClass *mc = MACHINE_CLASS(xpc);
+
+#define OC_MEMMAP_PROP_BASE(c, prop_name, name) \
+do { \
+ object_class_property_add(c, prop_name "-base", "uint64_t", \
+ xen_pvh_get_ ## name ## _base, \
+ xen_pvh_set_ ## name ## _base, NULL, NULL); \
+ object_class_property_set_description(oc, prop_name "-base", \
+ "Set base address for " prop_name); \
+} while (0)
+
+#define OC_MEMMAP_PROP_SIZE(c, prop_name, name) \
+do { \
+ object_class_property_add(c, prop_name "-size", "uint64_t", \
+ xen_pvh_get_ ## name ## _size, \
+ xen_pvh_set_ ## name ## _size, NULL, NULL); \
+ object_class_property_set_description(oc, prop_name "-size", \
+ "Set memory range size for " prop_name); \
+} while (0)
+
+#define OC_MEMMAP_PROP(c, prop_name, name) \
+do { \
+ OC_MEMMAP_PROP_BASE(c, prop_name, name); \
+ OC_MEMMAP_PROP_SIZE(c, prop_name, name); \
+} while (0)
+
+ /*
+ * We provide memmap properties to allow Xen to move things to other
+ * addresses for example when users need to accomodate the memory-map
+ * for 1:1 mapped devices/memory.
+ */
+ OC_MEMMAP_PROP(oc, "ram-low", ram_low);
+ OC_MEMMAP_PROP(oc, "ram-high", ram_high);
+
+ if (xpc->has_virtio_mmio) {
+ OC_MEMMAP_PROP(oc, "virtio-mmio", virtio_mmio);
+ }
+
+ if (xpc->has_pci) {
+ OC_MEMMAP_PROP(oc, "pci-ecam", pci_ecam);
+ OC_MEMMAP_PROP(oc, "pci-mmio", pci_mmio);
+ OC_MEMMAP_PROP(oc, "pci-mmio-high", pci_mmio_high);
+
+ object_class_property_add(oc, "pci-intx-irq-base", "uint32_t",
+ xen_pvh_get_pci_intx_irq_base,
+ xen_pvh_set_pci_intx_irq_base,
+ NULL, NULL);
+ object_class_property_set_description(oc, "pci-intx-irq-base",
+ "Set PCI INTX interrupt base line.");
+ }
+
+#ifdef CONFIG_TPM
+ if (xpc->has_tpm) {
+ object_class_property_add(oc, "tpm-base-addr", "uint64_t",
+ xen_pvh_get_tpm_base,
+ xen_pvh_set_tpm_base,
+ NULL, NULL);
+ object_class_property_set_description(oc, "tpm-base-addr",
+ "Set Base address for TPM device.");
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
+ }
+#endif
+}
+
+static void xen_pvh_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->init = xen_pvh_init;
+
+ mc->desc = "Xen PVH machine";
+ mc->max_cpus = 1;
+ mc->default_machine_opts = "accel=xen";
+ /* Set to zero to make sure that the real ram size is passed. */
+ mc->default_ram_size = 0;
+}
+
+static const TypeInfo xen_pvh_info = {
+ .name = TYPE_XEN_PVH_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(XenPVHMachineState),
+ .class_size = sizeof(XenPVHMachineClass),
+ .class_init = xen_pvh_class_init,
+};
+
+static void xen_pvh_register_types(void)
+{
+ type_register_static(&xen_pvh_info);
+}
+
+type_init(xen_pvh_register_types);
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
index 2150869..5698cc7 100644
--- a/hw/xen/xen_devconfig.c
+++ b/hw/xen/xen_devconfig.c
@@ -1,8 +1,8 @@
#include "qemu/osdep.h"
#include "hw/xen/xen-legacy-backend.h"
#include "qemu/option.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
+#include "system/blockdev.h"
+#include "system/system.h"
/* ------------------------------------------------------------- */
@@ -66,11 +66,3 @@ int xen_config_dev_vkbd(int vdev)
xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
return xen_config_dev_all(fe, be);
}
-
-int xen_config_dev_console(int vdev)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
- return xen_config_dev_all(fe, be);
-}
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index 3635d1b..9d16644 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -766,6 +766,57 @@ static void xen_pt_destroy(PCIDevice *d) {
}
/* init */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 42000
+static bool xen_pt_need_gsi(void)
+{
+ FILE *fp;
+ int len;
+ /*
+ * The max length of guest_type is "PVH"+'\n'+'\0', it is 5,
+ * so here set the length of type to be twice.
+ */
+ char type[10];
+ const char *guest_type = "/sys/hypervisor/guest_type";
+
+ fp = fopen(guest_type, "r");
+ if (!fp) {
+ error_report("Cannot open %s: %s", guest_type, strerror(errno));
+ return false;
+ }
+
+ if (fgets(type, sizeof(type), fp)) {
+ len = strlen(type);
+ if (len) {
+ type[len - 1] = '\0';
+ if (!strcmp(type, "PVH")) {
+ fclose(fp);
+ return true;
+ }
+ }
+ }
+
+ fclose(fp);
+ return false;
+}
+
+static int xen_pt_map_pirq_for_gsi(PCIDevice *d, int *pirq)
+{
+ int gsi;
+ XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
+
+ gsi = xc_pcidev_get_gsi(xen_xc,
+ PCI_SBDF(s->real_device.domain,
+ s->real_device.bus,
+ s->real_device.dev,
+ s->real_device.func));
+ if (gsi >= 0) {
+ return xc_physdev_map_pirq_gsi(xen_xc, xen_domid, gsi, pirq);
+ }
+
+ return gsi;
+}
+#endif
+
static void xen_pt_realize(PCIDevice *d, Error **errp)
{
ERRP_GUARD();
@@ -847,7 +898,16 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
goto out;
}
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 42000
+ if (xen_pt_need_gsi()) {
+ rc = xen_pt_map_pirq_for_gsi(d, &pirq);
+ } else {
+ rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
+ }
+#else
rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
+#endif
+
if (rc < 0) {
XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (err: %d)\n",
machine_irq, pirq, errno);
@@ -931,10 +991,9 @@ static void xen_pt_unregister_device(PCIDevice *d)
xen_pt_destroy(d);
}
-static Property xen_pci_passthrough_properties[] = {
+static const Property xen_pci_passthrough_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
- DEFINE_PROP_END_OF_LIST(),
};
static void xen_pci_passthrough_instance_init(Object *obj)
@@ -988,7 +1047,7 @@ static void xen_igd_clear_slot(DeviceState *qdev, Error **errp)
xpdc->pci_qdev_realize(qdev, errp);
}
-static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
+static void xen_pci_passthrough_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1020,7 +1079,7 @@ static const TypeInfo xen_pci_passthrough_info = {
.class_init = xen_pci_passthrough_class_init,
.class_size = sizeof(XenPTDeviceClass),
.instance_init = xen_pci_passthrough_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ INTERFACE_PCIE_DEVICE },
{ },
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 6c2e3f4..2c0cec9 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -347,7 +347,7 @@ static const IGDDeviceIDInfo igd_combo_id_infos[] = {
{0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
};
-static void isa_bridge_class_init(ObjectClass *klass, void *data)
+static void isa_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -363,7 +363,7 @@ static const TypeInfo isa_bridge_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = isa_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
index c5ad71e..fe95b62 100644
--- a/hw/xen/xen_pvdev.c
+++ b/hw/xen/xen_pvdev.c
@@ -22,6 +22,7 @@
#include "qemu/main-loop.h"
#include "hw/qdev-core.h"
#include "hw/xen/xen-legacy-backend.h"
+#include "hw/xen/xen-bus-helper.h"
#include "hw/xen/xen_pvdev.h"
/* private */
@@ -81,12 +82,9 @@ int xenstore_write_str(const char *base, const char *node, const char *val)
char *xenstore_read_str(const char *base, const char *node)
{
- char abspath[XEN_BUFSIZE];
- unsigned int len;
char *str, *ret = NULL;
- snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
- str = qemu_xen_xs_read(xenstore, 0, abspath, &len);
+ str = xs_node_read(xenstore, 0, NULL, NULL, "%s/%s", base, node);
if (str != NULL) {
/* move to qemu-allocated memory to make sure
* callers can safely g_free() stuff. */
@@ -275,7 +273,7 @@ void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
QTAILQ_REMOVE(&xendevs, xendev, next);
- qdev_unplug(&xendev->qdev, NULL);
+ qdev_unplug(DEVICE(xendev), NULL);
}
void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
diff --git a/hw/xen/xen_stubs.c b/hw/xen/xen_stubs.c
new file mode 100644
index 0000000..5e565df
--- /dev/null
+++ b/hw/xen/xen_stubs.c
@@ -0,0 +1,51 @@
+/*
+ * Various stubs for xen functions
+ *
+ * Those functions are used only if xen_enabled(). This file is linked only if
+ * CONFIG_XEN is not set, so they should never be called.
+ *
+ * Copyright (c) 2025 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/xen.h"
+#include "system/xen-mapcache.h"
+
+void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
+{
+ g_assert_not_reached();
+}
+
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size,
+ struct MemoryRegion *mr, Error **errp)
+{
+ g_assert_not_reached();
+}
+
+bool xen_mr_is_memory(MemoryRegion *mr)
+{
+ g_assert_not_reached();
+}
+
+void xen_invalidate_map_cache_entry(uint8_t *buffer)
+{
+ g_assert_not_reached();
+}
+
+ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
+{
+ g_assert_not_reached();
+}
+
+uint8_t *xen_map_cache(MemoryRegion *mr,
+ hwaddr phys_addr,
+ hwaddr size,
+ ram_addr_t ram_addr_offset,
+ uint8_t lock,
+ bool dma,
+ bool is_write)
+{
+ g_assert_not_reached();
+}
diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c
index 24395f4..99c0249 100644
--- a/hw/xenpv/xen_machine_pv.c
+++ b/hw/xenpv/xen_machine_pv.c
@@ -27,8 +27,8 @@
#include "hw/boards.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen-bus.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/sysemu.h"
+#include "system/block-backend.h"
+#include "system/system.h"
static void xen_init_pv(MachineState *machine)
{
diff --git a/hw/xtensa/Kconfig b/hw/xtensa/Kconfig
index fc5c785..1f0492d 100644
--- a/hw/xtensa/Kconfig
+++ b/hw/xtensa/Kconfig
@@ -18,4 +18,4 @@ config XTENSA_XTFPGA
select DEVICE_TREE
select OPENCORES_ETH
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
diff --git a/hw/xtensa/bootparam.h b/hw/xtensa/bootparam.h
index f57ff85..4418c78 100644
--- a/hw/xtensa/bootparam.h
+++ b/hw/xtensa/bootparam.h
@@ -2,6 +2,7 @@
#define HW_XTENSA_BOOTPARAM_H
#include "exec/cpu-common.h"
+#include "exec/tswap.h"
#define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/
#define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */
diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c
index 8cef88c..e388531 100644
--- a/hw/xtensa/pic_cpu.c
+++ b/hw/xtensa/pic_cpu.c
@@ -27,6 +27,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "exec/cpu-interrupt.h"
#include "hw/irq.h"
#include "qemu/log.h"
#include "qemu/timer.h"
diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c
index 2160e61..49d17e7 100644
--- a/hw/xtensa/sim.c
+++ b/hw/xtensa/sim.c
@@ -27,12 +27,12 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
+#include "system/reset.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "elf.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qemu/error-report.h"
#include "xtensa_memory.h"
#include "xtensa_sim.h"
@@ -100,7 +100,8 @@ void xtensa_sim_load_kernel(XtensaCPU *cpu, MachineState *machine)
if (kernel_filename) {
uint64_t elf_entry;
int success = load_elf(kernel_filename, NULL, translate_phys_addr, cpu,
- &elf_entry, NULL, NULL, NULL, TARGET_BIG_ENDIAN,
+ &elf_entry, NULL, NULL, NULL,
+ TARGET_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
EM_XTENSA, 0, 0);
if (success > 0) {
diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c
index 5310a88..b10866c 100644
--- a/hw/xtensa/virt.c
+++ b/hw/xtensa/virt.c
@@ -27,13 +27,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/pci-host/gpex.h"
#include "net/net.h"
#include "elf.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qemu/error-report.h"
#include "xtensa_memory.h"
#include "xtensa_sim.h"
@@ -93,7 +93,7 @@ static void create_pcie(MachineState *ms, CPUXtensaState *env, int irq_base,
/* Connect IRQ lines. */
extints = xtensa_get_extints(env);
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
void *q = extints[irq_base + i];
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, q);
diff --git a/hw/xtensa/xtensa_memory.c b/hw/xtensa/xtensa_memory.c
index 2c1095f..13a6077 100644
--- a/hw/xtensa/xtensa_memory.c
+++ b/hw/xtensa/xtensa_memory.c
@@ -27,7 +27,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qemu/error-report.h"
#include "xtensa_memory.h"
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index 955e886..6efffae 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -29,20 +29,21 @@
#include "qemu/units.h"
#include "qapi/error.h"
#include "cpu.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
#include "elf.h"
-#include "exec/memory.h"
-#include "hw/char/serial.h"
+#include "system/memory.h"
+#include "exec/tswap.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
#include "hw/sysbus.h"
#include "hw/block/flash.h"
#include "chardev/char.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/device_tree.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
#include "bootparam.h"
@@ -397,7 +398,8 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
uint64_t elf_entry;
int success = load_elf(kernel_filename, NULL, translate_phys_addr, cpu,
- &elf_entry, NULL, NULL, NULL, TARGET_BIG_ENDIAN,
+ &elf_entry, NULL, NULL, NULL,
+ TARGET_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
EM_XTENSA, 0, 0);
if (success > 0) {
entry_point = elf_entry;
@@ -415,8 +417,7 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
}
}
if (entry_point != env->pc) {
- uint8_t boot[] = {
-#if TARGET_BIG_ENDIAN
+ uint8_t boot_be[] = {
0x60, 0x00, 0x08, /* j 1f */
0x00, /* .literal_position */
0x00, 0x00, 0x00, 0x00, /* .literal entry_pc */
@@ -425,7 +426,8 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
0x10, 0xff, 0xfe, /* l32r a0, entry_pc */
0x12, 0xff, 0xfe, /* l32r a2, entry_a2 */
0x0a, 0x00, 0x00, /* jx a0 */
-#else
+ };
+ uint8_t boot_le[] = {
0x06, 0x02, 0x00, /* j 1f */
0x00, /* .literal_position */
0x00, 0x00, 0x00, 0x00, /* .literal entry_pc */
@@ -434,14 +436,16 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
0x01, 0xfe, 0xff, /* l32r a0, entry_pc */
0x21, 0xfe, 0xff, /* l32r a2, entry_a2 */
0xa0, 0x00, 0x00, /* jx a0 */
-#endif
};
+ const size_t boot_sz = TARGET_BIG_ENDIAN ? sizeof(boot_be)
+ : sizeof(boot_le);
+ uint8_t *boot = TARGET_BIG_ENDIAN ? boot_be : boot_le;
uint32_t entry_pc = tswap32(entry_point);
uint32_t entry_a2 = tswap32(tagptr);
memcpy(boot + 4, &entry_pc, sizeof(entry_pc));
memcpy(boot + 8, &entry_a2, sizeof(entry_a2));
- cpu_physical_memory_write(env->pc, boot, sizeof(boot));
+ cpu_physical_memory_write(env->pc, boot, boot_sz);
}
} else {
if (flash) {
@@ -581,7 +585,7 @@ static void xtfpga_kc705_nommu_init(MachineState *machine)
xtfpga_init(&kc705_board, machine);
}
-static void xtfpga_lx60_class_init(ObjectClass *oc, void *data)
+static void xtfpga_lx60_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -598,7 +602,7 @@ static const TypeInfo xtfpga_lx60_type = {
.class_init = xtfpga_lx60_class_init,
};
-static void xtfpga_lx60_nommu_class_init(ObjectClass *oc, void *data)
+static void xtfpga_lx60_nommu_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -615,7 +619,7 @@ static const TypeInfo xtfpga_lx60_nommu_type = {
.class_init = xtfpga_lx60_nommu_class_init,
};
-static void xtfpga_lx200_class_init(ObjectClass *oc, void *data)
+static void xtfpga_lx200_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -632,7 +636,7 @@ static const TypeInfo xtfpga_lx200_type = {
.class_init = xtfpga_lx200_class_init,
};
-static void xtfpga_lx200_nommu_class_init(ObjectClass *oc, void *data)
+static void xtfpga_lx200_nommu_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -649,7 +653,7 @@ static const TypeInfo xtfpga_lx200_nommu_type = {
.class_init = xtfpga_lx200_nommu_class_init,
};
-static void xtfpga_ml605_class_init(ObjectClass *oc, void *data)
+static void xtfpga_ml605_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -666,7 +670,7 @@ static const TypeInfo xtfpga_ml605_type = {
.class_init = xtfpga_ml605_class_init,
};
-static void xtfpga_ml605_nommu_class_init(ObjectClass *oc, void *data)
+static void xtfpga_ml605_nommu_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -683,7 +687,7 @@ static const TypeInfo xtfpga_ml605_nommu_type = {
.class_init = xtfpga_ml605_nommu_class_init,
};
-static void xtfpga_kc705_class_init(ObjectClass *oc, void *data)
+static void xtfpga_kc705_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -700,7 +704,7 @@ static const TypeInfo xtfpga_kc705_type = {
.class_init = xtfpga_kc705_class_init,
};
-static void xtfpga_kc705_nommu_class_init(ObjectClass *oc, void *data)
+static void xtfpga_kc705_nommu_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);