aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS4
-rw-r--r--Makefile2
-rw-r--r--Makefile.objs1
-rw-r--r--accel/accel.c1
-rw-r--r--audio/Makefile.objs2
-rw-r--r--audio/alsaaudio.c370
-rw-r--r--audio/audio.c859
-rw-r--r--audio/audio.h30
-rw-r--r--audio/audio_int.h37
-rw-r--r--audio/audio_legacy.c544
-rw-r--r--audio/audio_template.h42
-rw-r--r--audio/audio_win_int.c18
-rw-r--r--audio/coreaudio.c51
-rw-r--r--audio/dsound_template.h6
-rw-r--r--audio/dsoundaudio.c61
-rw-r--r--audio/noaudio.c3
-rw-r--r--audio/ossaudio.c191
-rw-r--r--audio/paaudio.c111
-rw-r--r--audio/sdlaudio.c50
-rw-r--r--audio/spiceaudio.c11
-rw-r--r--audio/wavaudio.c75
-rw-r--r--audio/wavcapture.c2
-rw-r--r--backends/cryptodev-vhost-user.c18
-rw-r--r--backends/hostmem-file.c23
-rw-r--r--backends/hostmem-memfd.c18
-rw-r--r--block.c440
-rw-r--r--block/commit.c16
-rw-r--r--block/dirty-bitmap.c174
-rw-r--r--block/file-posix.c270
-rw-r--r--block/gluster.c10
-rw-r--r--block/mirror.c8
-rw-r--r--block/qapi.c12
-rw-r--r--block/qcow2-bitmap.c170
-rw-r--r--block/qcow2.c29
-rw-r--r--block/qcow2.h1
-rw-r--r--block/raw-format.c3
-rw-r--r--block/replication.c7
-rw-r--r--block/stream.c21
-rw-r--r--blockdev.c116
-rwxr-xr-xconfigure113
-rw-r--r--contrib/libvhost-user/libvhost-user-glib.c11
-rw-r--r--contrib/libvhost-user/libvhost-user-glib.h3
-rw-r--r--contrib/libvhost-user/libvhost-user.c468
-rw-r--r--contrib/libvhost-user/libvhost-user.h86
-rw-r--r--default-configs/ppc-softmmu.mak2
-rw-r--r--docs/devel/decodetree.rst221
-rw-r--r--docs/devel/index.rst2
-rw-r--r--docs/interop/firmware.json20
-rw-r--r--docs/interop/qcow2.txt9
-rw-r--r--docs/interop/vhost-user.json232
-rw-r--r--docs/interop/vhost-user.txt386
-rw-r--r--hw/acpi/ich9.c15
-rw-r--r--hw/acpi/nvdimm.c26
-rw-r--r--hw/acpi/piix4.c14
-rw-r--r--hw/arm/collie.c9
-rw-r--r--hw/arm/digic_boards.c3
-rw-r--r--hw/arm/gumstix.c10
-rw-r--r--hw/arm/mainstone.c5
-rw-r--r--hw/arm/musicpal.c8
-rw-r--r--hw/arm/omap2.c2
-rw-r--r--hw/arm/omap_sx1.c10
-rw-r--r--hw/arm/versatilepb.c3
-rw-r--r--hw/arm/vexpress.c10
-rw-r--r--hw/arm/virt.c7
-rw-r--r--hw/arm/xilinx_zynq.c7
-rw-r--r--hw/arm/z2.c6
-rw-r--r--hw/audio/ac97.c2
-rw-r--r--hw/audio/adlib.c2
-rw-r--r--hw/audio/cs4231a.c6
-rw-r--r--hw/audio/es1370.c4
-rw-r--r--hw/audio/gus.c2
-rw-r--r--hw/audio/hda-codec.c18
-rw-r--r--hw/audio/lm4549.c6
-rw-r--r--hw/audio/milkymist-ac97.c2
-rw-r--r--hw/audio/pcspk.c2
-rw-r--r--hw/audio/sb16.c14
-rw-r--r--hw/audio/wm8750.c6
-rw-r--r--hw/block/nvme.c6
-rw-r--r--hw/block/pflash_cfi01.c128
-rw-r--r--hw/block/pflash_cfi02.c81
-rw-r--r--hw/block/vhost-user-blk.c50
-rw-r--r--hw/char/spapr_vty.c58
-rw-r--r--hw/core/machine.c65
-rw-r--r--hw/core/qdev.c21
-rw-r--r--hw/core/sysbus.c3
-rw-r--r--hw/display/xlnx_dp.c2
-rw-r--r--hw/i2c/Kconfig4
-rw-r--r--hw/i2c/Makefile.objs1
-rw-r--r--hw/i2c/mpc_i2c.c357
-rw-r--r--hw/i386/acpi-build.c6
-rw-r--r--hw/i386/intel_iommu.c559
-rw-r--r--hw/i386/intel_iommu_internal.h54
-rw-r--r--hw/i386/pc.c63
-rw-r--r--hw/i386/pc_piix.c4
-rw-r--r--hw/i386/pc_q35.c4
-rw-r--r--hw/i386/pc_sysfw.c245
-rw-r--r--hw/i386/trace-events2
-rw-r--r--hw/input/tsc210x.c2
-rw-r--r--hw/intc/Makefile.objs2
-rw-r--r--hw/intc/pnv_xive.c1753
-rw-r--r--hw/intc/pnv_xive_regs.h248
-rw-r--r--hw/intc/spapr_xive.c86
-rw-r--r--hw/intc/xics_kvm.c4
-rw-r--r--hw/intc/xics_spapr.c24
-rw-r--r--hw/intc/xive.c113
-rw-r--r--hw/isa/lpc_ich9.c1
-rw-r--r--hw/lm32/lm32_boards.c8
-rw-r--r--hw/lm32/milkymist.c5
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c6
-rw-r--r--hw/microblaze/petalogix_s3adsp1800_mmu.c5
-rw-r--r--hw/mips/mips_malta.c21
-rw-r--r--hw/mips/mips_r4k.c5
-rw-r--r--hw/net/spapr_llan.c110
-rw-r--r--hw/nvram/fw_cfg.c9
-rw-r--r--hw/nvram/spapr_nvram.c42
-rw-r--r--hw/pci-bridge/gen_pcie_root_port.c4
-rw-r--r--hw/pci-bridge/pcie_root_port.c4
-rw-r--r--hw/pci/pcie.c38
-rw-r--r--hw/ppc/e500.c54
-rw-r--r--hw/ppc/mac_newworld.c4
-rw-r--r--hw/ppc/mac_oldworld.c4
-rw-r--r--hw/ppc/pnv.c252
-rw-r--r--hw/ppc/pnv_core.c189
-rw-r--r--hw/ppc/pnv_lpc.c316
-rw-r--r--hw/ppc/pnv_occ.c127
-rw-r--r--hw/ppc/pnv_psi.c425
-rw-r--r--hw/ppc/pnv_xscom.c33
-rw-r--r--hw/ppc/ppc.c106
-rw-r--r--hw/ppc/ppc405_boards.c102
-rw-r--r--hw/ppc/sam460ex.c42
-rw-r--r--hw/ppc/spapr.c361
-rw-r--r--hw/ppc/spapr_caps.c254
-rw-r--r--hw/ppc/spapr_cpu_core.c52
-rw-r--r--hw/ppc/spapr_drc.c134
-rw-r--r--hw/ppc/spapr_events.c92
-rw-r--r--hw/ppc/spapr_hcall.c120
-rw-r--r--hw/ppc/spapr_iommu.c107
-rw-r--r--hw/ppc/spapr_irq.c104
-rw-r--r--hw/ppc/spapr_ovec.c46
-rw-r--r--hw/ppc/spapr_pci.c212
-rw-r--r--hw/ppc/spapr_pci_vfio.c14
-rw-r--r--hw/ppc/spapr_rng.c18
-rw-r--r--hw/ppc/spapr_rtas.c30
-rw-r--r--hw/ppc/spapr_rtas_ddw.c42
-rw-r--r--hw/ppc/spapr_rtc.c16
-rw-r--r--hw/ppc/spapr_vio.c116
-rw-r--r--hw/ppc/virtex_ml507.c5
-rw-r--r--hw/scsi/spapr_vscsi.c14
-rw-r--r--hw/scsi/vhost-user-scsi.c20
-rw-r--r--hw/sd/Kconfig6
-rw-r--r--hw/sd/Makefile.objs1
-rw-r--r--hw/sd/sdhci-internal.h34
-rw-r--r--hw/sd/sdhci-pci.c87
-rw-r--r--hw/sd/sdhci.c98
-rw-r--r--hw/sh4/r2d.c17
-rw-r--r--hw/usb/dev-audio.c2
-rw-r--r--hw/vfio/common.c2
-rw-r--r--hw/vfio/display.c169
-rw-r--r--hw/vfio/pci.c12
-rw-r--r--hw/vfio/pci.h2
-rw-r--r--hw/vfio/spapr.c49
-rw-r--r--hw/vfio/trace-events9
-rw-r--r--hw/virtio/vhost-stub.c4
-rw-r--r--hw/virtio/vhost-user.c163
-rw-r--r--hw/virtio/vhost.c96
-rw-r--r--hw/virtio/virtio-balloon.c78
-rw-r--r--hw/xtensa/xtfpga.c12
-rw-r--r--include/block/block.h13
-rw-r--r--include/block/block_int.h14
-rw-r--r--include/block/dirty-bitmap.h24
-rw-r--r--include/hw/acpi/ich9.h2
-rw-r--r--include/hw/block/flash.h58
-rw-r--r--include/hw/boards.h2
-rw-r--r--include/hw/i386/intel_iommu.h28
-rw-r--r--include/hw/i386/pc.h10
-rw-r--r--include/hw/mem/nvdimm.h10
-rw-r--r--include/hw/pci-host/spapr.h44
-rw-r--r--include/hw/pci/pcie.h6
-rw-r--r--include/hw/pci/pcie_port.h1
-rw-r--r--include/hw/pci/pcie_regs.h4
-rw-r--r--include/hw/ppc/pnv.h42
-rw-r--r--include/hw/ppc/pnv_core.h14
-rw-r--r--include/hw/ppc/pnv_lpc.h26
-rw-r--r--include/hw/ppc/pnv_occ.h17
-rw-r--r--include/hw/ppc/pnv_psi.h59
-rw-r--r--include/hw/ppc/pnv_xive.h93
-rw-r--r--include/hw/ppc/pnv_xscom.h21
-rw-r--r--include/hw/ppc/ppc.h1
-rw-r--r--include/hw/ppc/spapr.h194
-rw-r--r--include/hw/ppc/spapr_cpu_core.h24
-rw-r--r--include/hw/ppc/spapr_drc.h108
-rw-r--r--include/hw/ppc/spapr_irq.h58
-rw-r--r--include/hw/ppc/spapr_ovec.h30
-rw-r--r--include/hw/ppc/spapr_vio.h74
-rw-r--r--include/hw/ppc/spapr_xive.h18
-rw-r--r--include/hw/ppc/xics_spapr.h6
-rw-r--r--include/hw/ppc/xive.h4
-rw-r--r--include/hw/qdev-core.h2
-rw-r--r--include/hw/vfio/vfio-common.h6
-rw-r--r--include/hw/virtio/vhost-backend.h10
-rw-r--r--include/hw/virtio/vhost-user-blk.h3
-rw-r--r--include/hw/virtio/vhost-user-scsi.h2
-rw-r--r--include/hw/virtio/vhost-user.h2
-rw-r--r--include/hw/virtio/vhost.h18
-rw-r--r--include/qemu/osdep.h13
-rw-r--r--include/qom/object.h3
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--migration/block-dirty-bitmap.c23
-rw-r--r--nbd/server.c13
-rw-r--r--net/vhost-user.c13
-rw-r--r--pc-bios/u-boot.e500bin388672 -> 349148 bytes
-rw-r--r--qapi/Makefile.objs6
-rw-r--r--qapi/audio.json304
-rw-r--r--qapi/block-core.json100
-rw-r--r--qapi/qapi-schema.json1
-rw-r--r--qapi/ui.json14
-rw-r--r--qemu-deprecated.texi13
-rw-r--r--qemu-io-cmds.c4
-rw-r--r--qemu-options.hx241
-rw-r--r--qom/object.c39
m---------roms/u-boot0
-rwxr-xr-xscripts/decodetree.py333
-rw-r--r--scripts/qemugdb/timers.py6
-rwxr-xr-xscripts/qmp/qmp-shell4
-rw-r--r--slirp/src/state.c1
-rw-r--r--slirp/src/state.h0
-rw-r--r--target/hppa/cpu.h10
-rw-r--r--target/hppa/gdbstub.c20
-rw-r--r--target/hppa/helper.c10
-rw-r--r--target/hppa/helper.h1
-rw-r--r--target/hppa/insns.decode3
-rw-r--r--target/hppa/mem_helper.c67
-rw-r--r--target/hppa/op_helper.c7
-rw-r--r--target/hppa/trace-events18
-rw-r--r--target/hppa/translate.c51
-rw-r--r--target/ppc/cpu-qom.h1
-rw-r--r--target/ppc/cpu.h59
-rw-r--r--target/ppc/excp_helper.c30
-rw-r--r--target/ppc/internal.h27
-rw-r--r--target/ppc/kvm.c206
-rw-r--r--target/ppc/kvm_ppc.h23
-rw-r--r--target/ppc/machine.c8
-rw-r--r--target/ppc/mmu-hash64.c2
-rw-r--r--target/ppc/translate.c22
-rw-r--r--target/ppc/translate/vmx-impl.inc.c27
-rw-r--r--target/ppc/translate/vsx-impl.inc.c65
-rw-r--r--target/ppc/translate_init.inc.c7
-rw-r--r--target/riscv/Makefile.objs19
-rw-r--r--target/riscv/insn16.decode129
-rw-r--r--target/riscv/insn32-64.decode72
-rw-r--r--target/riscv/insn32.decode201
-rw-r--r--target/riscv/insn_trans/trans_privileged.inc.c110
-rw-r--r--target/riscv/insn_trans/trans_rva.inc.c218
-rw-r--r--target/riscv/insn_trans/trans_rvc.inc.c327
-rw-r--r--target/riscv/insn_trans/trans_rvd.inc.c442
-rw-r--r--target/riscv/insn_trans/trans_rvf.inc.c439
-rw-r--r--target/riscv/insn_trans/trans_rvi.inc.c568
-rw-r--r--target/riscv/insn_trans/trans_rvm.inc.c120
-rw-r--r--target/riscv/translate.c1835
-rw-r--r--tests/ahci-test.c81
-rw-r--r--tests/boot-serial-test.c4
-rwxr-xr-xtests/decode/check.sh6
-rw-r--r--tests/decode/err_pattern_group_empty.decode6
-rw-r--r--tests/decode/err_pattern_group_ident1.decode10
-rw-r--r--tests/decode/err_pattern_group_ident2.decode11
-rw-r--r--tests/decode/err_pattern_group_nest1.decode13
-rw-r--r--tests/decode/err_pattern_group_overlap1.decode6
-rw-r--r--tests/decode/err_width1.decode5
-rw-r--r--tests/decode/err_width2.decode5
-rw-r--r--tests/decode/err_width3.decode5
-rw-r--r--tests/decode/err_width4.decode5
-rw-r--r--tests/decode/succ_pattern_group_nest1.decode22
-rw-r--r--tests/libqos/libqos.c9
-rw-r--r--tests/libqos/libqos.h1
-rw-r--r--tests/pnv-xscom-test.c2
-rw-r--r--tests/prom-env-test.c13
-rw-r--r--tests/pxe-test.c19
-rwxr-xr-xtests/qemu-iotests/0517
-rw-r--r--tests/qemu-iotests/051.out9
-rw-r--r--tests/qemu-iotests/051.pc.out9
-rwxr-xr-xtests/qemu-iotests/124113
-rw-r--r--tests/qemu-iotests/124.out4
-rwxr-xr-xtests/qemu-iotests/23231
-rw-r--r--tests/qemu-iotests/232.out32
-rw-r--r--tests/qemu-iotests/236.out28
-rw-r--r--tests/qemu-iotests/245991
-rw-r--r--tests/qemu-iotests/245.out5
-rwxr-xr-xtests/qemu-iotests/246114
-rw-r--r--tests/qemu-iotests/246.out295
-rw-r--r--tests/qemu-iotests/group2
-rw-r--r--tests/test-announce-self.c21
-rw-r--r--tests/vhost-user-test.c5
-rw-r--r--tests/virtio-blk-test.c2
-rw-r--r--thunk.c2
-rw-r--r--ui/Makefile.objs4
-rw-r--r--ui/curses.c315
-rw-r--r--ui/vnc.c26
-rw-r--r--util/memfd.c10
-rw-r--r--util/oslib-posix.c53
-rw-r--r--util/oslib-win32.c5
-rw-r--r--vl.c135
301 files changed, 17632 insertions, 6147 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index cf09a4c127..0e7baa9aa2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -117,6 +117,8 @@ F: cpus.c
F: exec.c
F: accel/tcg/
F: accel/stubs/tcg-stub.c
+F: scripts/decodetree.py
+F: docs/devel/decodetree.rst
F: include/exec/cpu*.h
F: include/exec/exec-all.h
F: include/exec/helper*.h
@@ -984,6 +986,7 @@ L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/e500*
F: hw/gpio/mpc8xxx.c
+F: hw/i2c/mpc_i2c.c
F: hw/net/fsl_etsec/
F: hw/pci-host/ppce500.c
F: include/hw/ppc/ppc_e500.h
@@ -1452,6 +1455,7 @@ vhost
M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
F: hw/*/*vhost*
+F: docs/interop/vhost-user.json
F: docs/interop/vhost-user.txt
F: contrib/vhost-user-*/
diff --git a/Makefile b/Makefile
index 6ccb8639b0..abd78a9826 100644
--- a/Makefile
+++ b/Makefile
@@ -497,7 +497,7 @@ Makefile: $(version-obj-y)
# Build libraries
libqemuutil.a: $(util-obj-y) $(trace-obj-y) $(stub-obj-y)
-libvhost-user.a: $(libvhost-user-obj-y)
+libvhost-user.a: $(libvhost-user-obj-y) $(util-obj-y) $(stub-obj-y)
######################################################################
diff --git a/Makefile.objs b/Makefile.objs
index 31a84b7d41..72debbf5c5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -182,6 +182,7 @@ trace-events-subdirs += qapi
trace-events-subdirs += qom
trace-events-subdirs += scsi
trace-events-subdirs += target/arm
+trace-events-subdirs += target/hppa
trace-events-subdirs += target/i386
trace-events-subdirs += target/mips
trace-events-subdirs += target/ppc
diff --git a/accel/accel.c b/accel/accel.c
index 0d5b370dfd..8deb475b5d 100644
--- a/accel/accel.c
+++ b/accel/accel.c
@@ -66,6 +66,7 @@ static int accel_init_machine(AccelClass *acc, MachineState *ms)
*(acc->allowed) = false;
object_unref(OBJECT(accel));
}
+ object_set_accelerator_compat_props(acc->compat_props);
return ret;
}
diff --git a/audio/Makefile.objs b/audio/Makefile.objs
index db4fa7f18f..dca87f6347 100644
--- a/audio/Makefile.objs
+++ b/audio/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
+common-obj-y = audio.o audio_legacy.o noaudio.o wavaudio.o mixeng.o
common-obj-$(CONFIG_SPICE) += spiceaudio.o
common-obj-$(CONFIG_AUDIO_COREAUDIO) += coreaudio.o
common-obj-$(CONFIG_AUDIO_DSOUND) += dsoundaudio.o
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 635be73bf4..49e6884309 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -33,28 +33,9 @@
#define AUDIO_CAP "alsa"
#include "audio_int.h"
-typedef struct ALSAConf {
- int size_in_usec_in;
- int size_in_usec_out;
- const char *pcm_name_in;
- const char *pcm_name_out;
- unsigned int buffer_size_in;
- unsigned int period_size_in;
- unsigned int buffer_size_out;
- unsigned int period_size_out;
- unsigned int threshold;
-
- int buffer_size_in_overridden;
- int period_size_in_overridden;
-
- int buffer_size_out_overridden;
- int period_size_out_overridden;
-} ALSAConf;
-
struct pollhlp {
snd_pcm_t *handle;
struct pollfd *pfds;
- ALSAConf *conf;
int count;
int mask;
};
@@ -66,6 +47,7 @@ typedef struct ALSAVoiceOut {
void *pcm_buf;
snd_pcm_t *handle;
struct pollhlp pollhlp;
+ Audiodev *dev;
} ALSAVoiceOut;
typedef struct ALSAVoiceIn {
@@ -73,21 +55,18 @@ typedef struct ALSAVoiceIn {
snd_pcm_t *handle;
void *pcm_buf;
struct pollhlp pollhlp;
+ Audiodev *dev;
} ALSAVoiceIn;
struct alsa_params_req {
int freq;
snd_pcm_format_t fmt;
int nchannels;
- int size_in_usec;
- int override_mask;
- unsigned int buffer_size;
- unsigned int period_size;
};
struct alsa_params_obt {
int freq;
- audfmt_e fmt;
+ AudioFormat fmt;
int endianness;
int nchannels;
snd_pcm_uframes_t samples;
@@ -294,16 +273,16 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len);
}
-static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
+static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
{
switch (fmt) {
- case AUD_FMT_S8:
+ case AUDIO_FORMAT_S8:
return SND_PCM_FORMAT_S8;
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_U8:
return SND_PCM_FORMAT_U8;
- case AUD_FMT_S16:
+ case AUDIO_FORMAT_S16:
if (endianness) {
return SND_PCM_FORMAT_S16_BE;
}
@@ -311,7 +290,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
return SND_PCM_FORMAT_S16_LE;
}
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_U16:
if (endianness) {
return SND_PCM_FORMAT_U16_BE;
}
@@ -319,7 +298,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
return SND_PCM_FORMAT_U16_LE;
}
- case AUD_FMT_S32:
+ case AUDIO_FORMAT_S32:
if (endianness) {
return SND_PCM_FORMAT_S32_BE;
}
@@ -327,7 +306,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
return SND_PCM_FORMAT_S32_LE;
}
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_U32:
if (endianness) {
return SND_PCM_FORMAT_U32_BE;
}
@@ -344,58 +323,58 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
}
}
-static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
+static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
int *endianness)
{
switch (alsafmt) {
case SND_PCM_FORMAT_S8:
*endianness = 0;
- *fmt = AUD_FMT_S8;
+ *fmt = AUDIO_FORMAT_S8;
break;
case SND_PCM_FORMAT_U8:
*endianness = 0;
- *fmt = AUD_FMT_U8;
+ *fmt = AUDIO_FORMAT_U8;
break;
case SND_PCM_FORMAT_S16_LE:
*endianness = 0;
- *fmt = AUD_FMT_S16;
+ *fmt = AUDIO_FORMAT_S16;
break;
case SND_PCM_FORMAT_U16_LE:
*endianness = 0;
- *fmt = AUD_FMT_U16;
+ *fmt = AUDIO_FORMAT_U16;
break;
case SND_PCM_FORMAT_S16_BE:
*endianness = 1;
- *fmt = AUD_FMT_S16;
+ *fmt = AUDIO_FORMAT_S16;
break;
case SND_PCM_FORMAT_U16_BE:
*endianness = 1;
- *fmt = AUD_FMT_U16;
+ *fmt = AUDIO_FORMAT_U16;
break;
case SND_PCM_FORMAT_S32_LE:
*endianness = 0;
- *fmt = AUD_FMT_S32;
+ *fmt = AUDIO_FORMAT_S32;
break;
case SND_PCM_FORMAT_U32_LE:
*endianness = 0;
- *fmt = AUD_FMT_U32;
+ *fmt = AUDIO_FORMAT_U32;
break;
case SND_PCM_FORMAT_S32_BE:
*endianness = 1;
- *fmt = AUD_FMT_S32;
+ *fmt = AUDIO_FORMAT_S32;
break;
case SND_PCM_FORMAT_U32_BE:
*endianness = 1;
- *fmt = AUD_FMT_U32;
+ *fmt = AUDIO_FORMAT_U32;
break;
default:
@@ -408,17 +387,18 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
static void alsa_dump_info (struct alsa_params_req *req,
struct alsa_params_obt *obt,
- snd_pcm_format_t obtfmt)
+ snd_pcm_format_t obtfmt,
+ AudiodevAlsaPerDirectionOptions *apdo)
{
- dolog ("parameter | requested value | obtained value\n");
- dolog ("format | %10d | %10d\n", req->fmt, obtfmt);
- dolog ("channels | %10d | %10d\n",
- req->nchannels, obt->nchannels);
- dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
- dolog ("============================================\n");
- dolog ("requested: buffer size %d period size %d\n",
- req->buffer_size, req->period_size);
- dolog ("obtained: samples %ld\n", obt->samples);
+ dolog("parameter | requested value | obtained value\n");
+ dolog("format | %10d | %10d\n", req->fmt, obtfmt);
+ dolog("channels | %10d | %10d\n",
+ req->nchannels, obt->nchannels);
+ dolog("frequency | %10d | %10d\n", req->freq, obt->freq);
+ dolog("============================================\n");
+ dolog("requested: buffer len %" PRId32 " period len %" PRId32 "\n",
+ apdo->buffer_length, apdo->period_length);
+ dolog("obtained: samples %ld\n", obt->samples);
}
static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
@@ -451,23 +431,23 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
}
}
-static int alsa_open (int in, struct alsa_params_req *req,
- struct alsa_params_obt *obt, snd_pcm_t **handlep,
- ALSAConf *conf)
+static int alsa_open(bool in, struct alsa_params_req *req,
+ struct alsa_params_obt *obt, snd_pcm_t **handlep,
+ Audiodev *dev)
{
+ AudiodevAlsaOptions *aopts = &dev->u.alsa;
+ AudiodevAlsaPerDirectionOptions *apdo = in ? aopts->in : aopts->out;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params;
int err;
- int size_in_usec;
unsigned int freq, nchannels;
- const char *pcm_name = in ? conf->pcm_name_in : conf->pcm_name_out;
+ const char *pcm_name = apdo->has_dev ? apdo->dev : "default";
snd_pcm_uframes_t obt_buffer_size;
const char *typ = in ? "ADC" : "DAC";
snd_pcm_format_t obtfmt;
freq = req->freq;
nchannels = req->nchannels;
- size_in_usec = req->size_in_usec;
snd_pcm_hw_params_alloca (&hw_params);
@@ -527,79 +507,42 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- if (req->buffer_size) {
- unsigned long obt;
+ if (apdo->buffer_length) {
+ int dir = 0;
+ unsigned int btime = apdo->buffer_length;
- if (size_in_usec) {
- int dir = 0;
- unsigned int btime = req->buffer_size;
+ err = snd_pcm_hw_params_set_buffer_time_near(
+ handle, hw_params, &btime, &dir);
- err = snd_pcm_hw_params_set_buffer_time_near (
- handle,
- hw_params,
- &btime,
- &dir
- );
- obt = btime;
- }
- else {
- snd_pcm_uframes_t bsize = req->buffer_size;
-
- err = snd_pcm_hw_params_set_buffer_size_near (
- handle,
- hw_params,
- &bsize
- );
- obt = bsize;
- }
if (err < 0) {
- alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
- size_in_usec ? "time" : "size", req->buffer_size);
+ alsa_logerr2(err, typ, "Failed to set buffer time to %" PRId32 "\n",
+ apdo->buffer_length);
goto err;
}
- if ((req->override_mask & 2) && (obt - req->buffer_size))
- dolog ("Requested buffer %s %u was rejected, using %lu\n",
- size_in_usec ? "time" : "size", req->buffer_size, obt);
+ if (apdo->has_buffer_length && btime != apdo->buffer_length) {
+ dolog("Requested buffer time %" PRId32
+ " was rejected, using %u\n", apdo->buffer_length, btime);
+ }
}
- if (req->period_size) {
- unsigned long obt;
+ if (apdo->period_length) {
+ int dir = 0;
+ unsigned int ptime = apdo->period_length;
- if (size_in_usec) {
- int dir = 0;
- unsigned int ptime = req->period_size;
-
- err = snd_pcm_hw_params_set_period_time_near (
- handle,
- hw_params,
- &ptime,
- &dir
- );
- obt = ptime;
- }
- else {
- int dir = 0;
- snd_pcm_uframes_t psize = req->period_size;
-
- err = snd_pcm_hw_params_set_period_size_near (
- handle,
- hw_params,
- &psize,
- &dir
- );
- obt = psize;
- }
+ err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &ptime,
+ &dir);
if (err < 0) {
- alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
- size_in_usec ? "time" : "size", req->period_size);
+ alsa_logerr2(err, typ, "Failed to set period time to %" PRId32 "\n",
+ apdo->period_length);
goto err;
}
- if (((req->override_mask & 1) && (obt - req->period_size)))
- dolog ("Requested period %s %u was rejected, using %lu\n",
- size_in_usec ? "time" : "size", req->period_size, obt);
+ if (apdo->has_period_length && ptime != apdo->period_length) {
+ dolog("Requested period time %" PRId32 " was rejected, using %d\n",
+ apdo->period_length, ptime);
+ }
}
err = snd_pcm_hw_params (handle, hw_params);
@@ -631,30 +574,12 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- if (!in && conf->threshold) {
- snd_pcm_uframes_t threshold;
- int bytes_per_sec;
-
- bytes_per_sec = freq << (nchannels == 2);
-
- switch (obt->fmt) {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
- break;
-
- case AUD_FMT_S16:
- case AUD_FMT_U16:
- bytes_per_sec <<= 1;
- break;
-
- case AUD_FMT_S32:
- case AUD_FMT_U32:
- bytes_per_sec <<= 2;
- break;
- }
-
- threshold = (conf->threshold * bytes_per_sec) / 1000;
- alsa_set_threshold (handle, threshold);
+ if (!in && aopts->has_threshold && aopts->threshold) {
+ struct audsettings as = { .freq = freq };
+ alsa_set_threshold(
+ handle,
+ audio_buffer_frames(qapi_AudiodevAlsaPerDirectionOptions_base(apdo),
+ &as, aopts->threshold));
}
obt->nchannels = nchannels;
@@ -667,11 +592,11 @@ static int alsa_open (int in, struct alsa_params_req *req,
obt->nchannels != req->nchannels ||
obt->freq != req->freq) {
dolog ("Audio parameters for %s\n", typ);
- alsa_dump_info (req, obt, obtfmt);
+ alsa_dump_info(req, obt, obtfmt, apdo);
}
#ifdef DEBUG
- alsa_dump_info (req, obt, obtfmt);
+ alsa_dump_info(req, obt, obtfmt, pdo);
#endif
return 0;
@@ -797,19 +722,13 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
struct alsa_params_obt obt;
snd_pcm_t *handle;
struct audsettings obt_as;
- ALSAConf *conf = drv_opaque;
+ Audiodev *dev = drv_opaque;
req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
- req.period_size = conf->period_size_out;
- req.buffer_size = conf->buffer_size_out;
- req.size_in_usec = conf->size_in_usec_out;
- req.override_mask =
- (conf->period_size_out_overridden ? 1 : 0) |
- (conf->buffer_size_out_overridden ? 2 : 0);
-
- if (alsa_open (0, &req, &obt, &handle, conf)) {
+
+ if (alsa_open(0, &req, &obt, &handle, dev)) {
return -1;
}
@@ -830,7 +749,7 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
}
alsa->handle = handle;
- alsa->pollhlp.conf = conf;
+ alsa->dev = dev;
return 0;
}
@@ -870,16 +789,12 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+ AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.out;
switch (cmd) {
case VOICE_ENABLE:
{
- va_list ap;
- int poll_mode;
-
- va_start (ap, cmd);
- poll_mode = va_arg (ap, int);
- va_end (ap);
+ bool poll_mode = apdo->try_poll;
ldebug ("enabling voice\n");
if (poll_mode && alsa_poll_out (hw)) {
@@ -908,19 +823,13 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
struct alsa_params_obt obt;
snd_pcm_t *handle;
struct audsettings obt_as;
- ALSAConf *conf = drv_opaque;
+ Audiodev *dev = drv_opaque;
req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
- req.period_size = conf->period_size_in;
- req.buffer_size = conf->buffer_size_in;
- req.size_in_usec = conf->size_in_usec_in;
- req.override_mask =
- (conf->period_size_in_overridden ? 1 : 0) |
- (conf->buffer_size_in_overridden ? 2 : 0);
-
- if (alsa_open (1, &req, &obt, &handle, conf)) {
+
+ if (alsa_open(1, &req, &obt, &handle, dev)) {
return -1;
}
@@ -941,7 +850,7 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
}
alsa->handle = handle;
- alsa->pollhlp.conf = conf;
+ alsa->dev = dev;
return 0;
}
@@ -1083,16 +992,12 @@ static int alsa_read (SWVoiceIn *sw, void *buf, int size)
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+ AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.in;
switch (cmd) {
case VOICE_ENABLE:
{
- va_list ap;
- int poll_mode;
-
- va_start (ap, cmd);
- poll_mode = va_arg (ap, int);
- va_end (ap);
+ bool poll_mode = apdo->try_poll;
ldebug ("enabling voice\n");
if (poll_mode && alsa_poll_in (hw)) {
@@ -1115,88 +1020,54 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
return -1;
}
-static ALSAConf glob_conf = {
- .buffer_size_out = 4096,
- .period_size_out = 1024,
- .pcm_name_out = "default",
- .pcm_name_in = "default",
-};
+static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo)
+{
+ if (!apdo->has_try_poll) {
+ apdo->try_poll = true;
+ apdo->has_try_poll = true;
+ }
+}
-static void *alsa_audio_init (void)
+static void *alsa_audio_init(Audiodev *dev)
{
- ALSAConf *conf = g_malloc(sizeof(ALSAConf));
- *conf = glob_conf;
- return conf;
+ AudiodevAlsaOptions *aopts;
+ assert(dev->driver == AUDIODEV_DRIVER_ALSA);
+
+ aopts = &dev->u.alsa;
+ alsa_init_per_direction(aopts->in);
+ alsa_init_per_direction(aopts->out);
+
+ /*
+ * need to define them, as otherwise alsa produces no sound
+ * doesn't set has_* so alsa_open can identify it wasn't set by the user
+ */
+ if (!dev->u.alsa.out->has_period_length) {
+ /* 1024 frames assuming 44100Hz */
+ dev->u.alsa.out->period_length = 1024 * 1000000 / 44100;
+ }
+ if (!dev->u.alsa.out->has_buffer_length) {
+ /* 4096 frames assuming 44100Hz */
+ dev->u.alsa.out->buffer_length = 4096ll * 1000000 / 44100;
+ }
+
+ /*
+ * OptsVisitor sets unspecified optional fields to zero, but do not depend
+ * on it...
+ */
+ if (!dev->u.alsa.in->has_period_length) {
+ dev->u.alsa.in->period_length = 0;
+ }
+ if (!dev->u.alsa.in->has_buffer_length) {
+ dev->u.alsa.in->buffer_length = 0;
+ }
+
+ return dev;
}
static void alsa_audio_fini (void *opaque)
{
- g_free(opaque);
}
-static struct audio_option alsa_options[] = {
- {
- .name = "DAC_SIZE_IN_USEC",
- .tag = AUD_OPT_BOOL,
- .valp = &glob_conf.size_in_usec_out,
- .descr = "DAC period/buffer size in microseconds (otherwise in frames)"
- },
- {
- .name = "DAC_PERIOD_SIZE",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.period_size_out,
- .descr = "DAC period size (0 to go with system default)",
- .overriddenp = &glob_conf.period_size_out_overridden
- },
- {
- .name = "DAC_BUFFER_SIZE",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.buffer_size_out,
- .descr = "DAC buffer size (0 to go with system default)",
- .overriddenp = &glob_conf.buffer_size_out_overridden
- },
- {
- .name = "ADC_SIZE_IN_USEC",
- .tag = AUD_OPT_BOOL,
- .valp = &glob_conf.size_in_usec_in,
- .descr =
- "ADC period/buffer size in microseconds (otherwise in frames)"
- },
- {
- .name = "ADC_PERIOD_SIZE",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.period_size_in,
- .descr = "ADC period size (0 to go with system default)",
- .overriddenp = &glob_conf.period_size_in_overridden
- },
- {
- .name = "ADC_BUFFER_SIZE",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.buffer_size_in,
- .descr = "ADC buffer size (0 to go with system default)",
- .overriddenp = &glob_conf.buffer_size_in_overridden
- },
- {
- .name = "THRESHOLD",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.threshold,
- .descr = "(undocumented)"
- },
- {
- .name = "DAC_DEV",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.pcm_name_out,
- .descr = "DAC device name (for instance dmix)"
- },
- {
- .name = "ADC_DEV",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.pcm_name_in,
- .descr = "ADC device name"
- },
- { /* End of list */ }
-};
-
static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out,
.fini_out = alsa_fini_out,
@@ -1214,7 +1085,6 @@ static struct audio_pcm_ops alsa_pcm_ops = {
static struct audio_driver alsa_audio_driver = {
.name = "alsa",
.descr = "ALSA http://www.alsa-project.org",
- .options = alsa_options,
.init = alsa_audio_init,
.fini = alsa_audio_fini,
.pcm_ops = &alsa_pcm_ops,
diff --git a/audio/audio.c b/audio/audio.c
index 909c817103..5fd9a58a80 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -26,6 +26,9 @@
#include "audio.h"
#include "monitor/monitor.h"
#include "qemu/timer.h"
+#include "qapi/error.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qapi-visit-audio.h"
#include "sysemu/sysemu.h"
#include "qemu/cutils.h"
#include "sysemu/replay.h"
@@ -46,14 +49,16 @@
The 1st one is the one used by default, that is the reason
that we generate the list.
*/
-static const char *audio_prio_list[] = {
+const char *audio_prio_list[] = {
"spice",
CONFIG_AUDIO_DRIVERS
"none",
"wav",
+ NULL
};
static QLIST_HEAD(, audio_driver) audio_drivers;
+static AudiodevListHead audiodevs = QSIMPLEQ_HEAD_INITIALIZER(audiodevs);
void audio_driver_register(audio_driver *drv)
{
@@ -80,61 +85,6 @@ audio_driver *audio_driver_lookup(const char *name)
return NULL;
}
-static void audio_module_load_all(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(audio_prio_list); i++) {
- audio_driver_lookup(audio_prio_list[i]);
- }
-}
-
-struct fixed_settings {
- int enabled;
- int nb_voices;
- int greedy;
- struct audsettings settings;
-};
-
-static struct {
- struct fixed_settings fixed_out;
- struct fixed_settings fixed_in;
- union {
- int hertz;
- int64_t ticks;
- } period;
- int try_poll_in;
- int try_poll_out;
-} conf = {
- .fixed_out = { /* DAC fixed settings */
- .enabled = 1,
- .nb_voices = 1,
- .greedy = 1,
- .settings = {
- .freq = 44100,
- .nchannels = 2,
- .fmt = AUD_FMT_S16,
- .endianness = AUDIO_HOST_ENDIANNESS,
- }
- },
-
- .fixed_in = { /* ADC fixed settings */
- .enabled = 1,
- .nb_voices = 1,
- .greedy = 1,
- .settings = {
- .freq = 44100,
- .nchannels = 2,
- .fmt = AUD_FMT_S16,
- .endianness = AUDIO_HOST_ENDIANNESS,
- }
- },
-
- .period = { .hertz = 100 },
- .try_poll_in = 1,
- .try_poll_out = 1,
-};
-
static AudioState glob_audio_state;
const struct mixeng_volume nominal_volume = {
@@ -151,9 +101,6 @@ const struct mixeng_volume nominal_volume = {
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
#error No its not
#else
-static void audio_print_options (const char *prefix,
- struct audio_option *opt);
-
int audio_bug (const char *funcname, int cond)
{
if (cond) {
@@ -161,16 +108,9 @@ int audio_bug (const char *funcname, int cond)
AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
if (!shown) {
- struct audio_driver *d;
-
shown = 1;
AUD_log (NULL, "Save all your work and restart without audio\n");
- AUD_log (NULL, "Please send bug report to av1474@comtv.ru\n");
AUD_log (NULL, "I am sorry\n");
- d = glob_audio_state.drv;
- if (d) {
- audio_print_options (d->name, d->options);
- }
}
AUD_log (NULL, "Context:\n");
@@ -232,135 +172,6 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size)
return g_malloc0 (len);
}
-static char *audio_alloc_prefix (const char *s)
-{
- const char qemu_prefix[] = "QEMU_";
- size_t len, i;
- char *r, *u;
-
- if (!s) {
- return NULL;
- }
-
- len = strlen (s);
- r = g_malloc (len + sizeof (qemu_prefix));
-
- u = r + sizeof (qemu_prefix) - 1;
-
- pstrcpy (r, len + sizeof (qemu_prefix), qemu_prefix);
- pstrcat (r, len + sizeof (qemu_prefix), s);
-
- for (i = 0; i < len; ++i) {
- u[i] = qemu_toupper(u[i]);
- }
-
- return r;
-}
-
-static const char *audio_audfmt_to_string (audfmt_e fmt)
-{
- switch (fmt) {
- case AUD_FMT_U8:
- return "U8";
-
- case AUD_FMT_U16:
- return "U16";
-
- case AUD_FMT_S8:
- return "S8";
-
- case AUD_FMT_S16:
- return "S16";
-
- case AUD_FMT_U32:
- return "U32";
-
- case AUD_FMT_S32:
- return "S32";
- }
-
- dolog ("Bogus audfmt %d returning S16\n", fmt);
- return "S16";
-}
-
-static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
- int *defaultp)
-{
- if (!strcasecmp (s, "u8")) {
- *defaultp = 0;
- return AUD_FMT_U8;
- }
- else if (!strcasecmp (s, "u16")) {
- *defaultp = 0;
- return AUD_FMT_U16;
- }
- else if (!strcasecmp (s, "u32")) {
- *defaultp = 0;
- return AUD_FMT_U32;
- }
- else if (!strcasecmp (s, "s8")) {
- *defaultp = 0;
- return AUD_FMT_S8;
- }
- else if (!strcasecmp (s, "s16")) {
- *defaultp = 0;
- return AUD_FMT_S16;
- }
- else if (!strcasecmp (s, "s32")) {
- *defaultp = 0;
- return AUD_FMT_S32;
- }
- else {
- dolog ("Bogus audio format `%s' using %s\n",
- s, audio_audfmt_to_string (defval));
- *defaultp = 1;
- return defval;
- }
-}
-
-static audfmt_e audio_get_conf_fmt (const char *envname,
- audfmt_e defval,
- int *defaultp)
-{
- const char *var = getenv (envname);
- if (!var) {
- *defaultp = 1;
- return defval;
- }
- return audio_string_to_audfmt (var, defval, defaultp);
-}
-
-static int audio_get_conf_int (const char *key, int defval, int *defaultp)
-{
- int val;
- char *strval;
-
- strval = getenv (key);
- if (strval && !qemu_strtoi(strval, NULL, 10, &val)) {
- *defaultp = 0;
- return val;
- }
- else {
- *defaultp = 1;
- return defval;
- }
-}
-
-static const char *audio_get_conf_str (const char *key,
- const char *defval,
- int *defaultp)
-{
- const char *val = getenv (key);
- if (!val) {
- *defaultp = 1;
- return defval;
- }
- else {
- *defaultp = 0;
- return val;
- }
-}
-
void AUD_vlog (const char *cap, const char *fmt, va_list ap)
{
if (cap) {
@@ -379,167 +190,27 @@ void AUD_log (const char *cap, const char *fmt, ...)
va_end (ap);
}
-static void audio_print_options (const char *prefix,
- struct audio_option *opt)
-{
- char *uprefix;
-
- if (!prefix) {
- dolog ("No prefix specified\n");
- return;
- }
-
- if (!opt) {
- dolog ("No options\n");
- return;
- }
-
- uprefix = audio_alloc_prefix (prefix);
-
- for (; opt->name; opt++) {
- const char *state = "default";
- printf (" %s_%s: ", uprefix, opt->name);
-
- if (opt->overriddenp && *opt->overriddenp) {
- state = "current";
- }
-
- switch (opt->tag) {
- case AUD_OPT_BOOL:
- {
- int *intp = opt->valp;
- printf ("boolean, %s = %d\n", state, *intp ? 1 : 0);
- }
- break;
-
- case AUD_OPT_INT:
- {
- int *intp = opt->valp;
- printf ("integer, %s = %d\n", state, *intp);
- }
- break;
-
- case AUD_OPT_FMT:
- {
- audfmt_e *fmtp = opt->valp;
- printf (
- "format, %s = %s, (one of: U8 S8 U16 S16 U32 S32)\n",
- state,
- audio_audfmt_to_string (*fmtp)
- );
- }
- break;
-
- case AUD_OPT_STR:
- {
- const char **strp = opt->valp;
- printf ("string, %s = %s\n",
- state,
- *strp ? *strp : "(not set)");
- }
- break;
-
- default:
- printf ("???\n");
- dolog ("Bad value tag for option %s_%s %d\n",
- uprefix, opt->name, opt->tag);
- break;
- }
- printf (" %s\n", opt->descr);
- }
-
- g_free (uprefix);
-}
-
-static void audio_process_options (const char *prefix,
- struct audio_option *opt)
-{
- gchar *prefix_upper;
-
- if (audio_bug(__func__, !prefix)) {
- dolog ("prefix = NULL\n");
- return;
- }
-
- if (audio_bug(__func__, !opt)) {
- dolog ("opt = NULL\n");
- return;
- }
-
- prefix_upper = g_utf8_strup(prefix, -1);
-
- for (; opt->name; opt++) {
- char *optname;
- int def;
-
- if (!opt->valp) {
- dolog ("Option value pointer for `%s' is not set\n",
- opt->name);
- continue;
- }
-
- optname = g_strdup_printf("QEMU_%s_%s", prefix_upper, opt->name);
-
- def = 1;
- switch (opt->tag) {
- case AUD_OPT_BOOL:
- case AUD_OPT_INT:
- {
- int *intp = opt->valp;
- *intp = audio_get_conf_int (optname, *intp, &def);
- }
- break;
-
- case AUD_OPT_FMT:
- {
- audfmt_e *fmtp = opt->valp;
- *fmtp = audio_get_conf_fmt (optname, *fmtp, &def);
- }
- break;
-
- case AUD_OPT_STR:
- {
- const char **strp = opt->valp;
- *strp = audio_get_conf_str (optname, *strp, &def);
- }
- break;
-
- default:
- dolog ("Bad value tag for option `%s' - %d\n",
- optname, opt->tag);
- break;
- }
-
- if (!opt->overriddenp) {
- opt->overriddenp = &opt->overridden;
- }
- *opt->overriddenp = !def;
- g_free (optname);
- }
- g_free(prefix_upper);
-}
-
static void audio_print_settings (struct audsettings *as)
{
dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
switch (as->fmt) {
- case AUD_FMT_S8:
+ case AUDIO_FORMAT_S8:
AUD_log (NULL, "S8");
break;
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_U8:
AUD_log (NULL, "U8");
break;
- case AUD_FMT_S16:
+ case AUDIO_FORMAT_S16:
AUD_log (NULL, "S16");
break;
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_U16:
AUD_log (NULL, "U16");
break;
- case AUD_FMT_S32:
+ case AUDIO_FORMAT_S32:
AUD_log (NULL, "S32");
break;
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_U32:
AUD_log (NULL, "U32");
break;
default:
@@ -570,12 +241,12 @@ static int audio_validate_settings (struct audsettings *as)
invalid |= as->endianness != 0 && as->endianness != 1;
switch (as->fmt) {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
- case AUD_FMT_S16:
- case AUD_FMT_U16:
- case AUD_FMT_S32:
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_S8:
+ case AUDIO_FORMAT_U8:
+ case AUDIO_FORMAT_S16:
+ case AUDIO_FORMAT_U16:
+ case AUDIO_FORMAT_S32:
+ case AUDIO_FORMAT_U32:
break;
default:
invalid = 1;
@@ -591,25 +262,28 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
int bits = 8, sign = 0;
switch (as->fmt) {
- case AUD_FMT_S8:
+ case AUDIO_FORMAT_S8:
sign = 1;
/* fall through */
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_U8:
break;
- case AUD_FMT_S16:
+ case AUDIO_FORMAT_S16:
sign = 1;
/* fall through */
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_U16:
bits = 16;
break;
- case AUD_FMT_S32:
+ case AUDIO_FORMAT_S32:
sign = 1;
/* fall through */
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_U32:
bits = 32;
break;
+
+ default:
+ abort();
}
return info->freq == as->freq
&& info->nchannels == as->nchannels
@@ -623,24 +297,27 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
int bits = 8, sign = 0, shift = 0;
switch (as->fmt) {
- case AUD_FMT_S8:
+ case AUDIO_FORMAT_S8:
sign = 1;
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_U8:
break;
- case AUD_FMT_S16:
+ case AUDIO_FORMAT_S16:
sign = 1;
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_U16:
bits = 16;
shift = 1;
break;
- case AUD_FMT_S32:
+ case AUDIO_FORMAT_S32:
sign = 1;
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_U32:
bits = 32;
shift = 2;
break;
+
+ default:
+ abort();
}
info->freq = as->freq;
@@ -1132,11 +809,11 @@ static void audio_reset_timer (AudioState *s)
{
if (audio_is_timer_needed ()) {
timer_mod_anticipate_ns(s->ts,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + conf.period.ticks);
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->period_ticks);
if (!audio_timer_running) {
audio_timer_running = true;
audio_timer_last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- trace_audio_timer_start(conf.period.ticks / SCALE_MS);
+ trace_audio_timer_start(s->period_ticks / SCALE_MS);
}
} else {
timer_del(s->ts);
@@ -1150,16 +827,17 @@ static void audio_reset_timer (AudioState *s)
static void audio_timer (void *opaque)
{
int64_t now, diff;
+ AudioState *s = opaque;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
diff = now - audio_timer_last;
- if (diff > conf.period.ticks * 3 / 2) {
+ if (diff > s->period_ticks * 3 / 2) {
trace_audio_timer_delayed(diff / SCALE_MS);
}
audio_timer_last = now;
- audio_run ("timer");
- audio_reset_timer (opaque);
+ audio_run("timer");
+ audio_reset_timer(s);
}
/*
@@ -1219,7 +897,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
- hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
+ hw->pcm_ops->ctl_out(hw, VOICE_ENABLE);
audio_reset_timer (s);
}
}
@@ -1264,7 +942,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
- hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
+ hw->pcm_ops->ctl_in(hw, VOICE_ENABLE);
audio_reset_timer (s);
}
}
@@ -1585,169 +1263,10 @@ void audio_run (const char *msg)
#endif
}
-static struct audio_option audio_options[] = {
- /* DAC */
- {
- .name = "DAC_FIXED_SETTINGS",
- .tag = AUD_OPT_BOOL,
- .valp = &conf.fixed_out.enabled,
- .descr = "Use fixed settings for host DAC"
- },
- {
- .name = "DAC_FIXED_FREQ",
- .tag = AUD_OPT_INT,
- .valp = &conf.fixed_out.settings.freq,
- .descr = "Frequency for fixed host DAC"
- },
- {
- .name = "DAC_FIXED_FMT",
- .tag = AUD_OPT_FMT,
- .valp = &conf.fixed_out.settings.fmt,
- .descr = "Format for fixed host DAC"
- },
- {
- .name = "DAC_FIXED_CHANNELS",
- .tag = AUD_OPT_INT,
- .valp = &conf.fixed_out.settings.nchannels,
- .descr = "Number of channels for fixed DAC (1 - mono, 2 - stereo)"
- },
- {
- .name = "DAC_VOICES",
- .tag = AUD_OPT_INT,
- .valp = &conf.fixed_out.nb_voices,
- .descr = "Number of voices for DAC"
- },
- {
- .name = "DAC_TRY_POLL",
- .tag = AUD_OPT_BOOL,
- .valp = &conf.try_poll_out,
- .descr = "Attempt using poll mode for DAC"
- },
- /* ADC */
- {
- .name = "ADC_FIXED_SETTINGS",
- .tag = AUD_OPT_BOOL,
- .valp = &conf.fixed_in.enabled,
- .descr = "Use fixed settings for host ADC"
- },
- {
- .name = "ADC_FIXED_FREQ",
- .tag = AUD_OPT_INT,
- .valp = &conf.fixed_in.settings.freq,
- .descr = "Frequency for fixed host ADC"
- },
- {
- .name = "ADC_FIXED_FMT",
- .tag = AUD_OPT_FMT,
- .valp = &conf.fixed_in.settings.fmt,
- .descr = "Format for fixed host ADC"
- },
- {
- .name = "ADC_FIXED_CHANNELS",
- .tag = AUD_OPT_INT,
- .valp = &conf.fixed_in.settings.nchannels,
- .descr = "Number of channels for fixed ADC (1 - mono, 2 - stereo)"
- },
- {
- .name = "ADC_VOICES",
- .tag = AUD_OPT_INT,
- .valp = &conf.fixed_in.nb_voices,
- .descr = "Number of voices for ADC"
- },
- {
- .name = "ADC_TRY_POLL",
- .tag = AUD_OPT_BOOL,
- .valp = &conf.try_poll_in,
- .descr = "Attempt using poll mode for ADC"
- },
- /* Misc */
- {
- .name = "TIMER_PERIOD",
- .tag = AUD_OPT_INT,
- .valp = &conf.period.hertz,
- .descr = "Timer period in HZ (0 - use lowest possible)"
- },
- { /* End of list */ }
-};
-
-static void audio_pp_nb_voices (const char *typ, int nb)
-{
- switch (nb) {
- case 0:
- printf ("Does not support %s\n", typ);
- break;
- case 1:
- printf ("One %s voice\n", typ);
- break;
- case INT_MAX:
- printf ("Theoretically supports many %s voices\n", typ);
- break;
- default:
- printf ("Theoretically supports up to %d %s voices\n", nb, typ);
- break;
- }
-
-}
-
-void AUD_help (void)
-{
- struct audio_driver *d;
-
- /* make sure we print the help text for modular drivers too */
- audio_module_load_all();
-
- audio_process_options ("AUDIO", audio_options);
- QLIST_FOREACH(d, &audio_drivers, next) {
- if (d->options) {
- audio_process_options (d->name, d->options);
- }
- }
-
- printf ("Audio options:\n");
- audio_print_options ("AUDIO", audio_options);
- printf ("\n");
-
- printf ("Available drivers:\n");
-
- QLIST_FOREACH(d, &audio_drivers, next) {
-
- printf ("Name: %s\n", d->name);
- printf ("Description: %s\n", d->descr);
-
- audio_pp_nb_voices ("playback", d->max_voices_out);
- audio_pp_nb_voices ("capture", d->max_voices_in);
-
- if (d->options) {
- printf ("Options:\n");
- audio_print_options (d->name, d->options);
- }
- else {
- printf ("No options\n");
- }
- printf ("\n");
- }
-
- printf (
- "Options are settable through environment variables.\n"
- "Example:\n"
-#ifdef _WIN32
- " set QEMU_AUDIO_DRV=wav\n"
- " set QEMU_WAV_PATH=c:\\tune.wav\n"
-#else
- " export QEMU_AUDIO_DRV=wav\n"
- " export QEMU_WAV_PATH=$HOME/tune.wav\n"
- "(for csh replace export with setenv in the above)\n"
-#endif
- " qemu ...\n\n"
- );
-}
-
-static int audio_driver_init(AudioState *s, struct audio_driver *drv, bool msg)
+static int audio_driver_init(AudioState *s, struct audio_driver *drv,
+ bool msg, Audiodev *dev)
{
- if (drv->options) {
- audio_process_options (drv->name, drv->options);
- }
- s->drv_opaque = drv->init ();
+ s->drv_opaque = drv->init(dev);
if (s->drv_opaque) {
audio_init_nb_voices_out (drv);
@@ -1773,11 +1292,11 @@ static void audio_vm_change_state_handler (void *opaque, int running,
s->vm_running = running;
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
- hwo->pcm_ops->ctl_out (hwo, op, conf.try_poll_out);
+ hwo->pcm_ops->ctl_out(hwo, op);
}
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
- hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
+ hwi->pcm_ops->ctl_in(hwi, op);
}
audio_reset_timer (s);
}
@@ -1827,6 +1346,11 @@ void audio_cleanup(void)
s->drv->fini (s->drv_opaque);
s->drv = NULL;
}
+
+ if (s->dev) {
+ qapi_free_Audiodev(s->dev);
+ s->dev = NULL;
+ }
}
static const VMStateDescription vmstate_audio = {
@@ -1838,19 +1362,58 @@ static const VMStateDescription vmstate_audio = {
}
};
-static void audio_init (void)
+static void audio_validate_opts(Audiodev *dev, Error **errp);
+
+static AudiodevListEntry *audiodev_find(
+ AudiodevListHead *head, const char *drvname)
+{
+ AudiodevListEntry *e;
+ QSIMPLEQ_FOREACH(e, head, next) {
+ if (strcmp(AudiodevDriver_str(e->dev->driver), drvname) == 0) {
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+static int audio_init(Audiodev *dev)
{
size_t i;
int done = 0;
- const char *drvname;
+ const char *drvname = NULL;
VMChangeStateEntry *e;
AudioState *s = &glob_audio_state;
struct audio_driver *driver;
+ /* silence gcc warning about uninitialized variable */
+ AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
if (s->drv) {
- return;
+ if (dev) {
+ dolog("Cannot create more than one audio backend, sorry\n");
+ qapi_free_Audiodev(dev);
+ }
+ return -1;
}
+ if (dev) {
+ /* -audiodev option */
+ drvname = AudiodevDriver_str(dev->driver);
+ } else {
+ /* legacy implicit initialization */
+ head = audio_handle_legacy_opts();
+ /*
+ * In case of legacy initialization, all Audiodevs in the list will have
+ * the same configuration (except the driver), so it does't matter which
+ * one we chose. We need an Audiodev to set up AudioState before we can
+ * init a driver. Also note that dev at this point is still in the
+ * list.
+ */
+ dev = QSIMPLEQ_FIRST(&head)->dev;
+ audio_validate_opts(dev, &error_abort);
+ }
+ s->dev = dev;
+
QLIST_INIT (&s->hw_head_out);
QLIST_INIT (&s->hw_head_in);
QLIST_INIT (&s->cap_head);
@@ -1858,10 +1421,8 @@ static void audio_init (void)
s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);
- audio_process_options ("AUDIO", audio_options);
-
- s->nb_hw_voices_out = conf.fixed_out.nb_voices;
- s->nb_hw_voices_in = conf.fixed_in.nb_voices;
+ s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices;
+ s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices;
if (s->nb_hw_voices_out <= 0) {
dolog ("Bogus number of playback voices %d, setting to 1\n",
@@ -1875,46 +1436,42 @@ static void audio_init (void)
s->nb_hw_voices_in = 0;
}
- {
- int def;
- drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
- }
-
if (drvname) {
driver = audio_driver_lookup(drvname);
if (driver) {
- done = !audio_driver_init(s, driver, true);
+ done = !audio_driver_init(s, driver, true, dev);
} else {
dolog ("Unknown audio driver `%s'\n", drvname);
- dolog ("Run with -audio-help to list available drivers\n");
}
- }
-
- if (!done) {
- for (i = 0; !done && i < ARRAY_SIZE(audio_prio_list); i++) {
+ } else {
+ for (i = 0; audio_prio_list[i]; i++) {
+ AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]);
driver = audio_driver_lookup(audio_prio_list[i]);
- if (driver && driver->can_be_default) {
- done = !audio_driver_init(s, driver, false);
+
+ if (e && driver) {
+ s->dev = dev = e->dev;
+ audio_validate_opts(dev, &error_abort);
+ done = !audio_driver_init(s, driver, false, dev);
+ if (done) {
+ e->dev = NULL;
+ break;
+ }
}
}
}
+ audio_free_audiodev_list(&head);
if (!done) {
driver = audio_driver_lookup("none");
- done = !audio_driver_init(s, driver, false);
+ done = !audio_driver_init(s, driver, false, dev);
assert(done);
dolog("warning: Using timer based audio emulation\n");
}
- if (conf.period.hertz <= 0) {
- if (conf.period.hertz < 0) {
- dolog ("warning: Timer period is negative - %d "
- "treating as zero\n",
- conf.period.hertz);
- }
- conf.period.ticks = 1;
+ if (dev->timer_period <= 0) {
+ s->period_ticks = 1;
} else {
- conf.period.ticks = NANOSECONDS_PER_SECOND / conf.period.hertz;
+ s->period_ticks = NANOSECONDS_PER_SECOND / dev->timer_period;
}
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
@@ -1925,11 +1482,22 @@ static void audio_init (void)
QLIST_INIT (&s->card_head);
vmstate_register (NULL, 0, &vmstate_audio, s);
+ return 0;
+}
+
+void audio_free_audiodev_list(AudiodevListHead *head)
+{
+ AudiodevListEntry *e;
+ while ((e = QSIMPLEQ_FIRST(head))) {
+ QSIMPLEQ_REMOVE_HEAD(head, next);
+ qapi_free_Audiodev(e->dev);
+ g_free(e);
+ }
}
void AUD_register_card (const char *name, QEMUSoundCard *card)
{
- audio_init ();
+ audio_init(NULL);
card->name = g_strdup (name);
memset (&card->entries, 0, sizeof (card->entries));
QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
@@ -2069,3 +1637,174 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
}
}
}
+
+void audio_create_pdos(Audiodev *dev)
+{
+ switch (dev->driver) {
+#define CASE(DRIVER, driver, pdo_name) \
+ case AUDIODEV_DRIVER_##DRIVER: \
+ if (!dev->u.driver.has_in) { \
+ dev->u.driver.in = g_malloc0( \
+ sizeof(Audiodev##pdo_name##PerDirectionOptions)); \
+ dev->u.driver.has_in = true; \
+ } \
+ if (!dev->u.driver.has_out) { \
+ dev->u.driver.out = g_malloc0( \
+ sizeof(AudiodevAlsaPerDirectionOptions)); \
+ dev->u.driver.has_out = true; \
+ } \
+ break
+
+ CASE(NONE, none, );
+ CASE(ALSA, alsa, Alsa);
+ CASE(COREAUDIO, coreaudio, Coreaudio);
+ CASE(DSOUND, dsound, );
+ CASE(OSS, oss, Oss);
+ CASE(PA, pa, Pa);
+ CASE(SDL, sdl, );
+ CASE(SPICE, spice, );
+ CASE(WAV, wav, );
+
+ case AUDIODEV_DRIVER__MAX:
+ abort();
+ };
+}
+
+static void audio_validate_per_direction_opts(
+ AudiodevPerDirectionOptions *pdo, Error **errp)
+{
+ if (!pdo->has_fixed_settings) {
+ pdo->has_fixed_settings = true;
+ pdo->fixed_settings = true;
+ }
+ if (!pdo->fixed_settings &&
+ (pdo->has_frequency || pdo->has_channels || pdo->has_format)) {
+ error_setg(errp,
+ "You can't use frequency, channels or format with fixed-settings=off");
+ return;
+ }
+
+ if (!pdo->has_frequency) {
+ pdo->has_frequency = true;
+ pdo->frequency = 44100;
+ }
+ if (!pdo->has_channels) {
+ pdo->has_channels = true;
+ pdo->channels = 2;
+ }
+ if (!pdo->has_voices) {
+ pdo->has_voices = true;
+ pdo->voices = 1;
+ }
+ if (!pdo->has_format) {
+ pdo->has_format = true;
+ pdo->format = AUDIO_FORMAT_S16;
+ }
+}
+
+static void audio_validate_opts(Audiodev *dev, Error **errp)
+{
+ Error *err = NULL;
+
+ audio_create_pdos(dev);
+
+ audio_validate_per_direction_opts(audio_get_pdo_in(dev), &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ audio_validate_per_direction_opts(audio_get_pdo_out(dev), &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ if (!dev->has_timer_period) {
+ dev->has_timer_period = true;
+ dev->timer_period = 10000; /* 100Hz -> 10ms */
+ }
+}
+
+void audio_parse_option(const char *opt)
+{
+ AudiodevListEntry *e;
+ Audiodev *dev = NULL;
+
+ Visitor *v = qobject_input_visitor_new_str(opt, "driver", &error_fatal);
+ visit_type_Audiodev(v, NULL, &dev, &error_fatal);
+ visit_free(v);
+
+ audio_validate_opts(dev, &error_fatal);
+
+ e = g_malloc0(sizeof(AudiodevListEntry));
+ e->dev = dev;
+ QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next);
+}
+
+void audio_init_audiodevs(void)
+{
+ AudiodevListEntry *e;
+
+ QSIMPLEQ_FOREACH(e, &audiodevs, next) {
+ audio_init(e->dev);
+ }
+}
+
+audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo)
+{
+ return (audsettings) {
+ .freq = pdo->frequency,
+ .nchannels = pdo->channels,
+ .fmt = pdo->format,
+ .endianness = AUDIO_HOST_ENDIANNESS,
+ };
+}
+
+int audioformat_bytes_per_sample(AudioFormat fmt)
+{
+ switch (fmt) {
+ case AUDIO_FORMAT_U8:
+ case AUDIO_FORMAT_S8:
+ return 1;
+
+ case AUDIO_FORMAT_U16:
+ case AUDIO_FORMAT_S16:
+ return 2;
+
+ case AUDIO_FORMAT_U32:
+ case AUDIO_FORMAT_S32:
+ return 4;
+
+ case AUDIO_FORMAT__MAX:
+ ;
+ }
+ abort();
+}
+
+
+/* frames = freq * usec / 1e6 */
+int audio_buffer_frames(AudiodevPerDirectionOptions *pdo,
+ audsettings *as, int def_usecs)
+{
+ uint64_t usecs = pdo->has_buffer_length ? pdo->buffer_length : def_usecs;
+ return (as->freq * usecs + 500000) / 1000000;
+}
+
+/* samples = channels * frames = channels * freq * usec / 1e6 */
+int audio_buffer_samples(AudiodevPerDirectionOptions *pdo,
+ audsettings *as, int def_usecs)
+{
+ return as->nchannels * audio_buffer_frames(pdo, as, def_usecs);
+}
+
+/*
+ * bytes = bytes_per_sample * samples =
+ * bytes_per_sample * channels * freq * usec / 1e6
+ */
+int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo,
+ audsettings *as, int def_usecs)
+{
+ return audio_buffer_samples(pdo, as, def_usecs) *
+ audioformat_bytes_per_sample(as->fmt);
+}
diff --git a/audio/audio.h b/audio/audio.h
index f4339a185e..64b0f761bc 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -26,30 +26,31 @@
#define QEMU_AUDIO_H
#include "qemu/queue.h"
+#include "qapi/qapi-types-audio.h"
typedef void (*audio_callback_fn) (void *opaque, int avail);
-typedef enum {
- AUD_FMT_U8,
- AUD_FMT_S8,
- AUD_FMT_U16,
- AUD_FMT_S16,
- AUD_FMT_U32,
- AUD_FMT_S32
-} audfmt_e;
-
#ifdef HOST_WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1
#else
#define AUDIO_HOST_ENDIANNESS 0
#endif
-struct audsettings {
+typedef struct audsettings {
int freq;
int nchannels;
- audfmt_e fmt;
+ AudioFormat fmt;
int endianness;
-};
+} audsettings;
+
+audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo);
+int audioformat_bytes_per_sample(AudioFormat fmt);
+int audio_buffer_frames(AudiodevPerDirectionOptions *pdo,
+ audsettings *as, int def_usecs);
+int audio_buffer_samples(AudiodevPerDirectionOptions *pdo,
+ audsettings *as, int def_usecs);
+int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo,
+ audsettings *as, int def_usecs);
typedef enum {
AUD_CNOTIFY_ENABLE,
@@ -89,7 +90,6 @@ typedef struct QEMUAudioTimeStamp {
void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
-void AUD_help (void);
void AUD_register_card (const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture (
@@ -171,4 +171,8 @@ void audio_sample_to_uint64(void *samples, int pos,
void audio_sample_from_uint64(void *samples, int pos,
uint64_t left, uint64_t right);
+void audio_parse_option(const char *opt);
+void audio_init_audiodevs(void);
+void audio_legacy_help(void);
+
#endif /* QEMU_AUDIO_H */
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 6c451b995c..3f14842709 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -33,22 +33,6 @@
struct audio_pcm_ops;
-typedef enum {
- AUD_OPT_INT,
- AUD_OPT_FMT,
- AUD_OPT_STR,
- AUD_OPT_BOOL
-} audio_option_tag_e;
-
-struct audio_option {
- const char *name;
- audio_option_tag_e tag;
- void *valp;
- const char *descr;
- int *overriddenp;
- int overridden;
-};
-
struct audio_callback {
void *opaque;
audio_callback_fn fn;
@@ -145,8 +129,7 @@ typedef struct audio_driver audio_driver;
struct audio_driver {
const char *name;
const char *descr;
- struct audio_option *options;
- void *(*init) (void);
+ void *(*init) (Audiodev *);
void (*fini) (void *);
struct audio_pcm_ops *pcm_ops;
int can_be_default;
@@ -193,6 +176,7 @@ struct SWVoiceCap {
typedef struct AudioState {
struct audio_driver *drv;
+ Audiodev *dev;
void *drv_opaque;
QEMUTimer *ts;
@@ -203,10 +187,13 @@ typedef struct AudioState {
int nb_hw_voices_out;
int nb_hw_voices_in;
int vm_running;
+ int64_t period_ticks;
} AudioState;
extern const struct mixeng_volume nominal_volume;
+extern const char *audio_prio_list[];
+
void audio_driver_register(audio_driver *drv);
audio_driver *audio_driver_lookup(const char *name);
@@ -248,4 +235,18 @@ static inline int audio_ring_dist (int dst, int src, int len)
#define AUDIO_STRINGIFY_(n) #n
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
+typedef struct AudiodevListEntry {
+ Audiodev *dev;
+ QSIMPLEQ_ENTRY(AudiodevListEntry) next;
+} AudiodevListEntry;
+
+typedef QSIMPLEQ_HEAD(, AudiodevListEntry) AudiodevListHead;
+AudiodevListHead audio_handle_legacy_opts(void);
+
+void audio_free_audiodev_list(AudiodevListHead *head);
+
+void audio_create_pdos(Audiodev *dev);
+AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev);
+AudiodevPerDirectionOptions *audio_get_pdo_out(Audiodev *dev);
+
#endif /* QEMU_AUDIO_INT_H */
diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c
new file mode 100644
index 0000000000..6d140119d9
--- /dev/null
+++ b/audio/audio_legacy.c
@@ -0,0 +1,544 @@
+/*
+ * QEMU Audio subsystem: legacy configuration handling
+ *
+ * Copyright (c) 2015-2019 Zoltán Kővágó <DirtY.iCE.hu@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 "audio.h"
+#include "audio_int.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "qapi/qapi-visit-audio.h"
+#include "qapi/visitor-impl.h"
+
+#define AUDIO_CAP "audio-legacy"
+#include "audio_int.h"
+
+static uint32_t toui32(const char *str)
+{
+ unsigned long long ret;
+ if (parse_uint_full(str, &ret, 10) || ret > UINT32_MAX) {
+ dolog("Invalid integer value `%s'\n", str);
+ exit(1);
+ }
+ return ret;
+}
+
+/* helper functions to convert env variables */
+static void get_bool(const char *env, bool *dst, bool *has_dst)
+{
+ const char *val = getenv(env);
+ if (val) {
+ *dst = toui32(val) != 0;
+ *has_dst = true;
+ }
+}
+
+static void get_int(const char *env, uint32_t *dst, bool *has_dst)
+{
+ const char *val = getenv(env);
+ if (val) {
+ *dst = toui32(val);
+ *has_dst = true;
+ }
+}
+
+static void get_str(const char *env, char **dst, bool *has_dst)
+{
+ const char *val = getenv(env);
+ if (val) {
+ if (*has_dst) {
+ g_free(*dst);
+ }
+ *dst = g_strdup(val);
+ *has_dst = true;
+ }
+}
+
+static void get_fmt(const char *env, AudioFormat *dst, bool *has_dst)
+{
+ const char *val = getenv(env);
+ if (val) {
+ size_t i;
+ for (i = 0; AudioFormat_lookup.size; ++i) {
+ if (strcasecmp(val, AudioFormat_lookup.array[i]) == 0) {
+ *dst = i;
+ *has_dst = true;
+ return;
+ }
+ }
+
+ dolog("Invalid audio format `%s'\n", val);
+ exit(1);
+ }
+}
+
+
+static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst)
+{
+ const char *val = getenv(env);
+ if (val) {
+ *dst = toui32(val) * 1000;
+ *has_dst = true;
+ }
+}
+
+static uint32_t frames_to_usecs(uint32_t frames,
+ AudiodevPerDirectionOptions *pdo)
+{
+ uint32_t freq = pdo->has_frequency ? pdo->frequency : 44100;
+ return (frames * 1000000 + freq / 2) / freq;
+}
+
+
+static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
+ AudiodevPerDirectionOptions *pdo)
+{
+ const char *val = getenv(env);
+ if (val) {
+ *dst = frames_to_usecs(toui32(val), pdo);
+ *has_dst = true;
+ }
+}
+
+static uint32_t samples_to_usecs(uint32_t samples,
+ AudiodevPerDirectionOptions *pdo)
+{
+ uint32_t channels = pdo->has_channels ? pdo->channels : 2;
+ return frames_to_usecs(samples / channels, pdo);
+}
+
+static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
+ AudiodevPerDirectionOptions *pdo)
+{
+ const char *val = getenv(env);
+ if (val) {
+ *dst = samples_to_usecs(toui32(val), pdo);
+ *has_dst = true;
+ }
+}
+
+static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions *pdo)
+{
+ AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16;
+ uint32_t bytes_per_sample = audioformat_bytes_per_sample(fmt);
+ return samples_to_usecs(bytes / bytes_per_sample, pdo);
+}
+
+static void get_bytes_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
+ AudiodevPerDirectionOptions *pdo)
+{
+ const char *val = getenv(env);
+ if (val) {
+ *dst = bytes_to_usecs(toui32(val), pdo);
+ *has_dst = true;
+ }
+}
+
+/* backend specific functions */
+/* ALSA */
+static void handle_alsa_per_direction(
+ AudiodevAlsaPerDirectionOptions *apdo, const char *prefix)
+{
+ char buf[64];
+ size_t len = strlen(prefix);
+ bool size_in_usecs = false;
+ bool dummy;
+
+ memcpy(buf, prefix, len);
+ strcpy(buf + len, "TRY_POLL");
+ get_bool(buf, &apdo->try_poll, &apdo->has_try_poll);
+
+ strcpy(buf + len, "DEV");
+ get_str(buf, &apdo->dev, &apdo->has_dev);
+
+ strcpy(buf + len, "SIZE_IN_USEC");
+ get_bool(buf, &size_in_usecs, &dummy);
+
+ strcpy(buf + len, "PERIOD_SIZE");
+ get_int(buf, &apdo->period_length, &apdo->has_period_length);
+ if (apdo->has_period_length && !size_in_usecs) {
+ apdo->period_length = frames_to_usecs(
+ apdo->period_length,
+ qapi_AudiodevAlsaPerDirectionOptions_base(apdo));
+ }
+
+ strcpy(buf + len, "BUFFER_SIZE");
+ get_int(buf, &apdo->buffer_length, &apdo->has_buffer_length);
+ if (apdo->has_buffer_length && !size_in_usecs) {
+ apdo->buffer_length = frames_to_usecs(
+ apdo->buffer_length,
+ qapi_AudiodevAlsaPerDirectionOptions_base(apdo));
+ }
+}
+
+static void handle_alsa(Audiodev *dev)
+{
+ AudiodevAlsaOptions *aopt = &dev->u.alsa;
+ handle_alsa_per_direction(aopt->in, "QEMU_ALSA_ADC_");
+ handle_alsa_per_direction(aopt->out, "QEMU_ALSA_DAC_");
+
+ get_millis_to_usecs("QEMU_ALSA_THRESHOLD",
+ &aopt->threshold, &aopt->has_threshold);
+}
+
+/* coreaudio */
+static void handle_coreaudio(Audiodev *dev)
+{
+ get_frames_to_usecs(
+ "QEMU_COREAUDIO_BUFFER_SIZE",
+ &dev->u.coreaudio.out->buffer_length,
+ &dev->u.coreaudio.out->has_buffer_length,
+ qapi_AudiodevCoreaudioPerDirectionOptions_base(dev->u.coreaudio.out));
+ get_int("QEMU_COREAUDIO_BUFFER_COUNT",
+ &dev->u.coreaudio.out->buffer_count,
+ &dev->u.coreaudio.out->has_buffer_count);
+}
+
+/* dsound */
+static void handle_dsound(Audiodev *dev)
+{
+ get_millis_to_usecs("QEMU_DSOUND_LATENCY_MILLIS",
+ &dev->u.dsound.latency, &dev->u.dsound.has_latency);
+ get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_OUT",
+ &dev->u.dsound.out->buffer_length,
+ &dev->u.dsound.out->has_buffer_length,
+ dev->u.dsound.out);
+ get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_IN",
+ &dev->u.dsound.in->buffer_length,
+ &dev->u.dsound.in->has_buffer_length,
+ dev->u.dsound.in);
+}
+
+/* OSS */
+static void handle_oss_per_direction(
+ AudiodevOssPerDirectionOptions *opdo, const char *try_poll_env,
+ const char *dev_env)
+{
+ get_bool(try_poll_env, &opdo->try_poll, &opdo->has_try_poll);
+ get_str(dev_env, &opdo->dev, &opdo->has_dev);
+
+ get_bytes_to_usecs("QEMU_OSS_FRAGSIZE",
+ &opdo->buffer_length, &opdo->has_buffer_length,
+ qapi_AudiodevOssPerDirectionOptions_base(opdo));
+ get_int("QEMU_OSS_NFRAGS", &opdo->buffer_count,
+ &opdo->has_buffer_count);
+}
+
+static void handle_oss(Audiodev *dev)
+{
+ AudiodevOssOptions *oopt = &dev->u.oss;
+ handle_oss_per_direction(oopt->in, "QEMU_AUDIO_ADC_TRY_POLL",
+ "QEMU_OSS_ADC_DEV");
+ handle_oss_per_direction(oopt->out, "QEMU_AUDIO_DAC_TRY_POLL",
+ "QEMU_OSS_DAC_DEV");
+
+ get_bool("QEMU_OSS_MMAP", &oopt->try_mmap, &oopt->has_try_mmap);
+ get_bool("QEMU_OSS_EXCLUSIVE", &oopt->exclusive, &oopt->has_exclusive);
+ get_int("QEMU_OSS_POLICY", &oopt->dsp_policy, &oopt->has_dsp_policy);
+}
+
+/* pulseaudio */
+static void handle_pa_per_direction(
+ AudiodevPaPerDirectionOptions *ppdo, const char *env)
+{
+ get_str(env, &ppdo->name, &ppdo->has_name);
+}
+
+static void handle_pa(Audiodev *dev)
+{
+ handle_pa_per_direction(dev->u.pa.in, "QEMU_PA_SOURCE");
+ handle_pa_per_direction(dev->u.pa.out, "QEMU_PA_SINK");
+
+ get_samples_to_usecs(
+ "QEMU_PA_SAMPLES", &dev->u.pa.in->buffer_length,
+ &dev->u.pa.in->has_buffer_length,
+ qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.in));
+ get_samples_to_usecs(
+ "QEMU_PA_SAMPLES", &dev->u.pa.out->buffer_length,
+ &dev->u.pa.out->has_buffer_length,
+ qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.out));
+
+ get_str("QEMU_PA_SERVER", &dev->u.pa.server, &dev->u.pa.has_server);
+}
+
+/* SDL */
+static void handle_sdl(Audiodev *dev)
+{
+ /* SDL is output only */
+ get_samples_to_usecs("QEMU_SDL_SAMPLES", &dev->u.sdl.out->buffer_length,
+ &dev->u.sdl.out->has_buffer_length, dev->u.sdl.out);
+}
+
+/* wav */
+static void handle_wav(Audiodev *dev)
+{
+ get_int("QEMU_WAV_FREQUENCY",
+ &dev->u.wav.out->frequency, &dev->u.wav.out->has_frequency);
+ get_fmt("QEMU_WAV_FORMAT", &dev->u.wav.out->format,
+ &dev->u.wav.out->has_format);
+ get_int("QEMU_WAV_DAC_FIXED_CHANNELS",
+ &dev->u.wav.out->channels, &dev->u.wav.out->has_channels);
+ get_str("QEMU_WAV_PATH", &dev->u.wav.path, &dev->u.wav.has_path);
+}
+
+/* general */
+static void handle_per_direction(
+ AudiodevPerDirectionOptions *pdo, const char *prefix)
+{
+ char buf[64];
+ size_t len = strlen(prefix);
+
+ memcpy(buf, prefix, len);
+ strcpy(buf + len, "FIXED_SETTINGS");
+ get_bool(buf, &pdo->fixed_settings, &pdo->has_fixed_settings);
+
+ strcpy(buf + len, "FIXED_FREQ");
+ get_int(buf, &pdo->frequency, &pdo->has_frequency);
+
+ strcpy(buf + len, "FIXED_FMT");
+ get_fmt(buf, &pdo->format, &pdo->has_format);
+
+ strcpy(buf + len, "FIXED_CHANNELS");
+ get_int(buf, &pdo->channels, &pdo->has_channels);
+
+ strcpy(buf + len, "VOICES");
+ get_int(buf, &pdo->voices, &pdo->has_voices);
+}
+
+static AudiodevListEntry *legacy_opt(const char *drvname)
+{
+ AudiodevListEntry *e = g_malloc0(sizeof(AudiodevListEntry));
+ e->dev = g_malloc0(sizeof(Audiodev));
+ e->dev->id = g_strdup(drvname);
+ e->dev->driver = qapi_enum_parse(
+ &AudiodevDriver_lookup, drvname, -1, &error_abort);
+
+ audio_create_pdos(e->dev);
+
+ handle_per_direction(audio_get_pdo_in(e->dev), "QEMU_AUDIO_ADC_");
+ handle_per_direction(audio_get_pdo_out(e->dev), "QEMU_AUDIO_DAC_");
+
+ get_int("QEMU_AUDIO_TIMER_PERIOD",
+ &e->dev->timer_period, &e->dev->has_timer_period);
+
+ switch (e->dev->driver) {
+ case AUDIODEV_DRIVER_ALSA:
+ handle_alsa(e->dev);
+ break;
+
+ case AUDIODEV_DRIVER_COREAUDIO:
+ handle_coreaudio(e->dev);
+ break;
+
+ case AUDIODEV_DRIVER_DSOUND:
+ handle_dsound(e->dev);
+ break;
+
+ case AUDIODEV_DRIVER_OSS:
+ handle_oss(e->dev);
+ break;
+
+ case AUDIODEV_DRIVER_PA:
+ handle_pa(e->dev);
+ break;
+
+ case AUDIODEV_DRIVER_SDL:
+ handle_sdl(e->dev);
+ break;
+
+ case AUDIODEV_DRIVER_WAV:
+ handle_wav(e->dev);
+ break;
+
+ default:
+ break;
+ }
+
+ return e;
+}
+
+AudiodevListHead audio_handle_legacy_opts(void)
+{
+ const char *drvname = getenv("QEMU_AUDIO_DRV");
+ AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
+
+ if (drvname) {
+ AudiodevListEntry *e;
+ audio_driver *driver = audio_driver_lookup(drvname);
+ if (!driver) {
+ dolog("Unknown audio driver `%s'\n", drvname);
+ exit(1);
+ }
+ e = legacy_opt(drvname);
+ QSIMPLEQ_INSERT_TAIL(&head, e, next);
+ } else {
+ for (int i = 0; audio_prio_list[i]; i++) {
+ audio_driver *driver = audio_driver_lookup(audio_prio_list[i]);
+ if (driver && driver->can_be_default) {
+ AudiodevListEntry *e = legacy_opt(driver->name);
+ QSIMPLEQ_INSERT_TAIL(&head, e, next);
+ }
+ }
+ if (QSIMPLEQ_EMPTY(&head)) {
+ dolog("Internal error: no default audio driver available\n");
+ exit(1);
+ }
+ }
+
+ return head;
+}
+
+/* visitor to print -audiodev option */
+typedef struct {
+ Visitor visitor;
+
+ bool comma;
+ GList *path;
+} LegacyPrintVisitor;
+
+static void lv_start_struct(Visitor *v, const char *name, void **obj,
+ size_t size, Error **errp)
+{
+ LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
+ lv->path = g_list_append(lv->path, g_strdup(name));
+}
+
+static void lv_end_struct(Visitor *v, void **obj)
+{
+ LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
+ lv->path = g_list_delete_link(lv->path, g_list_last(lv->path));
+}
+
+static void lv_print_key(Visitor *v, const char *name)
+{
+ GList *e;
+ LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
+ if (lv->comma) {
+ putchar(',');
+ } else {
+ lv->comma = true;
+ }
+
+ for (e = lv->path; e; e = e->next) {
+ if (e->data) {
+ printf("%s.", (const char *) e->data);
+ }
+ }
+
+ printf("%s=", name);
+}
+
+static void lv_type_int64(Visitor *v, const char *name, int64_t *obj,
+ Error **errp)
+{
+ lv_print_key(v, name);
+ printf("%" PRIi64, *obj);
+}
+
+static void lv_type_uint64(Visitor *v, const char *name, uint64_t *obj,
+ Error **errp)
+{
+ lv_print_key(v, name);
+ printf("%" PRIu64, *obj);
+}
+
+static void lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
+{
+ lv_print_key(v, name);
+ printf("%s", *obj ? "on" : "off");
+}
+
+static void lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
+{
+ const char *str = *obj;
+ lv_print_key(v, name);
+
+ while (*str) {
+ if (*str == ',') {
+ putchar(',');
+ }
+ putchar(*str++);
+ }
+}
+
+static void lv_complete(Visitor *v, void *opaque)
+{
+ LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
+ assert(lv->path == NULL);
+}
+
+static void lv_free(Visitor *v)
+{
+ LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
+
+ g_list_free_full(lv->path, g_free);
+ g_free(lv);
+}
+
+static Visitor *legacy_visitor_new(void)
+{
+ LegacyPrintVisitor *lv = g_malloc0(sizeof(LegacyPrintVisitor));
+
+ lv->visitor.start_struct = lv_start_struct;
+ lv->visitor.end_struct = lv_end_struct;
+ /* lists not supported */
+ lv->visitor.type_int64 = lv_type_int64;
+ lv->visitor.type_uint64 = lv_type_uint64;
+ lv->visitor.type_bool = lv_type_bool;
+ lv->visitor.type_str = lv_type_str;
+
+ lv->visitor.type = VISITOR_OUTPUT;
+ lv->visitor.complete = lv_complete;
+ lv->visitor.free = lv_free;
+
+ return &lv->visitor;
+}
+
+void audio_legacy_help(void)
+{
+ AudiodevListHead head;
+ AudiodevListEntry *e;
+
+ printf("Environment variable based configuration deprecated.\n");
+ printf("Please use the new -audiodev option.\n");
+
+ head = audio_handle_legacy_opts();
+ printf("\nEquivalent -audiodev to your current environment variables:\n");
+ if (!getenv("QEMU_AUDIO_DRV")) {
+ printf("(Since you didn't specify QEMU_AUDIO_DRV, I'll list all "
+ "possibilities)\n");
+ }
+
+ QSIMPLEQ_FOREACH(e, &head, next) {
+ Visitor *v;
+ Audiodev *dev = e->dev;
+ printf("-audiodev ");
+
+ v = legacy_visitor_new();
+ visit_type_Audiodev(v, NULL, &dev, &error_abort);
+ visit_free(v);
+
+ printf("\n");
+ }
+ audio_free_audiodev_list(&head);
+}
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 7de227d2d1..1232bb54db 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -299,11 +299,42 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
return NULL;
}
+AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
+{
+ switch (dev->driver) {
+ case AUDIODEV_DRIVER_NONE:
+ return dev->u.none.TYPE;
+ case AUDIODEV_DRIVER_ALSA:
+ return qapi_AudiodevAlsaPerDirectionOptions_base(dev->u.alsa.TYPE);
+ case AUDIODEV_DRIVER_COREAUDIO:
+ return qapi_AudiodevCoreaudioPerDirectionOptions_base(
+ dev->u.coreaudio.TYPE);
+ case AUDIODEV_DRIVER_DSOUND:
+ return dev->u.dsound.TYPE;
+ case AUDIODEV_DRIVER_OSS:
+ return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
+ case AUDIODEV_DRIVER_PA:
+ return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
+ case AUDIODEV_DRIVER_SDL:
+ return dev->u.sdl.TYPE;
+ case AUDIODEV_DRIVER_SPICE:
+ return dev->u.spice.TYPE;
+ case AUDIODEV_DRIVER_WAV:
+ return dev->u.wav.TYPE;
+
+ case AUDIODEV_DRIVER__MAX:
+ break;
+ }
+ abort();
+}
+
static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
{
HW *hw;
+ AudioState *s = &glob_audio_state;
+ AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
- if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
+ if (pdo->fixed_settings) {
hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
if (hw) {
return hw;
@@ -331,9 +362,11 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
SW *sw;
HW *hw;
struct audsettings hw_as;
+ AudioState *s = &glob_audio_state;
+ AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
- if (glue (conf.fixed_, TYPE).enabled) {
- hw_as = glue (conf.fixed_, TYPE).settings;
+ if (pdo->fixed_settings) {
+ hw_as = audiodev_to_audsettings(pdo);
}
else {
hw_as = *as;
@@ -398,6 +431,7 @@ SW *glue (AUD_open_, TYPE) (
)
{
AudioState *s = &glob_audio_state;
+ AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
@@ -422,7 +456,7 @@ SW *glue (AUD_open_, TYPE) (
return sw;
}
- if (!glue (conf.fixed_, TYPE).enabled && sw) {
+ if (!pdo->fixed_settings && sw) {
glue (AUD_close_, TYPE) (card, sw);
sw = NULL;
}
diff --git a/audio/audio_win_int.c b/audio/audio_win_int.c
index 6900008d0c..b938fd667b 100644
--- a/audio/audio_win_int.c
+++ b/audio/audio_win_int.c
@@ -24,20 +24,20 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
wfx->cbSize = 0;
switch (as->fmt) {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_S8:
+ case AUDIO_FORMAT_U8:
wfx->wBitsPerSample = 8;
break;
- case AUD_FMT_S16:
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_S16:
+ case AUDIO_FORMAT_U16:
wfx->wBitsPerSample = 16;
wfx->nAvgBytesPerSec <<= 1;
wfx->nBlockAlign <<= 1;
break;
- case AUD_FMT_S32:
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_S32:
+ case AUDIO_FORMAT_U32:
wfx->wBitsPerSample = 32;
wfx->nAvgBytesPerSec <<= 2;
wfx->nBlockAlign <<= 2;
@@ -85,15 +85,15 @@ int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
switch (wfx->wBitsPerSample) {
case 8:
- as->fmt = AUD_FMT_U8;
+ as->fmt = AUDIO_FORMAT_U8;
break;
case 16:
- as->fmt = AUD_FMT_S16;
+ as->fmt = AUDIO_FORMAT_S16;
break;
case 32:
- as->fmt = AUD_FMT_S32;
+ as->fmt = AUDIO_FORMAT_S32;
break;
default:
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 638c60b300..1ee43b7d5f 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -36,11 +36,6 @@
#define MAC_OS_X_VERSION_10_6 1060
#endif
-typedef struct {
- int buffer_frames;
- int nbuffers;
-} CoreaudioConf;
-
typedef struct coreaudioVoiceOut {
HWVoiceOut hw;
pthread_mutex_t mutex;
@@ -507,7 +502,9 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
int err;
const char *typ = "playback";
AudioValueRange frameRange;
- CoreaudioConf *conf = drv_opaque;
+ Audiodev *dev = drv_opaque;
+ AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
+ int frames;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
@@ -538,16 +535,17 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
return -1;
}
- if (frameRange.mMinimum > conf->buffer_frames) {
+ frames = audio_buffer_frames(
+ qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
+ if (frameRange.mMinimum > frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
- }
- else if (frameRange.mMaximum < conf->buffer_frames) {
+ } else if (frameRange.mMaximum < frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
}
else {
- core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
+ core->audioDevicePropertyBufferFrameSize = frames;
}
/* set Buffer Frame Size */
@@ -568,7 +566,8 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
"Could not get device buffer frame size\n");
return -1;
}
- hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
+ hw->samples = (cpdo->has_buffer_count ? cpdo->buffer_count : 4) *
+ core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */
status = coreaudio_get_streamformat(core->outputDeviceID,
@@ -680,40 +679,15 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
-static CoreaudioConf glob_conf = {
- .buffer_frames = 512,
- .nbuffers = 4,
-};
-
-static void *coreaudio_audio_init (void)
+static void *coreaudio_audio_init(Audiodev *dev)
{
- CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
- *conf = glob_conf;
-
- return conf;
+ return dev;
}
static void coreaudio_audio_fini (void *opaque)
{
- g_free(opaque);
}
-static struct audio_option coreaudio_options[] = {
- {
- .name = "BUFFER_SIZE",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.buffer_frames,
- .descr = "Size of the buffer in frames"
- },
- {
- .name = "BUFFER_COUNT",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.nbuffers,
- .descr = "Number of buffers"
- },
- { /* End of list */ }
-};
-
static struct audio_pcm_ops coreaudio_pcm_ops = {
.init_out = coreaudio_init_out,
.fini_out = coreaudio_fini_out,
@@ -725,7 +699,6 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
static struct audio_driver coreaudio_audio_driver = {
.name = "coreaudio",
.descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
- .options = coreaudio_options,
.init = coreaudio_audio_init,
.fini = coreaudio_audio_fini,
.pcm_ops = &coreaudio_pcm_ops,
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index b439f33f58..8ece870c9e 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -167,17 +167,18 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
dsound *s = drv_opaque;
WAVEFORMATEX wfx;
struct audsettings obt_as;
- DSoundConf *conf = &s->conf;
#ifdef DSBTYPE_IN
const char *typ = "ADC";
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
DSCBUFFERDESC bd;
DSCBCAPS bc;
+ AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.in;
#else
const char *typ = "DAC";
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
DSBUFFERDESC bd;
DSBCAPS bc;
+ AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.out;
#endif
if (!s->FIELD2) {
@@ -193,8 +194,8 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
memset (&bd, 0, sizeof (bd));
bd.dwSize = sizeof (bd);
bd.lpwfxFormat = &wfx;
+ bd.dwBufferBytes = audio_buffer_bytes(pdo, as, 92880);
#ifdef DSBTYPE_IN
- bd.dwBufferBytes = conf->bufsize_in;
hr = IDirectSoundCapture_CreateCaptureBuffer (
s->dsound_capture,
&bd,
@@ -203,7 +204,6 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
);
#else
bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
- bd.dwBufferBytes = conf->bufsize_out;
hr = IDirectSound_CreateSoundBuffer (
s->dsound,
&bd,
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 3ed73a30d1..a7d04b5033 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -32,6 +32,7 @@
#define AUDIO_CAP "dsound"
#include "audio_int.h"
+#include "qemu/host-utils.h"
#include <windows.h>
#include <mmsystem.h>
@@ -43,16 +44,10 @@
/* #define DEBUG_DSOUND */
typedef struct {
- int bufsize_in;
- int bufsize_out;
- int latency_millis;
-} DSoundConf;
-
-typedef struct {
LPDIRECTSOUND dsound;
LPDIRECTSOUNDCAPTURE dsound_capture;
struct audsettings settings;
- DSoundConf conf;
+ Audiodev *dev;
} dsound;
typedef struct {
@@ -248,9 +243,9 @@ static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
dsound_log_hresult (hr);
}
-static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
+static uint64_t usecs_to_bytes(struct audio_pcm_info *info, uint32_t usecs)
{
- return (millis * info->bytes_per_second) / 1000;
+ return muldiv64(usecs, info->bytes_per_second, 1000000);
}
#ifdef DEBUG_DSOUND
@@ -478,7 +473,7 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
LPVOID p1, p2;
int bufsize;
dsound *s = ds->s;
- DSoundConf *conf = &s->conf;
+ AudiodevDsoundOptions *dso = &s->dev->u.dsound;
if (!dsb) {
dolog ("Attempt to run empty with playback buffer\n");
@@ -501,14 +496,14 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
len = live << hwshift;
if (ds->first_time) {
- if (conf->latency_millis) {
+ if (dso->latency) {
DWORD cur_blat;
cur_blat = audio_ring_dist (wpos, ppos, bufsize);
ds->first_time = 0;
old_pos = wpos;
old_pos +=
- millis_to_bytes (&hw->info, conf->latency_millis) - cur_blat;
+ usecs_to_bytes(&hw->info, dso->latency) - cur_blat;
old_pos %= bufsize;
old_pos &= ~hw->info.align;
}
@@ -747,12 +742,6 @@ static int dsound_run_in (HWVoiceIn *hw)
return decr;
}
-static DSoundConf glob_conf = {
- .bufsize_in = 16384,
- .bufsize_out = 16384,
- .latency_millis = 10
-};
-
static void dsound_audio_fini (void *opaque)
{
HRESULT hr;
@@ -783,13 +772,22 @@ static void dsound_audio_fini (void *opaque)
g_free(s);
}
-static void *dsound_audio_init (void)
+static void *dsound_audio_init(Audiodev *dev)
{
int err;
HRESULT hr;
dsound *s = g_malloc0(sizeof(dsound));
+ AudiodevDsoundOptions *dso;
+
+ assert(dev->driver == AUDIODEV_DRIVER_DSOUND);
+ s->dev = dev;
+ dso = &dev->u.dsound;
+
+ if (!dso->has_latency) {
+ dso->has_latency = true;
+ dso->latency = 10000; /* 10 ms */
+ }
- s->conf = glob_conf;
hr = CoInitialize (NULL);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not initialize COM\n");
@@ -854,28 +852,6 @@ static void *dsound_audio_init (void)
return s;
}
-static struct audio_option dsound_options[] = {
- {
- .name = "LATENCY_MILLIS",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.latency_millis,
- .descr = "(undocumented)"
- },
- {
- .name = "BUFSIZE_OUT",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.bufsize_out,
- .descr = "(undocumented)"
- },
- {
- .name = "BUFSIZE_IN",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.bufsize_in,
- .descr = "(undocumented)"
- },
- { /* End of list */ }
-};
-
static struct audio_pcm_ops dsound_pcm_ops = {
.init_out = dsound_init_out,
.fini_out = dsound_fini_out,
@@ -893,7 +869,6 @@ static struct audio_pcm_ops dsound_pcm_ops = {
static struct audio_driver dsound_audio_driver = {
.name = "dsound",
.descr = "DirectSound http://wikipedia.org/wiki/DirectSound",
- .options = dsound_options,
.init = dsound_audio_init,
.fini = dsound_audio_fini,
.pcm_ops = &dsound_pcm_ops,
diff --git a/audio/noaudio.c b/audio/noaudio.c
index 1bfebeca7d..ccc611fc84 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -136,7 +136,7 @@ static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
return 0;
}
-static void *no_audio_init (void)
+static void *no_audio_init(Audiodev *dev)
{
return &no_audio_init;
}
@@ -163,7 +163,6 @@ static struct audio_pcm_ops no_pcm_ops = {
static struct audio_driver no_audio_driver = {
.name = "none",
.descr = "Timer based audio emulation",
- .options = NULL,
.init = no_audio_init,
.fini = no_audio_fini,
.pcm_ops = &no_pcm_ops,
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 6c69622b4c..fc28981a39 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -37,16 +37,6 @@
#define USE_DSP_POLICY
#endif
-typedef struct OSSConf {
- int try_mmap;
- int nfrags;
- int fragsize;
- const char *devpath_out;
- const char *devpath_in;
- int exclusive;
- int policy;
-} OSSConf;
-
typedef struct OSSVoiceOut {
HWVoiceOut hw;
void *pcm_buf;
@@ -56,7 +46,7 @@ typedef struct OSSVoiceOut {
int fragsize;
int mmapped;
int pending;
- OSSConf *conf;
+ Audiodev *dev;
} OSSVoiceOut;
typedef struct OSSVoiceIn {
@@ -65,12 +55,12 @@ typedef struct OSSVoiceIn {
int fd;
int nfrags;
int fragsize;
- OSSConf *conf;
+ Audiodev *dev;
} OSSVoiceIn;
struct oss_params {
int freq;
- audfmt_e fmt;
+ int fmt;
int nchannels;
int nfrags;
int fragsize;
@@ -148,16 +138,16 @@ static int oss_write (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len);
}
-static int aud_to_ossfmt (audfmt_e fmt, int endianness)
+static int aud_to_ossfmt (AudioFormat fmt, int endianness)
{
switch (fmt) {
- case AUD_FMT_S8:
+ case AUDIO_FORMAT_S8:
return AFMT_S8;
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_U8:
return AFMT_U8;
- case AUD_FMT_S16:
+ case AUDIO_FORMAT_S16:
if (endianness) {
return AFMT_S16_BE;
}
@@ -165,7 +155,7 @@ static int aud_to_ossfmt (audfmt_e fmt, int endianness)
return AFMT_S16_LE;
}
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_U16:
if (endianness) {
return AFMT_U16_BE;
}
@@ -182,37 +172,37 @@ static int aud_to_ossfmt (audfmt_e fmt, int endianness)
}
}
-static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
+static int oss_to_audfmt (int ossfmt, AudioFormat *fmt, int *endianness)
{
switch (ossfmt) {
case AFMT_S8:
*endianness = 0;
- *fmt = AUD_FMT_S8;
+ *fmt = AUDIO_FORMAT_S8;
break;
case AFMT_U8:
*endianness = 0;
- *fmt = AUD_FMT_U8;
+ *fmt = AUDIO_FORMAT_U8;
break;
case AFMT_S16_LE:
*endianness = 0;
- *fmt = AUD_FMT_S16;
+ *fmt = AUDIO_FORMAT_S16;
break;
case AFMT_U16_LE:
*endianness = 0;
- *fmt = AUD_FMT_U16;
+ *fmt = AUDIO_FORMAT_U16;
break;
case AFMT_S16_BE:
*endianness = 1;
- *fmt = AUD_FMT_S16;
+ *fmt = AUDIO_FORMAT_S16;
break;
case AFMT_U16_BE:
*endianness = 1;
- *fmt = AUD_FMT_U16;
+ *fmt = AUDIO_FORMAT_U16;
break;
default:
@@ -262,19 +252,25 @@ static int oss_get_version (int fd, int *version, const char *typ)
}
#endif
-static int oss_open (int in, struct oss_params *req,
- struct oss_params *obt, int *pfd, OSSConf* conf)
+static int oss_open(int in, struct oss_params *req, audsettings *as,
+ struct oss_params *obt, int *pfd, Audiodev *dev)
{
+ AudiodevOssOptions *oopts = &dev->u.oss;
+ AudiodevOssPerDirectionOptions *opdo = in ? oopts->in : oopts->out;
int fd;
- int oflags = conf->exclusive ? O_EXCL : 0;
+ int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0;
audio_buf_info abinfo;
int fmt, freq, nchannels;
int setfragment = 1;
- const char *dspname = in ? conf->devpath_in : conf->devpath_out;
+ const char *dspname = opdo->has_dev ? opdo->dev : "/dev/dsp";
const char *typ = in ? "ADC" : "DAC";
+#ifdef USE_DSP_POLICY
+ int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5;
+#endif
/* Kludge needed to have working mmap on Linux */
- oflags |= conf->try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
+ oflags |= (oopts->has_try_mmap && oopts->try_mmap) ?
+ O_RDWR : (in ? O_RDONLY : O_WRONLY);
fd = open (dspname, oflags | O_NONBLOCK);
if (-1 == fd) {
@@ -285,6 +281,9 @@ static int oss_open (int in, struct oss_params *req,
freq = req->freq;
nchannels = req->nchannels;
fmt = req->fmt;
+ req->nfrags = opdo->has_buffer_count ? opdo->buffer_count : 4;
+ req->fragsize = audio_buffer_bytes(
+ qapi_AudiodevOssPerDirectionOptions_base(opdo), as, 23220);
if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
@@ -308,18 +307,18 @@ static int oss_open (int in, struct oss_params *req,
}
#ifdef USE_DSP_POLICY
- if (conf->policy >= 0) {
+ if (policy >= 0) {
int version;
if (!oss_get_version (fd, &version, typ)) {
trace_oss_version(version);
if (version >= 0x040000) {
- int policy = conf->policy;
- if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
+ int policy2 = policy;
+ if (ioctl(fd, SNDCTL_DSP_POLICY, &policy2)) {
oss_logerr2 (errno, typ,
"Failed to set timing policy to %d\n",
- conf->policy);
+ policy);
goto err;
}
setfragment = 0;
@@ -500,19 +499,18 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
int endianness;
int err;
int fd;
- audfmt_e effective_fmt;
+ AudioFormat effective_fmt;
struct audsettings obt_as;
- OSSConf *conf = drv_opaque;
+ Audiodev *dev = drv_opaque;
+ AudiodevOssOptions *oopts = &dev->u.oss;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
- req.fragsize = conf->fragsize;
- req.nfrags = conf->nfrags;
- if (oss_open (0, &req, &obt, &fd, conf)) {
+ if (oss_open(0, &req, as, &obt, &fd, dev)) {
return -1;
}
@@ -539,7 +537,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
oss->mmapped = 0;
- if (conf->try_mmap) {
+ if (oopts->has_try_mmap && oopts->try_mmap) {
oss->pcm_buf = mmap (
NULL,
hw->samples << hw->info.shift,
@@ -597,7 +595,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
}
oss->fd = fd;
- oss->conf = conf;
+ oss->dev = dev;
return 0;
}
@@ -605,16 +603,12 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
int trig;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+ AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
switch (cmd) {
case VOICE_ENABLE:
{
- va_list ap;
- int poll_mode;
-
- va_start (ap, cmd);
- poll_mode = va_arg (ap, int);
- va_end (ap);
+ bool poll_mode = opdo->try_poll;
ldebug ("enabling voice\n");
if (poll_mode) {
@@ -667,18 +661,16 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
int endianness;
int err;
int fd;
- audfmt_e effective_fmt;
+ AudioFormat effective_fmt;
struct audsettings obt_as;
- OSSConf *conf = drv_opaque;
+ Audiodev *dev = drv_opaque;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
- req.fragsize = conf->fragsize;
- req.nfrags = conf->nfrags;
- if (oss_open (1, &req, &obt, &fd, conf)) {
+ if (oss_open(1, &req, as, &obt, &fd, dev)) {
return -1;
}
@@ -712,7 +704,7 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
}
oss->fd = fd;
- oss->conf = conf;
+ oss->dev = dev;
return 0;
}
@@ -803,16 +795,12 @@ static int oss_read (SWVoiceIn *sw, void *buf, int size)
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+ AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
switch (cmd) {
case VOICE_ENABLE:
{
- va_list ap;
- int poll_mode;
-
- va_start (ap, cmd);
- poll_mode = va_arg (ap, int);
- va_end (ap);
+ bool poll_mode = opdo->try_poll;
if (poll_mode) {
oss_poll_in (hw);
@@ -832,82 +820,36 @@ static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
return 0;
}
-static OSSConf glob_conf = {
- .try_mmap = 0,
- .nfrags = 4,
- .fragsize = 4096,
- .devpath_out = "/dev/dsp",
- .devpath_in = "/dev/dsp",
- .exclusive = 0,
- .policy = 5
-};
+static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo)
+{
+ if (!opdo->has_try_poll) {
+ opdo->try_poll = true;
+ opdo->has_try_poll = true;
+ }
+}
-static void *oss_audio_init (void)
+static void *oss_audio_init(Audiodev *dev)
{
- OSSConf *conf = g_malloc(sizeof(OSSConf));
- *conf = glob_conf;
+ AudiodevOssOptions *oopts;
+ assert(dev->driver == AUDIODEV_DRIVER_OSS);
+
+ oopts = &dev->u.oss;
+ oss_init_per_direction(oopts->in);
+ oss_init_per_direction(oopts->out);
- if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
- access(conf->devpath_out, R_OK | W_OK) < 0) {
- g_free(conf);
+ if (access(oopts->in->has_dev ? oopts->in->dev : "/dev/dsp",
+ R_OK | W_OK) < 0 ||
+ access(oopts->out->has_dev ? oopts->out->dev : "/dev/dsp",
+ R_OK | W_OK) < 0) {
return NULL;
}
- return conf;
+ return dev;
}
static void oss_audio_fini (void *opaque)
{
- g_free(opaque);
}
-static struct audio_option oss_options[] = {
- {
- .name = "FRAGSIZE",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.fragsize,
- .descr = "Fragment size in bytes"
- },
- {
- .name = "NFRAGS",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.nfrags,
- .descr = "Number of fragments"
- },
- {
- .name = "MMAP",
- .tag = AUD_OPT_BOOL,
- .valp = &glob_conf.try_mmap,
- .descr = "Try using memory mapped access"
- },
- {
- .name = "DAC_DEV",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.devpath_out,
- .descr = "Path to DAC device"
- },
- {
- .name = "ADC_DEV",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.devpath_in,
- .descr = "Path to ADC device"
- },
- {
- .name = "EXCLUSIVE",
- .tag = AUD_OPT_BOOL,
- .valp = &glob_conf.exclusive,
- .descr = "Open device in exclusive mode (vmix won't work)"
- },
-#ifdef USE_DSP_POLICY
- {
- .name = "POLICY",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.policy,
- .descr = "Set the timing policy of the device, -1 to use fragment mode",
- },
-#endif
- { /* End of list */ }
-};
-
static struct audio_pcm_ops oss_pcm_ops = {
.init_out = oss_init_out,
.fini_out = oss_fini_out,
@@ -925,7 +867,6 @@ static struct audio_pcm_ops oss_pcm_ops = {
static struct audio_driver oss_audio_driver = {
.name = "oss",
.descr = "OSS http://www.opensound.com",
- .options = oss_options,
.init = oss_audio_init,
.fini = oss_audio_fini,
.pcm_ops = &oss_pcm_ops,
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 6153b908da..5d410ed73f 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -2,6 +2,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "audio.h"
+#include "qapi/opts-visitor.h"
#include <pulse/pulseaudio.h>
@@ -10,14 +11,7 @@
#include "audio_pt_int.h"
typedef struct {
- int samples;
- char *server;
- char *sink;
- char *source;
-} PAConf;
-
-typedef struct {
- PAConf conf;
+ Audiodev *dev;
pa_threaded_mainloop *mainloop;
pa_context *context;
} paaudio;
@@ -32,6 +26,7 @@ typedef struct {
void *pcm_buf;
struct audio_pt pt;
paaudio *g;
+ int samples;
} PAVoiceOut;
typedef struct {
@@ -46,6 +41,7 @@ typedef struct {
const void *read_data;
size_t read_index, read_length;
paaudio *g;
+ int samples;
} PAVoiceIn;
static void qpa_audio_fini(void *opaque);
@@ -227,7 +223,7 @@ static void *qpa_thread_out (void *arg)
}
}
- decr = to_mix = audio_MIN(pa->live, pa->g->conf.samples >> 5);
+ decr = to_mix = audio_MIN(pa->live, pa->samples >> 5);
rpos = pa->rpos;
if (audio_pt_unlock(&pa->pt, __func__)) {
@@ -319,7 +315,7 @@ static void *qpa_thread_in (void *arg)
}
}
- incr = to_grab = audio_MIN(pa->dead, pa->g->conf.samples >> 5);
+ incr = to_grab = audio_MIN(pa->dead, pa->samples >> 5);
wpos = pa->wpos;
if (audio_pt_unlock(&pa->pt, __func__)) {
@@ -385,21 +381,21 @@ static int qpa_read (SWVoiceIn *sw, void *buf, int len)
return audio_pcm_sw_read (sw, buf, len);
}
-static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
+static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
{
int format;
switch (afmt) {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_S8:
+ case AUDIO_FORMAT_U8:
format = PA_SAMPLE_U8;
break;
- case AUD_FMT_S16:
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_S16:
+ case AUDIO_FORMAT_U16:
format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
break;
- case AUD_FMT_S32:
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_S32:
+ case AUDIO_FORMAT_U32:
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
break;
default:
@@ -410,26 +406,26 @@ static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
return format;
}
-static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
+static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
{
switch (fmt) {
case PA_SAMPLE_U8:
- return AUD_FMT_U8;
+ return AUDIO_FORMAT_U8;
case PA_SAMPLE_S16BE:
*endianness = 1;
- return AUD_FMT_S16;
+ return AUDIO_FORMAT_S16;
case PA_SAMPLE_S16LE:
*endianness = 0;
- return AUD_FMT_S16;
+ return AUDIO_FORMAT_S16;
case PA_SAMPLE_S32BE:
*endianness = 1;
- return AUD_FMT_S32;
+ return AUDIO_FORMAT_S32;
case PA_SAMPLE_S32LE:
*endianness = 0;
- return AUD_FMT_S32;
+ return AUDIO_FORMAT_S32;
default:
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
- return AUD_FMT_U8;
+ return AUDIO_FORMAT_U8;
}
}
@@ -546,6 +542,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
struct audsettings obt_as = *as;
PAVoiceOut *pa = (PAVoiceOut *) hw;
paaudio *g = pa->g = drv_opaque;
+ AudiodevPaOptions *popts = &g->dev->u.pa;
+ AudiodevPaPerDirectionOptions *ppdo = popts->out;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
@@ -566,7 +564,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
g,
"qemu",
PA_STREAM_PLAYBACK,
- g->conf.sink,
+ ppdo->has_name ? ppdo->name : NULL,
&ss,
NULL, /* channel map */
&ba, /* buffering attributes */
@@ -578,7 +576,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
}
audio_pcm_init_info (&hw->info, &obt_as);
- hw->samples = g->conf.samples;
+ hw->samples = pa->samples = audio_buffer_samples(
+ qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
pa->rpos = hw->rpos;
if (!pa->pcm_buf) {
@@ -612,6 +611,8 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
struct audsettings obt_as = *as;
PAVoiceIn *pa = (PAVoiceIn *) hw;
paaudio *g = pa->g = drv_opaque;
+ AudiodevPaOptions *popts = &g->dev->u.pa;
+ AudiodevPaPerDirectionOptions *ppdo = popts->in;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
@@ -623,7 +624,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
g,
"qemu",
PA_STREAM_RECORD,
- g->conf.source,
+ ppdo->has_name ? ppdo->name : NULL,
&ss,
NULL, /* channel map */
NULL, /* buffering attributes */
@@ -635,7 +636,8 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
}
audio_pcm_init_info (&hw->info, &obt_as);
- hw->samples = g->conf.samples;
+ hw->samples = pa->samples = audio_buffer_samples(
+ qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
pa->wpos = hw->wpos;
if (!pa->pcm_buf) {
@@ -808,13 +810,13 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
}
/* common */
-static PAConf glob_conf = {
- .samples = 4096,
-};
-
-static void *qpa_audio_init (void)
+static void *qpa_audio_init(Audiodev *dev)
{
- if (glob_conf.server == NULL) {
+ paaudio *g;
+ AudiodevPaOptions *popts = &dev->u.pa;
+ const char *server;
+
+ if (!popts->has_server) {
char pidfile[64];
char *runtime;
struct stat st;
@@ -829,8 +831,12 @@ static void *qpa_audio_init (void)
}
}
- paaudio *g = g_malloc(sizeof(paaudio));
- g->conf = glob_conf;
+ assert(dev->driver == AUDIODEV_DRIVER_PA);
+
+ g = g_malloc(sizeof(paaudio));
+ server = popts->has_server ? popts->server : NULL;
+
+ g->dev = dev;
g->mainloop = NULL;
g->context = NULL;
@@ -840,14 +846,14 @@ static void *qpa_audio_init (void)
}
g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
- g->conf.server);
+ server);
if (!g->context) {
goto fail;
}
pa_context_set_state_callback (g->context, context_state_cb, g);
- if (pa_context_connect (g->context, g->conf.server, 0, NULL) < 0) {
+ if (pa_context_connect(g->context, server, 0, NULL) < 0) {
qpa_logerr (pa_context_errno (g->context),
"pa_context_connect() failed\n");
goto fail;
@@ -910,34 +916,6 @@ static void qpa_audio_fini (void *opaque)
g_free(g);
}
-struct audio_option qpa_options[] = {
- {
- .name = "SAMPLES",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.samples,
- .descr = "buffer size in samples"
- },
- {
- .name = "SERVER",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.server,
- .descr = "server address"
- },
- {
- .name = "SINK",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.sink,
- .descr = "sink device name"
- },
- {
- .name = "SOURCE",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.source,
- .descr = "source device name"
- },
- { /* End of list */ }
-};
-
static struct audio_pcm_ops qpa_pcm_ops = {
.init_out = qpa_init_out,
.fini_out = qpa_fini_out,
@@ -955,7 +933,6 @@ static struct audio_pcm_ops qpa_pcm_ops = {
static struct audio_driver pa_audio_driver = {
.name = "pa",
.descr = "http://www.pulseaudio.org/",
- .options = qpa_options,
.init = qpa_audio_init,
.fini = qpa_audio_fini,
.pcm_ops = &qpa_pcm_ops,
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index f7ee70b153..ff9248ba68 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -44,16 +44,11 @@ typedef struct SDLVoiceOut {
int decr;
} SDLVoiceOut;
-static struct {
- int nb_samples;
-} conf = {
- .nb_samples = 1024
-};
-
static struct SDLAudioState {
int exit;
int initialized;
bool driver_created;
+ Audiodev *dev;
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
@@ -68,19 +63,19 @@ static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
}
-static int aud_to_sdlfmt (audfmt_e fmt)
+static int aud_to_sdlfmt (AudioFormat fmt)
{
switch (fmt) {
- case AUD_FMT_S8:
+ case AUDIO_FORMAT_S8:
return AUDIO_S8;
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_U8:
return AUDIO_U8;
- case AUD_FMT_S16:
+ case AUDIO_FORMAT_S16:
return AUDIO_S16LSB;
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_U16:
return AUDIO_U16LSB;
default:
@@ -92,37 +87,37 @@ static int aud_to_sdlfmt (audfmt_e fmt)
}
}
-static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
+static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness)
{
switch (sdlfmt) {
case AUDIO_S8:
*endianness = 0;
- *fmt = AUD_FMT_S8;
+ *fmt = AUDIO_FORMAT_S8;
break;
case AUDIO_U8:
*endianness = 0;
- *fmt = AUD_FMT_U8;
+ *fmt = AUDIO_FORMAT_U8;
break;
case AUDIO_S16LSB:
*endianness = 0;
- *fmt = AUD_FMT_S16;
+ *fmt = AUDIO_FORMAT_S16;
break;
case AUDIO_U16LSB:
*endianness = 0;
- *fmt = AUD_FMT_U16;
+ *fmt = AUDIO_FORMAT_U16;
break;
case AUDIO_S16MSB:
*endianness = 1;
- *fmt = AUD_FMT_S16;
+ *fmt = AUDIO_FORMAT_S16;
break;
case AUDIO_U16MSB:
*endianness = 1;
- *fmt = AUD_FMT_U16;
+ *fmt = AUDIO_FORMAT_U16;
break;
default:
@@ -265,13 +260,13 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
SDL_AudioSpec req, obt;
int endianness;
int err;
- audfmt_e effective_fmt;
+ AudioFormat effective_fmt;
struct audsettings obt_as;
req.freq = as->freq;
req.format = aud_to_sdlfmt (as->fmt);
req.channels = as->nchannels;
- req.samples = conf.nb_samples;
+ req.samples = audio_buffer_samples(s->dev->u.sdl.out, as, 11610);
req.callback = sdl_callback;
req.userdata = sdl;
@@ -315,7 +310,7 @@ static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
-static void *sdl_audio_init (void)
+static void *sdl_audio_init(Audiodev *dev)
{
SDLAudioState *s = &glob_sdl;
if (s->driver_created) {
@@ -329,6 +324,7 @@ static void *sdl_audio_init (void)
}
s->driver_created = true;
+ s->dev = dev;
return s;
}
@@ -338,18 +334,9 @@ static void sdl_audio_fini (void *opaque)
sdl_close (s);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
s->driver_created = false;
+ s->dev = NULL;
}
-static struct audio_option sdl_options[] = {
- {
- .name = "SAMPLES",
- .tag = AUD_OPT_INT,
- .valp = &conf.nb_samples,
- .descr = "Size of SDL buffer in samples"
- },
- { /* End of list */ }
-};
-
static struct audio_pcm_ops sdl_pcm_ops = {
.init_out = sdl_init_out,
.fini_out = sdl_fini_out,
@@ -361,7 +348,6 @@ static struct audio_pcm_ops sdl_pcm_ops = {
static struct audio_driver sdl_audio_driver = {
.name = "sdl",
.descr = "SDL http://www.libsdl.org",
- .options = sdl_options,
.init = sdl_audio_init,
.fini = sdl_audio_fini,
.pcm_ops = &sdl_pcm_ops,
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 6ad0eafbc6..4f7873af5a 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -77,7 +77,7 @@ static const SpiceRecordInterface record_sif = {
.base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
};
-static void *spice_audio_init (void)
+static void *spice_audio_init(Audiodev *dev)
{
if (!using_spice) {
return NULL;
@@ -130,7 +130,7 @@ static int line_out_init(HWVoiceOut *hw, struct audsettings *as,
settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
#endif
settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
- settings.fmt = AUD_FMT_S16;
+ settings.fmt = AUDIO_FORMAT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &settings);
@@ -258,7 +258,7 @@ static int line_in_init(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
settings.freq = SPICE_INTERFACE_RECORD_FREQ;
#endif
settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
- settings.fmt = AUD_FMT_S16;
+ settings.fmt = AUDIO_FORMAT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &settings);
@@ -373,10 +373,6 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
return 0;
}
-static struct audio_option audio_options[] = {
- { /* end of list */ },
-};
-
static struct audio_pcm_ops audio_callbacks = {
.init_out = line_out_init,
.fini_out = line_out_fini,
@@ -394,7 +390,6 @@ static struct audio_pcm_ops audio_callbacks = {
static struct audio_driver spice_audio_driver = {
.name = "spice",
.descr = "spice audio driver",
- .options = audio_options,
.init = spice_audio_init,
.fini = spice_audio_fini,
.pcm_ops = &audio_callbacks,
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 40adfa30c3..8d30f57296 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu/host-utils.h"
#include "qemu/timer.h"
+#include "qapi/opts-visitor.h"
#include "audio.h"
#define AUDIO_CAP "wav"
@@ -37,11 +38,6 @@ typedef struct WAVVoiceOut {
int total_samples;
} WAVVoiceOut;
-typedef struct {
- struct audsettings settings;
- const char *wav_path;
-} WAVConf;
-
static int wav_run_out (HWVoiceOut *hw, int live)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
@@ -112,25 +108,30 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
- WAVConf *conf = drv_opaque;
- struct audsettings wav_as = conf->settings;
+ Audiodev *dev = drv_opaque;
+ AudiodevWavOptions *wopts = &dev->u.wav;
+ struct audsettings wav_as = audiodev_to_audsettings(dev->u.wav.out);
+ const char *wav_path = wopts->has_path ? wopts->path : "qemu.wav";
stereo = wav_as.nchannels == 2;
switch (wav_as.fmt) {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
+ case AUDIO_FORMAT_S8:
+ case AUDIO_FORMAT_U8:
bits16 = 0;
break;
- case AUD_FMT_S16:
- case AUD_FMT_U16:
+ case AUDIO_FORMAT_S16:
+ case AUDIO_FORMAT_U16:
bits16 = 1;
break;
- case AUD_FMT_S32:
- case AUD_FMT_U32:
+ case AUDIO_FORMAT_S32:
+ case AUDIO_FORMAT_U32:
dolog ("WAVE files can not handle 32bit formats\n");
return -1;
+
+ default:
+ abort();
}
hdr[34] = bits16 ? 0x10 : 0x08;
@@ -151,10 +152,10 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
- wav->f = fopen (conf->wav_path, "wb");
+ wav->f = fopen(wav_path, "wb");
if (!wav->f) {
dolog ("Failed to open wave file `%s'\nReason: %s\n",
- conf->wav_path, strerror (errno));
+ wav_path, strerror(errno));
g_free (wav->pcm_buf);
wav->pcm_buf = NULL;
return -1;
@@ -222,54 +223,17 @@ static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
-static WAVConf glob_conf = {
- .settings.freq = 44100,
- .settings.nchannels = 2,
- .settings.fmt = AUD_FMT_S16,
- .wav_path = "qemu.wav"
-};
-
-static void *wav_audio_init (void)
+static void *wav_audio_init(Audiodev *dev)
{
- WAVConf *conf = g_malloc(sizeof(WAVConf));
- *conf = glob_conf;
- return conf;
+ assert(dev->driver == AUDIODEV_DRIVER_WAV);
+ return dev;
}
static void wav_audio_fini (void *opaque)
{
ldebug ("wav_fini");
- g_free(opaque);
}
-static struct audio_option wav_options[] = {
- {
- .name = "FREQUENCY",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.settings.freq,
- .descr = "Frequency"
- },
- {
- .name = "FORMAT",
- .tag = AUD_OPT_FMT,
- .valp = &glob_conf.settings.fmt,
- .descr = "Format"
- },
- {
- .name = "DAC_FIXED_CHANNELS",
- .tag = AUD_OPT_INT,
- .valp = &glob_conf.settings.nchannels,
- .descr = "Number of channels (1 - mono, 2 - stereo)"
- },
- {
- .name = "PATH",
- .tag = AUD_OPT_STR,
- .valp = &glob_conf.wav_path,
- .descr = "Path to wave file"
- },
- { /* End of list */ }
-};
-
static struct audio_pcm_ops wav_pcm_ops = {
.init_out = wav_init_out,
.fini_out = wav_fini_out,
@@ -281,7 +245,6 @@ static struct audio_pcm_ops wav_pcm_ops = {
static struct audio_driver wav_audio_driver = {
.name = "wav",
.descr = "WAV renderer http://wikipedia.org/wiki/WAV",
- .options = wav_options,
.init = wav_audio_init,
.fini = wav_audio_fini,
.pcm_ops = &wav_pcm_ops,
diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index cd24570aa7..74320dfecc 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -136,7 +136,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
as.freq = freq;
as.nchannels = 1 << stereo;
- as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
+ as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
as.endianness = 0;
ops.notify = wav_notify;
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index d539f14d59..1052a5d0e9 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -47,7 +47,7 @@
typedef struct CryptoDevBackendVhostUser {
CryptoDevBackend parent_obj;
- VhostUserState *vhost_user;
+ VhostUserState vhost_user;
CharBackend chr;
char *chr_name;
bool opened;
@@ -104,7 +104,7 @@ cryptodev_vhost_user_start(int queues,
continue;
}
- options.opaque = s->vhost_user;
+ options.opaque = &s->vhost_user;
options.backend_type = VHOST_BACKEND_TYPE_USER;
options.cc = b->conf.peers.ccs[i];
s->vhost_crypto[i] = cryptodev_vhost_init(&options);
@@ -182,7 +182,6 @@ static void cryptodev_vhost_user_init(
size_t i;
Error *local_err = NULL;
Chardev *chr;
- VhostUserState *user;
CryptoDevBackendClient *cc;
CryptoDevBackendVhostUser *s =
CRYPTODEV_BACKEND_VHOST_USER(backend);
@@ -213,15 +212,10 @@ static void cryptodev_vhost_user_init(
}
}
- user = vhost_user_init();
- if (!user) {
- error_setg(errp, "Failed to init vhost_user");
+ if (!vhost_user_init(&s->vhost_user, &s->chr, errp)) {
return;
}
- user->chr = &s->chr;
- s->vhost_user = user;
-
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
cryptodev_vhost_user_event, NULL, s, NULL, true);
@@ -307,11 +301,7 @@ static void cryptodev_vhost_user_cleanup(
}
}
- if (s->vhost_user) {
- vhost_user_cleanup(s->vhost_user);
- g_free(s->vhost_user);
- s->vhost_user = NULL;
- }
+ vhost_user_cleanup(&s->vhost_user);
}
static void cryptodev_vhost_user_set_chardev(Object *obj,
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index ce54788048..37ac6445d2 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -56,6 +56,29 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
error_setg(errp, "mem-path property not set");
return;
}
+
+ /*
+ * Verify pmem file size since starting a guest with an incorrect size
+ * leads to confusing failures inside the guest.
+ */
+ if (fb->is_pmem) {
+ Error *local_err = NULL;
+ uint64_t size;
+
+ size = qemu_get_pmem_size(fb->mem_path, &local_err);
+ if (!size) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (backend->size > size) {
+ error_setg(errp, "size property %" PRIu64 " is larger than "
+ "pmem file \"%s\" size %" PRIu64, backend->size,
+ fb->mem_path, size);
+ return;
+ }
+ }
+
backend->force_prealloc = mem_prealloc;
name = host_memory_backend_get_name(backend);
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 98c9bf3240..46b15b916a 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -154,15 +154,13 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
"Huge pages size (ex: 2M, 1G)",
&error_abort);
}
- if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
- object_class_property_add_bool(oc, "seal",
- memfd_backend_get_seal,
- memfd_backend_set_seal,
- &error_abort);
- object_class_property_set_description(oc, "seal",
- "Seal growing & shrinking",
- &error_abort);
- }
+ object_class_property_add_bool(oc, "seal",
+ memfd_backend_get_seal,
+ memfd_backend_set_seal,
+ &error_abort);
+ object_class_property_set_description(oc, "seal",
+ "Seal growing & shrinking",
+ &error_abort);
}
static const TypeInfo memfd_backend_info = {
@@ -175,7 +173,7 @@ static const TypeInfo memfd_backend_info = {
static void register_types(void)
{
- if (qemu_memfd_check(0)) {
+ if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
type_register_static(&memfd_backend_info);
}
}
diff --git a/block.c b/block.c
index ccf008c177..ed9253c786 100644
--- a/block.c
+++ b/block.c
@@ -1163,13 +1163,6 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
*/
open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_PROTOCOL);
- /*
- * Snapshots should be writable.
- */
- if (flags & BDRV_O_TEMPORARY) {
- open_flags |= BDRV_O_RDWR;
- }
-
return open_flags;
}
@@ -1698,6 +1691,7 @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
typedef struct BlockReopenQueueEntry {
bool prepared;
+ bool perms_checked;
BDRVReopenState state;
QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry;
} BlockReopenQueueEntry;
@@ -2132,6 +2126,8 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *old_bs = child->bs;
int i;
+ assert(!child->frozen);
+
if (old_bs && new_bs) {
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
}
@@ -2348,6 +2344,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) &&
bdrv_inherits_from_recursive(backing_hd, bs);
+ if (bdrv_is_backing_chain_frozen(bs, backing_bs(bs), errp)) {
+ return;
+ }
+
if (backing_hd) {
bdrv_ref(backing_hd);
}
@@ -2983,6 +2983,74 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
NULL, errp);
}
+/* Return true if the NULL-terminated @list contains @str */
+static bool is_str_in_list(const char *str, const char *const *list)
+{
+ if (str && list) {
+ int i;
+ for (i = 0; list[i] != NULL; i++) {
+ if (!strcmp(str, list[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ * Check that every option set in @bs->options is also set in
+ * @new_opts.
+ *
+ * Options listed in the common_options list and in
+ * @bs->drv->mutable_opts are skipped.
+ *
+ * Return 0 on success, otherwise return -EINVAL and set @errp.
+ */
+static int bdrv_reset_options_allowed(BlockDriverState *bs,
+ const QDict *new_opts, Error **errp)
+{
+ const QDictEntry *e;
+ /* These options are common to all block drivers and are handled
+ * in bdrv_reopen_prepare() so they can be left out of @new_opts */
+ const char *const common_options[] = {
+ "node-name", "discard", "cache.direct", "cache.no-flush",
+ "read-only", "auto-read-only", "detect-zeroes", NULL
+ };
+
+ for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
+ if (!qdict_haskey(new_opts, e->key) &&
+ !is_str_in_list(e->key, common_options) &&
+ !is_str_in_list(e->key, bs->drv->mutable_opts)) {
+ error_setg(errp, "Option '%s' cannot be reset "
+ "to its default value", e->key);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Returns true if @child can be reached recursively from @bs
+ */
+static bool bdrv_recurse_has_child(BlockDriverState *bs,
+ BlockDriverState *child)
+{
+ BdrvChild *c;
+
+ if (bs == child) {
+ return true;
+ }
+
+ QLIST_FOREACH(c, &bs->children, next) {
+ if (bdrv_recurse_has_child(c->bs, child)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/*
* Adds a BlockDriverState to a simple queue for an atomic, transactional
* reopen of multiple devices.
@@ -3010,7 +3078,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
QDict *options,
const BdrvChildRole *role,
QDict *parent_options,
- int parent_flags)
+ int parent_flags,
+ bool keep_old_opts)
{
assert(bs != NULL);
@@ -3050,13 +3119,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
*/
/* Old explicitly set values (don't overwrite by inherited value) */
- if (bs_entry) {
- old_options = qdict_clone_shallow(bs_entry->state.explicit_options);
- } else {
- old_options = qdict_clone_shallow(bs->explicit_options);
+ if (bs_entry || keep_old_opts) {
+ old_options = qdict_clone_shallow(bs_entry ?
+ bs_entry->state.explicit_options :
+ bs->explicit_options);
+ bdrv_join_options(bs, options, old_options);
+ qobject_unref(old_options);
}
- bdrv_join_options(bs, options, old_options);
- qobject_unref(old_options);
explicit_options = qdict_clone_shallow(options);
@@ -3068,10 +3137,12 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
flags = bdrv_get_flags(bs);
}
- /* Old values are used for options that aren't set yet */
- old_options = qdict_clone_shallow(bs->options);
- bdrv_join_options(bs, options, old_options);
- qobject_unref(old_options);
+ if (keep_old_opts) {
+ /* Old values are used for options that aren't set yet */
+ old_options = qdict_clone_shallow(bs->options);
+ bdrv_join_options(bs, options, old_options);
+ qobject_unref(old_options);
+ }
/* We have the final set of options so let's update the flags */
options_copy = qdict_clone_shallow(options);
@@ -3104,9 +3175,21 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
bs_entry->state.perm = UINT64_MAX;
bs_entry->state.shared_perm = 0;
+ /*
+ * If keep_old_opts is false then it means that unspecified
+ * options must be reset to their original value. We don't allow
+ * resetting 'backing' but we need to know if the option is
+ * missing in order to decide if we have to return an error.
+ */
+ if (!keep_old_opts) {
+ bs_entry->state.backing_missing =
+ !qdict_haskey(options, "backing") &&
+ !qdict_haskey(options, "backing.driver");
+ }
+
QLIST_FOREACH(child, &bs->children, next) {
- QDict *new_child_options;
- char *child_key_dot;
+ QDict *new_child_options = NULL;
+ bool child_keep_old = keep_old_opts;
/* reopen can only change the options of block devices that were
* implicitly created and inherited options. For other (referenced)
@@ -3115,13 +3198,32 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
continue;
}
- child_key_dot = g_strdup_printf("%s.", child->name);
- qdict_extract_subqdict(explicit_options, NULL, child_key_dot);
- qdict_extract_subqdict(options, &new_child_options, child_key_dot);
- g_free(child_key_dot);
+ /* Check if the options contain a child reference */
+ if (qdict_haskey(options, child->name)) {
+ const char *childref = qdict_get_try_str(options, child->name);
+ /*
+ * The current child must not be reopened if the child
+ * reference is null or points to a different node.
+ */
+ if (g_strcmp0(childref, child->bs->node_name)) {
+ continue;
+ }
+ /*
+ * If the child reference points to the current child then
+ * reopen it with its existing set of options (note that
+ * it can still inherit new options from the parent).
+ */
+ child_keep_old = true;
+ } else {
+ /* Extract child options ("child-name.*") */
+ char *child_key_dot = g_strdup_printf("%s.", child->name);
+ qdict_extract_subqdict(explicit_options, NULL, child_key_dot);
+ qdict_extract_subqdict(options, &new_child_options, child_key_dot);
+ g_free(child_key_dot);
+ }
bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options,
- child->role, options, flags);
+ child->role, options, flags, child_keep_old);
}
return bs_queue;
@@ -3129,9 +3231,10 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
BlockDriverState *bs,
- QDict *options)
+ QDict *options, bool keep_old_opts)
{
- return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0);
+ return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0,
+ keep_old_opts);
}
/*
@@ -3151,23 +3254,44 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
* All affected nodes must be drained between bdrv_reopen_queue() and
* bdrv_reopen_multiple().
*/
-int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp)
+int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
{
int ret = -1;
BlockReopenQueueEntry *bs_entry, *next;
- Error *local_err = NULL;
assert(bs_queue != NULL);
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
assert(bs_entry->state.bs->quiesce_counter > 0);
- if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) {
- error_propagate(errp, local_err);
+ if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) {
goto cleanup;
}
bs_entry->prepared = true;
}
+ QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
+ BDRVReopenState *state = &bs_entry->state;
+ ret = bdrv_check_perm(state->bs, bs_queue, state->perm,
+ state->shared_perm, NULL, errp);
+ if (ret < 0) {
+ goto cleanup_perm;
+ }
+ /* Check if new_backing_bs would accept the new permissions */
+ if (state->replace_backing_bs && state->new_backing_bs) {
+ uint64_t nperm, nshared;
+ bdrv_child_perm(state->bs, state->new_backing_bs,
+ NULL, &child_backing, bs_queue,
+ state->perm, state->shared_perm,
+ &nperm, &nshared);
+ ret = bdrv_check_update_perm(state->new_backing_bs, NULL,
+ nperm, nshared, NULL, errp);
+ if (ret < 0) {
+ goto cleanup_perm;
+ }
+ }
+ bs_entry->perms_checked = true;
+ }
+
/* If we reach this point, we have success and just need to apply the
* changes
*/
@@ -3176,7 +3300,23 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
}
ret = 0;
+cleanup_perm:
+ QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
+ BDRVReopenState *state = &bs_entry->state;
+
+ if (!bs_entry->perms_checked) {
+ continue;
+ }
+ if (ret == 0) {
+ bdrv_set_perm(state->bs, state->perm, state->shared_perm);
+ } else {
+ bdrv_abort_perm_update(state->bs);
+ if (state->replace_backing_bs && state->new_backing_bs) {
+ bdrv_abort_perm_update(state->new_backing_bs);
+ }
+ }
+ }
cleanup:
QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
if (ret) {
@@ -3186,6 +3326,9 @@ cleanup:
qobject_unref(bs_entry->state.explicit_options);
qobject_unref(bs_entry->state.options);
}
+ if (bs_entry->state.new_backing_bs) {
+ bdrv_unref(bs_entry->state.new_backing_bs);
+ }
g_free(bs_entry);
}
g_free(bs_queue);
@@ -3203,8 +3346,8 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
bdrv_subtree_drained_begin(bs);
- queue = bdrv_reopen_queue(NULL, bs, opts);
- ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, errp);
+ queue = bdrv_reopen_queue(NULL, bs, opts, true);
+ ret = bdrv_reopen_multiple(queue, errp);
bdrv_subtree_drained_end(bs);
return ret;
@@ -3258,6 +3401,101 @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs,
}
/*
+ * Take a BDRVReopenState and check if the value of 'backing' in the
+ * reopen_state->options QDict is valid or not.
+ *
+ * If 'backing' is missing from the QDict then return 0.
+ *
+ * If 'backing' contains the node name of the backing file of
+ * reopen_state->bs then return 0.
+ *
+ * If 'backing' contains a different node name (or is null) then check
+ * whether the current backing file can be replaced with the new one.
+ * If that's the case then reopen_state->replace_backing_bs is set to
+ * true and reopen_state->new_backing_bs contains a pointer to the new
+ * backing BlockDriverState (or NULL).
+ *
+ * Return 0 on success, otherwise return < 0 and set @errp.
+ */
+static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
+ Error **errp)
+{
+ BlockDriverState *bs = reopen_state->bs;
+ BlockDriverState *overlay_bs, *new_backing_bs;
+ QObject *value;
+ const char *str;
+
+ value = qdict_get(reopen_state->options, "backing");
+ if (value == NULL) {
+ return 0;
+ }
+
+ switch (qobject_type(value)) {
+ case QTYPE_QNULL:
+ new_backing_bs = NULL;
+ break;
+ case QTYPE_QSTRING:
+ str = qobject_get_try_str(value);
+ new_backing_bs = bdrv_lookup_bs(NULL, str, errp);
+ if (new_backing_bs == NULL) {
+ return -EINVAL;
+ } else if (bdrv_recurse_has_child(new_backing_bs, bs)) {
+ error_setg(errp, "Making '%s' a backing file of '%s' "
+ "would create a cycle", str, bs->node_name);
+ return -EINVAL;
+ }
+ break;
+ default:
+ /* 'backing' does not allow any other data type */
+ g_assert_not_reached();
+ }
+
+ /*
+ * TODO: before removing the x- prefix from x-blockdev-reopen we
+ * should move the new backing file into the right AioContext
+ * instead of returning an error.
+ */
+ if (new_backing_bs) {
+ if (bdrv_get_aio_context(new_backing_bs) != bdrv_get_aio_context(bs)) {
+ error_setg(errp, "Cannot use a new backing file "
+ "with a different AioContext");
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Find the "actual" backing file by skipping all links that point
+ * to an implicit node, if any (e.g. a commit filter node).
+ */
+ overlay_bs = bs;
+ while (backing_bs(overlay_bs) && backing_bs(overlay_bs)->implicit) {
+ overlay_bs = backing_bs(overlay_bs);
+ }
+
+ /* If we want to replace the backing file we need some extra checks */
+ if (new_backing_bs != backing_bs(overlay_bs)) {
+ /* Check for implicit nodes between bs and its backing file */
+ if (bs != overlay_bs) {
+ error_setg(errp, "Cannot change backing link if '%s' has "
+ "an implicit backing file", bs->node_name);
+ return -EPERM;
+ }
+ /* Check if the backing link that we want to replace is frozen */
+ if (bdrv_is_backing_chain_frozen(overlay_bs, backing_bs(overlay_bs),
+ errp)) {
+ return -EPERM;
+ }
+ reopen_state->replace_backing_bs = true;
+ if (new_backing_bs) {
+ bdrv_ref(new_backing_bs);
+ reopen_state->new_backing_bs = new_backing_bs;
+ }
+ }
+
+ return 0;
+}
+
+/*
* Prepares a BlockDriverState for reopen. All changes are staged in the
* 'opaque' field of the BDRVReopenState, which is used and allocated by
* the block driver layer .bdrv_reopen_prepare()
@@ -3355,6 +3593,17 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
}
if (drv->bdrv_reopen_prepare) {
+ /*
+ * If a driver-specific option is missing, it means that we
+ * should reset it to its default value.
+ * But not all options allow that, so we need to check it first.
+ */
+ ret = bdrv_reset_options_allowed(reopen_state->bs,
+ reopen_state->options, errp);
+ if (ret) {
+ goto error;
+ }
+
ret = drv->bdrv_reopen_prepare(reopen_state, queue, &local_err);
if (ret) {
if (local_err != NULL) {
@@ -3378,6 +3627,30 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
drv_prepared = true;
+ /*
+ * We must provide the 'backing' option if the BDS has a backing
+ * file or if the image file has a backing file name as part of
+ * its metadata. Otherwise the 'backing' option can be omitted.
+ */
+ if (drv->supports_backing && reopen_state->backing_missing &&
+ (backing_bs(reopen_state->bs) || reopen_state->bs->backing_file[0])) {
+ error_setg(errp, "backing is missing for '%s'",
+ reopen_state->bs->node_name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * Allow changing the 'backing' option. The new value can be
+ * either a reference to an existing node (using its node name)
+ * or NULL to simply detach the current backing file.
+ */
+ ret = bdrv_reopen_parse_backing(reopen_state, errp);
+ if (ret < 0) {
+ goto error;
+ }
+ qdict_del(reopen_state->options, "backing");
+
/* Options that are not handled are only okay if they are unchanged
* compared to the old state. It is expected that some options are only
* used for the initial open, but not reopen (e.g. filename) */
@@ -3430,12 +3703,6 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
} while ((entry = qdict_next(reopen_state->options, entry)));
}
- ret = bdrv_check_perm(reopen_state->bs, queue, reopen_state->perm,
- reopen_state->shared_perm, NULL, errp);
- if (ret < 0) {
- goto error;
- }
-
ret = 0;
/* Restore the original reopen_state->options QDict */
@@ -3493,6 +3760,11 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
bs->detect_zeroes = reopen_state->detect_zeroes;
+ if (reopen_state->replace_backing_bs) {
+ qdict_del(bs->explicit_options, "backing");
+ qdict_del(bs->options, "backing");
+ }
+
/* Remove child references from bs->options and bs->explicit_options.
* Child options were already removed in bdrv_reopen_queue_child() */
QLIST_FOREACH(child, &bs->children, next) {
@@ -3500,10 +3772,22 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
qdict_del(bs->options, child->name);
}
- bdrv_refresh_limits(bs, NULL);
+ /*
+ * Change the backing file if a new one was specified. We do this
+ * after updating bs->options, so bdrv_refresh_filename() (called
+ * from bdrv_set_backing_hd()) has the new values.
+ */
+ if (reopen_state->replace_backing_bs) {
+ BlockDriverState *old_backing_bs = backing_bs(bs);
+ assert(!old_backing_bs || !old_backing_bs->implicit);
+ /* Abort the permission update on the backing bs we're detaching */
+ if (old_backing_bs) {
+ bdrv_abort_perm_update(old_backing_bs);
+ }
+ bdrv_set_backing_hd(bs, reopen_state->new_backing_bs, &error_abort);
+ }
- bdrv_set_perm(reopen_state->bs, reopen_state->perm,
- reopen_state->shared_perm);
+ bdrv_refresh_limits(bs, NULL);
new_can_write =
!bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
@@ -3536,8 +3820,6 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
if (drv->bdrv_reopen_abort) {
drv->bdrv_reopen_abort(reopen_state);
}
-
- bdrv_abort_perm_update(reopen_state->bs);
}
@@ -3717,6 +3999,11 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
if (!should_update_child(c, to)) {
continue;
}
+ if (c->frozen) {
+ error_setg(errp, "Cannot change '%s' link to '%s'",
+ c->name, from->node_name);
+ goto out;
+ }
list = g_slist_prepend(list, c);
perm |= c->perm;
shared &= c->shared_perm;
@@ -3929,6 +4216,63 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
}
/*
+ * Return true if at least one of the backing links between @bs and
+ * @base is frozen. @errp is set if that's the case.
+ */
+bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
+ Error **errp)
+{
+ BlockDriverState *i;
+
+ for (i = bs; i != base && i->backing; i = backing_bs(i)) {
+ if (i->backing->frozen) {
+ error_setg(errp, "Cannot change '%s' link from '%s' to '%s'",
+ i->backing->name, i->node_name,
+ backing_bs(i)->node_name);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Freeze all backing links between @bs and @base.
+ * If any of the links is already frozen the operation is aborted and
+ * none of the links are modified.
+ * Returns 0 on success. On failure returns < 0 and sets @errp.
+ */
+int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
+ Error **errp)
+{
+ BlockDriverState *i;
+
+ if (bdrv_is_backing_chain_frozen(bs, base, errp)) {
+ return -EPERM;
+ }
+
+ for (i = bs; i != base && i->backing; i = backing_bs(i)) {
+ i->backing->frozen = true;
+ }
+
+ return 0;
+}
+
+/*
+ * Unfreeze all backing links between @bs and @base. The caller must
+ * ensure that all links are frozen before using this function.
+ */
+void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base)
+{
+ BlockDriverState *i;
+
+ for (i = bs; i != base && i->backing; i = backing_bs(i)) {
+ assert(i->backing->frozen);
+ i->backing->frozen = false;
+ }
+}
+
+/*
* Drops images above 'base' up to and including 'top', and sets the image
* above 'top' to have base as its backing file.
*
@@ -3977,6 +4321,14 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
goto exit;
}
+ /* This function changes all links that point to top and makes
+ * them point to base. Check that none of them is frozen. */
+ QLIST_FOREACH(c, &top->parents, next_parent) {
+ if (c->frozen) {
+ goto exit;
+ }
+ }
+
/* If 'base' recursively inherits from 'top' then we should set
* base->inherits_from to top->inherits_from after 'top' and all
* other intermediate nodes have been dropped.
diff --git a/block/commit.c b/block/commit.c
index 3b46ca7f97..ba60fef58a 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -39,6 +39,7 @@ typedef struct CommitBlockJob {
BlockDriverState *base_bs;
BlockdevOnError on_error;
bool base_read_only;
+ bool chain_frozen;
char *backing_file_str;
} CommitBlockJob;
@@ -68,6 +69,9 @@ static int commit_prepare(Job *job)
{
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
+ bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
+ s->chain_frozen = false;
+
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
* the normal backing chain can be restored. */
blk_unref(s->base);
@@ -84,6 +88,10 @@ static void commit_abort(Job *job)
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
BlockDriverState *top_bs = blk_bs(s->top);
+ if (s->chain_frozen) {
+ bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
+ }
+
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
bdrv_ref(top_bs);
bdrv_ref(s->commit_top_bs);
@@ -330,6 +338,11 @@ void commit_start(const char *job_id, BlockDriverState *bs,
}
}
+ if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
+ goto fail;
+ }
+ s->chain_frozen = true;
+
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
if (ret < 0) {
goto fail;
@@ -362,6 +375,9 @@ void commit_start(const char *job_id, BlockDriverState *bs,
return;
fail:
+ if (s->chain_frozen) {
+ bdrv_unfreeze_backing_chain(commit_top_bs, base);
+ }
if (s->base) {
blk_unref(s->base);
}
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index c6d4acebfa..59e6ebb861 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -28,29 +28,12 @@
#include "block/block_int.h"
#include "block/blockjob.h"
-/**
- * A BdrvDirtyBitmap can be in four possible user-visible states:
- * (1) Active: successor is NULL, and disabled is false: full r/w mode
- * (2) Disabled: successor is NULL, and disabled is true: qualified r/w mode,
- * guest writes are dropped, but monitor writes are possible,
- * through commands like merge and clear.
- * (3) Frozen: successor is not NULL.
- * A frozen bitmap cannot be renamed, deleted, cleared, set,
- * enabled, merged to, etc. A frozen bitmap can only abdicate()
- * or reclaim().
- * In this state, the anonymous successor bitmap may be either
- * Active and recording writes from the guest (e.g. backup jobs),
- * but it can be Disabled and not recording writes.
- * (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap
- * in any way from the monitor.
- */
struct BdrvDirtyBitmap {
QemuMutex *mutex;
HBitmap *bitmap; /* Dirty bitmap implementation */
HBitmap *meta; /* Meta dirty bitmap */
- bool qmp_locked; /* Bitmap is locked, it can't be modified
- through QMP */
- BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
+ bool busy; /* Bitmap is busy, it can't be used via QMP */
+ BdrvDirtyBitmap *successor; /* Anonymous child, if any. */
char *name; /* Optional non-empty unique ID */
int64_t size; /* Size of the bitmap, in bytes */
bool disabled; /* Bitmap is disabled. It ignores all writes to
@@ -63,6 +46,9 @@ struct BdrvDirtyBitmap {
and this bitmap must remain unchanged while
this flag is set. */
bool persistent; /* bitmap must be saved to owner disk image */
+ bool inconsistent; /* bitmap is persistent, but inconsistent.
+ It cannot be used at all in any way, except
+ a QMP user can remove it. */
bool migration; /* Bitmap is selected for migration, it should
not be stored on the next inactivation
(persistent flag doesn't matter until next
@@ -183,41 +169,58 @@ const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
}
/* Called with BQL taken. */
-bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
+bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap)
{
return bitmap->successor;
}
-/* Both conditions disallow user-modification via QMP. */
-bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap) {
- return bdrv_dirty_bitmap_frozen(bitmap) ||
- bdrv_dirty_bitmap_qmp_locked(bitmap);
+static bool bdrv_dirty_bitmap_busy(const BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->busy;
}
-void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked)
+void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy)
{
qemu_mutex_lock(bitmap->mutex);
- bitmap->qmp_locked = qmp_locked;
+ bitmap->busy = busy;
qemu_mutex_unlock(bitmap->mutex);
}
-bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap)
-{
- return bitmap->qmp_locked;
-}
-
/* Called with BQL taken. */
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
{
- return !(bitmap->disabled || bitmap->successor);
+ return !bitmap->disabled;
}
-/* Called with BQL taken. */
+/**
+ * bdrv_dirty_bitmap_status: This API is now deprecated.
+ * Called with BQL taken.
+ *
+ * A BdrvDirtyBitmap can be in four possible user-visible states:
+ * (1) Active: successor is NULL, and disabled is false: full r/w mode
+ * (2) Disabled: successor is NULL, and disabled is true: qualified r/w mode,
+ * guest writes are dropped, but monitor writes are possible,
+ * through commands like merge and clear.
+ * (3) Frozen: successor is not NULL.
+ * A frozen bitmap cannot be renamed, deleted, cleared, set,
+ * enabled, merged to, etc. A frozen bitmap can only abdicate()
+ * or reclaim().
+ * In this state, the anonymous successor bitmap may be either
+ * Active and recording writes from the guest (e.g. backup jobs),
+ * or it can be Disabled and not recording writes.
+ * (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap
+ * in any way from the monitor.
+ * (5) Inconsistent: This is a persistent bitmap whose "in use" bit is set, and
+ * is unusable by QEMU. It can be deleted to remove it from
+ * the qcow2.
+ */
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
{
- if (bdrv_dirty_bitmap_frozen(bitmap)) {
+ if (bdrv_dirty_bitmap_inconsistent(bitmap)) {
+ return DIRTY_BITMAP_STATUS_INCONSISTENT;
+ } else if (bdrv_dirty_bitmap_has_successor(bitmap)) {
return DIRTY_BITMAP_STATUS_FROZEN;
- } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
+ } else if (bdrv_dirty_bitmap_busy(bitmap)) {
return DIRTY_BITMAP_STATUS_LOCKED;
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
return DIRTY_BITMAP_STATUS_DISABLED;
@@ -226,9 +229,44 @@ DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
}
}
+/* Called with BQL taken. */
+static bool bdrv_dirty_bitmap_recording(BdrvDirtyBitmap *bitmap)
+{
+ return !bitmap->disabled || (bitmap->successor &&
+ !bitmap->successor->disabled);
+}
+
+int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
+ Error **errp)
+{
+ if ((flags & BDRV_BITMAP_BUSY) && bdrv_dirty_bitmap_busy(bitmap)) {
+ error_setg(errp, "Bitmap '%s' is currently in use by another"
+ " operation and cannot be used", bitmap->name);
+ return -1;
+ }
+
+ if ((flags & BDRV_BITMAP_RO) && bdrv_dirty_bitmap_readonly(bitmap)) {
+ error_setg(errp, "Bitmap '%s' is readonly and cannot be modified",
+ bitmap->name);
+ return -1;
+ }
+
+ if ((flags & BDRV_BITMAP_INCONSISTENT) &&
+ bdrv_dirty_bitmap_inconsistent(bitmap)) {
+ error_setg(errp, "Bitmap '%s' is inconsistent and cannot be used",
+ bitmap->name);
+ error_append_hint(errp, "Try block-dirty-bitmap-remove to delete"
+ " this bitmap from disk");
+ return -1;
+ }
+
+ return 0;
+}
+
/**
* Create a successor bitmap destined to replace this bitmap after an operation.
- * Requires that the bitmap is not frozen and has no successor.
+ * Requires that the bitmap is not marked busy and has no successor.
+ * The successor will be enabled if the parent bitmap was.
* Called with BQL taken.
*/
int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
@@ -237,12 +275,14 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
uint64_t granularity;
BdrvDirtyBitmap *child;
- if (bdrv_dirty_bitmap_frozen(bitmap)) {
- error_setg(errp, "Cannot create a successor for a bitmap that is "
- "currently frozen");
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY, errp)) {
+ return -1;
+ }
+ if (bdrv_dirty_bitmap_has_successor(bitmap)) {
+ error_setg(errp, "Cannot create a successor for a bitmap that already "
+ "has one");
return -1;
}
- assert(!bitmap->successor);
/* Create an anonymous successor */
granularity = bdrv_dirty_bitmap_granularity(bitmap);
@@ -253,15 +293,16 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
/* Successor will be on or off based on our current state. */
child->disabled = bitmap->disabled;
+ bitmap->disabled = true;
- /* Install the successor and freeze the parent */
+ /* Install the successor and mark the parent as busy */
bitmap->successor = child;
+ bitmap->busy = true;
return 0;
}
void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap)
{
- assert(!bdrv_dirty_bitmap_frozen(bitmap));
bitmap->disabled = false;
}
@@ -278,7 +319,8 @@ void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap)
static void bdrv_release_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap)
{
assert(!bitmap->active_iterators);
- assert(!bdrv_dirty_bitmap_frozen(bitmap));
+ assert(!bdrv_dirty_bitmap_busy(bitmap));
+ assert(!bdrv_dirty_bitmap_has_successor(bitmap));
assert(!bitmap->meta);
QLIST_REMOVE(bitmap, list);
hbitmap_free(bitmap->bitmap);
@@ -310,6 +352,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
bitmap->successor = NULL;
successor->persistent = bitmap->persistent;
bitmap->persistent = false;
+ bitmap->busy = false;
bdrv_release_dirty_bitmap(bs, bitmap);
return successor;
@@ -318,7 +361,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
/**
* In cases of failure where we can no longer safely delete the parent,
* we may wish to re-join the parent and child/successor.
- * The merged parent will be un-frozen, but not explicitly re-enabled.
+ * The merged parent will be marked as not busy.
+ * The marged parent will be enabled if and only if the successor was enabled.
* Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken.
*/
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
@@ -336,6 +380,9 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
error_setg(errp, "Merging of parent and successor bitmap failed");
return NULL;
}
+
+ parent->disabled = successor->disabled;
+ parent->busy = false;
bdrv_release_dirty_bitmap_locked(successor);
parent->successor = NULL;
@@ -366,7 +413,8 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
- assert(!bdrv_dirty_bitmap_frozen(bitmap));
+ assert(!bdrv_dirty_bitmap_busy(bitmap));
+ assert(!bdrv_dirty_bitmap_has_successor(bitmap));
assert(!bitmap->active_iterators);
hbitmap_truncate(bitmap->bitmap, bytes);
bitmap->size = bytes;
@@ -384,7 +432,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
/**
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
- * There must not be any frozen bitmaps attached.
+ * There must not be any busy bitmaps attached.
* This function does not remove persistent bitmaps from the storage.
* Called with BQL taken.
*/
@@ -421,7 +469,6 @@ void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{
bdrv_dirty_bitmap_lock(bitmap);
- assert(!bdrv_dirty_bitmap_frozen(bitmap));
bitmap->disabled = true;
bdrv_dirty_bitmap_unlock(bitmap);
}
@@ -448,7 +495,11 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
info->has_name = !!bm->name;
info->name = g_strdup(bm->name);
info->status = bdrv_dirty_bitmap_status(bm);
+ info->recording = bdrv_dirty_bitmap_recording(bm);
+ info->busy = bdrv_dirty_bitmap_busy(bm);
info->persistent = bm->persistent;
+ info->has_inconsistent = bm->inconsistent;
+ info->inconsistent = bm->inconsistent;
entry->value = info;
*plist = entry;
plist = &entry->next;
@@ -531,7 +582,6 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes)
{
- assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, offset, bytes);
}
@@ -548,7 +598,6 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes)
{
- assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_reset(bitmap->bitmap, offset, bytes);
}
@@ -691,7 +740,7 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
}
/* Called with BQL taken. */
-void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
+void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, bool persistent)
{
qemu_mutex_lock(bitmap->mutex);
bitmap->persistent = persistent;
@@ -699,6 +748,16 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
}
/* Called with BQL taken. */
+void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap)
+{
+ qemu_mutex_lock(bitmap->mutex);
+ assert(bitmap->persistent == true);
+ bitmap->inconsistent = true;
+ bitmap->disabled = true;
+ qemu_mutex_unlock(bitmap->mutex);
+}
+
+/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration)
{
qemu_mutex_lock(bitmap->mutex);
@@ -706,11 +765,16 @@ void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration)
qemu_mutex_unlock(bitmap->mutex);
}
-bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
+bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap)
{
return bitmap->persistent && !bitmap->migration;
}
+bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->inconsistent;
+}
+
bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
{
BdrvDirtyBitmap *bm;
@@ -757,15 +821,11 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
qemu_mutex_lock(dest->mutex);
- if (bdrv_dirty_bitmap_user_locked(dest)) {
- error_setg(errp, "Bitmap '%s' is currently in use by another"
- " operation and cannot be modified", dest->name);
+ if (bdrv_dirty_bitmap_check(dest, BDRV_BITMAP_DEFAULT, errp)) {
goto out;
}
- if (bdrv_dirty_bitmap_readonly(dest)) {
- error_setg(errp, "Bitmap '%s' is readonly and cannot be modified",
- dest->name);
+ if (bdrv_dirty_bitmap_check(src, BDRV_BITMAP_ALLOW_RO, errp)) {
goto out;
}
diff --git a/block/file-posix.c b/block/file-posix.c
index ba6ab62a38..d102f3b222 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -144,6 +144,9 @@ typedef struct BDRVRawState {
uint64_t locked_perm;
uint64_t locked_shared_perm;
+ int perm_change_fd;
+ BDRVReopenState *reopen_state;
+
#ifdef CONFIG_XFS
bool is_xfs:1;
#endif
@@ -154,6 +157,7 @@ typedef struct BDRVRawState {
bool page_cache_inconsistent:1;
bool has_fallocate;
bool needs_alignment;
+ bool drop_cache;
bool check_cache_dropped;
PRManager *pr_mgr;
@@ -162,6 +166,7 @@ typedef struct BDRVRawState {
typedef struct BDRVRawReopenState {
int fd;
int open_flags;
+ bool drop_cache;
bool check_cache_dropped;
} BDRVRawReopenState;
@@ -373,13 +378,21 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
}
}
-static void raw_parse_flags(int bdrv_flags, int *open_flags)
+static void raw_parse_flags(int bdrv_flags, int *open_flags, bool has_writers)
{
+ bool read_write = false;
assert(open_flags != NULL);
*open_flags |= O_BINARY;
*open_flags &= ~O_ACCMODE;
- if (bdrv_flags & BDRV_O_RDWR) {
+
+ if (bdrv_flags & BDRV_O_AUTO_RDONLY) {
+ read_write = has_writers;
+ } else if (bdrv_flags & BDRV_O_RDWR) {
+ read_write = true;
+ }
+
+ if (read_write) {
*open_flags |= O_RDWR;
} else {
*open_flags |= O_RDONLY;
@@ -422,6 +435,13 @@ static QemuOptsList raw_runtime_opts = {
.type = QEMU_OPT_STRING,
.help = "id of persistent reservation manager object (default: none)",
},
+#if defined(__linux__)
+ {
+ .name = "drop-cache",
+ .type = QEMU_OPT_BOOL,
+ .help = "invalidate page cache during live migration (default: on)",
+ },
+#endif
{
.name = "x-check-cache-dropped",
.type = QEMU_OPT_BOOL,
@@ -431,6 +451,8 @@ static QemuOptsList raw_runtime_opts = {
},
};
+static const char *const mutable_opts[] = { "x-check-cache-dropped", NULL };
+
static int raw_open_common(BlockDriverState *bs, QDict *options,
int bdrv_flags, int open_flags,
bool device, Error **errp)
@@ -511,28 +533,17 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
}
}
+ s->drop_cache = qemu_opt_get_bool(opts, "drop-cache", true);
s->check_cache_dropped = qemu_opt_get_bool(opts, "x-check-cache-dropped",
false);
s->open_flags = open_flags;
- raw_parse_flags(bdrv_flags, &s->open_flags);
+ raw_parse_flags(bdrv_flags, &s->open_flags, false);
s->fd = -1;
fd = qemu_open(filename, s->open_flags, 0644);
ret = fd < 0 ? -errno : 0;
- if (ret == -EACCES || ret == -EROFS) {
- /* Try to degrade to read-only, but if it doesn't work, still use the
- * normal error message. */
- if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
- bdrv_flags &= ~BDRV_O_RDWR;
- raw_parse_flags(bdrv_flags, &s->open_flags);
- assert(!(s->open_flags & O_CREAT));
- fd = qemu_open(filename, s->open_flags);
- ret = fd < 0 ? -errno : 0;
- }
- }
-
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not open '%s'", filename);
if (ret == -EROFS) {
@@ -842,13 +853,77 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
return ret;
}
+static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
+ int *open_flags, uint64_t perm, bool force_dup,
+ Error **errp)
+{
+ BDRVRawState *s = bs->opaque;
+ int fd = -1;
+ int ret;
+ bool has_writers = perm &
+ (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_RESIZE);
+ int fcntl_flags = O_APPEND | O_NONBLOCK;
+#ifdef O_NOATIME
+ fcntl_flags |= O_NOATIME;
+#endif
+
+ *open_flags = 0;
+ if (s->type == FTYPE_CD) {
+ *open_flags |= O_NONBLOCK;
+ }
+
+ raw_parse_flags(flags, open_flags, has_writers);
+
+#ifdef O_ASYNC
+ /* Not all operating systems have O_ASYNC, and those that don't
+ * will not let us track the state into rs->open_flags (typically
+ * you achieve the same effect with an ioctl, for example I_SETSIG
+ * on Solaris). But we do not use O_ASYNC, so that's fine.
+ */
+ assert((s->open_flags & O_ASYNC) == 0);
+#endif
+
+ if (!force_dup && *open_flags == s->open_flags) {
+ /* We're lucky, the existing fd is fine */
+ return s->fd;
+ }
+
+ if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
+ /* dup the original fd */
+ fd = qemu_dup(s->fd);
+ if (fd >= 0) {
+ ret = fcntl_setfl(fd, *open_flags);
+ if (ret) {
+ qemu_close(fd);
+ fd = -1;
+ }
+ }
+ }
+
+ /* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
+ if (fd == -1) {
+ const char *normalized_filename = bs->filename;
+ ret = raw_normalize_devicepath(&normalized_filename, errp);
+ if (ret >= 0) {
+ assert(!(*open_flags & O_CREAT));
+ fd = qemu_open(normalized_filename, *open_flags);
+ if (fd == -1) {
+ error_setg_errno(errp, errno, "Could not reopen file");
+ return -1;
+ }
+ }
+ }
+
+ return fd;
+}
+
static int raw_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
BDRVRawState *s;
BDRVRawReopenState *rs;
QemuOpts *opts;
- int ret = 0;
+ int ret;
Error *local_err = NULL;
assert(state != NULL);
@@ -858,7 +933,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
state->opaque = g_new0(BDRVRawReopenState, 1);
rs = state->opaque;
- rs->fd = -1;
/* Handle options changes */
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
@@ -869,6 +943,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
goto out;
}
+ rs->drop_cache = qemu_opt_get_bool_del(opts, "drop-cache", true);
rs->check_cache_dropped =
qemu_opt_get_bool_del(opts, "x-check-cache-dropped", false);
@@ -877,50 +952,12 @@ static int raw_reopen_prepare(BDRVReopenState *state,
* bdrv_reopen_prepare() will detect changes and complain. */
qemu_opts_to_qdict(opts, state->options);
- if (s->type == FTYPE_CD) {
- rs->open_flags |= O_NONBLOCK;
- }
-
- raw_parse_flags(state->flags, &rs->open_flags);
-
- int fcntl_flags = O_APPEND | O_NONBLOCK;
-#ifdef O_NOATIME
- fcntl_flags |= O_NOATIME;
-#endif
-
-#ifdef O_ASYNC
- /* Not all operating systems have O_ASYNC, and those that don't
- * will not let us track the state into rs->open_flags (typically
- * you achieve the same effect with an ioctl, for example I_SETSIG
- * on Solaris). But we do not use O_ASYNC, so that's fine.
- */
- assert((s->open_flags & O_ASYNC) == 0);
-#endif
-
- if ((rs->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
- /* dup the original fd */
- rs->fd = qemu_dup(s->fd);
- if (rs->fd >= 0) {
- ret = fcntl_setfl(rs->fd, rs->open_flags);
- if (ret) {
- qemu_close(rs->fd);
- rs->fd = -1;
- }
- }
- }
-
- /* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
- if (rs->fd == -1) {
- const char *normalized_filename = state->bs->filename;
- ret = raw_normalize_devicepath(&normalized_filename, errp);
- if (ret >= 0) {
- assert(!(rs->open_flags & O_CREAT));
- rs->fd = qemu_open(normalized_filename, rs->open_flags);
- if (rs->fd == -1) {
- error_setg_errno(errp, errno, "Could not reopen file");
- ret = -1;
- }
- }
+ rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags,
+ state->perm, true, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -1;
+ goto out;
}
/* Fail already reopen_prepare() if we can't get a working O_DIRECT
@@ -928,13 +965,19 @@ static int raw_reopen_prepare(BDRVReopenState *state,
if (rs->fd != -1) {
raw_probe_alignment(state->bs, rs->fd, &local_err);
if (local_err) {
- qemu_close(rs->fd);
- rs->fd = -1;
error_propagate(errp, local_err);
ret = -EINVAL;
+ goto out_fd;
}
}
+ s->reopen_state = state;
+ ret = 0;
+out_fd:
+ if (ret < 0) {
+ qemu_close(rs->fd);
+ rs->fd = -1;
+ }
out:
qemu_opts_del(opts);
return ret;
@@ -944,29 +987,26 @@ static void raw_reopen_commit(BDRVReopenState *state)
{
BDRVRawReopenState *rs = state->opaque;
BDRVRawState *s = state->bs->opaque;
- Error *local_err = NULL;
+ s->drop_cache = rs->drop_cache;
s->check_cache_dropped = rs->check_cache_dropped;
s->open_flags = rs->open_flags;
- /* Copy locks to the new fd before closing the old one. */
- raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
- s->locked_shared_perm, false, &local_err);
- if (local_err) {
- /* shouldn't fail in a sane host, but report it just in case. */
- error_report_err(local_err);
- }
qemu_close(s->fd);
s->fd = rs->fd;
g_free(state->opaque);
state->opaque = NULL;
+
+ assert(s->reopen_state == state);
+ s->reopen_state = NULL;
}
static void raw_reopen_abort(BDRVReopenState *state)
{
BDRVRawReopenState *rs = state->opaque;
+ BDRVRawState *s = state->bs->opaque;
/* nothing to do if NULL, we didn't get far enough */
if (rs == NULL) {
@@ -979,6 +1019,9 @@ static void raw_reopen_abort(BDRVReopenState *state)
}
g_free(state->opaque);
state->opaque = NULL;
+
+ assert(s->reopen_state == state);
+ s->reopen_state = NULL;
}
static int hdev_get_max_transfer_length(BlockDriverState *bs, int fd)
@@ -2531,6 +2574,10 @@ static void coroutine_fn raw_co_invalidate_cache(BlockDriverState *bs,
return;
}
+ if (!s->drop_cache) {
+ return;
+ }
+
if (s->open_flags & O_DIRECT) {
return; /* No host kernel page cache */
}
@@ -2664,12 +2711,78 @@ static QemuOptsList raw_create_opts = {
static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
Error **errp)
{
- return raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
+ BDRVRawState *s = bs->opaque;
+ BDRVRawReopenState *rs = NULL;
+ int open_flags;
+ int ret;
+
+ if (s->perm_change_fd) {
+ /*
+ * In the context of reopen, this function may be called several times
+ * (directly and recursively while change permissions of the parent).
+ * This is even true for children that don't inherit from the original
+ * reopen node, so s->reopen_state is not set.
+ *
+ * Ignore all but the first call.
+ */
+ return 0;
+ }
+
+ if (s->reopen_state) {
+ /* We already have a new file descriptor to set permissions for */
+ assert(s->reopen_state->perm == perm);
+ assert(s->reopen_state->shared_perm == shared);
+ rs = s->reopen_state->opaque;
+ s->perm_change_fd = rs->fd;
+ } else {
+ /* We may need a new fd if auto-read-only switches the mode */
+ ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm,
+ false, errp);
+ if (ret < 0) {
+ return ret;
+ } else if (ret != s->fd) {
+ s->perm_change_fd = ret;
+ }
+ }
+
+ /* Prepare permissions on old fd to avoid conflicts between old and new,
+ * but keep everything locked that new will need. */
+ ret = raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ /* Copy locks to the new fd */
+ if (s->perm_change_fd) {
+ ret = raw_apply_lock_bytes(NULL, s->perm_change_fd, perm, ~shared,
+ false, errp);
+ if (ret < 0) {
+ raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
+ goto fail;
+ }
+ }
+ return 0;
+
+fail:
+ if (s->perm_change_fd && !s->reopen_state) {
+ qemu_close(s->perm_change_fd);
+ }
+ s->perm_change_fd = 0;
+ return ret;
}
static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
{
BDRVRawState *s = bs->opaque;
+
+ /* For reopen, we have already switched to the new fd (.bdrv_set_perm is
+ * called after .bdrv_reopen_commit) */
+ if (s->perm_change_fd && s->fd != s->perm_change_fd) {
+ qemu_close(s->fd);
+ s->fd = s->perm_change_fd;
+ }
+ s->perm_change_fd = 0;
+
raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL);
s->perm = perm;
s->shared_perm = shared;
@@ -2677,6 +2790,15 @@ static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
static void raw_abort_perm_update(BlockDriverState *bs)
{
+ BDRVRawState *s = bs->opaque;
+
+ /* For reopen, .bdrv_reopen_abort is called afterwards and will close
+ * the file descriptor. */
+ if (s->perm_change_fd && !s->reopen_state) {
+ qemu_close(s->perm_change_fd);
+ }
+ s->perm_change_fd = 0;
+
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
}
@@ -2766,6 +2888,7 @@ BlockDriver bdrv_file = {
.bdrv_set_perm = raw_set_perm,
.bdrv_abort_perm_update = raw_abort_perm_update,
.create_opts = &raw_create_opts,
+ .mutable_opts = mutable_opts,
};
/***********************************************/
@@ -3217,6 +3340,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
+ .mutable_opts = mutable_opts,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
@@ -3343,6 +3467,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
+ .mutable_opts = mutable_opts,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
@@ -3476,6 +3601,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
+ .mutable_opts = mutable_opts,
.bdrv_co_preadv = raw_co_preadv,
.bdrv_co_pwritev = raw_co_pwritev,
diff --git a/block/gluster.c b/block/gluster.c
index af64330211..51f184cbd8 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -20,6 +20,10 @@
#include "qemu/option.h"
#include "qemu/cutils.h"
+#ifdef CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT
+# define glfs_ftruncate(fd, offset) glfs_ftruncate(fd, offset, NULL, NULL)
+#endif
+
#define GLUSTER_OPT_FILENAME "filename"
#define GLUSTER_OPT_VOLUME "volume"
#define GLUSTER_OPT_PATH "path"
@@ -725,7 +729,11 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
/*
* AIO callback routine called from GlusterFS thread.
*/
-static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
+static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
+#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
+ struct glfs_stat *pre, struct glfs_stat *post,
+#endif
+ void *arg)
{
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
diff --git a/block/mirror.c b/block/mirror.c
index 726d3c27fb..010fdafd79 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -630,6 +630,10 @@ static int mirror_exit_common(Job *job)
}
s->prepared = true;
+ if (bdrv_chain_contains(src, target_bs)) {
+ bdrv_unfreeze_backing_chain(mirror_top_bs, target_bs);
+ }
+
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
/* Make sure that the source BDS doesn't go away during bdrv_replace_node,
@@ -1639,6 +1643,10 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
goto fail;
}
}
+
+ if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
+ goto fail;
+ }
}
QTAILQ_INIT(&s->ops_in_flight);
diff --git a/block/qapi.c b/block/qapi.c
index 6002a768f8..21edab34fc 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -493,14 +493,14 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
}
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_READ],
- &ds->has_x_rd_latency_histogram,
- &ds->x_rd_latency_histogram);
+ &ds->has_rd_latency_histogram,
+ &ds->rd_latency_histogram);
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_WRITE],
- &ds->has_x_wr_latency_histogram,
- &ds->x_wr_latency_histogram);
+ &ds->has_wr_latency_histogram,
+ &ds->wr_latency_histogram);
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_FLUSH],
- &ds->has_x_flush_latency_histogram,
- &ds->x_flush_latency_histogram);
+ &ds->has_flush_latency_histogram,
+ &ds->flush_latency_histogram);
}
static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 9d968bdcda..e53a1609d7 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -343,11 +343,17 @@ static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
uint32_t granularity;
BdrvDirtyBitmap *bitmap = NULL;
- if (bm->flags & BME_FLAG_IN_USE) {
- error_setg(errp, "Bitmap '%s' is in use", bm->name);
+ granularity = 1U << bm->granularity_bits;
+ bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp);
+ if (bitmap == NULL) {
goto fail;
}
+ if (bm->flags & BME_FLAG_IN_USE) {
+ /* Data is unusable, skip loading it */
+ return bitmap;
+ }
+
ret = bitmap_table_load(bs, &bm->table, &bitmap_table);
if (ret < 0) {
error_setg_errno(errp, -ret,
@@ -356,12 +362,6 @@ static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
goto fail;
}
- granularity = 1U << bm->granularity_bits;
- bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp);
- if (bitmap == NULL) {
- goto fail;
- }
-
ret = load_bitmap_data(bs, bitmap_table, bm->table.size, bitmap);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read bitmap '%s' from image",
@@ -462,10 +462,25 @@ static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry)
return len;
}
- fail = (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) ||
- (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits));
+ if (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) {
+ return -EINVAL;
+ }
+
+ if (!(entry->flags & BME_FLAG_IN_USE) &&
+ (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits)))
+ {
+ /*
+ * We've loaded a valid bitmap (IN_USE not set) or we are going to
+ * store a valid bitmap, but the allocated bitmap table size is not
+ * enough to store this bitmap.
+ *
+ * Note, that it's OK to have an invalid bitmap with invalid size due
+ * to a bitmap that was not correctly saved after image resize.
+ */
+ return -EINVAL;
+ }
- return fail ? -EINVAL : 0;
+ return 0;
}
static inline void bitmap_directory_to_be(uint8_t *dir, size_t size)
@@ -950,6 +965,7 @@ bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp)
Qcow2Bitmap *bm;
GSList *created_dirty_bitmaps = NULL;
bool header_updated = false;
+ bool needs_update = false;
if (s->nb_bitmaps == 0) {
/* No bitmaps - nothing to do */
@@ -963,35 +979,39 @@ bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp)
}
QSIMPLEQ_FOREACH(bm, bm_list, entry) {
- if (!(bm->flags & BME_FLAG_IN_USE)) {
- BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp);
- if (bitmap == NULL) {
- goto fail;
- }
+ BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp);
+ if (bitmap == NULL) {
+ goto fail;
+ }
- if (!(bm->flags & BME_FLAG_AUTO)) {
- bdrv_disable_dirty_bitmap(bitmap);
- }
- bdrv_dirty_bitmap_set_persistance(bitmap, true);
+ bdrv_dirty_bitmap_set_persistence(bitmap, true);
+ if (bm->flags & BME_FLAG_IN_USE) {
+ bdrv_dirty_bitmap_set_inconsistent(bitmap);
+ } else {
+ /* NB: updated flags only get written if can_write(bs) is true. */
bm->flags |= BME_FLAG_IN_USE;
- created_dirty_bitmaps =
- g_slist_append(created_dirty_bitmaps, bitmap);
+ needs_update = true;
+ }
+ if (!(bm->flags & BME_FLAG_AUTO)) {
+ bdrv_disable_dirty_bitmap(bitmap);
}
+ created_dirty_bitmaps =
+ g_slist_append(created_dirty_bitmaps, bitmap);
}
- if (created_dirty_bitmaps != NULL) {
- if (can_write(bs)) {
- /* in_use flags must be updated */
- int ret = update_ext_header_and_dir_in_place(bs, bm_list);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "Can't update bitmap directory");
- goto fail;
- }
- header_updated = true;
- } else {
- g_slist_foreach(created_dirty_bitmaps, set_readonly_helper,
- (gpointer)true);
+ if (needs_update && can_write(bs)) {
+ /* in_use flags must be updated */
+ int ret = update_ext_header_and_dir_in_place(bs, bm_list);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Can't update bitmap directory");
+ goto fail;
}
+ header_updated = true;
+ }
+
+ if (!can_write(bs)) {
+ g_slist_foreach(created_dirty_bitmaps, set_readonly_helper,
+ (gpointer)true);
}
g_slist_free(created_dirty_bitmaps);
@@ -1113,23 +1133,21 @@ int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated,
}
QSIMPLEQ_FOREACH(bm, bm_list, entry) {
- if (!(bm->flags & BME_FLAG_IN_USE)) {
- BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name);
- if (bitmap == NULL) {
- continue;
- }
-
- if (!bdrv_dirty_bitmap_readonly(bitmap)) {
- error_setg(errp, "Bitmap %s is not readonly but not marked"
- "'IN_USE' in the image. Something went wrong,"
- "all the bitmaps may be corrupted", bm->name);
- ret = -EINVAL;
- goto out;
- }
+ BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name);
+ if (bitmap == NULL) {
+ continue;
+ }
- bm->flags |= BME_FLAG_IN_USE;
- ro_dirty_bitmaps = g_slist_append(ro_dirty_bitmaps, bitmap);
+ if (!bdrv_dirty_bitmap_readonly(bitmap)) {
+ error_setg(errp, "Bitmap %s was loaded prior to rw-reopen, but was "
+ "not marked as readonly. This is a bug, something went "
+ "wrong. All of the bitmaps may be corrupted", bm->name);
+ ret = -EINVAL;
+ goto out;
}
+
+ bm->flags |= BME_FLAG_IN_USE;
+ ro_dirty_bitmaps = g_slist_append(ro_dirty_bitmaps, bitmap);
}
if (ro_dirty_bitmaps != NULL) {
@@ -1157,6 +1175,52 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp)
return qcow2_reopen_bitmaps_rw_hint(bs, NULL, errp);
}
+/* Checks to see if it's safe to resize bitmaps */
+int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+ int ret = 0;
+
+ if (s->nb_bitmaps == 0) {
+ return 0;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return -EINVAL;
+ }
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name);
+ if (bitmap == NULL) {
+ /*
+ * We rely on all bitmaps being in-memory to be able to resize them,
+ * Otherwise, we'd need to resize them on disk explicitly
+ */
+ error_setg(errp, "Cannot resize qcow2 with persistent bitmaps that "
+ "were not loaded into memory");
+ ret = -ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * The checks against readonly and busy are redundant, but certainly
+ * do no harm. checks against inconsistent are crucial:
+ */
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
+ ret = -ENOTSUP;
+ goto out;
+ }
+ }
+
+out:
+ bitmap_list_free(bm_list);
+ return ret;
+}
+
/* store_bitmap_data()
* Store bitmap to image, filling bitmap table accordingly.
*/
@@ -1424,9 +1488,9 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
Qcow2Bitmap *bm;
- if (!bdrv_dirty_bitmap_get_persistance(bitmap) ||
- bdrv_dirty_bitmap_readonly(bitmap))
- {
+ if (!bdrv_dirty_bitmap_get_persistence(bitmap) ||
+ bdrv_dirty_bitmap_readonly(bitmap) ||
+ bdrv_dirty_bitmap_inconsistent(bitmap)) {
continue;
}
@@ -1542,7 +1606,7 @@ int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp)
for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL;
bitmap = bdrv_dirty_bitmap_next(bs, bitmap))
{
- if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
bdrv_dirty_bitmap_set_readonly(bitmap, true);
}
}
diff --git a/block/qcow2.c b/block/qcow2.c
index c4dd876fb4..0dd77c6367 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -627,6 +627,30 @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
return 0;
}
+static const char *const mutable_opts[] = {
+ QCOW2_OPT_LAZY_REFCOUNTS,
+ QCOW2_OPT_DISCARD_REQUEST,
+ QCOW2_OPT_DISCARD_SNAPSHOT,
+ QCOW2_OPT_DISCARD_OTHER,
+ QCOW2_OPT_OVERLAP,
+ QCOW2_OPT_OVERLAP_TEMPLATE,
+ QCOW2_OPT_OVERLAP_MAIN_HEADER,
+ QCOW2_OPT_OVERLAP_ACTIVE_L1,
+ QCOW2_OPT_OVERLAP_ACTIVE_L2,
+ QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
+ QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
+ QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
+ QCOW2_OPT_OVERLAP_INACTIVE_L1,
+ QCOW2_OPT_OVERLAP_INACTIVE_L2,
+ QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
+ QCOW2_OPT_CACHE_SIZE,
+ QCOW2_OPT_L2_CACHE_SIZE,
+ QCOW2_OPT_L2_CACHE_ENTRY_SIZE,
+ QCOW2_OPT_REFCOUNT_CACHE_SIZE,
+ QCOW2_OPT_CACHE_CLEAN_INTERVAL,
+ NULL
+};
+
static QemuOptsList qcow2_runtime_opts = {
.name = "qcow2",
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
@@ -3646,9 +3670,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
}
/* cannot proceed if image has bitmaps */
- if (s->nb_bitmaps) {
- /* TODO: resize bitmaps in the image */
- error_setg(errp, "Can't resize an image which has bitmaps");
+ if (qcow2_truncate_bitmaps_check(bs, errp)) {
ret = -ENOTSUP;
goto fail;
}
@@ -5275,6 +5297,7 @@ BlockDriver bdrv_qcow2 = {
.create_opts = &qcow2_create_opts,
.strong_runtime_opts = qcow2_strong_runtime_opts,
+ .mutable_opts = mutable_opts,
.bdrv_co_check = qcow2_co_check,
.bdrv_amend_options = qcow2_amend_options,
diff --git a/block/qcow2.h b/block/qcow2.h
index de2a3bdfc5..fdee297f33 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -723,6 +723,7 @@ Qcow2BitmapInfoList *qcow2_get_bitmap_info_list(BlockDriverState *bs,
int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated,
Error **errp);
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
+int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
diff --git a/block/raw-format.c b/block/raw-format.c
index e3e5ba2c8a..cec29986cc 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -37,6 +37,8 @@ typedef struct BDRVRawState {
bool has_size;
} BDRVRawState;
+static const char *const mutable_opts[] = { "offset", "size", NULL };
+
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
@@ -570,6 +572,7 @@ BlockDriver bdrv_raw = {
.create_opts = &raw_create_opts,
.bdrv_has_zero_init = &raw_has_zero_init,
.strong_runtime_opts = raw_strong_runtime_opts,
+ .mutable_opts = mutable_opts,
};
static void bdrv_raw_init(void)
diff --git a/block/replication.c b/block/replication.c
index 4c80b54daf..b95bd28802 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -374,19 +374,18 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
QDict *opts = qdict_new();
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs,
- opts);
+ opts, true);
}
if (s->orig_secondary_read_only) {
QDict *opts = qdict_new();
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs,
- opts);
+ opts, true);
}
if (reopen_queue) {
- bdrv_reopen_multiple(bdrv_get_aio_context(bs),
- reopen_queue, &local_err);
+ bdrv_reopen_multiple(reopen_queue, &local_err);
error_propagate(errp, local_err);
}
diff --git a/block/stream.c b/block/stream.c
index e14579ff80..6253c86fae 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -35,6 +35,7 @@ typedef struct StreamBlockJob {
BlockdevOnError on_error;
char *backing_file_str;
bool bs_read_only;
+ bool chain_frozen;
} StreamBlockJob;
static int coroutine_fn stream_populate(BlockBackend *blk,
@@ -49,6 +50,16 @@ static int coroutine_fn stream_populate(BlockBackend *blk,
return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ);
}
+static void stream_abort(Job *job)
+{
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
+
+ if (s->chain_frozen) {
+ BlockJob *bjob = &s->common;
+ bdrv_unfreeze_backing_chain(blk_bs(bjob->blk), s->base);
+ }
+}
+
static int stream_prepare(Job *job)
{
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
@@ -58,6 +69,9 @@ static int stream_prepare(Job *job)
Error *local_err = NULL;
int ret = 0;
+ bdrv_unfreeze_backing_chain(bs, base);
+ s->chain_frozen = false;
+
if (bs->backing) {
const char *base_id = NULL, *base_fmt = NULL;
if (base) {
@@ -208,6 +222,7 @@ static const BlockJobDriver stream_job_driver = {
.free = block_job_free,
.run = stream_run,
.prepare = stream_prepare,
+ .abort = stream_abort,
.clean = stream_clean,
.user_resume = block_job_user_resume,
.drain = block_job_drain,
@@ -254,9 +269,15 @@ void stream_start(const char *job_id, BlockDriverState *bs,
&error_abort);
}
+ if (bdrv_freeze_backing_chain(bs, base, errp) < 0) {
+ job_early_fail(&s->common.job);
+ goto fail;
+ }
+
s->base = base;
s->backing_file_str = g_strdup(backing_file_str);
s->bs_read_only = bs_read_only;
+ s->chain_frozen = true;
s->on_error = on_error;
trace_stream_start(bs, base, s);
diff --git a/blockdev.c b/blockdev.c
index 871966ca13..53df2eb875 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1257,7 +1257,6 @@ out_aio_context:
* @node: The name of the BDS node to search for bitmaps
* @name: The name of the bitmap to search for
* @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
- * @paio: Output pointer for aio_context acquisition, if desired. Can be NULL.
* @errp: Output pointer for error information. Can be NULL.
*
* @return: A bitmap object on success, or NULL on failure.
@@ -2011,11 +2010,7 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
return;
}
- if (bdrv_dirty_bitmap_user_locked(state->bitmap)) {
- error_setg(errp, "Cannot modify a bitmap in use by another operation");
- return;
- } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) {
- error_setg(errp, "Cannot clear a readonly bitmap");
+ if (bdrv_dirty_bitmap_check(state->bitmap, BDRV_BITMAP_DEFAULT, errp)) {
return;
}
@@ -2060,10 +2055,7 @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common,
return;
}
- if (bdrv_dirty_bitmap_user_locked(state->bitmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation"
- " and cannot be enabled", action->name);
+ if (bdrv_dirty_bitmap_check(state->bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
return;
}
@@ -2101,10 +2093,7 @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common,
return;
}
- if (bdrv_dirty_bitmap_user_locked(state->bitmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation"
- " and cannot be disabled", action->name);
+ if (bdrv_dirty_bitmap_check(state->bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
return;
}
@@ -2875,7 +2864,7 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bdrv_disable_dirty_bitmap(bitmap);
}
- bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
+ bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
out:
if (aio_context) {
aio_context_release(aio_context);
@@ -2895,14 +2884,12 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
return;
}
- if (bdrv_dirty_bitmap_user_locked(bitmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation and"
- " cannot be removed", name);
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
+ errp)) {
return;
}
- if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
@@ -2934,13 +2921,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
return;
}
- if (bdrv_dirty_bitmap_user_locked(bitmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation"
- " and cannot be cleared", name);
- return;
- } else if (bdrv_dirty_bitmap_readonly(bitmap)) {
- error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name);
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
return;
}
@@ -2958,10 +2939,7 @@ void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
return;
}
- if (bdrv_dirty_bitmap_user_locked(bitmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation"
- " and cannot be enabled", name);
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
return;
}
@@ -2979,10 +2957,7 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
return;
}
- if (bdrv_dirty_bitmap_user_locked(bitmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation"
- " and cannot be disabled", name);
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
return;
}
@@ -3561,10 +3536,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
bdrv_unref(target_bs);
goto out;
}
- if (bdrv_dirty_bitmap_user_locked(bmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation"
- " and cannot be used for backup", backup->bitmap);
+ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
goto out;
}
}
@@ -3674,10 +3646,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
goto out;
}
- if (bdrv_dirty_bitmap_user_locked(bmap)) {
- error_setg(errp,
- "Bitmap '%s' is currently in use by another operation"
- " and cannot be used for backup", backup->bitmap);
+ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
goto out;
}
}
@@ -4287,6 +4256,53 @@ fail:
visit_free(v);
}
+void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp)
+{
+ BlockDriverState *bs;
+ AioContext *ctx;
+ QObject *obj;
+ Visitor *v = qobject_output_visitor_new(&obj);
+ Error *local_err = NULL;
+ BlockReopenQueue *queue;
+ QDict *qdict;
+
+ /* Check for the selected node name */
+ if (!options->has_node_name) {
+ error_setg(errp, "Node name not specified");
+ goto fail;
+ }
+
+ bs = bdrv_find_node(options->node_name);
+ if (!bs) {
+ error_setg(errp, "Cannot find node named '%s'", options->node_name);
+ goto fail;
+ }
+
+ /* Put all options in a QDict and flatten it */
+ visit_type_BlockdevOptions(v, NULL, &options, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ visit_complete(v, &obj);
+ qdict = qobject_to(QDict, obj);
+
+ qdict_flatten(qdict);
+
+ /* Perform the reopen operation */
+ ctx = bdrv_get_aio_context(bs);
+ aio_context_acquire(ctx);
+ bdrv_subtree_drained_begin(bs);
+ queue = bdrv_reopen_queue(NULL, bs, qdict, false);
+ bdrv_reopen_multiple(queue, errp);
+ bdrv_subtree_drained_end(bs);
+ aio_context_release(ctx);
+
+fail:
+ visit_free(v);
+}
+
void qmp_blockdev_del(const char *node_name, Error **errp)
{
AioContext *aio_context;
@@ -4452,22 +4468,22 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
aio_context_release(old_context);
}
-void qmp_x_block_latency_histogram_set(
- const char *device,
+void qmp_block_latency_histogram_set(
+ const char *id,
bool has_boundaries, uint64List *boundaries,
bool has_boundaries_read, uint64List *boundaries_read,
bool has_boundaries_write, uint64List *boundaries_write,
bool has_boundaries_flush, uint64List *boundaries_flush,
Error **errp)
{
- BlockBackend *blk = blk_by_name(device);
+ BlockBackend *blk = qmp_get_blk(NULL, id, errp);
BlockAcctStats *stats;
int ret;
if (!blk) {
- error_setg(errp, "Device '%s' not found", device);
return;
}
+
stats = blk_get_stats(blk);
if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
@@ -4482,7 +4498,7 @@ void qmp_x_block_latency_histogram_set(
stats, BLOCK_ACCT_READ,
has_boundaries_read ? boundaries_read : boundaries);
if (ret) {
- error_setg(errp, "Device '%s' set read boundaries fail", device);
+ error_setg(errp, "Device '%s' set read boundaries fail", id);
return;
}
}
@@ -4492,7 +4508,7 @@ void qmp_x_block_latency_histogram_set(
stats, BLOCK_ACCT_WRITE,
has_boundaries_write ? boundaries_write : boundaries);
if (ret) {
- error_setg(errp, "Device '%s' set write boundaries fail", device);
+ error_setg(errp, "Device '%s' set write boundaries fail", id);
return;
}
}
@@ -4502,7 +4518,7 @@ void qmp_x_block_latency_histogram_set(
stats, BLOCK_ACCT_FLUSH,
has_boundaries_flush ? boundaries_flush : boundaries);
if (ret) {
- error_setg(errp, "Device '%s' set flush boundaries fail", device);
+ error_setg(errp, "Device '%s' set flush boundaries fail", id);
return;
}
}
diff --git a/configure b/configure
index cab830a4c9..7071f52584 100755
--- a/configure
+++ b/configure
@@ -456,6 +456,8 @@ glusterfs_xlator_opt="no"
glusterfs_discard="no"
glusterfs_fallocate="no"
glusterfs_zerofill="no"
+glusterfs_ftruncate_has_stat="no"
+glusterfs_iocb_has_stat="no"
gtk=""
gtk_gl="no"
tls_priority="NORMAL"
@@ -1109,8 +1111,6 @@ for opt do
;;
--disable-slirp) slirp="no"
;;
- --enable-slirp=git) slirp="git"
- ;;
--enable-slirp=system) slirp="system"
;;
--disable-vde) vde="no"
@@ -1222,6 +1222,10 @@ for opt do
;;
--enable-curses) curses="yes"
;;
+ --disable-iconv) iconv="no"
+ ;;
+ --enable-iconv) iconv="yes"
+ ;;
--disable-curl) curl="no"
;;
--enable-curl) curl="yes"
@@ -1711,6 +1715,7 @@ disabled with --disable-FEATURE, default is enabled if available:
gtk gtk UI
vte vte support for the gtk UI
curses curses UI
+ iconv font glyph conversion support
vnc VNC UI support
vnc-sasl SASL encryption for VNC server
vnc-jpeg JPEG lossy compression for VNC server
@@ -3433,7 +3438,51 @@ EOF
fi
##########################################
+# iconv probe
+if test "$iconv" != "no" ; then
+ cat > $TMPC << EOF
+#include <iconv.h>
+int main(void) {
+ iconv_t conv = iconv_open("WCHAR_T", "UCS-2");
+ return conv != (iconv_t) -1;
+}
+EOF
+ iconv_prefix_list="/usr/local:/usr"
+ iconv_lib_list=":-liconv"
+ IFS=:
+ for iconv_prefix in $iconv_prefix_list; do
+ IFS=:
+ iconv_cflags="-I$iconv_prefix/include"
+ iconv_ldflags="-L$iconv_prefix/lib"
+ for iconv_link in $iconv_lib_list; do
+ unset IFS
+ iconv_lib="$iconv_ldflags $iconv_link"
+ echo "looking at iconv in '$iconv_cflags' '$iconv_lib'" >> config.log
+ if compile_prog "$iconv_cflags" "$iconv_lib" ; then
+ iconv_found=yes
+ break
+ fi
+ done
+ if test "$iconv_found" = yes ; then
+ break
+ fi
+ done
+ if test "$iconv_found" = "yes" ; then
+ iconv=yes
+ else
+ if test "$iconv" = "yes" ; then
+ feature_not_found "iconv" "Install iconv devel"
+ fi
+ iconv=no
+ fi
+fi
+
+##########################################
# curses probe
+if test "$iconv" = "no" ; then
+ # curses will need iconv
+ curses=no
+fi
if test "$curses" != "no" ; then
if test "$mingw32" = "yes" ; then
curses_inc_list="$($pkg_config --cflags ncurses 2>/dev/null):"
@@ -3447,14 +3496,17 @@ if test "$curses" != "no" ; then
#include <locale.h>
#include <curses.h>
#include <wchar.h>
+#include <langinfo.h>
int main(void) {
+ const char *codeset;
wchar_t wch = L'w';
setlocale(LC_ALL, "");
resize_term(0, 0);
addwstr(L"wide chars\n");
addnwstr(&wch, 1);
add_wch(WACS_DEGREE);
- return 0;
+ codeset = nl_langinfo(CODESET);
+ return codeset != 0;
}
EOF
IFS=:
@@ -4091,6 +4143,38 @@ if test "$glusterfs" != "no" ; then
glusterfs_fallocate="yes"
glusterfs_zerofill="yes"
fi
+ cat > $TMPC << EOF
+#include <glusterfs/api/glfs.h>
+
+int
+main(void)
+{
+ /* new glfs_ftruncate() passes two additional args */
+ return glfs_ftruncate(NULL, 0, NULL, NULL);
+}
+EOF
+ if compile_prog "$glusterfs_cflags" "$glusterfs_libs" ; then
+ glusterfs_ftruncate_has_stat="yes"
+ fi
+ cat > $TMPC << EOF
+#include <glusterfs/api/glfs.h>
+
+/* new glfs_io_cbk() passes two additional glfs_stat structs */
+static void
+glusterfs_iocb(glfs_fd_t *fd, ssize_t ret, struct glfs_stat *prestat, struct glfs_stat *poststat, void *data)
+{}
+
+int
+main(void)
+{
+ glfs_io_cbk iocb = &glusterfs_iocb;
+ iocb(NULL, 0 , NULL, NULL, NULL);
+ return 0;
+}
+EOF
+ if compile_prog "$glusterfs_cflags" "$glusterfs_libs" ; then
+ glusterfs_iocb_has_stat="yes"
+ fi
else
if test "$glusterfs" = "yes" ; then
feature_not_found "GlusterFS backend support" \
@@ -5780,8 +5864,6 @@ case "$slirp" in
"" | yes)
if $pkg_config slirp; then
slirp=system
- elif test -e "${source_path}/.git" && test $git_update = 'yes' ; then
- slirp=git
elif test -e "${source_path}/slirp/Makefile" ; then
slirp=internal
elif test -z "$slirp" ; then
@@ -5799,10 +5881,7 @@ case "$slirp" in
esac
case "$slirp" in
- git | internal)
- if test "$slirp" = git; then
- git_submodules="${git_submodules} slirp"
- fi
+ internal)
mkdir -p slirp
slirp_cflags="-I\$(SRC_PATH)/slirp/src -I\$(BUILD_DIR)/slirp/src"
slirp_libs="-L\$(BUILD_DIR)/slirp -lslirp"
@@ -6217,6 +6296,7 @@ echo "libgcrypt $gcrypt"
echo "nettle $nettle $(echo_version $nettle $nettle_version)"
echo "libtasn1 $tasn1"
echo "PAM $auth_pam"
+echo "iconv support $iconv"
echo "curses support $curses"
echo "virgl support $virglrenderer $(echo_version $virglrenderer $virgl_version)"
echo "curl support $curl"
@@ -6464,7 +6544,7 @@ if test "$slirp" != "no"; then
echo "SLIRP_CFLAGS=$slirp_cflags" >> $config_host_mak
echo "SLIRP_LIBS=$slirp_libs" >> $config_host_mak
fi
-if [ "$slirp" = "git" -o "$slirp" = "internal" ]; then
+if [ "$slirp" = "internal" ]; then
echo "config-host.h: subdir-slirp" >> $config_host_mak
fi
if test "$vde" = "yes" ; then
@@ -6552,6 +6632,11 @@ fi
if test "$cocoa" = "yes" ; then
echo "CONFIG_COCOA=y" >> $config_host_mak
fi
+if test "$iconv" = "yes" ; then
+ echo "CONFIG_ICONV=y" >> $config_host_mak
+ echo "ICONV_CFLAGS=$iconv_cflags" >> $config_host_mak
+ echo "ICONV_LIBS=$iconv_lib" >> $config_host_mak
+fi
if test "$curses" = "yes" ; then
echo "CONFIG_CURSES=m" >> $config_host_mak
echo "CURSES_CFLAGS=$curses_inc" >> $config_host_mak
@@ -6976,6 +7061,14 @@ if test "$glusterfs_zerofill" = "yes" ; then
echo "CONFIG_GLUSTERFS_ZEROFILL=y" >> $config_host_mak
fi
+if test "$glusterfs_ftruncate_has_stat" = "yes" ; then
+ echo "CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT=y" >> $config_host_mak
+fi
+
+if test "$glusterfs_iocb_has_stat" = "yes" ; then
+ echo "CONFIG_GLUSTERFS_IOCB_HAS_STAT=y" >> $config_host_mak
+fi
+
if test "$libssh2" = "yes" ; then
echo "CONFIG_LIBSSH2=m" >> $config_host_mak
echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
diff --git a/contrib/libvhost-user/libvhost-user-glib.c b/contrib/libvhost-user/libvhost-user-glib.c
index 545f089587..42660a1b36 100644
--- a/contrib/libvhost-user/libvhost-user-glib.c
+++ b/contrib/libvhost-user/libvhost-user-glib.c
@@ -68,15 +68,16 @@ static GSourceFuncs vug_src_funcs = {
NULL
};
-static GSource *
-vug_source_new(VuDev *dev, int fd, GIOCondition cond,
+GSource *
+vug_source_new(VugDev *gdev, int fd, GIOCondition cond,
vu_watch_cb vu_cb, gpointer data)
{
+ VuDev *dev = &gdev->parent;
GSource *gsrc;
VugSrc *src;
guint id;
- g_assert(dev);
+ g_assert(gdev);
g_assert(fd >= 0);
g_assert(vu_cb);
@@ -106,7 +107,7 @@ set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt)
g_assert(cb);
dev = container_of(vu_dev, VugDev, parent);
- src = vug_source_new(vu_dev, fd, vu_evt, cb, pvt);
+ src = vug_source_new(dev, fd, vu_evt, cb, pvt);
g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src);
}
@@ -141,7 +142,7 @@ vug_init(VugDev *dev, int socket,
dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL,
(GDestroyNotify) g_source_destroy);
- dev->src = vug_source_new(&dev->parent, socket, G_IO_IN, vug_watch, NULL);
+ dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL);
}
void
diff --git a/contrib/libvhost-user/libvhost-user-glib.h b/contrib/libvhost-user/libvhost-user-glib.h
index 6b2110b94c..d3200f3afc 100644
--- a/contrib/libvhost-user/libvhost-user-glib.h
+++ b/contrib/libvhost-user/libvhost-user-glib.h
@@ -29,4 +29,7 @@ void vug_init(VugDev *dev, int socket,
vu_panic_cb panic, const VuDevIface *iface);
void vug_deinit(VugDev *dev);
+GSource *vug_source_new(VugDev *dev, int fd, GIOCondition cond,
+ vu_watch_cb vu_cb, gpointer data);
+
#endif /* LIBVHOST_USER_GLIB_H */
diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
index 3f14b4138b..e08d6c7b97 100644
--- a/contrib/libvhost-user/libvhost-user.c
+++ b/contrib/libvhost-user/libvhost-user.c
@@ -41,6 +41,8 @@
#endif
#include "qemu/atomic.h"
+#include "qemu/osdep.h"
+#include "qemu/memfd.h"
#include "libvhost-user.h"
@@ -53,6 +55,18 @@
_min1 < _min2 ? _min1 : _min2; })
#endif
+/* Round number down to multiple */
+#define ALIGN_DOWN(n, m) ((n) / (m) * (m))
+
+/* Round number up to multiple */
+#define ALIGN_UP(n, m) ALIGN_DOWN((n) + (m) - 1, (m))
+
+/* Align each region to cache line size in inflight buffer */
+#define INFLIGHT_ALIGNMENT 64
+
+/* The version of inflight buffer */
+#define INFLIGHT_VERSION 1
+
#define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64)
/* The version of the protocol we support */
@@ -66,6 +80,20 @@
} \
} while (0)
+static inline
+bool has_feature(uint64_t features, unsigned int fbit)
+{
+ assert(fbit < 64);
+ return !!(features & (1ULL << fbit));
+}
+
+static inline
+bool vu_has_feature(VuDev *dev,
+ unsigned int fbit)
+{
+ return has_feature(dev->features, fbit);
+}
+
static const char *
vu_request_to_string(unsigned int req)
{
@@ -100,6 +128,8 @@ vu_request_to_string(unsigned int req)
REQ(VHOST_USER_POSTCOPY_ADVISE),
REQ(VHOST_USER_POSTCOPY_LISTEN),
REQ(VHOST_USER_POSTCOPY_END),
+ REQ(VHOST_USER_GET_INFLIGHT_FD),
+ REQ(VHOST_USER_SET_INFLIGHT_FD),
REQ(VHOST_USER_MAX),
};
#undef REQ
@@ -890,6 +920,91 @@ vu_check_queue_msg_file(VuDev *dev, VhostUserMsg *vmsg)
return true;
}
+static int
+inflight_desc_compare(const void *a, const void *b)
+{
+ VuVirtqInflightDesc *desc0 = (VuVirtqInflightDesc *)a,
+ *desc1 = (VuVirtqInflightDesc *)b;
+
+ if (desc1->counter > desc0->counter &&
+ (desc1->counter - desc0->counter) < VIRTQUEUE_MAX_SIZE * 2) {
+ return 1;
+ }
+
+ return -1;
+}
+
+static int
+vu_check_queue_inflights(VuDev *dev, VuVirtq *vq)
+{
+ int i = 0;
+
+ if (!has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ return 0;
+ }
+
+ if (unlikely(!vq->inflight)) {
+ return -1;
+ }
+
+ if (unlikely(!vq->inflight->version)) {
+ /* initialize the buffer */
+ vq->inflight->version = INFLIGHT_VERSION;
+ return 0;
+ }
+
+ vq->used_idx = vq->vring.used->idx;
+ vq->resubmit_num = 0;
+ vq->resubmit_list = NULL;
+ vq->counter = 0;
+
+ if (unlikely(vq->inflight->used_idx != vq->used_idx)) {
+ vq->inflight->desc[vq->inflight->last_batch_head].inflight = 0;
+
+ barrier();
+
+ vq->inflight->used_idx = vq->used_idx;
+ }
+
+ for (i = 0; i < vq->inflight->desc_num; i++) {
+ if (vq->inflight->desc[i].inflight == 1) {
+ vq->inuse++;
+ }
+ }
+
+ vq->shadow_avail_idx = vq->last_avail_idx = vq->inuse + vq->used_idx;
+
+ if (vq->inuse) {
+ vq->resubmit_list = malloc(sizeof(VuVirtqInflightDesc) * vq->inuse);
+ if (!vq->resubmit_list) {
+ return -1;
+ }
+
+ for (i = 0; i < vq->inflight->desc_num; i++) {
+ if (vq->inflight->desc[i].inflight) {
+ vq->resubmit_list[vq->resubmit_num].index = i;
+ vq->resubmit_list[vq->resubmit_num].counter =
+ vq->inflight->desc[i].counter;
+ vq->resubmit_num++;
+ }
+ }
+
+ if (vq->resubmit_num > 1) {
+ qsort(vq->resubmit_list, vq->resubmit_num,
+ sizeof(VuVirtqInflightDesc), inflight_desc_compare);
+ }
+ vq->counter = vq->resubmit_list[0].counter + 1;
+ }
+
+ /* in case of I/O hang after reconnecting */
+ if (eventfd_write(vq->kick_fd, 1)) {
+ return -1;
+ }
+
+ return 0;
+}
+
static bool
vu_set_vring_kick_exec(VuDev *dev, VhostUserMsg *vmsg)
{
@@ -907,10 +1022,8 @@ vu_set_vring_kick_exec(VuDev *dev, VhostUserMsg *vmsg)
dev->vq[index].kick_fd = -1;
}
- if (!(vmsg->payload.u64 & VHOST_USER_VRING_NOFD_MASK)) {
- dev->vq[index].kick_fd = vmsg->fds[0];
- DPRINT("Got kick_fd: %d for vq: %d\n", vmsg->fds[0], index);
- }
+ dev->vq[index].kick_fd = vmsg->fds[0];
+ DPRINT("Got kick_fd: %d for vq: %d\n", vmsg->fds[0], index);
dev->vq[index].started = true;
if (dev->iface->queue_set_started) {
@@ -925,6 +1038,10 @@ vu_set_vring_kick_exec(VuDev *dev, VhostUserMsg *vmsg)
dev->vq[index].kick_fd, index);
}
+ if (vu_check_queue_inflights(dev, &dev->vq[index])) {
+ vu_panic(dev, "Failed to check inflights for vq: %d\n", index);
+ }
+
return false;
}
@@ -995,8 +1112,11 @@ vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg)
dev->vq[index].call_fd = -1;
}
- if (!(vmsg->payload.u64 & VHOST_USER_VRING_NOFD_MASK)) {
- dev->vq[index].call_fd = vmsg->fds[0];
+ dev->vq[index].call_fd = vmsg->fds[0];
+
+ /* in case of I/O hang after reconnecting */
+ if (eventfd_write(vmsg->fds[0], 1)) {
+ return -1;
}
DPRINT("Got call_fd: %d for vq: %d\n", vmsg->fds[0], index);
@@ -1020,9 +1140,7 @@ vu_set_vring_err_exec(VuDev *dev, VhostUserMsg *vmsg)
dev->vq[index].err_fd = -1;
}
- if (!(vmsg->payload.u64 & VHOST_USER_VRING_NOFD_MASK)) {
- dev->vq[index].err_fd = vmsg->fds[0];
- }
+ dev->vq[index].err_fd = vmsg->fds[0];
return false;
}
@@ -1215,6 +1333,116 @@ vu_set_postcopy_end(VuDev *dev, VhostUserMsg *vmsg)
return true;
}
+static inline uint64_t
+vu_inflight_queue_size(uint16_t queue_size)
+{
+ return ALIGN_UP(sizeof(VuDescStateSplit) * queue_size +
+ sizeof(uint16_t), INFLIGHT_ALIGNMENT);
+}
+
+static bool
+vu_get_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
+{
+ int fd;
+ void *addr;
+ uint64_t mmap_size;
+ uint16_t num_queues, queue_size;
+
+ if (vmsg->size != sizeof(vmsg->payload.inflight)) {
+ vu_panic(dev, "Invalid get_inflight_fd message:%d", vmsg->size);
+ vmsg->payload.inflight.mmap_size = 0;
+ return true;
+ }
+
+ num_queues = vmsg->payload.inflight.num_queues;
+ queue_size = vmsg->payload.inflight.queue_size;
+
+ DPRINT("set_inflight_fd num_queues: %"PRId16"\n", num_queues);
+ DPRINT("set_inflight_fd queue_size: %"PRId16"\n", queue_size);
+
+ mmap_size = vu_inflight_queue_size(queue_size) * num_queues;
+
+ addr = qemu_memfd_alloc("vhost-inflight", mmap_size,
+ F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL,
+ &fd, NULL);
+
+ if (!addr) {
+ vu_panic(dev, "Failed to alloc vhost inflight area");
+ vmsg->payload.inflight.mmap_size = 0;
+ return true;
+ }
+
+ memset(addr, 0, mmap_size);
+
+ dev->inflight_info.addr = addr;
+ dev->inflight_info.size = vmsg->payload.inflight.mmap_size = mmap_size;
+ dev->inflight_info.fd = vmsg->fds[0] = fd;
+ vmsg->fd_num = 1;
+ vmsg->payload.inflight.mmap_offset = 0;
+
+ DPRINT("send inflight mmap_size: %"PRId64"\n",
+ vmsg->payload.inflight.mmap_size);
+ DPRINT("send inflight mmap offset: %"PRId64"\n",
+ vmsg->payload.inflight.mmap_offset);
+
+ return true;
+}
+
+static bool
+vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
+{
+ int fd, i;
+ uint64_t mmap_size, mmap_offset;
+ uint16_t num_queues, queue_size;
+ void *rc;
+
+ if (vmsg->fd_num != 1 ||
+ vmsg->size != sizeof(vmsg->payload.inflight)) {
+ vu_panic(dev, "Invalid set_inflight_fd message size:%d fds:%d",
+ vmsg->size, vmsg->fd_num);
+ return false;
+ }
+
+ fd = vmsg->fds[0];
+ mmap_size = vmsg->payload.inflight.mmap_size;
+ mmap_offset = vmsg->payload.inflight.mmap_offset;
+ num_queues = vmsg->payload.inflight.num_queues;
+ queue_size = vmsg->payload.inflight.queue_size;
+
+ DPRINT("set_inflight_fd mmap_size: %"PRId64"\n", mmap_size);
+ DPRINT("set_inflight_fd mmap_offset: %"PRId64"\n", mmap_offset);
+ DPRINT("set_inflight_fd num_queues: %"PRId16"\n", num_queues);
+ DPRINT("set_inflight_fd queue_size: %"PRId16"\n", queue_size);
+
+ rc = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, mmap_offset);
+
+ if (rc == MAP_FAILED) {
+ vu_panic(dev, "set_inflight_fd mmap error: %s", strerror(errno));
+ return false;
+ }
+
+ if (dev->inflight_info.fd) {
+ close(dev->inflight_info.fd);
+ }
+
+ if (dev->inflight_info.addr) {
+ munmap(dev->inflight_info.addr, dev->inflight_info.size);
+ }
+
+ dev->inflight_info.fd = fd;
+ dev->inflight_info.addr = rc;
+ dev->inflight_info.size = mmap_size;
+
+ for (i = 0; i < num_queues; i++) {
+ dev->vq[i].inflight = (VuVirtqInflight *)rc;
+ dev->vq[i].inflight->desc_num = queue_size;
+ rc = (void *)((char *)rc + vu_inflight_queue_size(queue_size));
+ }
+
+ return false;
+}
+
static bool
vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
{
@@ -1285,13 +1513,18 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
case VHOST_USER_SET_CONFIG:
return vu_set_config(dev, vmsg);
case VHOST_USER_NONE:
- break;
+ /* if you need processing before exit, override iface->process_msg */
+ exit(0);
case VHOST_USER_POSTCOPY_ADVISE:
return vu_set_postcopy_advise(dev, vmsg);
case VHOST_USER_POSTCOPY_LISTEN:
return vu_set_postcopy_listen(dev, vmsg);
case VHOST_USER_POSTCOPY_END:
return vu_set_postcopy_end(dev, vmsg);
+ case VHOST_USER_GET_INFLIGHT_FD:
+ return vu_get_inflight_fd(dev, vmsg);
+ case VHOST_USER_SET_INFLIGHT_FD:
+ return vu_set_inflight_fd(dev, vmsg);
default:
vmsg_close_fds(vmsg);
vu_panic(dev, "Unhandled request: %d", vmsg->request);
@@ -1359,8 +1592,24 @@ vu_deinit(VuDev *dev)
close(vq->err_fd);
vq->err_fd = -1;
}
+
+ if (vq->resubmit_list) {
+ free(vq->resubmit_list);
+ vq->resubmit_list = NULL;
+ }
+
+ vq->inflight = NULL;
}
+ if (dev->inflight_info.addr) {
+ munmap(dev->inflight_info.addr, dev->inflight_info.size);
+ dev->inflight_info.addr = NULL;
+ }
+
+ if (dev->inflight_info.fd > 0) {
+ close(dev->inflight_info.fd);
+ dev->inflight_info.fd = -1;
+ }
vu_close_log(dev);
if (dev->slave_fd != -1) {
@@ -1687,20 +1936,6 @@ vu_queue_empty(VuDev *dev, VuVirtq *vq)
return vring_avail_idx(vq) == vq->last_avail_idx;
}
-static inline
-bool has_feature(uint64_t features, unsigned int fbit)
-{
- assert(fbit < 64);
- return !!(features & (1ULL << fbit));
-}
-
-static inline
-bool vu_has_feature(VuDev *dev,
- unsigned int fbit)
-{
- return has_feature(dev->features, fbit);
-}
-
static bool
vring_notify(VuDev *dev, VuVirtq *vq)
{
@@ -1829,12 +2064,6 @@ virtqueue_map_desc(VuDev *dev,
*p_num_sg = num_sg;
}
-/* Round number down to multiple */
-#define ALIGN_DOWN(n, m) ((n) / (m) * (m))
-
-/* Round number up to multiple */
-#define ALIGN_UP(n, m) ALIGN_DOWN((n) + (m) - 1, (m))
-
static void *
virtqueue_alloc_element(size_t sz,
unsigned out_num, unsigned in_num)
@@ -1853,49 +2082,20 @@ virtqueue_alloc_element(size_t sz,
return elem;
}
-void *
-vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz)
+static void *
+vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz)
{
- unsigned int i, head, max, desc_len;
+ struct vring_desc *desc = vq->vring.desc;
uint64_t desc_addr, read_len;
+ unsigned int desc_len;
+ unsigned int max = vq->vring.num;
+ unsigned int i = idx;
VuVirtqElement *elem;
- unsigned out_num, in_num;
+ unsigned int out_num = 0, in_num = 0;
struct iovec iov[VIRTQUEUE_MAX_SIZE];
struct vring_desc desc_buf[VIRTQUEUE_MAX_SIZE];
- struct vring_desc *desc;
int rc;
- if (unlikely(dev->broken) ||
- unlikely(!vq->vring.avail)) {
- return NULL;
- }
-
- if (vu_queue_empty(dev, vq)) {
- return NULL;
- }
- /* Needed after virtio_queue_empty(), see comment in
- * virtqueue_num_heads(). */
- smp_rmb();
-
- /* When we start there are none of either input nor output. */
- out_num = in_num = 0;
-
- max = vq->vring.num;
- if (vq->inuse >= vq->vring.num) {
- vu_panic(dev, "Virtqueue size exceeded");
- return NULL;
- }
-
- if (!virtqueue_get_head(dev, vq, vq->last_avail_idx++, &head)) {
- return NULL;
- }
-
- if (vu_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
- vring_set_avail_event(vq, vq->last_avail_idx);
- }
-
- i = head;
- desc = vq->vring.desc;
if (desc[i].flags & VRING_DESC_F_INDIRECT) {
if (desc[i].len % sizeof(struct vring_desc)) {
vu_panic(dev, "Invalid size for indirect buffer table");
@@ -1947,12 +2147,13 @@ vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz)
} while (rc == VIRTQUEUE_READ_DESC_MORE);
if (rc == VIRTQUEUE_READ_DESC_ERROR) {
+ vu_panic(dev, "read descriptor error");
return NULL;
}
/* Now copy what we have collected and mapped */
elem = virtqueue_alloc_element(sz, out_num, in_num);
- elem->index = head;
+ elem->index = idx;
for (i = 0; i < out_num; i++) {
elem->out_sg[i] = iov[i];
}
@@ -1960,11 +2161,142 @@ vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz)
elem->in_sg[i] = iov[out_num + i];
}
+ return elem;
+}
+
+static int
+vu_queue_inflight_get(VuDev *dev, VuVirtq *vq, int desc_idx)
+{
+ if (!has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ return 0;
+ }
+
+ if (unlikely(!vq->inflight)) {
+ return -1;
+ }
+
+ vq->inflight->desc[desc_idx].counter = vq->counter++;
+ vq->inflight->desc[desc_idx].inflight = 1;
+
+ return 0;
+}
+
+static int
+vu_queue_inflight_pre_put(VuDev *dev, VuVirtq *vq, int desc_idx)
+{
+ if (!has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ return 0;
+ }
+
+ if (unlikely(!vq->inflight)) {
+ return -1;
+ }
+
+ vq->inflight->last_batch_head = desc_idx;
+
+ return 0;
+}
+
+static int
+vu_queue_inflight_post_put(VuDev *dev, VuVirtq *vq, int desc_idx)
+{
+ if (!has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ return 0;
+ }
+
+ if (unlikely(!vq->inflight)) {
+ return -1;
+ }
+
+ barrier();
+
+ vq->inflight->desc[desc_idx].inflight = 0;
+
+ barrier();
+
+ vq->inflight->used_idx = vq->used_idx;
+
+ return 0;
+}
+
+void *
+vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz)
+{
+ int i;
+ unsigned int head;
+ VuVirtqElement *elem;
+
+ if (unlikely(dev->broken) ||
+ unlikely(!vq->vring.avail)) {
+ return NULL;
+ }
+
+ if (unlikely(vq->resubmit_list && vq->resubmit_num > 0)) {
+ i = (--vq->resubmit_num);
+ elem = vu_queue_map_desc(dev, vq, vq->resubmit_list[i].index, sz);
+
+ if (!vq->resubmit_num) {
+ free(vq->resubmit_list);
+ vq->resubmit_list = NULL;
+ }
+
+ return elem;
+ }
+
+ if (vu_queue_empty(dev, vq)) {
+ return NULL;
+ }
+ /*
+ * Needed after virtio_queue_empty(), see comment in
+ * virtqueue_num_heads().
+ */
+ smp_rmb();
+
+ if (vq->inuse >= vq->vring.num) {
+ vu_panic(dev, "Virtqueue size exceeded");
+ return NULL;
+ }
+
+ if (!virtqueue_get_head(dev, vq, vq->last_avail_idx++, &head)) {
+ return NULL;
+ }
+
+ if (vu_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
+ vring_set_avail_event(vq, vq->last_avail_idx);
+ }
+
+ elem = vu_queue_map_desc(dev, vq, head, sz);
+
+ if (!elem) {
+ return NULL;
+ }
+
vq->inuse++;
+ vu_queue_inflight_get(dev, vq, head);
+
return elem;
}
+static void
+vu_queue_detach_element(VuDev *dev, VuVirtq *vq, VuVirtqElement *elem,
+ size_t len)
+{
+ vq->inuse--;
+ /* unmap, when DMA support is added */
+}
+
+void
+vu_queue_unpop(VuDev *dev, VuVirtq *vq, VuVirtqElement *elem,
+ size_t len)
+{
+ vq->last_avail_idx--;
+ vu_queue_detach_element(dev, vq, elem, len);
+}
+
bool
vu_queue_rewind(VuDev *dev, VuVirtq *vq, unsigned int num)
{
@@ -2106,5 +2438,7 @@ vu_queue_push(VuDev *dev, VuVirtq *vq,
const VuVirtqElement *elem, unsigned int len)
{
vu_queue_fill(dev, vq, elem, len, 0);
+ vu_queue_inflight_pre_put(dev, vq, elem->index);
vu_queue_flush(dev, vq, 1);
+ vu_queue_inflight_post_put(dev, vq, elem->index);
}
diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h
index 4aa55b4d2d..414ceb0a2f 100644
--- a/contrib/libvhost-user/libvhost-user.h
+++ b/contrib/libvhost-user/libvhost-user.h
@@ -53,6 +53,7 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_CONFIG = 9,
VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10,
VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12,
VHOST_USER_PROTOCOL_F_MAX
};
@@ -91,6 +92,8 @@ typedef enum VhostUserRequest {
VHOST_USER_POSTCOPY_ADVISE = 28,
VHOST_USER_POSTCOPY_LISTEN = 29,
VHOST_USER_POSTCOPY_END = 30,
+ VHOST_USER_GET_INFLIGHT_FD = 31,
+ VHOST_USER_SET_INFLIGHT_FD = 32,
VHOST_USER_MAX
} VhostUserRequest;
@@ -138,6 +141,13 @@ typedef struct VhostUserVringArea {
uint64_t offset;
} VhostUserVringArea;
+typedef struct VhostUserInflight {
+ uint64_t mmap_size;
+ uint64_t mmap_offset;
+ uint16_t num_queues;
+ uint16_t queue_size;
+} VhostUserInflight;
+
#if defined(_WIN32)
# define VU_PACKED __attribute__((gcc_struct, packed))
#else
@@ -145,7 +155,7 @@ typedef struct VhostUserVringArea {
#endif
typedef struct VhostUserMsg {
- VhostUserRequest request;
+ int request;
#define VHOST_USER_VERSION_MASK (0x3)
#define VHOST_USER_REPLY_MASK (0x1 << 2)
@@ -163,6 +173,7 @@ typedef struct VhostUserMsg {
VhostUserLog log;
VhostUserConfig config;
VhostUserVringArea area;
+ VhostUserInflight inflight;
} payload;
int fds[VHOST_MEMORY_MAX_NREGIONS];
@@ -234,9 +245,61 @@ typedef struct VuRing {
uint32_t flags;
} VuRing;
+typedef struct VuDescStateSplit {
+ /* Indicate whether this descriptor is inflight or not.
+ * Only available for head-descriptor. */
+ uint8_t inflight;
+
+ /* Padding */
+ uint8_t padding[5];
+
+ /* Maintain a list for the last batch of used descriptors.
+ * Only available when batching is used for submitting */
+ uint16_t next;
+
+ /* Used to preserve the order of fetching available descriptors.
+ * Only available for head-descriptor. */
+ uint64_t counter;
+} VuDescStateSplit;
+
+typedef struct VuVirtqInflight {
+ /* The feature flags of this region. Now it's initialized to 0. */
+ uint64_t features;
+
+ /* The version of this region. It's 1 currently.
+ * Zero value indicates a vm reset happened. */
+ uint16_t version;
+
+ /* The size of VuDescStateSplit array. It's equal to the virtqueue
+ * size. Slave could get it from queue size field of VhostUserInflight. */
+ uint16_t desc_num;
+
+ /* The head of list that track the last batch of used descriptors. */
+ uint16_t last_batch_head;
+
+ /* Storing the idx value of used ring */
+ uint16_t used_idx;
+
+ /* Used to track the state of each descriptor in descriptor table */
+ VuDescStateSplit desc[0];
+} VuVirtqInflight;
+
+typedef struct VuVirtqInflightDesc {
+ uint16_t index;
+ uint64_t counter;
+} VuVirtqInflightDesc;
+
typedef struct VuVirtq {
VuRing vring;
+ VuVirtqInflight *inflight;
+
+ VuVirtqInflightDesc *resubmit_list;
+
+ uint16_t resubmit_num;
+
+ uint64_t counter;
+
/* Next head to pop */
uint16_t last_avail_idx;
@@ -279,11 +342,18 @@ typedef void (*vu_set_watch_cb) (VuDev *dev, int fd, int condition,
vu_watch_cb cb, void *data);
typedef void (*vu_remove_watch_cb) (VuDev *dev, int fd);
+typedef struct VuDevInflightInfo {
+ int fd;
+ void *addr;
+ uint64_t size;
+} VuDevInflightInfo;
+
struct VuDev {
int sock;
uint32_t nregions;
VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE];
+ VuDevInflightInfo inflight_info;
int log_call_fd;
int slave_fd;
uint64_t log_size;
@@ -458,6 +528,20 @@ void vu_queue_notify(VuDev *dev, VuVirtq *vq);
*/
void *vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz);
+
+/**
+ * vu_queue_unpop:
+ * @dev: a VuDev context
+ * @vq: a VuVirtq queue
+ * @elem: The #VuVirtqElement
+ * @len: number of bytes written
+ *
+ * Pretend the most recent element wasn't popped from the virtqueue. The next
+ * call to vu_queue_pop() will refetch the element.
+ */
+void vu_queue_unpop(VuDev *dev, VuVirtq *vq, VuVirtqElement *elem,
+ size_t len);
+
/**
* vu_queue_rewind:
* @dev: a VuDev context
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 6ea36d4090..bf86128a0c 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -1,6 +1,8 @@
# Default configuration for ppc-softmmu
# For embedded PPCs:
+CONFIG_MPC_I2C=y
+CONFIG_DS1338=y
CONFIG_E500=y
CONFIG_PPC405=y
CONFIG_PPC440=y
diff --git a/docs/devel/decodetree.rst b/docs/devel/decodetree.rst
new file mode 100644
index 0000000000..44ac621ea8
--- /dev/null
+++ b/docs/devel/decodetree.rst
@@ -0,0 +1,221 @@
+========================
+Decodetree Specification
+========================
+
+A *decodetree* is built from instruction *patterns*. A pattern may
+represent a single architectural instruction or a group of same, depending
+on what is convenient for further processing.
+
+Each pattern has both *fixedbits* and *fixedmask*, the combination of which
+describes the condition under which the pattern is matched::
+
+ (insn & fixedmask) == fixedbits
+
+Each pattern may have *fields*, which are extracted from the insn and
+passed along to the translator. Examples of such are registers,
+immediates, and sub-opcodes.
+
+In support of patterns, one may declare *fields*, *argument sets*, and
+*formats*, each of which may be re-used to simplify further definitions.
+
+Fields
+======
+
+Syntax::
+
+ field_def := '%' identifier ( unnamed_field )+ ( !function=identifier )?
+ unnamed_field := number ':' ( 's' ) number
+
+For *unnamed_field*, the first number is the least-significant bit position
+of the field and the second number is the length of the field. If the 's' is
+present, the field is considered signed. If multiple ``unnamed_fields`` are
+present, they are concatenated. In this way one can define disjoint fields.
+
+If ``!function`` is specified, the concatenated result is passed through the
+named function, taking and returning an integral value.
+
+FIXME: the fields of the structure into which this result will be stored
+is restricted to ``int``. Which means that we cannot expand 64-bit items.
+
+Field examples:
+
++---------------------------+---------------------------------------------+
+| Input | Generated code |
++===========================+=============================================+
+| %disp 0:s16 | sextract(i, 0, 16) |
++---------------------------+---------------------------------------------+
+| %imm9 16:6 10:3 | extract(i, 16, 6) << 3 | extract(i, 10, 3) |
++---------------------------+---------------------------------------------+
+| %disp12 0:s1 1:1 2:10 | sextract(i, 0, 1) << 11 | |
+| | extract(i, 1, 1) << 10 | |
+| | extract(i, 2, 10) |
++---------------------------+---------------------------------------------+
+| %shimm8 5:s8 13:1 | expand_shimm8(sextract(i, 5, 8) << 1 | |
+| !function=expand_shimm8 | extract(i, 13, 1)) |
++---------------------------+---------------------------------------------+
+
+Argument Sets
+=============
+
+Syntax::
+
+ args_def := '&' identifier ( args_elt )+ ( !extern )?
+ args_elt := identifier
+
+Each *args_elt* defines an argument within the argument set.
+Each argument set will be rendered as a C structure "arg_$name"
+with each of the fields being one of the member arguments.
+
+If ``!extern`` is specified, the backing structure is assumed
+to have been already declared, typically via a second decoder.
+
+Argument sets are useful when one wants to define helper functions
+for the translator functions that can perform operations on a common
+set of arguments. This can ensure, for instance, that the ``AND``
+pattern and the ``OR`` pattern put their operands into the same named
+structure, so that a common ``gen_logic_insn`` may be able to handle
+the operations common between the two.
+
+Argument set examples::
+
+ &reg3 ra rb rc
+ &loadstore reg base offset
+
+
+Formats
+=======
+
+Syntax::
+
+ fmt_def := '@' identifier ( fmt_elt )+
+ fmt_elt := fixedbit_elt | field_elt | field_ref | args_ref
+ fixedbit_elt := [01.-]+
+ field_elt := identifier ':' 's'? number
+ field_ref := '%' identifier | identifier '=' '%' identifier
+ args_ref := '&' identifier
+
+Defining a format is a handy way to avoid replicating groups of fields
+across many instruction patterns.
+
+A *fixedbit_elt* describes a contiguous sequence of bits that must
+be 1, 0, or don't care. The difference between '.' and '-'
+is that '.' means that the bit will be covered with a field or a
+final 0 or 1 from the pattern, and '-' means that the bit is really
+ignored by the cpu and will not be specified.
+
+A *field_elt* describes a simple field only given a width; the position of
+the field is implied by its position with respect to other *fixedbit_elt*
+and *field_elt*.
+
+If any *fixedbit_elt* or *field_elt* appear, then all bits must be defined.
+Padding with a *fixedbit_elt* of all '.' is an easy way to accomplish that.
+
+A *field_ref* incorporates a field by reference. This is the only way to
+add a complex field to a format. A field may be renamed in the process
+via assignment to another identifier. This is intended to allow the
+same argument set be used with disjoint named fields.
+
+A single *args_ref* may specify an argument set to use for the format.
+The set of fields in the format must be a subset of the arguments in
+the argument set. If an argument set is not specified, one will be
+inferred from the set of fields.
+
+It is recommended, but not required, that all *field_ref* and *args_ref*
+appear at the end of the line, not interleaving with *fixedbit_elf* or
+*field_elt*.
+
+Format examples::
+
+ @opr ...... ra:5 rb:5 ... 0 ....... rc:5
+ @opi ...... ra:5 lit:8 1 ....... rc:5
+
+Patterns
+========
+
+Syntax::
+
+ pat_def := identifier ( pat_elt )+
+ pat_elt := fixedbit_elt | field_elt | field_ref | args_ref | fmt_ref | const_elt
+ fmt_ref := '@' identifier
+ const_elt := identifier '=' number
+
+The *fixedbit_elt* and *field_elt* specifiers are unchanged from formats.
+A pattern that does not specify a named format will have one inferred
+from a referenced argument set (if present) and the set of fields.
+
+A *const_elt* allows a argument to be set to a constant value. This may
+come in handy when fields overlap between patterns and one has to
+include the values in the *fixedbit_elt* instead.
+
+The decoder will call a translator function for each pattern matched.
+
+Pattern examples::
+
+ addl_r 010000 ..... ..... .... 0000000 ..... @opr
+ addl_i 010000 ..... ..... .... 0000000 ..... @opi
+
+which will, in part, invoke::
+
+ trans_addl_r(ctx, &arg_opr, insn)
+
+and::
+
+ trans_addl_i(ctx, &arg_opi, insn)
+
+Pattern Groups
+==============
+
+Syntax::
+
+ group := '{' ( pat_def | group )+ '}'
+
+A *group* begins with a lone open-brace, with all subsequent lines
+indented two spaces, and ending with a lone close-brace. Groups
+may be nested, increasing the required indentation of the lines
+within the nested group to two spaces per nesting level.
+
+Unlike ungrouped patterns, grouped patterns are allowed to overlap.
+Conflicts are resolved by selecting the patterns in order. If all
+of the fixedbits for a pattern match, its translate function will
+be called. If the translate function returns false, then subsequent
+patterns within the group will be matched.
+
+The following example from PA-RISC shows specialization of the *or*
+instruction::
+
+ {
+ {
+ nop 000010 ----- ----- 0000 001001 0 00000
+ copy 000010 00000 r1:5 0000 001001 0 rt:5
+ }
+ or 000010 rt2:5 r1:5 cf:4 001001 0 rt:5
+ }
+
+When the *cf* field is zero, the instruction has no side effects,
+and may be specialized. When the *rt* field is zero, the output
+is discarded and so the instruction has no effect. When the *rt2*
+field is zero, the operation is ``reg[rt] | 0`` and so encodes
+the canonical register copy operation.
+
+The output from the generator might look like::
+
+ switch (insn & 0xfc000fe0) {
+ case 0x08000240:
+ /* 000010.. ........ ....0010 010..... */
+ if ((insn & 0x0000f000) == 0x00000000) {
+ /* 000010.. ........ 00000010 010..... */
+ if ((insn & 0x0000001f) == 0x00000000) {
+ /* 000010.. ........ 00000010 01000000 */
+ extract_decode_Fmt_0(&u.f_decode0, insn);
+ if (trans_nop(ctx, &u.f_decode0)) return true;
+ }
+ if ((insn & 0x03e00000) == 0x00000000) {
+ /* 00001000 000..... 00000010 010..... */
+ extract_decode_Fmt_1(&u.f_decode1, insn);
+ if (trans_copy(ctx, &u.f_decode1)) return true;
+ }
+ }
+ extract_decode_Fmt_2(&u.f_decode2, insn);
+ if (trans_or(ctx, &u.f_decode2)) return true;
+ return false;
+ }
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index 6b11e49caa..ebbab636ce 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -19,4 +19,4 @@ Contents:
migration
stable-process
testing
-
+ decodetree
diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
index 28f9bc1591..ff8c2ce5f2 100644
--- a/docs/interop/firmware.json
+++ b/docs/interop/firmware.json
@@ -212,9 +212,13 @@
#
# @executable: Identifies the firmware executable. The firmware
# executable may be shared by multiple virtual machine
-# definitions. The corresponding QEMU command line option
-# is "-drive
-# if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format".
+# definitions. The preferred corresponding QEMU command
+# line options are
+# -drive if=none,id=pflash0,readonly=on,file=@executable.@filename,format=@executable.@format
+# -machine pflash0=pflash0
+# or equivalent -blockdev instead of -drive.
+# With QEMU versions older than 4.0, you have to use
+# -drive if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format
#
# @nvram-template: Identifies the NVRAM template compatible with
# @executable. Management software instantiates an
@@ -225,9 +229,13 @@
# individual copies of it are. An NVRAM file is
# typically used for persistently storing the
# non-volatile UEFI variables of a virtual machine
-# definition. The corresponding QEMU command line
-# option is "-drive
-# if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format".
+# definition. The preferred corresponding QEMU
+# command line options are
+# -drive if=none,id=pflash1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
+# -machine pflash1=pflash1
+# or equivalent -blockdev instead of -drive.
+# With QEMU versions older than 4.0, you have to use
+# -drive if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format
#
# Since: 3.0
##
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
index 8c3098d8d9..af5711e533 100644
--- a/docs/interop/qcow2.txt
+++ b/docs/interop/qcow2.txt
@@ -633,7 +633,10 @@ Structure of a bitmap directory entry:
Bit
0: in_use
The bitmap was not saved correctly and may be
- inconsistent.
+ inconsistent. Although the bitmap metadata is still
+ well-formed from a qcow2 perspective, the metadata
+ (such as the auto flag or bitmap size) or data
+ contents may be outdated.
1: auto
The bitmap must reflect all changes of the virtual
@@ -761,8 +764,8 @@ corresponding range of the virtual disk (see above) was written to while the
bitmap was 'enabled'. An unset bit means that this range was not written to.
The software doesn't have to sync the bitmap in the image file with its
-representation in RAM after each write. Flag 'in_use' should be set while the
-bitmap is not synced.
+representation in RAM after each write or metadata change. Flag 'in_use'
+should be set while the bitmap is not synced.
In the image file the 'enabled' state is reflected by the 'auto' flag. If this
flag is set, the software must consider the bitmap as 'enabled' and start
diff --git a/docs/interop/vhost-user.json b/docs/interop/vhost-user.json
new file mode 100644
index 0000000000..ae88c03117
--- /dev/null
+++ b/docs/interop/vhost-user.json
@@ -0,0 +1,232 @@
+# -*- Mode: Python -*-
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Authors:
+# Marc-André Lureau <marcandre.lureau@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+##
+# = vhost user backend discovery & capabilities
+##
+
+##
+# @VHostUserBackendType:
+#
+# List the various vhost user backend types.
+#
+# @9p: 9p virtio console
+# @balloon: virtio balloon
+# @block: virtio block
+# @caif: virtio caif
+# @console: virtio console
+# @crypto: virtio crypto
+# @gpu: virtio gpu
+# @input: virtio input
+# @net: virtio net
+# @rng: virtio rng
+# @rpmsg: virtio remote processor messaging
+# @rproc-serial: virtio remoteproc serial link
+# @scsi: virtio scsi
+# @vsock: virtio vsock transport
+#
+# Since: 4.0
+##
+{
+ 'enum': 'VHostUserBackendType',
+ 'data': [
+ '9p',
+ 'balloon',
+ 'block',
+ 'caif',
+ 'console',
+ 'crypto',
+ 'gpu',
+ 'input',
+ 'net',
+ 'rng',
+ 'rpmsg',
+ 'rproc-serial',
+ 'scsi',
+ 'vsock'
+ ]
+}
+
+##
+# @VHostUserBackendInputFeature:
+#
+# List of vhost user "input" features.
+#
+# @evdev-path: The --evdev-path command line option is supported.
+# @no-grab: The --no-grab command line option is supported.
+#
+# Since: 4.0
+##
+{
+ 'enum': 'VHostUserBackendInputFeature',
+ 'data': [ 'evdev-path', 'no-grab' ]
+}
+
+##
+# @VHostUserBackendCapabilitiesInput:
+#
+# Capabilities reported by vhost user "input" backends
+#
+# @features: list of supported features.
+#
+# Since: 4.0
+##
+{
+ 'struct': 'VHostUserBackendCapabilitiesInput',
+ 'data': {
+ 'features': [ 'VHostUserBackendInputFeature' ]
+ }
+}
+
+##
+# @VHostUserBackendGPUFeature:
+#
+# List of vhost user "gpu" features.
+#
+# @render-node: The --render-node command line option is supported.
+# @virgl: The --virgl command line option is supported.
+#
+# Since: 4.0
+##
+{
+ 'enum': 'VHostUserBackendGPUFeature',
+ 'data': [ 'render-node', 'virgl' ]
+}
+
+##
+# @VHostUserBackendCapabilitiesGPU:
+#
+# Capabilities reported by vhost user "gpu" backends.
+#
+# @features: list of supported features.
+#
+# Since: 4.0
+##
+{
+ 'struct': 'VHostUserBackendCapabilitiesGPU',
+ 'data': {
+ 'features': [ 'VHostUserBackendGPUFeature' ]
+ }
+}
+
+##
+# @VHostUserBackendCapabilities:
+#
+# Capabilities reported by vhost user backends.
+#
+# @type: The vhost user backend type.
+#
+# Since: 4.0
+##
+{
+ 'union': 'VHostUserBackendCapabilities',
+ 'base': { 'type': 'VHostUserBackendType' },
+ 'discriminator': 'type',
+ 'data': {
+ 'input': 'VHostUserBackendCapabilitiesInput',
+ 'gpu': 'VHostUserBackendCapabilitiesGPU'
+ }
+}
+
+##
+# @VhostUserBackend:
+#
+# Describes a vhost user backend to management software.
+#
+# It is possible for multiple @VhostUserBackend elements to match the
+# search criteria of management software. Applications thus need rules
+# to pick one of the many matches, and users need the ability to
+# override distro defaults.
+#
+# It is recommended to create vhost user backend JSON files (each
+# containing a single @VhostUserBackend root element) with a
+# double-digit prefix, for example "50-qemu-gpu.json",
+# "50-crosvm-gpu.json", etc, so they can be sorted in predictable
+# order. The backend JSON files should be searched for in three
+# directories:
+#
+# - /usr/share/qemu/vhost-user -- populated by distro-provided
+# packages (XDG_DATA_DIRS covers
+# /usr/share by default),
+#
+# - /etc/qemu/vhost-user -- exclusively for sysadmins' local additions,
+#
+# - $XDG_CONFIG_HOME/qemu/vhost-user -- exclusively for per-user local
+# additions (XDG_CONFIG_HOME
+# defaults to $HOME/.config).
+#
+# Top-down, the list of directories goes from general to specific.
+#
+# Management software should build a list of files from all three
+# locations, then sort the list by filename (i.e., basename
+# component). Management software should choose the first JSON file on
+# the sorted list that matches the search criteria. If a more specific
+# directory has a file with same name as a less specific directory,
+# then the file in the more specific directory takes effect. If the
+# more specific file is zero length, it hides the less specific one.
+#
+# For example, if a distro ships
+#
+# - /usr/share/qemu/vhost-user/50-qemu-gpu.json
+#
+# - /usr/share/qemu/vhost-user/50-crosvm-gpu.json
+#
+# then the sysadmin can prevent the default QEMU being used at all with
+#
+# $ touch /etc/qemu/vhost-user/50-qemu-gpu.json
+#
+# The sysadmin can replace/alter the distro default OVMF with
+#
+# $ vim /etc/qemu/vhost-user/50-qemu-gpu.json
+#
+# or they can provide a parallel QEMU GPU with higher priority
+#
+# $ vim /etc/qemu/vhost-user/10-qemu-gpu.json
+#
+# or they can provide a parallel OVMF with lower priority
+#
+# $ vim /etc/qemu/vhost-user/99-qemu-gpu.json
+#
+# @type: The vhost user backend type.
+#
+# @description: Provides a human-readable description of the backend.
+# Management software may or may not display @description.
+#
+# @binary: Absolute path to the backend binary.
+#
+# @tags: An optional list of auxiliary strings associated with the
+# backend for which @description is not appropriate, due to the
+# latter's possible exposure to the end-user. @tags serves
+# development and debugging purposes only, and management
+# software shall explicitly ignore it.
+#
+# Since: 4.0
+#
+# Example:
+#
+# {
+# "description": "QEMU vhost-user-gpu",
+# "type": "gpu",
+# "binary": "/usr/libexec/qemu/vhost-user-gpu",
+# "tags": [
+# "CONFIG_OPENGL_DMABUF=y"
+# ]
+# }
+#
+##
+{
+ 'struct' : 'VhostUserBackend',
+ 'data' : {
+ 'description': 'str',
+ 'type': 'VHostUserBackendType',
+ 'binary': 'str',
+ '*tags': [ 'str' ]
+ }
+}
diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt
index c2194711d9..4dbd530cb9 100644
--- a/docs/interop/vhost-user.txt
+++ b/docs/interop/vhost-user.txt
@@ -17,8 +17,13 @@ The protocol defines 2 sides of the communication, master and slave. Master is
the application that shares its virtqueues, in our case QEMU. Slave is the
consumer of the virtqueues.
-In the current implementation QEMU is the Master, and the Slave is intended to
-be a software Ethernet switch running in user space, such as Snabbswitch.
+In the current implementation QEMU is the Master, and the Slave is the
+external process consuming the virtio queues, for example a software
+Ethernet switch running in user space, such as Snabbswitch, or a block
+device backend processing read & write to a virtual disk. In order to
+facilitate interoperability between various backend implementations,
+it is recommended to follow the "Backend program conventions"
+described in this document.
Master and slave can be either a client (i.e. connecting) or server (listening)
in the socket communication.
@@ -142,6 +147,17 @@ Depending on the request type, payload can be:
Offset: a 64-bit offset of this area from the start of the
supplied file descriptor
+ * Inflight description
+ -----------------------------------------------------
+ | mmap size | mmap offset | num queues | queue size |
+ -----------------------------------------------------
+
+ mmap size: a 64-bit size of area to track inflight I/O
+ mmap offset: a 64-bit offset of this area from the start
+ of the supplied file descriptor
+ num queues: a 16-bit number of virtqueues
+ queue size: a 16-bit size of virtqueues
+
In QEMU the vhost-user message is implemented with the following struct:
typedef struct VhostUserMsg {
@@ -157,6 +173,7 @@ typedef struct VhostUserMsg {
struct vhost_iotlb_msg iotlb;
VhostUserConfig config;
VhostUserVringArea area;
+ VhostUserInflight inflight;
};
} QEMU_PACKED VhostUserMsg;
@@ -175,6 +192,7 @@ the ones that do:
* VHOST_USER_GET_PROTOCOL_FEATURES
* VHOST_USER_GET_VRING_BASE
* VHOST_USER_SET_LOG_BASE (if VHOST_USER_PROTOCOL_F_LOG_SHMFD)
+ * VHOST_USER_GET_INFLIGHT_FD (if VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)
[ Also see the section on REPLY_ACK protocol extension. ]
@@ -188,6 +206,7 @@ in the ancillary data:
* VHOST_USER_SET_VRING_CALL
* VHOST_USER_SET_VRING_ERR
* VHOST_USER_SET_SLAVE_REQ_FD
+ * VHOST_USER_SET_INFLIGHT_FD (if VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)
If Master is unable to send the full message or receives a wrong reply it will
close the connection. An optional reconnection mechanism can be implemented.
@@ -382,6 +401,256 @@ If VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD protocol feature is negotiated,
slave can send file descriptors (at most 8 descriptors in each message)
to master via ancillary data using this fd communication channel.
+Inflight I/O tracking
+---------------------
+
+To support reconnecting after restart or crash, slave may need to resubmit
+inflight I/Os. If virtqueue is processed in order, we can easily achieve
+that by getting the inflight descriptors from descriptor table (split virtqueue)
+or descriptor ring (packed virtqueue). However, it can't work when we process
+descriptors out-of-order because some entries which store the information of
+inflight descriptors in available ring (split virtqueue) or descriptor
+ring (packed virtqueue) might be overrided by new entries. To solve this
+problem, slave need to allocate an extra buffer to store this information of inflight
+descriptors and share it with master for persistent. VHOST_USER_GET_INFLIGHT_FD and
+VHOST_USER_SET_INFLIGHT_FD are used to transfer this buffer between master
+and slave. And the format of this buffer is described below:
+
+-------------------------------------------------------
+| queue0 region | queue1 region | ... | queueN region |
+-------------------------------------------------------
+
+N is the number of available virtqueues. Slave could get it from num queues
+field of VhostUserInflight.
+
+For split virtqueue, queue region can be implemented as:
+
+typedef struct DescStateSplit {
+ /* Indicate whether this descriptor is inflight or not.
+ * Only available for head-descriptor. */
+ uint8_t inflight;
+
+ /* Padding */
+ uint8_t padding[5];
+
+ /* Maintain a list for the last batch of used descriptors.
+ * Only available when batching is used for submitting */
+ uint16_t next;
+
+ /* Used to preserve the order of fetching available descriptors.
+ * Only available for head-descriptor. */
+ uint64_t counter;
+} DescStateSplit;
+
+typedef struct QueueRegionSplit {
+ /* The feature flags of this region. Now it's initialized to 0. */
+ uint64_t features;
+
+ /* The version of this region. It's 1 currently.
+ * Zero value indicates an uninitialized buffer */
+ uint16_t version;
+
+ /* The size of DescStateSplit array. It's equal to the virtqueue
+ * size. Slave could get it from queue size field of VhostUserInflight. */
+ uint16_t desc_num;
+
+ /* The head of list that track the last batch of used descriptors. */
+ uint16_t last_batch_head;
+
+ /* Store the idx value of used ring */
+ uint16_t used_idx;
+
+ /* Used to track the state of each descriptor in descriptor table */
+ DescStateSplit desc[0];
+} QueueRegionSplit;
+
+To track inflight I/O, the queue region should be processed as follows:
+
+When receiving available buffers from the driver:
+
+ 1. Get the next available head-descriptor index from available ring, i
+
+ 2. Set desc[i].counter to the value of global counter
+
+ 3. Increase global counter by 1
+
+ 4. Set desc[i].inflight to 1
+
+When supplying used buffers to the driver:
+
+ 1. Get corresponding used head-descriptor index, i
+
+ 2. Set desc[i].next to last_batch_head
+
+ 3. Set last_batch_head to i
+
+ 4. Steps 1,2,3 may be performed repeatedly if batching is possible
+
+ 5. Increase the idx value of used ring by the size of the batch
+
+ 6. Set the inflight field of each DescStateSplit entry in the batch to 0
+
+ 7. Set used_idx to the idx value of used ring
+
+When reconnecting:
+
+ 1. If the value of used_idx does not match the idx value of used ring (means
+ the inflight field of DescStateSplit entries in last batch may be incorrect),
+
+ (a) Subtract the value of used_idx from the idx value of used ring to get
+ last batch size of DescStateSplit entries
+
+ (b) Set the inflight field of each DescStateSplit entry to 0 in last batch
+ list which starts from last_batch_head
+
+ (c) Set used_idx to the idx value of used ring
+
+ 2. Resubmit inflight DescStateSplit entries in order of their counter value
+
+For packed virtqueue, queue region can be implemented as:
+
+typedef struct DescStatePacked {
+ /* Indicate whether this descriptor is inflight or not.
+ * Only available for head-descriptor. */
+ uint8_t inflight;
+
+ /* Padding */
+ uint8_t padding;
+
+ /* Link to the next free entry */
+ uint16_t next;
+
+ /* Link to the last entry of descriptor list.
+ * Only available for head-descriptor. */
+ uint16_t last;
+
+ /* The length of descriptor list.
+ * Only available for head-descriptor. */
+ uint16_t num;
+
+ /* Used to preserve the order of fetching available descriptors.
+ * Only available for head-descriptor. */
+ uint64_t counter;
+
+ /* The buffer id */
+ uint16_t id;
+
+ /* The descriptor flags */
+ uint16_t flags;
+
+ /* The buffer length */
+ uint32_t len;
+
+ /* The buffer address */
+ uint64_t addr;
+} DescStatePacked;
+
+typedef struct QueueRegionPacked {
+ /* The feature flags of this region. Now it's initialized to 0. */
+ uint64_t features;
+
+ /* The version of this region. It's 1 currently.
+ * Zero value indicates an uninitialized buffer */
+ uint16_t version;
+
+ /* The size of DescStatePacked array. It's equal to the virtqueue
+ * size. Slave could get it from queue size field of VhostUserInflight. */
+ uint16_t desc_num;
+
+ /* The head of free DescStatePacked entry list */
+ uint16_t free_head;
+
+ /* The old head of free DescStatePacked entry list */
+ uint16_t old_free_head;
+
+ /* The used index of descriptor ring */
+ uint16_t used_idx;
+
+ /* The old used index of descriptor ring */
+ uint16_t old_used_idx;
+
+ /* Device ring wrap counter */
+ uint8_t used_wrap_counter;
+
+ /* The old device ring wrap counter */
+ uint8_t old_used_wrap_counter;
+
+ /* Padding */
+ uint8_t padding[7];
+
+ /* Used to track the state of each descriptor fetched from descriptor ring */
+ DescStatePacked desc[0];
+} QueueRegionPacked;
+
+To track inflight I/O, the queue region should be processed as follows:
+
+When receiving available buffers from the driver:
+
+ 1. Get the next available descriptor entry from descriptor ring, d
+
+ 2. If d is head descriptor,
+
+ (a) Set desc[old_free_head].num to 0
+
+ (b) Set desc[old_free_head].counter to the value of global counter
+
+ (c) Increase global counter by 1
+
+ (d) Set desc[old_free_head].inflight to 1
+
+ 3. If d is last descriptor, set desc[old_free_head].last to free_head
+
+ 4. Increase desc[old_free_head].num by 1
+
+ 5. Set desc[free_head].addr, desc[free_head].len, desc[free_head].flags,
+ desc[free_head].id to d.addr, d.len, d.flags, d.id
+
+ 6. Set free_head to desc[free_head].next
+
+ 7. If d is last descriptor, set old_free_head to free_head
+
+When supplying used buffers to the driver:
+
+ 1. Get corresponding used head-descriptor entry from descriptor ring, d
+
+ 2. Get corresponding DescStatePacked entry, e
+
+ 3. Set desc[e.last].next to free_head
+
+ 4. Set free_head to the index of e
+
+ 5. Steps 1,2,3,4 may be performed repeatedly if batching is possible
+
+ 6. Increase used_idx by the size of the batch and update used_wrap_counter if needed
+
+ 7. Update d.flags
+
+ 8. Set the inflight field of each head DescStatePacked entry in the batch to 0
+
+ 9. Set old_free_head, old_used_idx, old_used_wrap_counter to free_head, used_idx,
+ used_wrap_counter
+
+When reconnecting:
+
+ 1. If used_idx does not match old_used_idx (means the inflight field of DescStatePacked
+ entries in last batch may be incorrect),
+
+ (a) Get the next descriptor ring entry through old_used_idx, d
+
+ (b) Use old_used_wrap_counter to calculate the available flags
+
+ (c) If d.flags is not equal to the calculated flags value (means slave has
+ submitted the buffer to guest driver before crash, so it has to commit the
+ in-progres update), set old_free_head, old_used_idx, old_used_wrap_counter
+ to free_head, used_idx, used_wrap_counter
+
+ 2. Set free_head, used_idx, used_wrap_counter to old_free_head, old_used_idx,
+ old_used_wrap_counter (roll back any in-progress update)
+
+ 3. Set the inflight field of each DescStatePacked entry in free list to 0
+
+ 4. Resubmit inflight DescStatePacked entries in order of their counter value
+
Protocol features
-----------------
@@ -397,6 +666,7 @@ Protocol features
#define VHOST_USER_PROTOCOL_F_CONFIG 9
#define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD 10
#define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER 11
+#define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD 12
Master message types
--------------------
@@ -761,6 +1031,26 @@ Master message types
was previously sent.
The value returned is an error indication; 0 is success.
+ * VHOST_USER_GET_INFLIGHT_FD
+ Id: 31
+ Equivalent ioctl: N/A
+ Master payload: inflight description
+
+ When VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD protocol feature has been
+ successfully negotiated, this message is submitted by master to get
+ a shared buffer from slave. The shared buffer will be used to track
+ inflight I/O by slave. QEMU should retrieve a new one when vm reset.
+
+ * VHOST_USER_SET_INFLIGHT_FD
+ Id: 32
+ Equivalent ioctl: N/A
+ Master payload: inflight description
+
+ When VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD protocol feature has been
+ successfully negotiated, this message is submitted by master to send
+ the shared inflight buffer back to slave so that slave could get
+ inflight I/O after a crash or restart.
+
Slave message types
-------------------
@@ -835,3 +1125,95 @@ resilient for selective requests.
For the message types that already solicit a reply from the client, the
presence of VHOST_USER_PROTOCOL_F_REPLY_ACK or need_reply bit being set brings
no behavioural change. (See the 'Communication' section for details.)
+
+Backend program conventions
+---------------------------
+
+vhost-user backends can provide various devices & services and may
+need to be configured manually depending on the use case. However, it
+is a good idea to follow the conventions listed here when
+possible. Users, QEMU or libvirt, can then rely on some common
+behaviour to avoid heterogenous configuration and management of the
+backend programs and facilitate interoperability.
+
+Each backend installed on a host system should come with at least one
+JSON file that conforms to the vhost-user.json schema. Each file
+informs the management applications about the backend type, and binary
+location. In addition, it defines rules for management apps for
+picking the highest priority backend when multiple match the search
+criteria (see @VhostUserBackend documentation in the schema file).
+
+If the backend is not capable of enabling a requested feature on the
+host (such as 3D acceleration with virgl), or the initialization
+failed, the backend should fail to start early and exit with a status
+!= 0. It may also print a message to stderr for further details.
+
+The backend program must not daemonize itself, but it may be
+daemonized by the management layer. It may also have a restricted
+access to the system.
+
+File descriptors 0, 1 and 2 will exist, and have regular
+stdin/stdout/stderr usage (they may have been redirected to /dev/null
+by the management layer, or to a log handler).
+
+The backend program must end (as quickly and cleanly as possible) when
+the SIGTERM signal is received. Eventually, it may receive SIGKILL by
+the management layer after a few seconds.
+
+The following command line options have an expected behaviour. They
+are mandatory, unless explicitly said differently:
+
+* --socket-path=PATH
+
+This option specify the location of the vhost-user Unix domain socket.
+It is incompatible with --fd.
+
+* --fd=FDNUM
+
+When this argument is given, the backend program is started with the
+vhost-user socket as file descriptor FDNUM. It is incompatible with
+--socket-path.
+
+* --print-capabilities
+
+Output to stdout the backend capabilities in JSON format, and then
+exit successfully. Other options and arguments should be ignored, and
+the backend program should not perform its normal function. The
+capabilities can be reported dynamically depending on the host
+capabilities.
+
+The JSON output is described in the vhost-user.json schema, by
+@VHostUserBackendCapabilities. Example:
+{
+ "type": "foo",
+ "features": [
+ "feature-a",
+ "feature-b"
+ ]
+}
+
+vhost-user-input
+----------------
+
+Command line options:
+
+* --evdev-path=PATH (optional)
+
+Specify the linux input device.
+
+* --no-grab (optional)
+
+Do no request exclusive access to the input device.
+
+vhost-user-gpu
+--------------
+
+Command line options:
+
+* --render-node=PATH (optional)
+
+Specify the GPU DRM render node.
+
+* --virgl (optional)
+
+Enable virgl rendering support.
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index c5d8646abc..e53dfe1ee3 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -483,13 +483,24 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
NULL);
}
+void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
+ !lpc->pm.acpi_memory_hotplug.is_enabled)
+ error_setg(errp,
+ "memory hotplug is not enabled: %s.memory-hotplug-support "
+ "is not set", object_get_typename(OBJECT(lpc)));
+}
+
void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
- if (lpc->pm.acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
nvdimm_acpi_plug_cb(hotplug_dev, dev);
} else {
diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index e53b2cb681..9fdad6dc3f 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -382,7 +382,7 @@ nvdimm_build_structure_caps(GArray *structures, uint32_t capabilities)
nfit_caps->capabilities = cpu_to_le32(capabilities);
}
-static GArray *nvdimm_build_device_structure(AcpiNVDIMMState *state)
+static GArray *nvdimm_build_device_structure(NVDIMMState *state)
{
GSList *device_list = nvdimm_get_device_list();
GArray *structures = g_array_new(false, true /* clear */, 1);
@@ -416,7 +416,7 @@ static void nvdimm_init_fit_buffer(NvdimmFitBuffer *fit_buf)
fit_buf->fit = g_array_new(false, true /* clear */, 1);
}
-static void nvdimm_build_fit_buffer(AcpiNVDIMMState *state)
+static void nvdimm_build_fit_buffer(NVDIMMState *state)
{
NvdimmFitBuffer *fit_buf = &state->fit_buf;
@@ -425,12 +425,12 @@ static void nvdimm_build_fit_buffer(AcpiNVDIMMState *state)
fit_buf->dirty = true;
}
-void nvdimm_plug(AcpiNVDIMMState *state)
+void nvdimm_plug(NVDIMMState *state)
{
nvdimm_build_fit_buffer(state);
}
-static void nvdimm_build_nfit(AcpiNVDIMMState *state, GArray *table_offsets,
+static void nvdimm_build_nfit(NVDIMMState *state, GArray *table_offsets,
GArray *table_data, BIOSLinker *linker)
{
NvdimmFitBuffer *fit_buf = &state->fit_buf;
@@ -570,7 +570,7 @@ nvdimm_dsm_no_payload(uint32_t func_ret_status, hwaddr dsm_mem_addr)
#define NVDIMM_QEMU_RSVD_HANDLE_ROOT 0x10000
/* Read FIT data, defined in docs/specs/acpi_nvdimm.txt. */
-static void nvdimm_dsm_func_read_fit(AcpiNVDIMMState *state, NvdimmDsmIn *in,
+static void nvdimm_dsm_func_read_fit(NVDIMMState *state, NvdimmDsmIn *in,
hwaddr dsm_mem_addr)
{
NvdimmFitBuffer *fit_buf = &state->fit_buf;
@@ -619,7 +619,7 @@ exit:
}
static void
-nvdimm_dsm_handle_reserved_root_method(AcpiNVDIMMState *state,
+nvdimm_dsm_handle_reserved_root_method(NVDIMMState *state,
NvdimmDsmIn *in, hwaddr dsm_mem_addr)
{
switch (in->function) {
@@ -863,7 +863,7 @@ nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size)
static void
nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
- AcpiNVDIMMState *state = opaque;
+ NVDIMMState *state = opaque;
NvdimmDsmIn *in;
hwaddr dsm_mem_addr = val;
@@ -925,7 +925,7 @@ void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev)
}
}
-void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io,
+void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io,
FWCfgState *fw_cfg, Object *owner)
{
memory_region_init_io(&state->io_mr, owner, &nvdimm_dsm_ops, state,
@@ -992,7 +992,7 @@ static void nvdimm_build_common_dsm(Aml *dev)
field = aml_field(NVDIMM_DSM_IOPORT, AML_DWORD_ACC, AML_NOLOCK,
AML_PRESERVE);
aml_append(field, aml_named_field(NVDIMM_DSM_NOTIFY,
- sizeof(uint32_t) * BITS_PER_BYTE));
+ NVDIMM_ACPI_IO_LEN * BITS_PER_BYTE));
aml_append(method, field);
/*
@@ -1086,7 +1086,7 @@ static void nvdimm_build_common_dsm(Aml *dev)
*/
aml_append(method, aml_store(handle, aml_name(NVDIMM_DSM_HANDLE)));
aml_append(method, aml_store(aml_arg(1), aml_name(NVDIMM_DSM_REVISION)));
- aml_append(method, aml_store(aml_arg(2), aml_name(NVDIMM_DSM_FUNCTION)));
+ aml_append(method, aml_store(function, aml_name(NVDIMM_DSM_FUNCTION)));
/*
* The fourth parameter (Arg3) of _DSM is a package which contains
@@ -1260,7 +1260,7 @@ static void nvdimm_build_nvdimm_devices(Aml *root_dev, uint32_t ram_slots)
}
static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
- BIOSLinker *linker, GArray *dsm_dma_arrea,
+ BIOSLinker *linker, GArray *dsm_dma_area,
uint32_t ram_slots)
{
Aml *ssdt, *sb_scope, *dev;
@@ -1307,7 +1307,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
NVDIMM_ACPI_MEM_ADDR);
bios_linker_loader_alloc(linker,
- NVDIMM_DSM_MEM_FILE, dsm_dma_arrea,
+ NVDIMM_DSM_MEM_FILE, dsm_dma_area,
sizeof(NvdimmDsmIn), false /* high memory */);
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, mem_addr_offset, sizeof(uint32_t),
@@ -1319,7 +1319,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
}
void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
- BIOSLinker *linker, AcpiNVDIMMState *state,
+ BIOSLinker *linker, NVDIMMState *state,
uint32_t ram_slots)
{
GSList *device_list;
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 8fd25a5926..9c079d6834 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -28,7 +28,6 @@
#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "qemu/range.h"
-#include "hw/nvram/fw_cfg.h"
#include "exec/address-spaces.h"
#include "hw/acpi/piix4.h"
#include "hw/acpi/pcihp.h"
@@ -381,9 +380,17 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
static void piix4_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
+ PIIX4PMState *s = PIIX4_PM(hotplug_dev);
+
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
- } else if (!object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ if (!s->acpi_memory_hotplug.is_enabled) {
+ error_setg(errp,
+ "memory hotplug is not enabled: %s.memory-hotplug-support "
+ "is not set", object_get_typename(OBJECT(s)));
+ }
+ } else if (
!object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
error_setg(errp, "acpi: device pre plug request for not supported"
" device type: %s", object_get_typename(OBJECT(dev)));
@@ -395,8 +402,7 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
{
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
- if (s->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
nvdimm_acpi_plug_cb(hotplug_dev, dev);
} else {
diff --git a/hw/arm/collie.c b/hw/arm/collie.c
index 3ca4e078fe..d12604c573 100644
--- a/hw/arm/collie.c
+++ b/hw/arm/collie.c
@@ -9,6 +9,7 @@
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/boards.h"
@@ -35,14 +36,14 @@ static void collie_init(MachineState *machine)
s = sa1110_init(sysmem, collie_binfo.ram_size, machine->cpu_type);
dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
+ pflash_cfi01_register(SA_CS0, "collie.fl1", 0x02000000,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+ 64 * KiB, 4, 0x00, 0x00, 0x00, 0x00, 0);
dinfo = drive_get(IF_PFLASH, 0, 1);
- pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
+ pflash_cfi01_register(SA_CS1, "collie.fl2", 0x02000000,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
+ 64 * KiB, 4, 0x00, 0x00, 0x00, 0x00, 0);
sysbus_create_simple("scoop", 0x40800000, NULL);
diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c
index 9f11dcd11f..304e4d1a29 100644
--- a/hw/arm/digic_boards.c
+++ b/hw/arm/digic_boards.c
@@ -129,9 +129,8 @@ static void digic4_add_k8p3215uqb_rom(DigicBoardState *s, hwaddr addr,
#define FLASH_K8P3215UQB_SIZE (4 * 1024 * 1024)
#define FLASH_K8P3215UQB_SECTOR_SIZE (64 * 1024)
- pflash_cfi02_register(addr, NULL, "pflash", FLASH_K8P3215UQB_SIZE,
+ pflash_cfi02_register(addr, "pflash", FLASH_K8P3215UQB_SIZE,
NULL, FLASH_K8P3215UQB_SECTOR_SIZE,
- FLASH_K8P3215UQB_SIZE / FLASH_K8P3215UQB_SECTOR_SIZE,
DIGIC4_ROM_MAX_SIZE / FLASH_K8P3215UQB_SIZE,
4,
0x00EC, 0x007E, 0x0003, 0x0001,
diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c
index 56cb763c4e..79886ce378 100644
--- a/hw/arm/gumstix.c
+++ b/hw/arm/gumstix.c
@@ -72,10 +72,9 @@ static void connex_init(MachineState *machine)
#else
be = 0;
#endif
- if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
+ if (!pflash_cfi01_register(0x00000000, "connext.rom", connex_rom,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- sector_len, connex_rom / sector_len,
- 2, 0, 0, 0, 0, be)) {
+ sector_len, 2, 0, 0, 0, 0, be)) {
error_report("Error registering flash memory");
exit(1);
}
@@ -109,10 +108,9 @@ static void verdex_init(MachineState *machine)
#else
be = 0;
#endif
- if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
+ if (!pflash_cfi01_register(0x00000000, "verdex.rom", verdex_rom,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- sector_len, verdex_rom / sector_len,
- 2, 0, 0, 0, 0, be)) {
+ sector_len, 2, 0, 0, 0, 0, be)) {
error_report("Error registering flash memory");
exit(1);
}
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
index 0beb5c426b..e96738ad26 100644
--- a/hw/arm/mainstone.c
+++ b/hw/arm/mainstone.c
@@ -148,12 +148,11 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
exit(1);
}
- if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
+ if (!pflash_cfi01_register(mainstone_flash_base[i],
i ? "mainstone.flash1" : "mainstone.flash0",
MAINSTONE_FLASH,
blk_by_legacy_dinfo(dinfo),
- sector_len, MAINSTONE_FLASH / sector_len,
- 4, 0, 0, 0, 0, be)) {
+ sector_len, 4, 0, 0, 0, 0, be)) {
error_report("Error registering flash memory");
exit(1);
}
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index de4a12e496..93ec3c5698 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1635,16 +1635,16 @@ static void musicpal_init(MachineState *machine)
* image is smaller than 32 MB.
*/
#ifdef TARGET_WORDS_BIGENDIAN
- pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
+ pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX,
"musicpal.flash", flash_size,
- blk, 0x10000, (flash_size + 0xffff) >> 16,
+ blk, 0x10000,
MP_FLASH_SIZE_MAX / flash_size,
2, 0x00BF, 0x236D, 0x0000, 0x0000,
0x5555, 0x2AAA, 1);
#else
- pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
+ pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX,
"musicpal.flash", flash_size,
- blk, 0x10000, (flash_size + 0xffff) >> 16,
+ blk, 0x10000,
MP_FLASH_SIZE_MAX / flash_size,
2, 0x00BF, 0x236D, 0x0000, 0x0000,
0x5555, 0x2AAA, 0);
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index 94dffb2f57..446223906e 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -273,7 +273,7 @@ static void omap_eac_format_update(struct omap_eac_s *s)
* does I2S specify it? */
/* All register writes are 16 bits so we we store 16-bit samples
* in the buffers regardless of AGCFR[B8_16] value. */
- fmt.fmt = AUD_FMT_U16;
+ 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);
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index 84550f0236..95a4fe7e7f 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -152,11 +152,10 @@ static void sx1_init(MachineState *machine, const int version)
#endif
if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
- if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
+ if (!pflash_cfi01_register(OMAP_CS0_BASE,
"omap_sx1.flash0-1", flash_size,
blk_by_legacy_dinfo(dinfo),
- sector_size, flash_size / sector_size,
- 4, 0, 0, 0, 0, be)) {
+ sector_size, 4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory %d.\n",
fl_idx);
}
@@ -176,11 +175,10 @@ static void sx1_init(MachineState *machine, const int version)
memory_region_add_subregion(address_space,
OMAP_CS1_BASE + flash1_size, &cs[1]);
- if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
+ if (!pflash_cfi01_register(OMAP_CS1_BASE,
"omap_sx1.flash1-1", flash1_size,
blk_by_legacy_dinfo(dinfo),
- sector_size, flash1_size / sector_size,
- 4, 0, 0, 0, 0, be)) {
+ sector_size, 4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory %d.\n",
fl_idx);
}
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index 22b09a1e61..d67181810a 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -365,11 +365,10 @@ static void versatile_init(MachineState *machine, int board_id)
/* 0x34000000 NOR Flash */
dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
+ if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, "versatile.flash",
VERSATILE_FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
VERSATILE_FLASH_SECT_SIZE,
- VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");
}
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index c02d18ee61..f07134c424 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -512,10 +512,10 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
/* Open code a private version of pflash registration since we
* need to set non-default device width for VExpress platform.
*/
-static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
- DriveInfo *di)
+static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name,
+ DriveInfo *di)
{
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
if (di) {
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di),
@@ -536,7 +536,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
+ return PFLASH_CFI01(dev);
}
static void vexpress_common_init(MachineState *machine)
@@ -548,7 +548,7 @@ static void vexpress_common_init(MachineState *machine)
qemu_irq pic[64];
uint32_t sys_id;
DriveInfo *dinfo;
- pflash_t *pflash0;
+ PFlashCFI01 *pflash0;
I2CBus *i2c;
ram_addr_t vram_size, sram_size;
MemoryRegion *sysmem = get_system_memory();
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 7f66ddad89..ce2664a30b 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -35,6 +35,7 @@
#include "hw/arm/arm.h"
#include "hw/arm/primecell.h"
#include "hw/arm/virt.h"
+#include "hw/block/flash.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
#include "hw/vfio/vfio-amd-xgbe.h"
#include "hw/display/ramfb.h"
@@ -878,7 +879,7 @@ static void create_one_flash(const char *name, hwaddr flashbase,
* parameters as the flash devices on the Versatile Express board.
*/
DriveInfo *dinfo = drive_get_next(IF_PFLASH);
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
const uint64_t sectorlength = 256 * 1024;
@@ -1281,10 +1282,6 @@ static void virt_build_smbios(VirtMachineState *vms)
size_t smbios_tables_len, smbios_anchor_len;
const char *product = "QEMU Virtual Machine";
- if (!vms->fw_cfg) {
- return;
- }
-
if (kvm_enabled()) {
product = "KVM Virtual Machine";
}
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 57497b0c4d..b3b8215759 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -205,12 +205,11 @@ static void zynq_init(MachineState *machine)
DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
/* AMD */
- pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE,
+ pflash_cfi02_register(0xe2000000, "zynq.pflash", FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE,
- FLASH_SIZE/FLASH_SECTOR_SIZE, 1,
+ FLASH_SECTOR_SIZE, 1,
1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
- 0);
+ 0);
dev = qdev_create(NULL, "xilinx,zynq_slcr");
qdev_init_nofail(dev);
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index 3b75d4b39d..1f906ef20b 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -323,11 +323,9 @@ static void z2_init(MachineState *machine)
exit(1);
}
- if (!pflash_cfi01_register(Z2_FLASH_BASE,
- NULL, "z2.flash0", Z2_FLASH_SIZE,
+ if (!pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- sector_len, Z2_FLASH_SIZE / sector_len,
- 4, 0, 0, 0, 0, be)) {
+ sector_len, 4, 0, 0, 0, 0, be)) {
error_report("Error registering flash memory");
exit(1);
}
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index d799533aa9..2265622d44 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -365,7 +365,7 @@ static void open_voice (AC97LinkState *s, int index, int freq)
as.freq = freq;
as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = 0;
if (freq > 0) {
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 97b876c7e0..0957780a3d 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -269,7 +269,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
as.freq = s->freq;
as.nchannels = SHIFT;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = AUDIO_HOST_ENDIANNESS;
AUD_register_card ("adlib", &s->card);
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index 9089dcb47e..62da75eefe 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -288,7 +288,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)
switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
case 0:
- as.fmt = AUD_FMT_U8;
+ as.fmt = AUDIO_FORMAT_U8;
s->shift = as.nchannels == 2;
break;
@@ -298,7 +298,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)
case 3:
s->tab = ALawDecompressTable;
x_law:
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = AUDIO_HOST_ENDIANNESS;
s->shift = as.nchannels == 2;
break;
@@ -307,7 +307,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)
as.endianness = 1;
/* fall through */
case 2:
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
s->shift = as.nchannels;
break;
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 97789a0771..a5314d66fd 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -414,14 +414,14 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
i,
new_freq,
1 << (new_fmt & 1),
- (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8,
+ (new_fmt & 2) ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8,
d->shift);
if (new_freq) {
struct audsettings as;
as.freq = new_freq;
as.nchannels = 1 << (new_fmt & 1);
- as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
+ as.fmt = (new_fmt & 2) ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
as.endianness = 0;
if (i == ADC_CHANNEL) {
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index 8e0b27e0f2..b3e2a7fdd5 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -251,7 +251,7 @@ static void gus_realizefn (DeviceState *dev, Error **errp)
as.freq = s->freq;
as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = GUS_ENDIANNESS;
s->voice = AUD_open_out (
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 617a1c1016..c25bfa38b1 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -99,9 +99,9 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
}
switch (format & AC_FMT_BITS_MASK) {
- case AC_FMT_BITS_8: as->fmt = AUD_FMT_S8; break;
- case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
- case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
+ case AC_FMT_BITS_8: as->fmt = AUDIO_FORMAT_S8; break;
+ case AC_FMT_BITS_16: as->fmt = AUDIO_FORMAT_S16; break;
+ case AC_FMT_BITS_32: as->fmt = AUDIO_FORMAT_S32; break;
}
as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
@@ -134,12 +134,12 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
/* -------------------------------------------------------------------------- */
static const char *fmt2name[] = {
- [ AUD_FMT_U8 ] = "PCM-U8",
- [ AUD_FMT_S8 ] = "PCM-S8",
- [ AUD_FMT_U16 ] = "PCM-U16",
- [ AUD_FMT_S16 ] = "PCM-S16",
- [ AUD_FMT_U32 ] = "PCM-U32",
- [ AUD_FMT_S32 ] = "PCM-S32",
+ [ AUDIO_FORMAT_U8 ] = "PCM-U8",
+ [ AUDIO_FORMAT_S8 ] = "PCM-S8",
+ [ AUDIO_FORMAT_U16 ] = "PCM-U16",
+ [ AUDIO_FORMAT_S16 ] = "PCM-S16",
+ [ AUDIO_FORMAT_U32 ] = "PCM-U32",
+ [ AUDIO_FORMAT_S32 ] = "PCM-S32",
};
typedef struct HDAAudioState HDAAudioState;
diff --git a/hw/audio/lm4549.c b/hw/audio/lm4549.c
index a46f2301af..af8b22b541 100644
--- a/hw/audio/lm4549.c
+++ b/hw/audio/lm4549.c
@@ -185,7 +185,7 @@ void lm4549_write(lm4549_state *s,
struct audsettings as;
as.freq = value;
as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = 0;
s->voice = AUD_open_out(
@@ -255,7 +255,7 @@ static int lm4549_post_load(void *opaque, int version_id)
struct audsettings as;
as.freq = freq;
as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = 0;
s->voice = AUD_open_out(
@@ -292,7 +292,7 @@ void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)
/* Open a default voice */
as.freq = 48000;
as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = 0;
s->voice = AUD_open_out(
diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c
index bc8db71ae0..90cce1e6ed 100644
--- a/hw/audio/milkymist-ac97.c
+++ b/hw/audio/milkymist-ac97.c
@@ -308,7 +308,7 @@ static void milkymist_ac97_realize(DeviceState *dev, Error **errp)
as.freq = 48000;
as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = 1;
s->voice_in = AUD_open_in(&s->card, s->voice_in,
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
index b80a62ce90..fdbb4b6e99 100644
--- a/hw/audio/pcspk.c
+++ b/hw/audio/pcspk.c
@@ -162,7 +162,7 @@ static void pcspk_initfn(Object *obj)
static void pcspk_realizefn(DeviceState *dev, Error **errp)
{
- struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
+ struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUDIO_FORMAT_U8, 0};
ISADevice *isadev = ISA_DEVICE(dev);
PCSpkState *s = PC_SPEAKER(dev);
diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c
index c5b9bf79e8..65ea0cd938 100644
--- a/hw/audio/sb16.c
+++ b/hw/audio/sb16.c
@@ -66,7 +66,7 @@ typedef struct SB16State {
int fmt_stereo;
int fmt_signed;
int fmt_bits;
- audfmt_e fmt;
+ AudioFormat fmt;
int dma_auto;
int block_size;
int fifo;
@@ -224,7 +224,7 @@ static void continue_dma8 (SB16State *s)
static void dma_cmd8 (SB16State *s, int mask, int dma_len)
{
- s->fmt = AUD_FMT_U8;
+ s->fmt = AUDIO_FORMAT_U8;
s->use_hdma = 0;
s->fmt_bits = 8;
s->fmt_signed = 0;
@@ -319,18 +319,18 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
if (16 == s->fmt_bits) {
if (s->fmt_signed) {
- s->fmt = AUD_FMT_S16;
+ s->fmt = AUDIO_FORMAT_S16;
}
else {
- s->fmt = AUD_FMT_U16;
+ s->fmt = AUDIO_FORMAT_U16;
}
}
else {
if (s->fmt_signed) {
- s->fmt = AUD_FMT_S8;
+ s->fmt = AUDIO_FORMAT_S8;
}
else {
- s->fmt = AUD_FMT_U8;
+ s->fmt = AUDIO_FORMAT_U8;
}
}
@@ -852,7 +852,7 @@ static void legacy_reset (SB16State *s)
as.freq = s->freq;
as.nchannels = 1;
- as.fmt = AUD_FMT_U8;
+ as.fmt = AUDIO_FORMAT_U8;
as.endianness = 0;
s->voice = AUD_open_out (
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
index 169b006ade..ca0ad73caf 100644
--- a/hw/audio/wm8750.c
+++ b/hw/audio/wm8750.c
@@ -201,7 +201,7 @@ static void wm8750_set_format(WM8750State *s)
in_fmt.endianness = 0;
in_fmt.nchannels = 2;
in_fmt.freq = s->adc_hz;
- in_fmt.fmt = AUD_FMT_S16;
+ in_fmt.fmt = AUDIO_FORMAT_S16;
s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
@@ -214,7 +214,7 @@ static void wm8750_set_format(WM8750State *s)
out_fmt.endianness = 0;
out_fmt.nchannels = 2;
out_fmt.freq = s->dac_hz;
- out_fmt.fmt = AUD_FMT_S16;
+ out_fmt.fmt = AUDIO_FORMAT_S16;
s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
@@ -681,7 +681,7 @@ uint32_t wm8750_adc_dat(void *opaque)
if (s->idx_in >= sizeof(s->data_in)) {
wm8750_in_load(s);
if (s->idx_in >= sizeof(s->data_in)) {
- return 0x80008000; /* silence in AUD_FMT_S16 sample format */
+ return 0x80008000; /* silence in AUDIO_FORMAT_S16 sample format */
}
}
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 8325b5e88a..7caf92532a 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -324,8 +324,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
const uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
uint64_t slba = le64_to_cpu(rw->slba);
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
- uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
- uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
+ uint64_t offset = slba << data_shift;
+ uint32_t count = nlb << data_shift;
if (unlikely(slba + nlb > ns->id_ns.nsze)) {
trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
@@ -335,7 +335,7 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
req->has_sg = false;
block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
BLOCK_ACCT_WRITE);
- req->aiocb = blk_aio_pwrite_zeroes(n->conf.blk, aio_slba, aio_nlb,
+ req->aiocb = blk_aio_pwrite_zeroes(n->conf.blk, offset, count,
BDRV_REQ_MAY_UNMAP, nvme_rw_cb, req);
return NVME_NO_COMPLETE;
}
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index bffb4c40e7..125f70b8e4 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -49,12 +49,6 @@
#include "sysemu/sysemu.h"
#include "trace.h"
-#define PFLASH_BUG(fmt, ...) \
-do { \
- fprintf(stderr, "PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
- exit(1); \
-} while(0)
-
/* #define PFLASH_DEBUG */
#ifdef PFLASH_DEBUG
#define DPRINTF(fmt, ...) \
@@ -65,12 +59,10 @@ do { \
#define DPRINTF(fmt, ...) do { } while (0)
#endif
-#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01)
-
#define PFLASH_BE 0
#define PFLASH_SECURE 1
-struct pflash_t {
+struct PFlashCFI01 {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
@@ -109,17 +101,17 @@ static const VMStateDescription vmstate_pflash = {
.minimum_version_id = 1,
.post_load = pflash_post_load,
.fields = (VMStateField[]) {
- VMSTATE_UINT8(wcycle, pflash_t),
- VMSTATE_UINT8(cmd, pflash_t),
- VMSTATE_UINT8(status, pflash_t),
- VMSTATE_UINT64(counter, pflash_t),
+ VMSTATE_UINT8(wcycle, PFlashCFI01),
+ VMSTATE_UINT8(cmd, PFlashCFI01),
+ VMSTATE_UINT8(status, PFlashCFI01),
+ VMSTATE_UINT64(counter, PFlashCFI01),
VMSTATE_END_OF_LIST()
}
};
static void pflash_timer (void *opaque)
{
- pflash_t *pfl = opaque;
+ PFlashCFI01 *pfl = opaque;
trace_pflash_timer_expired(pfl->cmd);
/* Reset flash */
@@ -133,7 +125,7 @@ static void pflash_timer (void *opaque)
* If this code is called we know we have a device_width set for
* this flash.
*/
-static uint32_t pflash_cfi_query(pflash_t *pfl, hwaddr offset)
+static uint32_t pflash_cfi_query(PFlashCFI01 *pfl, hwaddr offset)
{
int i;
uint32_t resp = 0;
@@ -193,7 +185,7 @@ static uint32_t pflash_cfi_query(pflash_t *pfl, hwaddr offset)
/* Perform a device id query based on the bank width of the flash. */
-static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset)
+static uint32_t pflash_devid_query(PFlashCFI01 *pfl, hwaddr offset)
{
int i;
uint32_t resp;
@@ -241,7 +233,7 @@ static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset)
return resp;
}
-static uint32_t pflash_data_read(pflash_t *pfl, hwaddr offset,
+static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
int width, int be)
{
uint8_t *p;
@@ -284,8 +276,8 @@ static uint32_t pflash_data_read(pflash_t *pfl, hwaddr offset,
return ret;
}
-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
- int width, int be)
+static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
+ int width, int be)
{
hwaddr boff;
uint32_t ret;
@@ -398,7 +390,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
}
/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
+static void pflash_update(PFlashCFI01 *pfl, int offset,
int size)
{
int offset_end;
@@ -412,7 +404,7 @@ static void pflash_update(pflash_t *pfl, int offset,
}
}
-static inline void pflash_data_write(pflash_t *pfl, hwaddr offset,
+static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
uint32_t value, int width, int be)
{
uint8_t *p = pfl->storage;
@@ -448,7 +440,7 @@ static inline void pflash_data_write(pflash_t *pfl, hwaddr offset,
}
-static void pflash_write(pflash_t *pfl, hwaddr offset,
+static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
uint32_t value, int width, int be)
{
uint8_t *p;
@@ -507,6 +499,10 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
break;
case 0xe8: /* Write to buffer */
DPRINTF("%s: Write to buffer\n", __func__);
+ /* FIXME should save @offset, @width for case 1+ */
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Write to buffer emulation is flawed\n",
+ __func__);
pfl->status |= 0x80; /* Ready! */
break;
case 0xf0: /* Probe for AMD flash */
@@ -550,6 +546,7 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
/* Mask writeblock size based on device width, or bank width if
* device width not specified.
*/
+ /* FIXME check @offset, @width */
if (pfl->device_width) {
value = extract32(value, 0, pfl->device_width * 8);
} else {
@@ -587,7 +584,13 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
case 2:
switch (pfl->cmd) {
case 0xe8: /* Block write */
+ /* FIXME check @offset, @width */
if (!pfl->ro) {
+ /*
+ * FIXME writing straight to memory is *wrong*. We
+ * should write to a buffer, and flush it to memory
+ * only on confirm command (see below).
+ */
pflash_data_write(pfl, offset, value, width, be);
} else {
pfl->status |= 0x10; /* Programming error */
@@ -603,6 +606,7 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
pfl->wcycle++;
if (!pfl->ro) {
/* Flush the entire write buffer onto backing storage. */
+ /* FIXME premature! */
pflash_update(pfl, offset & mask, pfl->writeblock_size);
} else {
pfl->status |= 0x10; /* Programming error */
@@ -619,11 +623,15 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
switch (pfl->cmd) {
case 0xe8: /* Block write */
if (cmd == 0xd0) {
+ /* FIXME this is where we should write out the buffer */
pfl->wcycle = 0;
pfl->status |= 0x80;
} else {
- DPRINTF("%s: unknown command for \"write block\"\n", __func__);
- PFLASH_BUG("Write block confirm");
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Aborting write to buffer not implemented,"
+ " the data is already written to storage!\n"
+ "Flash device reset into READ mode.\n",
+ __func__);
goto reset_flash;
}
break;
@@ -654,7 +662,7 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value,
unsigned len, MemTxAttrs attrs)
{
- pflash_t *pfl = opaque;
+ PFlashCFI01 *pfl = opaque;
bool be = !!(pfl->features & (1 << PFLASH_BE));
if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
@@ -668,7 +676,7 @@ static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_
static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value,
unsigned len, MemTxAttrs attrs)
{
- pflash_t *pfl = opaque;
+ PFlashCFI01 *pfl = opaque;
bool be = !!(pfl->features & (1 << PFLASH_BE));
if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
@@ -687,7 +695,7 @@ static const MemoryRegionOps pflash_cfi01_ops = {
static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
{
- pflash_t *pfl = CFI_PFLASH01(dev);
+ PFlashCFI01 *pfl = PFLASH_CFI01(dev);
uint64_t total_len;
int ret;
uint64_t blocks_per_device, sector_len_per_device, device_len;
@@ -864,14 +872,14 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
}
static Property pflash_cfi01_properties[] = {
- DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
+ 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.
* If we're emulating flash devices wired in parallel the actual
* number of blocks per indvidual device will differ.
*/
- DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
- DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
+ DEFINE_PROP_UINT32("num-blocks", PFlashCFI01, nb_blocs, 0),
+ DEFINE_PROP_UINT64("sector-length", PFlashCFI01, sector_len, 0),
/* width here is the overall width of this QEMU device in bytes.
* The QEMU device may be emulating a number of flash devices
* wired up in parallel; the width of each individual flash
@@ -888,17 +896,17 @@ static Property pflash_cfi01_properties[] = {
* 16 bit devices making up a 32 bit wide QEMU device. This
* is deprecated for new uses of this device.
*/
- DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0),
- DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0),
- DEFINE_PROP_UINT8("max-device-width", struct pflash_t, max_device_width, 0),
- DEFINE_PROP_BIT("big-endian", struct pflash_t, features, PFLASH_BE, 0),
- DEFINE_PROP_BIT("secure", struct pflash_t, features, PFLASH_SECURE, 0),
- DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
- DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
- DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
- DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
- DEFINE_PROP_STRING("name", struct pflash_t, name),
- DEFINE_PROP_BOOL("old-multiple-chip-handling", struct pflash_t,
+ DEFINE_PROP_UINT8("width", PFlashCFI01, bank_width, 0),
+ DEFINE_PROP_UINT8("device-width", PFlashCFI01, device_width, 0),
+ DEFINE_PROP_UINT8("max-device-width", PFlashCFI01, max_device_width, 0),
+ DEFINE_PROP_BIT("big-endian", PFlashCFI01, features, PFLASH_BE, 0),
+ DEFINE_PROP_BIT("secure", PFlashCFI01, features, PFLASH_SECURE, 0),
+ DEFINE_PROP_UINT16("id0", PFlashCFI01, ident0, 0),
+ DEFINE_PROP_UINT16("id1", PFlashCFI01, ident1, 0),
+ DEFINE_PROP_UINT16("id2", PFlashCFI01, ident2, 0),
+ DEFINE_PROP_UINT16("id3", PFlashCFI01, ident3, 0),
+ DEFINE_PROP_STRING("name", PFlashCFI01, name),
+ DEFINE_PROP_BOOL("old-multiple-chip-handling", PFlashCFI01,
old_multiple_chip_handling, false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -915,9 +923,9 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
static const TypeInfo pflash_cfi01_info = {
- .name = TYPE_CFI_PFLASH01,
+ .name = TYPE_PFLASH_CFI01,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct pflash_t),
+ .instance_size = sizeof(PFlashCFI01),
.class_init = pflash_cfi01_class_init,
};
@@ -928,20 +936,23 @@ static void pflash_cfi01_register_types(void)
type_init(pflash_cfi01_register_types)
-pflash_t *pflash_cfi01_register(hwaddr base,
- DeviceState *qdev, const char *name,
- hwaddr size,
- BlockBackend *blk,
- uint32_t sector_len, int nb_blocs,
- int bank_width, uint16_t id0, uint16_t id1,
- uint16_t id2, uint16_t id3, int be)
+PFlashCFI01 *pflash_cfi01_register(hwaddr base,
+ const char *name,
+ hwaddr size,
+ BlockBackend *blk,
+ uint32_t sector_len,
+ int bank_width,
+ uint16_t id0, uint16_t id1,
+ uint16_t id2, uint16_t id3,
+ int be)
{
- DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01);
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
if (blk) {
qdev_prop_set_drive(dev, "drive", blk, &error_abort);
}
- qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
+ assert(size % sector_len == 0);
+ qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
qdev_prop_set_uint64(dev, "sector-length", sector_len);
qdev_prop_set_uint8(dev, "width", bank_width);
qdev_prop_set_bit(dev, "big-endian", !!be);
@@ -953,17 +964,22 @@ pflash_t *pflash_cfi01_register(hwaddr base,
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- return CFI_PFLASH01(dev);
+ return PFLASH_CFI01(dev);
+}
+
+BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl)
+{
+ return fl->blk;
}
-MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
+MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl)
{
return &fl->mem;
}
static void postload_update_cb(void *opaque, int running, RunState state)
{
- pflash_t *pfl = opaque;
+ PFlashCFI01 *pfl = opaque;
/* This is called after bdrv_invalidate_cache_all. */
qemu_del_vm_change_state_handler(pfl->vmstate);
@@ -975,7 +991,7 @@ static void postload_update_cb(void *opaque, int running, RunState state)
static int pflash_post_load(void *opaque, int version_id)
{
- pflash_t *pfl = opaque;
+ PFlashCFI01 *pfl = opaque;
if (!pfl->ro) {
pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 1588aeff5a..c9db430611 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -57,9 +57,7 @@ do { \
#define PFLASH_LAZY_ROMD_THRESHOLD 42
-#define CFI_PFLASH02(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH02)
-
-struct pflash_t {
+struct PFlashCFI02 {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
@@ -101,7 +99,7 @@ struct pflash_t {
/*
* Set up replicated mappings of the same region.
*/
-static void pflash_setup_mappings(pflash_t *pfl)
+static void pflash_setup_mappings(PFlashCFI02 *pfl)
{
unsigned i;
hwaddr size = memory_region_size(&pfl->orig_mem);
@@ -115,7 +113,7 @@ static void pflash_setup_mappings(pflash_t *pfl)
}
}
-static void pflash_register_memory(pflash_t *pfl, int rom_mode)
+static void pflash_register_memory(PFlashCFI02 *pfl, int rom_mode)
{
memory_region_rom_device_set_romd(&pfl->orig_mem, rom_mode);
pfl->rom_mode = rom_mode;
@@ -123,7 +121,7 @@ static void pflash_register_memory(pflash_t *pfl, int rom_mode)
static void pflash_timer (void *opaque)
{
- pflash_t *pfl = opaque;
+ PFlashCFI02 *pfl = opaque;
trace_pflash_timer_expired(pfl->cmd);
/* Reset flash */
@@ -137,8 +135,8 @@ static void pflash_timer (void *opaque)
pfl->cmd = 0;
}
-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
- int width, int be)
+static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
+ int width, int be)
{
hwaddr boff;
uint32_t ret;
@@ -246,7 +244,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
}
/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
+static void pflash_update(PFlashCFI02 *pfl, int offset,
int size)
{
int offset_end;
@@ -260,8 +258,8 @@ static void pflash_update(pflash_t *pfl, int offset,
}
}
-static void pflash_write (pflash_t *pfl, hwaddr offset,
- uint32_t value, int width, int be)
+static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
+ uint32_t value, int width, int be)
{
hwaddr boff;
uint8_t *p;
@@ -533,7 +531,7 @@ static const MemoryRegionOps pflash_cfi02_ops_le = {
static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
{
- pflash_t *pfl = CFI_PFLASH02(dev);
+ PFlashCFI02 *pfl = PFLASH_CFI02(dev);
uint32_t chip_len;
int ret;
Error *local_err = NULL;
@@ -679,25 +677,25 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
}
static Property pflash_cfi02_properties[] = {
- DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
- DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
- DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
- DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
- DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0),
- DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
- DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
- DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
- DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
- DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
- DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0),
- DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0),
- DEFINE_PROP_STRING("name", struct pflash_t, name),
+ DEFINE_PROP_DRIVE("drive", PFlashCFI02, blk),
+ DEFINE_PROP_UINT32("num-blocks", PFlashCFI02, nb_blocs, 0),
+ DEFINE_PROP_UINT32("sector-length", PFlashCFI02, sector_len, 0),
+ DEFINE_PROP_UINT8("width", PFlashCFI02, width, 0),
+ DEFINE_PROP_UINT8("mappings", PFlashCFI02, mappings, 0),
+ DEFINE_PROP_UINT8("big-endian", PFlashCFI02, be, 0),
+ DEFINE_PROP_UINT16("id0", PFlashCFI02, ident0, 0),
+ DEFINE_PROP_UINT16("id1", PFlashCFI02, ident1, 0),
+ DEFINE_PROP_UINT16("id2", PFlashCFI02, ident2, 0),
+ DEFINE_PROP_UINT16("id3", PFlashCFI02, ident3, 0),
+ 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, Error **errp)
{
- pflash_t *pfl = CFI_PFLASH02(dev);
+ PFlashCFI02 *pfl = PFLASH_CFI02(dev);
timer_del(&pfl->timer);
}
@@ -712,9 +710,9 @@ static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo pflash_cfi02_info = {
- .name = TYPE_CFI_PFLASH02,
+ .name = TYPE_PFLASH_CFI02,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct pflash_t),
+ .instance_size = sizeof(PFlashCFI02),
.class_init = pflash_cfi02_class_init,
};
@@ -725,22 +723,25 @@ static void pflash_cfi02_register_types(void)
type_init(pflash_cfi02_register_types)
-pflash_t *pflash_cfi02_register(hwaddr base,
- DeviceState *qdev, const char *name,
- hwaddr size,
- BlockBackend *blk, uint32_t sector_len,
- int nb_blocs, int nb_mappings, int width,
- uint16_t id0, uint16_t id1,
- uint16_t id2, uint16_t id3,
- uint16_t unlock_addr0, uint16_t unlock_addr1,
- int be)
+PFlashCFI02 *pflash_cfi02_register(hwaddr base,
+ const char *name,
+ hwaddr size,
+ BlockBackend *blk,
+ uint32_t sector_len,
+ int nb_mappings, int width,
+ uint16_t id0, uint16_t id1,
+ uint16_t id2, uint16_t id3,
+ uint16_t unlock_addr0,
+ uint16_t unlock_addr1,
+ int be)
{
- DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02);
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI02);
if (blk) {
qdev_prop_set_drive(dev, "drive", blk, &error_abort);
}
- qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
+ assert(size % sector_len == 0);
+ qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
qdev_prop_set_uint32(dev, "sector-length", sector_len);
qdev_prop_set_uint8(dev, "width", width);
qdev_prop_set_uint8(dev, "mappings", nb_mappings);
@@ -755,5 +756,5 @@ pflash_t *pflash_cfi02_register(hwaddr base,
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- return CFI_PFLASH02(dev);
+ return PFLASH_CFI02(dev);
}
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 44ac814016..28b81368f7 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -128,6 +128,21 @@ static void vhost_user_blk_start(VirtIODevice *vdev)
}
s->dev.acked_features = vdev->guest_features;
+
+ if (!s->inflight->addr) {
+ ret = vhost_dev_get_inflight(&s->dev, s->queue_size, s->inflight);
+ if (ret < 0) {
+ error_report("Error get inflight: %d", -ret);
+ goto err_guest_notifiers;
+ }
+ }
+
+ ret = vhost_dev_set_inflight(&s->dev, s->inflight);
+ if (ret < 0) {
+ error_report("Error set inflight: %d", -ret);
+ goto err_guest_notifiers;
+ }
+
ret = vhost_dev_start(&s->dev, vdev);
if (ret < 0) {
error_report("Error starting vhost: %d", -ret);
@@ -249,11 +264,17 @@ static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
}
}
+static void vhost_user_blk_reset(VirtIODevice *vdev)
+{
+ VHostUserBlk *s = VHOST_USER_BLK(vdev);
+
+ vhost_dev_free_inflight(s->inflight);
+}
+
static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
- VhostUserState *user;
struct vhost_virtqueue *vqs = NULL;
int i, ret;
@@ -272,15 +293,10 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
return;
}
- user = vhost_user_init();
- if (!user) {
- error_setg(errp, "vhost-user-blk: failed to init vhost_user");
+ if (!vhost_user_init(&s->vhost_user, &s->chardev, errp)) {
return;
}
- user->chr = &s->chardev;
- s->vhost_user = user;
-
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
sizeof(struct virtio_blk_config));
@@ -289,6 +305,8 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
vhost_user_blk_handle_output);
}
+ s->inflight = g_new0(struct vhost_inflight, 1);
+
s->dev.nvqs = s->num_queues;
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
s->dev.vq_index = 0;
@@ -297,7 +315,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
- ret = vhost_dev_init(&s->dev, s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
+ ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
if (ret < 0) {
error_setg(errp, "vhost-user-blk: vhost initialization failed: %s",
strerror(-ret));
@@ -321,11 +339,9 @@ vhost_err:
vhost_dev_cleanup(&s->dev);
virtio_err:
g_free(vqs);
+ g_free(s->inflight);
virtio_cleanup(vdev);
-
- vhost_user_cleanup(user);
- g_free(user);
- s->vhost_user = NULL;
+ vhost_user_cleanup(&s->vhost_user);
}
static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
@@ -336,14 +352,11 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
vhost_user_blk_set_status(vdev, 0);
vhost_dev_cleanup(&s->dev);
+ vhost_dev_free_inflight(s->inflight);
g_free(vqs);
+ g_free(s->inflight);
virtio_cleanup(vdev);
-
- if (s->vhost_user) {
- vhost_user_cleanup(s->vhost_user);
- g_free(s->vhost_user);
- s->vhost_user = NULL;
- }
+ vhost_user_cleanup(&s->vhost_user);
}
static void vhost_user_blk_instance_init(Object *obj)
@@ -386,6 +399,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data)
vdc->set_config = vhost_user_blk_set_config;
vdc->get_features = vhost_user_blk_get_features;
vdc->set_status = vhost_user_blk_set_status;
+ vdc->reset = vhost_user_blk_reset;
}
static const TypeInfo vhost_user_blk_info = {
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 6748334ded..617303dbaf 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -10,27 +10,27 @@
#define VTERM_BUFSIZE 16
-typedef struct VIOsPAPRVTYDevice {
- VIOsPAPRDevice sdev;
+typedef struct SpaprVioVty {
+ SpaprVioDevice sdev;
CharBackend chardev;
uint32_t in, out;
uint8_t buf[VTERM_BUFSIZE];
-} VIOsPAPRVTYDevice;
+} SpaprVioVty;
#define TYPE_VIO_SPAPR_VTY_DEVICE "spapr-vty"
#define VIO_SPAPR_VTY_DEVICE(obj) \
- OBJECT_CHECK(VIOsPAPRVTYDevice, (obj), TYPE_VIO_SPAPR_VTY_DEVICE)
+ OBJECT_CHECK(SpaprVioVty, (obj), TYPE_VIO_SPAPR_VTY_DEVICE)
static int vty_can_receive(void *opaque)
{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque);
+ SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(opaque);
return VTERM_BUFSIZE - (dev->in - dev->out);
}
static void vty_receive(void *opaque, const uint8_t *buf, int size)
{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque);
+ SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(opaque);
int i;
if ((dev->in == dev->out) && size) {
@@ -51,9 +51,9 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
}
}
-static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
+static int vty_getchars(SpaprVioDevice *sdev, uint8_t *buf, int max)
{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
+ SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(sdev);
int n = 0;
while ((n < max) && (dev->out != dev->in)) {
@@ -83,18 +83,18 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
return n;
}
-void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+void vty_putchars(SpaprVioDevice *sdev, uint8_t *buf, int len)
{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
+ SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(sdev);
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&dev->chardev, buf, len);
}
-static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
+static void spapr_vty_realize(SpaprVioDevice *sdev, Error **errp)
{
- VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
+ SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(sdev);
if (!qemu_chr_fe_backend_connected(&dev->chardev)) {
error_setg(errp, "chardev property not set");
@@ -106,14 +106,14 @@ static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
}
/* Forward declaration */
-static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_put_term_char(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
target_ulong len = args[1];
target_ulong char0_7 = args[2];
target_ulong char8_15 = args[3];
- VIOsPAPRDevice *sdev;
+ SpaprVioDevice *sdev;
uint8_t buf[16];
sdev = vty_lookup(spapr, reg);
@@ -133,14 +133,14 @@ static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_get_term_char(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
target_ulong *len = args + 0;
target_ulong *char0_7 = args + 1;
target_ulong *char8_15 = args + 2;
- VIOsPAPRDevice *sdev;
+ SpaprVioDevice *sdev;
uint8_t buf[16];
sdev = vty_lookup(spapr, reg);
@@ -159,7 +159,7 @@ static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-void spapr_vty_create(VIOsPAPRBus *bus, Chardev *chardev)
+void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev)
{
DeviceState *dev;
@@ -169,8 +169,8 @@ void spapr_vty_create(VIOsPAPRBus *bus, Chardev *chardev)
}
static Property spapr_vty_properties[] = {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev),
- DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+ DEFINE_SPAPR_PROPERTIES(SpaprVioVty, sdev),
+ DEFINE_PROP_CHR("chardev", SpaprVioVty, chardev),
DEFINE_PROP_END_OF_LIST(),
};
@@ -179,11 +179,11 @@ static const VMStateDescription vmstate_spapr_vty = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVTYDevice),
+ VMSTATE_SPAPR_VIO(sdev, SpaprVioVty),
- VMSTATE_UINT32(in, VIOsPAPRVTYDevice),
- VMSTATE_UINT32(out, VIOsPAPRVTYDevice),
- VMSTATE_BUFFER(buf, VIOsPAPRVTYDevice),
+ VMSTATE_UINT32(in, SpaprVioVty),
+ VMSTATE_UINT32(out, SpaprVioVty),
+ VMSTATE_BUFFER(buf, SpaprVioVty),
VMSTATE_END_OF_LIST()
},
};
@@ -191,7 +191,7 @@ static const VMStateDescription vmstate_spapr_vty = {
static void spapr_vty_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->realize = spapr_vty_realize;
k->dt_name = "vty";
@@ -205,13 +205,13 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data)
static const TypeInfo spapr_vty_info = {
.name = TYPE_VIO_SPAPR_VTY_DEVICE,
.parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(VIOsPAPRVTYDevice),
+ .instance_size = sizeof(SpaprVioVty),
.class_init = spapr_vty_class_init,
};
-VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
+SpaprVioDevice *spapr_vty_get_default(SpaprVioBus *bus)
{
- VIOsPAPRDevice *sdev, *selected;
+ SpaprVioDevice *sdev, *selected;
BusChild *kid;
/*
@@ -246,9 +246,9 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
return selected;
}
-VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg)
+SpaprVioDevice *vty_lookup(SpaprMachineState *spapr, target_ulong reg)
{
- VIOsPAPRDevice *sdev;
+ SpaprVioDevice *sdev;
sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!sdev && reg == 0) {
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 766ca5899d..743fef2898 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -22,6 +22,7 @@
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
#include "hw/pci/pci.h"
+#include "hw/mem/nvdimm.h"
GlobalProperty hw_compat_3_1[] = {
{ "pcie-root-port", "x-speed", "2_5" },
@@ -481,6 +482,47 @@ static void machine_set_memory_encryption(Object *obj, const char *value,
ms->memory_encryption = g_strdup(value);
}
+static bool machine_get_nvdimm(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return ms->nvdimms_state->is_enabled;
+}
+
+static void machine_set_nvdimm(Object *obj, bool value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ ms->nvdimms_state->is_enabled = value;
+}
+
+static char *machine_get_nvdimm_persistence(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return g_strdup(ms->nvdimms_state->persistence_string);
+}
+
+static void machine_set_nvdimm_persistence(Object *obj, const char *value,
+ Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ NVDIMMState *nvdimms_state = ms->nvdimms_state;
+
+ if (strcmp(value, "cpu") == 0) {
+ nvdimms_state->persistence = 3;
+ } else if (strcmp(value, "mem-ctrl") == 0) {
+ nvdimms_state->persistence = 2;
+ } else {
+ error_setg(errp, "-machine nvdimm-persistence=%s: unsupported option",
+ value);
+ return;
+ }
+
+ g_free(nvdimms_state->persistence_string);
+ nvdimms_state->persistence_string = g_strdup(value);
+}
+
void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
{
strList *item = g_new0(strList, 1);
@@ -791,6 +833,28 @@ static void machine_initfn(Object *obj)
ms->mem_merge = true;
ms->enable_graphics = true;
+ if (mc->nvdimm_supported) {
+ Object *obj = OBJECT(ms);
+
+ ms->nvdimms_state = g_new0(NVDIMMState, 1);
+ object_property_add_bool(obj, "nvdimm",
+ machine_get_nvdimm, machine_set_nvdimm,
+ &error_abort);
+ object_property_set_description(obj, "nvdimm",
+ "Set on/off to enable/disable "
+ "NVDIMM instantiation", NULL);
+
+ object_property_add_str(obj, "nvdimm-persistence",
+ machine_get_nvdimm_persistence,
+ machine_set_nvdimm_persistence,
+ &error_abort);
+ object_property_set_description(obj, "nvdimm-persistence",
+ "Set NVDIMM persistence"
+ "Valid values are cpu, mem-ctrl",
+ NULL);
+ }
+
+
/* Register notifier when init is done for sysbus sanity checks */
ms->sysbus_notifier.notify = machine_init_notify;
qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
@@ -809,6 +873,7 @@ static void machine_finalize(Object *obj)
g_free(ms->dt_compatible);
g_free(ms->firmware);
g_free(ms->device_memory);
+ g_free(ms->nvdimms_state);
}
bool machine_usb(MachineState *machine)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 512ce7ca7a..f9b6efe509 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -978,25 +978,12 @@ static void device_initfn(Object *obj)
QLIST_INIT(&dev->gpios);
}
-void object_apply_compat_props(Object *obj)
-{
- if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
- MachineState *m = MACHINE(qdev_get_machine());
- MachineClass *mc = MACHINE_GET_CLASS(m);
-
- if (m->accelerator) {
- AccelClass *ac = ACCEL_GET_CLASS(m->accelerator);
-
- if (ac->compat_props) {
- object_apply_global_props(obj, ac->compat_props, &error_abort);
- }
- }
- object_apply_global_props(obj, mc->compat_props, &error_abort);
- }
-}
-
static void device_post_init(Object *obj)
{
+ /*
+ * Note: ordered so that the user's global properties take
+ * precedence.
+ */
object_apply_compat_props(obj);
qdev_prop_set_globals(DEVICE(obj));
}
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 9f9edbcab9..307cf90a51 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -357,9 +357,6 @@ static void main_system_bus_create(void)
qbus_create_inplace(main_system_bus, system_bus_info.instance_size,
TYPE_SYSTEM_BUS, NULL, "main-system-bus");
OBJECT(main_system_bus)->free = g_free;
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
- "sysbus", OBJECT(main_system_bus), NULL);
}
BusState *sysbus_get_default(void)
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index cc0f9bc9cc..11b09bd18c 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -1260,7 +1260,7 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp)
as.freq = 44100;
as.nchannels = 2;
- as.fmt = AUD_FMT_S16;
+ as.fmt = AUDIO_FORMAT_S16;
as.endianness = 0;
AUD_register_card("xlnx_dp.audio", &s->aud_card);
diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig
index ef1caa6d89..820b24de5b 100644
--- a/hw/i2c/Kconfig
+++ b/hw/i2c/Kconfig
@@ -25,3 +25,7 @@ config BITBANG_I2C
config IMX_I2C
bool
select I2C
+
+config MPC_I2C
+ bool
+ select I2C
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 2a3c106551..5f76b6a990 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -9,5 +9,6 @@ common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
common-obj-$(CONFIG_NRF51_SOC) += microbit_i2c.o
+common-obj-$(CONFIG_MPC_I2C) += mpc_i2c.o
obj-$(CONFIG_OMAP) += omap_i2c.o
obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c
new file mode 100644
index 0000000000..693ca7ef6b
--- /dev/null
+++ b/hw/i2c/mpc_i2c.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Amit Tomar, <Amit.Tomar@freescale.com>
+ *
+ * Description:
+ * This file is derived from IMX I2C controller,
+ * by Jean-Christophe DUBOIS .
+ *
+ * Thanks to Scott Wood and Alexander Graf for their kind help on this.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 or later,
+ * as published by the Free Software Foundation.
+ *
+ * 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 "hw/i2c/i2c.h"
+#include "qemu/log.h"
+#include "hw/sysbus.h"
+
+/* #define DEBUG_I2C */
+
+#ifdef DEBUG_I2C
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stderr, "mpc_i2c[%s]: " fmt, __func__, ## __VA_ARGS__); \
+ } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define TYPE_MPC_I2C "mpc-i2c"
+#define MPC_I2C(obj) \
+ OBJECT_CHECK(MPCI2CState, (obj), TYPE_MPC_I2C)
+
+#define MPC_I2C_ADR 0x00
+#define MPC_I2C_FDR 0x04
+#define MPC_I2C_CR 0x08
+#define MPC_I2C_SR 0x0c
+#define MPC_I2C_DR 0x10
+#define MPC_I2C_DFSRR 0x14
+
+#define CCR_MEN (1 << 7)
+#define CCR_MIEN (1 << 6)
+#define CCR_MSTA (1 << 5)
+#define CCR_MTX (1 << 4)
+#define CCR_TXAK (1 << 3)
+#define CCR_RSTA (1 << 2)
+#define CCR_BCST (1 << 0)
+
+#define CSR_MCF (1 << 7)
+#define CSR_MAAS (1 << 6)
+#define CSR_MBB (1 << 5)
+#define CSR_MAL (1 << 4)
+#define CSR_SRW (1 << 2)
+#define CSR_MIF (1 << 1)
+#define CSR_RXAK (1 << 0)
+
+#define CADR_MASK 0xFE
+#define CFDR_MASK 0x3F
+#define CCR_MASK 0xFC
+#define CSR_MASK 0xED
+#define CDR_MASK 0xFF
+
+#define CYCLE_RESET 0xFF
+
+typedef struct MPCI2CState {
+ SysBusDevice parent_obj;
+
+ I2CBus *bus;
+ qemu_irq irq;
+ MemoryRegion iomem;
+
+ uint8_t address;
+ uint8_t adr;
+ uint8_t fdr;
+ uint8_t cr;
+ uint8_t sr;
+ uint8_t dr;
+ uint8_t dfssr;
+} MPCI2CState;
+
+static bool mpc_i2c_is_enabled(MPCI2CState *s)
+{
+ return s->cr & CCR_MEN;
+}
+
+static bool mpc_i2c_is_master(MPCI2CState *s)
+{
+ return s->cr & CCR_MSTA;
+}
+
+static bool mpc_i2c_direction_is_tx(MPCI2CState *s)
+{
+ return s->cr & CCR_MTX;
+}
+
+static bool mpc_i2c_irq_pending(MPCI2CState *s)
+{
+ return s->sr & CSR_MIF;
+}
+
+static bool mpc_i2c_irq_is_enabled(MPCI2CState *s)
+{
+ return s->cr & CCR_MIEN;
+}
+
+static void mpc_i2c_reset(DeviceState *dev)
+{
+ MPCI2CState *i2c = MPC_I2C(dev);
+
+ i2c->address = 0xFF;
+ i2c->adr = 0x00;
+ i2c->fdr = 0x00;
+ i2c->cr = 0x00;
+ i2c->sr = 0x81;
+ i2c->dr = 0x00;
+}
+
+static void mpc_i2c_irq(MPCI2CState *s)
+{
+ bool irq_active = false;
+
+ if (mpc_i2c_is_enabled(s) && mpc_i2c_irq_is_enabled(s)
+ && mpc_i2c_irq_pending(s)) {
+ irq_active = true;
+ }
+
+ if (irq_active) {
+ qemu_irq_raise(s->irq);
+ } else {
+ qemu_irq_lower(s->irq);
+ }
+}
+
+static void mpc_i2c_soft_reset(MPCI2CState *s)
+{
+ /* This is a soft reset. ADR is preserved during soft resets */
+ uint8_t adr = s->adr;
+ mpc_i2c_reset(DEVICE(s));
+ s->adr = adr;
+}
+
+static void mpc_i2c_address_send(MPCI2CState *s)
+{
+ /* if returns non zero slave address is not right */
+ if (i2c_start_transfer(s->bus, s->dr >> 1, s->dr & (0x01))) {
+ s->sr |= CSR_RXAK;
+ } else {
+ s->address = s->dr;
+ s->sr &= ~CSR_RXAK;
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ }
+}
+
+static void mpc_i2c_data_send(MPCI2CState *s)
+{
+ if (i2c_send(s->bus, s->dr)) {
+ /* End of transfer */
+ s->sr |= CSR_RXAK;
+ i2c_end_transfer(s->bus);
+ } else {
+ s->sr &= ~CSR_RXAK;
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ }
+}
+
+static void mpc_i2c_data_recive(MPCI2CState *s)
+{
+ int ret;
+ /* get the next byte */
+ ret = i2c_recv(s->bus);
+ if (ret >= 0) {
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ } else {
+ DPRINTF("read failed for device");
+ ret = 0xff;
+ }
+ s->dr = ret;
+}
+
+static uint64_t mpc_i2c_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MPCI2CState *s = opaque;
+ uint8_t value;
+
+ switch (addr) {
+ case MPC_I2C_ADR:
+ value = s->adr;
+ break;
+ case MPC_I2C_FDR:
+ value = s->fdr;
+ break;
+ case MPC_I2C_CR:
+ value = s->cr;
+ break;
+ case MPC_I2C_SR:
+ value = s->sr;
+ break;
+ case MPC_I2C_DR:
+ value = s->dr;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ if (mpc_i2c_direction_is_tx(s)) {
+ DPRINTF("MTX is set not in recv mode\n");
+ } else {
+ mpc_i2c_data_recive(s);
+ }
+ }
+ break;
+ default:
+ value = 0;
+ DPRINTF("ERROR: Bad read addr 0x%x\n", (unsigned int)addr);
+ break;
+ }
+
+ DPRINTF("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__,
+ addr, value);
+ return (uint64_t)value;
+}
+
+static void mpc_i2c_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ MPCI2CState *s = opaque;
+
+ DPRINTF("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", __func__,
+ addr, value);
+ switch (addr) {
+ case MPC_I2C_ADR:
+ s->adr = value & CADR_MASK;
+ break;
+ case MPC_I2C_FDR:
+ s->fdr = value & CFDR_MASK;
+ break;
+ case MPC_I2C_CR:
+ if (mpc_i2c_is_enabled(s) && ((value & CCR_MEN) == 0)) {
+ mpc_i2c_soft_reset(s);
+ break;
+ }
+ /* normal write */
+ s->cr = value & CCR_MASK;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ /* set the bus to busy after master is set as per RM */
+ s->sr |= CSR_MBB;
+ } else {
+ /* bus is not busy anymore */
+ s->sr &= ~CSR_MBB;
+ /* Reset the address for fresh write/read cycle */
+ if (s->address != CYCLE_RESET) {
+ i2c_end_transfer(s->bus);
+ s->address = CYCLE_RESET;
+ }
+ }
+ /* For restart end the onging transfer */
+ if (s->cr & CCR_RSTA) {
+ if (s->address != CYCLE_RESET) {
+ s->address = CYCLE_RESET;
+ i2c_end_transfer(s->bus);
+ s->cr &= ~CCR_RSTA;
+ }
+ }
+ break;
+ case MPC_I2C_SR:
+ s->sr = value & CSR_MASK;
+ /* Lower the interrupt */
+ if (!(s->sr & CSR_MIF) || !(s->sr & CSR_MAL)) {
+ mpc_i2c_irq(s);
+ }
+ break;
+ case MPC_I2C_DR:
+ /* if the device is not enabled, nothing to do */
+ if (!mpc_i2c_is_enabled(s)) {
+ break;
+ }
+ s->dr = value & CDR_MASK;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ if (s->address == CYCLE_RESET) {
+ mpc_i2c_address_send(s);
+ } else {
+ mpc_i2c_data_send(s);
+ }
+ }
+ break;
+ case MPC_I2C_DFSRR:
+ s->dfssr = value;
+ break;
+ default:
+ DPRINTF("ERROR: Bad write addr 0x%x\n", (unsigned int)addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps i2c_ops = {
+ .read = mpc_i2c_read,
+ .write = mpc_i2c_write,
+ .valid.max_access_size = 1,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription mpc_i2c_vmstate = {
+ .name = TYPE_MPC_I2C,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(address, MPCI2CState),
+ VMSTATE_UINT8(adr, MPCI2CState),
+ VMSTATE_UINT8(fdr, MPCI2CState),
+ VMSTATE_UINT8(cr, MPCI2CState),
+ VMSTATE_UINT8(sr, MPCI2CState),
+ VMSTATE_UINT8(dr, MPCI2CState),
+ VMSTATE_UINT8(dfssr, MPCI2CState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void mpc_i2c_realize(DeviceState *dev, Error **errp)
+{
+ MPCI2CState *i2c = MPC_I2C(dev);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
+ memory_region_init_io(&i2c->iomem, OBJECT(i2c), &i2c_ops, i2c,
+ "mpc-i2c", 0x14);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->iomem);
+ i2c->bus = i2c_init_bus(DEVICE(dev), "i2c");
+}
+
+static void mpc_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &mpc_i2c_vmstate ;
+ dc->reset = 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 void mpc_i2c_register_types(void)
+{
+ type_register_static(&mpc_i2c_type_info);
+}
+
+type_init(mpc_i2c_register_types)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 9ecc96dcc7..416da318ae 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1867,7 +1867,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(scope, method);
}
- if (pcms->acpi_nvdimm_state.is_enabled) {
+ if (machine->nvdimms_state->is_enabled) {
method = aml_method("_E04", 0, AML_NOTSERIALIZED);
aml_append(method, aml_notify(aml_name("\\_SB.NVDR"),
aml_int(0x80)));
@@ -2704,9 +2704,9 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
build_dmar_q35(tables_blob, tables->linker);
}
}
- if (pcms->acpi_nvdimm_state.is_enabled) {
+ if (machine->nvdimms_state->is_enabled) {
nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
- &pcms->acpi_nvdimm_state, machine->ram_slots);
+ machine->nvdimms_state, machine->ram_slots);
}
/* Add tables supplied by user (if any) */
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index ee22e754f0..b90de6c664 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -37,6 +37,27 @@
#include "kvm_i386.h"
#include "trace.h"
+/* context entry operations */
+#define VTD_CE_GET_RID2PASID(ce) \
+ ((ce)->val[1] & VTD_SM_CONTEXT_ENTRY_RID2PASID_MASK)
+#define VTD_CE_GET_PASID_DIR_TABLE(ce) \
+ ((ce)->val[0] & VTD_PASID_DIR_BASE_ADDR_MASK)
+
+/* 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_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write) {\
+ if (ret_fr) { \
+ ret_fr = -ret_fr; \
+ if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) { \
+ trace_vtd_fault_disabled(); \
+ } else { \
+ vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write); \
+ } \
+ goto error; \
+ } \
+}
+
static void vtd_address_space_refresh_all(IntelIOMMUState *s);
static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n);
@@ -512,9 +533,15 @@ static void vtd_generate_completion_event(IntelIOMMUState *s)
}
}
-static inline bool vtd_root_entry_present(VTDRootEntry *root)
+static inline bool vtd_root_entry_present(IntelIOMMUState *s,
+ VTDRootEntry *re,
+ uint8_t devfn)
{
- return root->val & VTD_ROOT_ENTRY_P;
+ if (s->root_scalable && devfn > UINT8_MAX / 2) {
+ return re->hi & VTD_ROOT_ENTRY_P;
+ }
+
+ return re->lo & VTD_ROOT_ENTRY_P;
}
static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index,
@@ -524,10 +551,11 @@ static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index,
addr = s->root + index * sizeof(*re);
if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) {
- re->val = 0;
+ re->lo = 0;
return -VTD_FR_ROOT_TABLE_INV;
}
- re->val = le64_to_cpu(re->val);
+ re->lo = le64_to_cpu(re->lo);
+ re->hi = le64_to_cpu(re->hi);
return 0;
}
@@ -536,18 +564,35 @@ static inline bool vtd_ce_present(VTDContextEntry *context)
return context->lo & VTD_CONTEXT_ENTRY_P;
}
-static int vtd_get_context_entry_from_root(VTDRootEntry *root, uint8_t index,
+static int vtd_get_context_entry_from_root(IntelIOMMUState *s,
+ VTDRootEntry *re,
+ uint8_t index,
VTDContextEntry *ce)
{
- dma_addr_t addr;
+ dma_addr_t addr, ce_size;
/* we have checked that root entry is present */
- addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * sizeof(*ce);
- if (dma_memory_read(&address_space_memory, addr, ce, sizeof(*ce))) {
+ ce_size = s->root_scalable ? VTD_CTX_ENTRY_SCALABLE_SIZE :
+ VTD_CTX_ENTRY_LEGACY_SIZE;
+
+ if (s->root_scalable && index > UINT8_MAX / 2) {
+ index = index & (~VTD_DEVFN_CHECK_MASK);
+ addr = re->hi & VTD_ROOT_ENTRY_CTP;
+ } else {
+ addr = re->lo & VTD_ROOT_ENTRY_CTP;
+ }
+
+ addr = addr + index * ce_size;
+ if (dma_memory_read(&address_space_memory, addr, ce, ce_size)) {
return -VTD_FR_CONTEXT_TABLE_INV;
}
+
ce->lo = le64_to_cpu(ce->lo);
ce->hi = le64_to_cpu(ce->hi);
+ if (ce_size == VTD_CTX_ENTRY_SCALABLE_SIZE) {
+ ce->val[2] = le64_to_cpu(ce->val[2]);
+ ce->val[3] = le64_to_cpu(ce->val[3]);
+ }
return 0;
}
@@ -600,6 +645,144 @@ static inline bool vtd_is_level_supported(IntelIOMMUState *s, uint32_t level)
(1ULL << (level - 2 + VTD_CAP_SAGAW_SHIFT));
}
+/* Return true if check passed, otherwise false */
+static inline bool vtd_pe_type_check(X86IOMMUState *x86_iommu,
+ VTDPASIDEntry *pe)
+{
+ switch (VTD_PE_GET_TYPE(pe)) {
+ case VTD_SM_PASID_ENTRY_FLT:
+ case VTD_SM_PASID_ENTRY_SLT:
+ case VTD_SM_PASID_ENTRY_NESTED:
+ break;
+ case VTD_SM_PASID_ENTRY_PT:
+ if (!x86_iommu->pt_supported) {
+ return false;
+ }
+ break;
+ default:
+ /* Unknwon type */
+ return false;
+ }
+ return true;
+}
+
+static int vtd_get_pasid_dire(dma_addr_t pasid_dir_base,
+ uint32_t pasid,
+ VTDPASIDDirEntry *pdire)
+{
+ uint32_t index;
+ dma_addr_t addr, entry_size;
+
+ index = VTD_PASID_DIR_INDEX(pasid);
+ entry_size = VTD_PASID_DIR_ENTRY_SIZE;
+ addr = pasid_dir_base + index * entry_size;
+ if (dma_memory_read(&address_space_memory, addr, pdire, entry_size)) {
+ return -VTD_FR_PASID_TABLE_INV;
+ }
+
+ return 0;
+}
+
+static int vtd_get_pasid_entry(IntelIOMMUState *s,
+ uint32_t pasid,
+ VTDPASIDDirEntry *pdire,
+ VTDPASIDEntry *pe)
+{
+ uint32_t index;
+ dma_addr_t addr, entry_size;
+ X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
+
+ index = VTD_PASID_TABLE_INDEX(pasid);
+ entry_size = VTD_PASID_ENTRY_SIZE;
+ addr = pdire->val & VTD_PASID_TABLE_BASE_ADDR_MASK;
+ addr = addr + index * entry_size;
+ if (dma_memory_read(&address_space_memory, addr, pe, entry_size)) {
+ return -VTD_FR_PASID_TABLE_INV;
+ }
+
+ /* Do translation type check */
+ if (!vtd_pe_type_check(x86_iommu, pe)) {
+ return -VTD_FR_PASID_TABLE_INV;
+ }
+
+ if (!vtd_is_level_supported(s, VTD_PE_GET_LEVEL(pe))) {
+ return -VTD_FR_PASID_TABLE_INV;
+ }
+
+ return 0;
+}
+
+static int vtd_get_pasid_entry_from_pasid(IntelIOMMUState *s,
+ dma_addr_t pasid_dir_base,
+ uint32_t pasid,
+ VTDPASIDEntry *pe)
+{
+ int ret;
+ VTDPASIDDirEntry pdire;
+
+ ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
+ if (ret) {
+ return ret;
+ }
+
+ ret = vtd_get_pasid_entry(s, pasid, &pdire, pe);
+ if (ret) {
+ return ret;
+ }
+
+ return ret;
+}
+
+static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
+ VTDContextEntry *ce,
+ VTDPASIDEntry *pe)
+{
+ uint32_t pasid;
+ dma_addr_t pasid_dir_base;
+ int ret = 0;
+
+ pasid = VTD_CE_GET_RID2PASID(ce);
+ pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
+ ret = vtd_get_pasid_entry_from_pasid(s, pasid_dir_base, pasid, pe);
+
+ return ret;
+}
+
+static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
+ VTDContextEntry *ce,
+ bool *pe_fpd_set)
+{
+ int ret;
+ uint32_t pasid;
+ dma_addr_t pasid_dir_base;
+ VTDPASIDDirEntry pdire;
+ VTDPASIDEntry pe;
+
+ pasid = VTD_CE_GET_RID2PASID(ce);
+ pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
+
+ ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
+ if (ret) {
+ return ret;
+ }
+
+ if (pdire.val & VTD_PASID_DIR_FPD) {
+ *pe_fpd_set = true;
+ return 0;
+ }
+
+ ret = vtd_get_pasid_entry(s, pasid, &pdire, &pe);
+ if (ret) {
+ return ret;
+ }
+
+ if (pe.val[0] & VTD_PASID_ENTRY_FPD) {
+ *pe_fpd_set = true;
+ }
+
+ return 0;
+}
+
/* Get the page-table level that hardware should use for the second-level
* page-table walk from the Address Width field of context-entry.
*/
@@ -608,17 +791,43 @@ static inline uint32_t vtd_ce_get_level(VTDContextEntry *ce)
return 2 + (ce->hi & VTD_CONTEXT_ENTRY_AW);
}
+static uint32_t vtd_get_iova_level(IntelIOMMUState *s,
+ VTDContextEntry *ce)
+{
+ VTDPASIDEntry pe;
+
+ if (s->root_scalable) {
+ vtd_ce_get_rid2pasid_entry(s, ce, &pe);
+ return VTD_PE_GET_LEVEL(&pe);
+ }
+
+ return vtd_ce_get_level(ce);
+}
+
static inline uint32_t vtd_ce_get_agaw(VTDContextEntry *ce)
{
return 30 + (ce->hi & VTD_CONTEXT_ENTRY_AW) * 9;
}
+static uint32_t vtd_get_iova_agaw(IntelIOMMUState *s,
+ VTDContextEntry *ce)
+{
+ VTDPASIDEntry pe;
+
+ if (s->root_scalable) {
+ vtd_ce_get_rid2pasid_entry(s, ce, &pe);
+ return 30 + ((pe.val[0] >> 2) & VTD_SM_PASID_ENTRY_AW) * 9;
+ }
+
+ return vtd_ce_get_agaw(ce);
+}
+
static inline uint32_t vtd_ce_get_type(VTDContextEntry *ce)
{
return ce->lo & VTD_CONTEXT_ENTRY_TT;
}
-/* Return true if check passed, otherwise false */
+/* Only for Legacy Mode. Return true if check passed, otherwise false */
static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu,
VTDContextEntry *ce)
{
@@ -639,7 +848,7 @@ static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu,
}
break;
default:
- /* Unknwon type */
+ /* Unknown type */
error_report_once("%s: unknown ce type: %"PRIu32, __func__,
vtd_ce_get_type(ce));
return false;
@@ -647,21 +856,36 @@ static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu,
return true;
}
-static inline uint64_t vtd_iova_limit(VTDContextEntry *ce, uint8_t aw)
+static inline uint64_t vtd_iova_limit(IntelIOMMUState *s,
+ VTDContextEntry *ce, uint8_t aw)
{
- uint32_t ce_agaw = vtd_ce_get_agaw(ce);
+ uint32_t ce_agaw = vtd_get_iova_agaw(s, ce);
return 1ULL << MIN(ce_agaw, aw);
}
/* Return true if IOVA passes range check, otherwise false. */
-static inline bool vtd_iova_range_check(uint64_t iova, VTDContextEntry *ce,
+static inline bool vtd_iova_range_check(IntelIOMMUState *s,
+ uint64_t iova, VTDContextEntry *ce,
uint8_t aw)
{
/*
* Check if @iova is above 2^X-1, where X is the minimum of MGAW
* in CAP_REG and AW in context-entry.
*/
- return !(iova & ~(vtd_iova_limit(ce, aw) - 1));
+ return !(iova & ~(vtd_iova_limit(s, ce, aw) - 1));
+}
+
+static dma_addr_t vtd_get_iova_pgtbl_base(IntelIOMMUState *s,
+ VTDContextEntry *ce)
+{
+ VTDPASIDEntry pe;
+
+ if (s->root_scalable) {
+ vtd_ce_get_rid2pasid_entry(s, ce, &pe);
+ return pe.val[0] & VTD_SM_PASID_ENTRY_SLPTPTR;
+ }
+
+ return vtd_ce_get_slpt_base(ce);
}
/*
@@ -707,17 +931,18 @@ static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
/* Given the @iova, get relevant @slptep. @slpte_level will be the last level
* of the translation, can be used for deciding the size of large page.
*/
-static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
+static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
+ uint64_t iova, bool is_write,
uint64_t *slptep, uint32_t *slpte_level,
bool *reads, bool *writes, uint8_t aw_bits)
{
- dma_addr_t addr = vtd_ce_get_slpt_base(ce);
- uint32_t level = vtd_ce_get_level(ce);
+ dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce);
+ uint32_t level = vtd_get_iova_level(s, ce);
uint32_t offset;
uint64_t slpte;
uint64_t access_right_check;
- if (!vtd_iova_range_check(iova, ce, aw_bits)) {
+ if (!vtd_iova_range_check(s, iova, ce, aw_bits)) {
error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ")",
__func__, iova);
return -VTD_FR_ADDR_BEYOND_MGAW;
@@ -733,7 +958,7 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
if (slpte == (uint64_t)-1) {
error_report_once("%s: detected read error on DMAR slpte "
"(iova=0x%" PRIx64 ")", __func__, iova);
- if (level == vtd_ce_get_level(ce)) {
+ if (level == vtd_get_iova_level(s, ce)) {
/* Invalid programming of context-entry */
return -VTD_FR_CONTEXT_ENTRY_INV;
} else {
@@ -962,29 +1187,96 @@ next:
/**
* vtd_page_walk - walk specific IOVA range, and call the hook
*
+ * @s: intel iommu state
* @ce: context entry to walk upon
* @start: IOVA address to start the walk
* @end: IOVA range end address (start <= addr < end)
* @info: page walking information struct
*/
-static int vtd_page_walk(VTDContextEntry *ce, uint64_t start, uint64_t end,
+static int vtd_page_walk(IntelIOMMUState *s, VTDContextEntry *ce,
+ uint64_t start, uint64_t end,
vtd_page_walk_info *info)
{
- dma_addr_t addr = vtd_ce_get_slpt_base(ce);
- uint32_t level = vtd_ce_get_level(ce);
+ dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce);
+ uint32_t level = vtd_get_iova_level(s, ce);
- if (!vtd_iova_range_check(start, ce, info->aw)) {
+ if (!vtd_iova_range_check(s, start, ce, info->aw)) {
return -VTD_FR_ADDR_BEYOND_MGAW;
}
- if (!vtd_iova_range_check(end, ce, info->aw)) {
+ if (!vtd_iova_range_check(s, end, ce, info->aw)) {
/* Fix end so that it reaches the maximum */
- end = vtd_iova_limit(ce, info->aw);
+ end = vtd_iova_limit(s, ce, info->aw);
}
return vtd_page_walk_level(addr, start, end, level, true, true, info);
}
+static int vtd_root_entry_rsvd_bits_check(IntelIOMMUState *s,
+ VTDRootEntry *re)
+{
+ /* Legacy Mode reserved bits check */
+ if (!s->root_scalable &&
+ (re->hi || (re->lo & VTD_ROOT_ENTRY_RSVD(s->aw_bits))))
+ goto rsvd_err;
+
+ /* Scalable Mode reserved bits check */
+ if (s->root_scalable &&
+ ((re->lo & VTD_ROOT_ENTRY_RSVD(s->aw_bits)) ||
+ (re->hi & VTD_ROOT_ENTRY_RSVD(s->aw_bits))))
+ goto rsvd_err;
+
+ return 0;
+
+rsvd_err:
+ error_report_once("%s: invalid root entry: hi=0x%"PRIx64
+ ", lo=0x%"PRIx64,
+ __func__, re->hi, re->lo);
+ return -VTD_FR_ROOT_ENTRY_RSVD;
+}
+
+static inline int vtd_context_entry_rsvd_bits_check(IntelIOMMUState *s,
+ VTDContextEntry *ce)
+{
+ if (!s->root_scalable &&
+ (ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI ||
+ ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO(s->aw_bits))) {
+ error_report_once("%s: invalid context entry: hi=%"PRIx64
+ ", lo=%"PRIx64" (reserved nonzero)",
+ __func__, ce->hi, ce->lo);
+ return -VTD_FR_CONTEXT_ENTRY_RSVD;
+ }
+
+ if (s->root_scalable &&
+ (ce->val[0] & VTD_SM_CONTEXT_ENTRY_RSVD_VAL0(s->aw_bits) ||
+ ce->val[1] & VTD_SM_CONTEXT_ENTRY_RSVD_VAL1 ||
+ ce->val[2] ||
+ ce->val[3])) {
+ error_report_once("%s: invalid context entry: val[3]=%"PRIx64
+ ", val[2]=%"PRIx64
+ ", val[1]=%"PRIx64
+ ", val[0]=%"PRIx64" (reserved nonzero)",
+ __func__, ce->val[3], ce->val[2],
+ ce->val[1], ce->val[0]);
+ return -VTD_FR_CONTEXT_ENTRY_RSVD;
+ }
+
+ return 0;
+}
+
+static int vtd_ce_rid2pasid_check(IntelIOMMUState *s,
+ VTDContextEntry *ce)
+{
+ VTDPASIDEntry pe;
+
+ /*
+ * Make sure in Scalable Mode, a present context entry
+ * has valid rid2pasid setting, which includes valid
+ * rid2pasid field and corresponding pasid entry setting
+ */
+ return vtd_ce_get_rid2pasid_entry(s, ce, &pe);
+}
+
/* Map a device to its corresponding domain (context-entry) */
static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
uint8_t devfn, VTDContextEntry *ce)
@@ -998,20 +1290,18 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
return ret_fr;
}
- if (!vtd_root_entry_present(&re)) {
+ if (!vtd_root_entry_present(s, &re, devfn)) {
/* Not error - it's okay we don't have root entry. */
trace_vtd_re_not_present(bus_num);
return -VTD_FR_ROOT_ENTRY_P;
}
- if (re.rsvd || (re.val & VTD_ROOT_ENTRY_RSVD(s->aw_bits))) {
- error_report_once("%s: invalid root entry: rsvd=0x%"PRIx64
- ", val=0x%"PRIx64" (reserved nonzero)",
- __func__, re.rsvd, re.val);
- return -VTD_FR_ROOT_ENTRY_RSVD;
+ ret_fr = vtd_root_entry_rsvd_bits_check(s, &re);
+ if (ret_fr) {
+ return ret_fr;
}
- ret_fr = vtd_get_context_entry_from_root(&re, devfn, ce);
+ ret_fr = vtd_get_context_entry_from_root(s, &re, devfn, ce);
if (ret_fr) {
return ret_fr;
}
@@ -1022,26 +1312,38 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
return -VTD_FR_CONTEXT_ENTRY_P;
}
- if ((ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI) ||
- (ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO(s->aw_bits))) {
- error_report_once("%s: invalid context entry: hi=%"PRIx64
- ", lo=%"PRIx64" (reserved nonzero)",
- __func__, ce->hi, ce->lo);
- return -VTD_FR_CONTEXT_ENTRY_RSVD;
+ ret_fr = vtd_context_entry_rsvd_bits_check(s, ce);
+ if (ret_fr) {
+ return ret_fr;
}
/* Check if the programming of context-entry is valid */
- if (!vtd_is_level_supported(s, vtd_ce_get_level(ce))) {
+ if (!s->root_scalable &&
+ !vtd_is_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, vtd_ce_get_level(ce));
+ __func__, ce->hi, ce->lo,
+ vtd_ce_get_level(ce));
return -VTD_FR_CONTEXT_ENTRY_INV;
}
- /* Do translation type check */
- if (!vtd_ce_type_check(x86_iommu, ce)) {
- /* Errors dumped in vtd_ce_type_check() */
- return -VTD_FR_CONTEXT_ENTRY_INV;
+ if (!s->root_scalable) {
+ /* Do translation type check */
+ if (!vtd_ce_type_check(x86_iommu, ce)) {
+ /* Errors dumped in vtd_ce_type_check() */
+ return -VTD_FR_CONTEXT_ENTRY_INV;
+ }
+ } else {
+ /*
+ * Check if the programming of context-entry.rid2pasid
+ * and corresponding pasid setting is valid, and thus
+ * avoids to check pasid entry fetching result in future
+ * helper function calling.
+ */
+ ret_fr = vtd_ce_rid2pasid_check(s, ce);
+ if (ret_fr) {
+ return ret_fr;
+ }
}
return 0;
@@ -1054,6 +1356,19 @@ static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry,
return 0;
}
+static uint16_t vtd_get_domain_id(IntelIOMMUState *s,
+ VTDContextEntry *ce)
+{
+ VTDPASIDEntry pe;
+
+ if (s->root_scalable) {
+ vtd_ce_get_rid2pasid_entry(s, ce, &pe);
+ return VTD_SM_PASID_ENTRY_DID(pe.val[1]);
+ }
+
+ return VTD_CONTEXT_ENTRY_DID(ce->hi);
+}
+
static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as,
VTDContextEntry *ce,
hwaddr addr, hwaddr size)
@@ -1065,10 +1380,10 @@ static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as,
.notify_unmap = true,
.aw = s->aw_bits,
.as = vtd_as,
- .domain_id = VTD_CONTEXT_ENTRY_DID(ce->hi),
+ .domain_id = vtd_get_domain_id(s, ce),
};
- return vtd_page_walk(ce, addr, addr + size, &info);
+ return vtd_page_walk(s, ce, addr, addr + size, &info);
}
static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as)
@@ -1103,35 +1418,24 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as)
}
/*
- * Fetch translation type for specific device. Returns <0 if error
- * happens, otherwise return the shifted type to check against
- * VTD_CONTEXT_TT_*.
+ * Check if specific device is configed to bypass address
+ * translation for DMA requests. In Scalable Mode, bypass
+ * 1st-level translation or 2nd-level translation, it depends
+ * on PGTT setting.
*/
-static int vtd_dev_get_trans_type(VTDAddressSpace *as)
+static bool vtd_dev_pt_enabled(VTDAddressSpace *as)
{
IntelIOMMUState *s;
VTDContextEntry ce;
+ VTDPASIDEntry pe;
int ret;
- s = as->iommu_state;
+ assert(as);
+ s = as->iommu_state;
ret = vtd_dev_to_context_entry(s, pci_bus_num(as->bus),
as->devfn, &ce);
if (ret) {
- return ret;
- }
-
- return vtd_ce_get_type(&ce);
-}
-
-static bool vtd_dev_pt_enabled(VTDAddressSpace *as)
-{
- int ret;
-
- assert(as);
-
- ret = vtd_dev_get_trans_type(as);
- if (ret < 0) {
/*
* Possibly failed to parse the context entry for some reason
* (e.g., during init, or any guest configuration errors on
@@ -1141,7 +1445,17 @@ static bool vtd_dev_pt_enabled(VTDAddressSpace *as)
return false;
}
- return ret == VTD_CONTEXT_TT_PASS_THROUGH;
+ if (s->root_scalable) {
+ ret = vtd_ce_get_rid2pasid_entry(s, &ce, &pe);
+ if (ret) {
+ error_report_once("%s: vtd_ce_get_rid2pasid_entry error: %"PRId32,
+ __func__, ret);
+ return false;
+ }
+ return (VTD_PE_GET_TYPE(&pe) == VTD_SM_PASID_ENTRY_PT);
+ }
+
+ return (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH);
}
/* Return whether the device is using IOMMU translation. */
@@ -1221,6 +1535,7 @@ 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_RESERVED_ERR] = false,
[VTD_FR_MAX] = false,
};
@@ -1322,18 +1637,17 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
cc_entry->context_cache_gen);
ce = cc_entry->context_entry;
is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;
+ if (!is_fpd_set && s->root_scalable) {
+ ret_fr = vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set);
+ VTD_PE_GET_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write);
+ }
} else {
ret_fr = vtd_dev_to_context_entry(s, bus_num, devfn, &ce);
is_fpd_set = ce.lo & VTD_CONTEXT_ENTRY_FPD;
- if (ret_fr) {
- ret_fr = -ret_fr;
- if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {
- trace_vtd_fault_disabled();
- } else {
- vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);
- }
- goto error;
+ if (!ret_fr && !is_fpd_set && s->root_scalable) {
+ ret_fr = vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set);
}
+ VTD_PE_GET_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write);
/* Update context-cache */
trace_vtd_iotlb_cc_update(bus_num, devfn, ce.hi, ce.lo,
cc_entry->context_cache_gen,
@@ -1367,21 +1681,13 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
return true;
}
- ret_fr = vtd_iova_to_slpte(&ce, addr, is_write, &slpte, &level,
+ ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &slpte, &level,
&reads, &writes, s->aw_bits);
- if (ret_fr) {
- ret_fr = -ret_fr;
- if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {
- trace_vtd_fault_disabled();
- } else {
- vtd_report_dmar_fault(s, source_id, addr, ret_fr, is_write);
- }
- goto error;
- }
+ VTD_PE_GET_FPD_ERR(ret_fr, is_fpd_set, s, source_id, addr, is_write);
page_mask = vtd_slpt_level_page_mask(level);
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
- vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,
+ vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce), addr, slpte,
access_flags, level);
out:
vtd_iommu_unlock(s);
@@ -1404,6 +1710,9 @@ static void vtd_root_table_setup(IntelIOMMUState *s)
{
s->root = vtd_get_quad_raw(s, DMAR_RTADDR_REG);
s->root_extended = s->root & VTD_RTADDR_RTT;
+ if (s->scalable_mode) {
+ s->root_scalable = s->root & VTD_RTADDR_SMT;
+ }
s->root &= VTD_RTADDR_ADDR_MASK(s->aw_bits);
trace_vtd_reg_dmar_root(s->root, s->root_extended);
@@ -1573,7 +1882,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
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_CONTEXT_ENTRY_DID(ce.hi)) {
+ domain_id == vtd_get_domain_id(s, &ce)) {
vtd_sync_shadow_page_table(vtd_as);
}
}
@@ -1591,7 +1900,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
QLIST_FOREACH(vtd_as, &(s->vtd_as_with_notifiers), next) {
ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
vtd_as->devfn, &ce);
- if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) {
+ if (!ret && domain_id == vtd_get_domain_id(s, &ce)) {
if (vtd_as_has_map_notifier(vtd_as)) {
/*
* As long as we have MAP notifications registered in
@@ -1699,7 +2008,7 @@ static void vtd_handle_gcmd_qie(IntelIOMMUState *s, bool en)
if (en) {
s->iq = iqa_val & VTD_IQA_IQA_MASK(s->aw_bits);
/* 2^(x+8) entries */
- s->iq_size = 1UL << ((iqa_val & VTD_IQA_QS) + 8);
+ s->iq_size = 1UL << ((iqa_val & VTD_IQA_QS) + 8 - (s->iq_dw ? 1 : 0));
s->qi_enabled = true;
trace_vtd_inv_qi_setup(s->iq, s->iq_size);
/* Ok - report back to driver */
@@ -1866,19 +2175,24 @@ static void vtd_handle_iotlb_write(IntelIOMMUState *s)
}
/* Fetch an Invalidation Descriptor from the Invalidation Queue */
-static bool vtd_get_inv_desc(dma_addr_t base_addr, uint32_t offset,
+static bool vtd_get_inv_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
- dma_addr_t addr = base_addr + offset * sizeof(*inv_desc);
- if (dma_memory_read(&address_space_memory, addr, inv_desc,
- sizeof(*inv_desc))) {
- error_report_once("Read INV DESC failed");
- inv_desc->lo = 0;
- inv_desc->hi = 0;
+ dma_addr_t base_addr = s->iq;
+ uint32_t offset = s->iq_head;
+ uint32_t dw = s->iq_dw ? 32 : 16;
+ dma_addr_t addr = base_addr + offset * dw;
+
+ if (dma_memory_read(&address_space_memory, addr, inv_desc, dw)) {
+ error_report_once("Read INV DESC failed.");
return false;
}
inv_desc->lo = le64_to_cpu(inv_desc->lo);
inv_desc->hi = le64_to_cpu(inv_desc->hi);
+ if (dw == 32) {
+ inv_desc->val[2] = le64_to_cpu(inv_desc->val[2]);
+ inv_desc->val[3] = le64_to_cpu(inv_desc->val[3]);
+ }
return true;
}
@@ -2084,10 +2398,11 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
uint8_t desc_type;
trace_vtd_inv_qi_head(s->iq_head);
- if (!vtd_get_inv_desc(s->iq, s->iq_head, &inv_desc)) {
+ if (!vtd_get_inv_desc(s, &inv_desc)) {
s->iq_last_desc_type = VTD_INV_DESC_NONE;
return false;
}
+
desc_type = inv_desc.lo & VTD_INV_DESC_TYPE;
/* FIXME: should update at first or at last? */
s->iq_last_desc_type = desc_type;
@@ -2107,6 +2422,17 @@ 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:
+ break;
+
case VTD_INV_DESC_WAIT:
trace_vtd_inv_desc("wait", inv_desc.hi, inv_desc.lo);
if (!vtd_process_wait_desc(s, &inv_desc)) {
@@ -2172,7 +2498,12 @@ static void vtd_handle_iqt_write(IntelIOMMUState *s)
{
uint64_t val = vtd_get_quad_raw(s, DMAR_IQT_REG);
- s->iq_tail = VTD_IQT_QT(val);
+ if (s->iq_dw && (val & VTD_IQT_QT_256_RSV_BIT)) {
+ error_report_once("%s: RSV bit is set: val=0x%"PRIx64,
+ __func__, val);
+ return;
+ }
+ s->iq_tail = VTD_IQT_QT(s->iq_dw, val);
trace_vtd_inv_qi_tail(s->iq_tail);
if (s->qi_enabled && !(vtd_get_long_raw(s, DMAR_FSTS_REG) & VTD_FSTS_IQE)) {
@@ -2441,6 +2772,12 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
} else {
vtd_set_quad(s, addr, val);
}
+ if (s->ecap & VTD_ECAP_SMTS &&
+ val & VTD_IQA_DW_MASK) {
+ s->iq_dw = true;
+ } else {
+ s->iq_dw = false;
+ }
break;
case DMAR_IQA_REG_HI:
@@ -2629,6 +2966,7 @@ static const VMStateDescription vtd_vmstate = {
VMSTATE_UINT8_ARRAY(csr, IntelIOMMUState, DMAR_REG_SIZE),
VMSTATE_UINT8(iq_last_desc_type, IntelIOMMUState),
VMSTATE_BOOL(root_extended, IntelIOMMUState),
+ VMSTATE_BOOL(root_scalable, IntelIOMMUState),
VMSTATE_BOOL(dmar_enabled, IntelIOMMUState),
VMSTATE_BOOL(qi_enabled, IntelIOMMUState),
VMSTATE_BOOL(intr_enabled, IntelIOMMUState),
@@ -2659,6 +2997,7 @@ static Property vtd_properties[] = {
DEFINE_PROP_UINT8("aw-bits", IntelIOMMUState, aw_bits,
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("dma-drain", IntelIOMMUState, dma_drain, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -3098,9 +3437,11 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
vtd_address_space_unmap(vtd_as, n);
if (vtd_dev_to_context_entry(s, bus_n, vtd_as->devfn, &ce) == 0) {
- trace_vtd_replay_ce_valid(bus_n, PCI_SLOT(vtd_as->devfn),
+ trace_vtd_replay_ce_valid(s->root_scalable ? "scalable mode" :
+ "legacy mode",
+ bus_n, PCI_SLOT(vtd_as->devfn),
PCI_FUNC(vtd_as->devfn),
- VTD_CONTEXT_ENTRY_DID(ce.hi),
+ vtd_get_domain_id(s, &ce),
ce.hi, ce.lo);
if (vtd_as_has_map_notifier(vtd_as)) {
/* This is required only for MAP typed notifiers */
@@ -3110,10 +3451,10 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
.notify_unmap = false,
.aw = s->aw_bits,
.as = vtd_as,
- .domain_id = VTD_CONTEXT_ENTRY_DID(ce.hi),
+ .domain_id = vtd_get_domain_id(s, &ce),
};
- vtd_page_walk(&ce, 0, ~0ULL, &info);
+ vtd_page_walk(s, &ce, 0, ~0ULL, &info);
}
} else {
trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn),
@@ -3137,6 +3478,7 @@ static void vtd_init(IntelIOMMUState *s)
s->root = 0;
s->root_extended = false;
+ s->root_scalable = false;
s->dmar_enabled = false;
s->intr_enabled = false;
s->iq_head = 0;
@@ -3145,6 +3487,7 @@ static void vtd_init(IntelIOMMUState *s)
s->iq_size = 0;
s->qi_enabled = false;
s->iq_last_desc_type = VTD_INV_DESC_NONE;
+ s->iq_dw = false;
s->next_frcd_reg = 0;
s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND |
VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS |
@@ -3190,6 +3533,11 @@ static void vtd_init(IntelIOMMUState *s)
s->cap |= VTD_CAP_CM;
}
+ /* TODO: read cap/ecap from host to decide which cap to be exposed. */
+ if (s->scalable_mode) {
+ s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_SLTS;
+ }
+
vtd_reset_caches(s);
/* Define registers with default values and bit semantics */
@@ -3199,7 +3547,7 @@ static void vtd_init(IntelIOMMUState *s)
vtd_define_long(s, DMAR_GCMD_REG, 0, 0xff800000UL, 0);
vtd_define_long_wo(s, DMAR_GCMD_REG, 0xff800000UL);
vtd_define_long(s, DMAR_GSTS_REG, 0, 0, 0);
- vtd_define_quad(s, DMAR_RTADDR_REG, 0, 0xfffffffffffff000ULL, 0);
+ vtd_define_quad(s, DMAR_RTADDR_REG, 0, 0xfffffffffffffc00ULL, 0);
vtd_define_quad(s, DMAR_CCMD_REG, 0, 0xe0000003ffffffffULL, 0);
vtd_define_quad_wo(s, DMAR_CCMD_REG, 0x3ffff0000ULL);
@@ -3222,7 +3570,7 @@ static void vtd_init(IntelIOMMUState *s)
vtd_define_quad(s, DMAR_IQH_REG, 0, 0, 0);
vtd_define_quad(s, DMAR_IQT_REG, 0, 0x7fff0ULL, 0);
- vtd_define_quad(s, DMAR_IQA_REG, 0, 0xfffffffffffff007ULL, 0);
+ vtd_define_quad(s, DMAR_IQA_REG, 0, 0xfffffffffffff807ULL, 0);
vtd_define_long(s, DMAR_ICS_REG, 0, 0, 0x1UL);
vtd_define_long(s, DMAR_IECTL_REG, 0x80000000UL, 0x80000000UL, 0);
vtd_define_long(s, DMAR_IEDATA_REG, 0, 0xffffffffUL, 0);
@@ -3301,6 +3649,11 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
return false;
}
+ if (s->scalable_mode && !s->dma_drain) {
+ error_setg(errp, "Need to set dma_drain for scalable mode");
+ return false;
+ }
+
return true;
}
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index 00e9edbc66..1160618177 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -172,6 +172,7 @@
/* RTADDR_REG */
#define VTD_RTADDR_RTT (1ULL << 11)
+#define VTD_RTADDR_SMT (1ULL << 10)
#define VTD_RTADDR_ADDR_MASK(aw) (VTD_HAW_MASK(aw) ^ 0xfffULL)
/* IRTA_REG */
@@ -189,6 +190,9 @@
#define VTD_ECAP_EIM (1ULL << 4)
#define VTD_ECAP_PT (1ULL << 6)
#define VTD_ECAP_MHMV (15ULL << 20)
+#define VTD_ECAP_SRS (1ULL << 31)
+#define VTD_ECAP_SMTS (1ULL << 43)
+#define VTD_ECAP_SLTS (1ULL << 46)
/* CAP_REG */
/* (offset >> 4) << 24 */
@@ -217,11 +221,14 @@
#define VTD_CAP_SAGAW_48bit (0x4ULL << VTD_CAP_SAGAW_SHIFT)
/* IQT_REG */
-#define VTD_IQT_QT(val) (((val) >> 4) & 0x7fffULL)
+#define VTD_IQT_QT(dw_bit, val) (dw_bit ? (((val) >> 5) & 0x3fffULL) : \
+ (((val) >> 4) & 0x7fffULL))
+#define VTD_IQT_QT_256_RSV_BIT 0x10
/* IQA_REG */
#define VTD_IQA_IQA_MASK(aw) (VTD_HAW_MASK(aw) ^ 0xfffULL)
#define VTD_IQA_QS 0x7ULL
+#define VTD_IQA_DW_MASK 0x800
/* IQH_REG */
#define VTD_IQH_QH_SHIFT 4
@@ -294,6 +301,8 @@ 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 */
+
/* This is not a normal fault reason. We use this to indicate some faults
* that are not referenced by the VT-d specification.
* Fault event with such reason should not be recorded.
@@ -321,6 +330,9 @@ union VTDInvDesc {
uint64_t lo;
uint64_t hi;
};
+ struct {
+ uint64_t val[4];
+ };
union {
VTDInvDescIEC iec;
};
@@ -335,6 +347,8 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_IEC 0x4 /* Interrupt Entry Cache
Invalidate Descriptor */
#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_NONE 0 /* Not an Invalidate Descriptor */
/* Masks for Invalidation Wait Descriptor*/
@@ -411,8 +425,8 @@ typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
#define VTD_PAGE_MASK_1G (~((1ULL << VTD_PAGE_SHIFT_1G) - 1))
struct VTDRootEntry {
- uint64_t val;
- uint64_t rsvd;
+ uint64_t lo;
+ uint64_t hi;
};
typedef struct VTDRootEntry VTDRootEntry;
@@ -423,6 +437,8 @@ typedef struct VTDRootEntry VTDRootEntry;
#define VTD_ROOT_ENTRY_NR (VTD_PAGE_SIZE / sizeof(VTDRootEntry))
#define VTD_ROOT_ENTRY_RSVD(aw) (0xffeULL | ~VTD_HAW_MASK(aw))
+#define VTD_DEVFN_CHECK_MASK 0x80
+
/* Masks for struct VTDContextEntry */
/* lo */
#define VTD_CONTEXT_ENTRY_P (1ULL << 0)
@@ -441,6 +457,38 @@ typedef struct VTDRootEntry VTDRootEntry;
#define VTD_CONTEXT_ENTRY_NR (VTD_PAGE_SIZE / sizeof(VTDContextEntry))
+#define VTD_CTX_ENTRY_LEGACY_SIZE 16
+#define VTD_CTX_ENTRY_SCALABLE_SIZE 32
+
+#define VTD_SM_CONTEXT_ENTRY_RID2PASID_MASK 0xfffff
+#define VTD_SM_CONTEXT_ENTRY_RSVD_VAL0(aw) (0x1e0ULL | ~VTD_HAW_MASK(aw))
+#define VTD_SM_CONTEXT_ENTRY_RSVD_VAL1 0xffffffffffe00000ULL
+
+/* PASID Table Related Definitions */
+#define VTD_PASID_DIR_BASE_ADDR_MASK (~0xfffULL)
+#define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL)
+#define VTD_PASID_DIR_ENTRY_SIZE 8
+#define VTD_PASID_ENTRY_SIZE 64
+#define VTD_PASID_DIR_BITS_MASK (0x3fffULL)
+#define VTD_PASID_DIR_INDEX(pasid) (((pasid) >> 6) & VTD_PASID_DIR_BITS_MASK)
+#define VTD_PASID_DIR_FPD (1ULL << 1) /* Fault Processing Disable */
+#define VTD_PASID_TABLE_BITS_MASK (0x3fULL)
+#define VTD_PASID_TABLE_INDEX(pasid) ((pasid) & VTD_PASID_TABLE_BITS_MASK)
+#define VTD_PASID_ENTRY_FPD (1ULL << 1) /* Fault Processing Disable */
+
+/* PASID Granular Translation Type Mask */
+#define VTD_SM_PASID_ENTRY_PGTT (7ULL << 6)
+#define VTD_SM_PASID_ENTRY_FLT (1ULL << 6)
+#define VTD_SM_PASID_ENTRY_SLT (2ULL << 6)
+#define VTD_SM_PASID_ENTRY_NESTED (3ULL << 6)
+#define VTD_SM_PASID_ENTRY_PT (4ULL << 6)
+
+#define VTD_SM_PASID_ENTRY_AW 7ULL /* Adjusted guest-address-width */
+#define VTD_SM_PASID_ENTRY_DID(val) ((val) & VTD_DOMAIN_ID_MASK)
+
+/* 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 */
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index c6d047b42b..6077d27361 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1809,7 +1809,7 @@ void pc_memory_init(PCMachineState *pcms,
}
/* Initialize PC system firmware */
- pc_system_firmware_init(rom_memory, !pcmc->pci_enabled);
+ pc_system_firmware_init(pcms, rom_memory);
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
@@ -2075,6 +2075,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
{
const PCMachineState *pcms = PC_MACHINE(hotplug_dev);
const PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+ const MachineState *ms = MACHINE(hotplug_dev);
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
const uint64_t legacy_align = TARGET_PAGE_SIZE;
@@ -2089,7 +2090,9 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
- if (is_nvdimm && !pcms->acpi_nvdimm_state.is_enabled) {
+ hotplug_handler_pre_plug(pcms->acpi_dev, dev, errp);
+
+ if (is_nvdimm && !ms->nvdimms_state->is_enabled) {
error_setg(errp, "nvdimm is not enabled: missing 'nvdimm' in '-M'");
return;
}
@@ -2103,6 +2106,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
{
Error *local_err = NULL;
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+ MachineState *ms = MACHINE(hotplug_dev);
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
pc_dimm_plug(PC_DIMM(dev), MACHINE(pcms), &local_err);
@@ -2111,7 +2115,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
}
if (is_nvdimm) {
- nvdimm_plug(&pcms->acpi_nvdimm_state);
+ nvdimm_plug(ms->nvdimms_state);
}
hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &error_abort);
@@ -2552,47 +2556,6 @@ static void pc_machine_set_smm(Object *obj, Visitor *v, const char *name,
visit_type_OnOffAuto(v, name, &pcms->smm, errp);
}
-static bool pc_machine_get_nvdimm(Object *obj, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- return pcms->acpi_nvdimm_state.is_enabled;
-}
-
-static void pc_machine_set_nvdimm(Object *obj, bool value, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- pcms->acpi_nvdimm_state.is_enabled = value;
-}
-
-static char *pc_machine_get_nvdimm_persistence(Object *obj, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- return g_strdup(pcms->acpi_nvdimm_state.persistence_string);
-}
-
-static void pc_machine_set_nvdimm_persistence(Object *obj, const char *value,
- Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- AcpiNVDIMMState *nvdimm_state = &pcms->acpi_nvdimm_state;
-
- if (strcmp(value, "cpu") == 0)
- nvdimm_state->persistence = 3;
- else if (strcmp(value, "mem-ctrl") == 0)
- nvdimm_state->persistence = 2;
- else {
- error_setg(errp, "-machine nvdimm-persistence=%s: unsupported option",
- value);
- return;
- }
-
- g_free(nvdimm_state->persistence_string);
- nvdimm_state->persistence_string = g_strdup(value);
-}
-
static bool pc_machine_get_smbus(Object *obj, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
@@ -2642,13 +2605,13 @@ static void pc_machine_initfn(Object *obj)
pcms->max_ram_below_4g = 0; /* use default */
pcms->smm = ON_OFF_AUTO_AUTO;
pcms->vmport = ON_OFF_AUTO_AUTO;
- /* nvdimm is disabled on default. */
- pcms->acpi_nvdimm_state.is_enabled = false;
/* acpi build is enabled by default if machine supports it */
pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build;
pcms->smbus_enabled = true;
pcms->sata_enabled = true;
pcms->pit_enabled = true;
+
+ pc_system_flash_create(pcms);
}
static void pc_machine_reset(void)
@@ -2780,6 +2743,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
hc->unplug = pc_machine_device_unplug_cb;
nc->nmi_monitor_handler = x86_nmi;
mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
+ mc->nvdimm_supported = true;
object_class_property_add(oc, PC_MACHINE_DEVMEM_REGION_SIZE, "int",
pc_machine_get_device_memory_region_size, NULL,
@@ -2804,13 +2768,6 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, PC_MACHINE_VMPORT,
"Enable vmport (pc & q35)", &error_abort);
- object_class_property_add_bool(oc, PC_MACHINE_NVDIMM,
- pc_machine_get_nvdimm, pc_machine_set_nvdimm, &error_abort);
-
- object_class_property_add_str(oc, PC_MACHINE_NVDIMM_PERSIST,
- pc_machine_get_nvdimm_persistence,
- pc_machine_set_nvdimm_persistence, &error_abort);
-
object_class_property_add_bool(oc, PC_MACHINE_SMBUS,
pc_machine_get_smbus, pc_machine_set_smbus, &error_abort);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 8770ecada9..8ad8e885c6 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -297,8 +297,8 @@ static void pc_init1(MachineState *machine,
PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);
}
- if (pcms->acpi_nvdimm_state.is_enabled) {
- nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
+ if (machine->nvdimms_state->is_enabled) {
+ nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
pcms->fw_cfg, OBJECT(pcms));
}
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index cfb9043e12..372c6b73be 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -329,8 +329,8 @@ static void pc_q35_init(MachineState *machine)
pc_vga_init(isa_bus, host_bus);
pc_nic_init(pcmc, isa_bus, host_bus);
- if (pcms->acpi_nvdimm_state.is_enabled) {
- nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
+ if (machine->nvdimms_state->is_enabled) {
+ nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
pcms->fw_cfg, OBJECT(pcms));
}
}
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 091e22dd60..c628540774 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -40,10 +40,16 @@
#define BIOS_FILENAME "bios.bin"
-typedef struct PcSysFwDevice {
- SysBusDevice busdev;
- uint8_t isapc_ram_fw;
-} PcSysFwDevice;
+/*
+ * We don't have a theoretically justifiable exact lower bound on the base
+ * address of any flash mapping. In practice, the IO-APIC MMIO range is
+ * [0xFEE00000..0xFEE01000] -- see IO_APIC_DEFAULT_ADDRESS --, leaving free
+ * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in
+ * size.
+ */
+#define FLASH_SIZE_LIMIT (8 * MiB)
+
+#define FLASH_SECTOR_SIZE 4096
static void pc_isa_bios_init(MemoryRegion *rom_memory,
MemoryRegion *flash_mem,
@@ -76,100 +82,118 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory,
memory_region_set_readonly(isa_bios, true);
}
-#define FLASH_MAP_UNIT_MAX 2
+static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
+ const char *name,
+ const char *alias_prop_name)
+{
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
-/* We don't have a theoretically justifiable exact lower bound on the base
- * address of any flash mapping. In practice, the IO-APIC MMIO range is
- * [0xFEE00000..0xFEE01000[ -- see IO_APIC_DEFAULT_ADDRESS --, leaving free
- * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in
- * size.
- */
-#define FLASH_MAP_BASE_MIN ((hwaddr)(4 * GiB - 8 * MiB))
+ qdev_prop_set_uint64(dev, "sector-length", FLASH_SECTOR_SIZE);
+ qdev_prop_set_uint8(dev, "width", 1);
+ qdev_prop_set_string(dev, "name", name);
+ object_property_add_child(OBJECT(pcms), name, OBJECT(dev),
+ &error_abort);
+ object_property_add_alias(OBJECT(pcms), alias_prop_name,
+ OBJECT(dev), "drive", &error_abort);
+ return PFLASH_CFI01(dev);
+}
-/* This function maps flash drives from 4G downward, in order of their unit
- * numbers. The mapping starts at unit#0, with unit number increments of 1, and
- * stops before the first missing flash drive, or before
- * unit#FLASH_MAP_UNIT_MAX, whichever is reached first.
- *
- * Addressing within one flash drive is of course not reversed.
- *
- * An error message is printed and the process exits if:
- * - the size of the backing file for a flash drive is non-positive, or not a
- * multiple of the required sector size, or
- * - the current mapping's base address would fall below FLASH_MAP_BASE_MIN.
+void pc_system_flash_create(PCMachineState *pcms)
+{
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+
+ if (pcmc->pci_enabled) {
+ pcms->flash[0] = pc_pflash_create(pcms, "system.flash0",
+ "pflash0");
+ pcms->flash[1] = pc_pflash_create(pcms, "system.flash1",
+ "pflash1");
+ }
+}
+
+static void pc_system_flash_cleanup_unused(PCMachineState *pcms)
+{
+ char *prop_name;
+ int i;
+ Object *dev_obj;
+
+ assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
+
+ for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
+ dev_obj = OBJECT(pcms->flash[i]);
+ if (!object_property_get_bool(dev_obj, "realized", &error_abort)) {
+ prop_name = g_strdup_printf("pflash%d", i);
+ object_property_del(OBJECT(pcms), prop_name, &error_abort);
+ g_free(prop_name);
+ object_unparent(dev_obj);
+ pcms->flash[i] = NULL;
+ }
+ }
+}
+
+/*
+ * Map the pcms->flash[] from 4GiB downward, and realize.
+ * Map them in descending order, i.e. pcms->flash[0] at the top,
+ * without gaps.
+ * Stop at the first pcms->flash[0] lacking a block backend.
+ * Set each flash's size from its block backend. Fatal error if the
+ * size isn't a non-zero multiple of 4KiB, or the total size exceeds
+ * FLASH_SIZE_LIMIT.
*
- * The drive with unit#0 (if available) is mapped at the highest address, and
- * it is passed to pc_isa_bios_init(). Merging several drives for isa-bios is
+ * If pcms->flash[0] has a block backend, its memory is passed to
+ * pc_isa_bios_init(). Merging several flash devices for isa-bios is
* not supported.
*/
-static void pc_system_flash_init(MemoryRegion *rom_memory)
+static void pc_system_flash_map(PCMachineState *pcms,
+ MemoryRegion *rom_memory)
{
- int unit;
- DriveInfo *pflash_drv;
+ hwaddr total_size = 0;
+ int i;
BlockBackend *blk;
int64_t size;
- char *fatal_errmsg = NULL;
- hwaddr phys_addr = 0x100000000ULL;
- int sector_bits, sector_size;
- pflash_t *system_flash;
+ PFlashCFI01 *system_flash;
MemoryRegion *flash_mem;
- char name[64];
void *flash_ptr;
int ret, flash_size;
- sector_bits = 12;
- sector_size = 1 << sector_bits;
+ assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
- for (unit = 0;
- (unit < FLASH_MAP_UNIT_MAX &&
- (pflash_drv = drive_get(IF_PFLASH, 0, unit)) != NULL);
- ++unit) {
- blk = blk_by_legacy_dinfo(pflash_drv);
+ for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
+ system_flash = pcms->flash[i];
+ blk = pflash_cfi01_get_blk(system_flash);
+ if (!blk) {
+ break;
+ }
size = blk_getlength(blk);
if (size < 0) {
- fatal_errmsg = g_strdup_printf("failed to get backing file size");
- } else if (size == 0) {
- fatal_errmsg = g_strdup_printf("PC system firmware (pflash) "
- "cannot have zero size");
- } else if ((size % sector_size) != 0) {
- fatal_errmsg = g_strdup_printf("PC system firmware (pflash) "
- "must be a multiple of 0x%x", sector_size);
- } else if (phys_addr < size || phys_addr - size < FLASH_MAP_BASE_MIN) {
- fatal_errmsg = g_strdup_printf("oversized backing file, pflash "
- "segments cannot be mapped under "
- TARGET_FMT_plx, FLASH_MAP_BASE_MIN);
+ error_report("can't get size of block device %s: %s",
+ blk_name(blk), strerror(-size));
+ exit(1);
}
- if (fatal_errmsg != NULL) {
- Location loc;
-
- /* push a new, "none" location on the location stack; overwrite its
- * contents with the location saved in the option; print the error
- * (includes location); pop the top
- */
- loc_push_none(&loc);
- if (pflash_drv->opts != NULL) {
- qemu_opts_loc_restore(pflash_drv->opts);
- }
- error_report("%s", fatal_errmsg);
- loc_pop(&loc);
- g_free(fatal_errmsg);
+ if (size == 0 || size % FLASH_SECTOR_SIZE != 0) {
+ error_report("system firmware block device %s has invalid size "
+ "%" PRId64,
+ blk_name(blk), size);
+ info_report("its size must be a non-zero multiple of 0x%x",
+ FLASH_SECTOR_SIZE);
exit(1);
}
+ if ((hwaddr)size != size
+ || total_size > HWADDR_MAX - size
+ || total_size + size > FLASH_SIZE_LIMIT) {
+ error_report("combined size of system firmware exceeds "
+ "%" PRIu64 " bytes",
+ FLASH_SIZE_LIMIT);
+ exit(1);
+ }
+
+ total_size += size;
+ qdev_prop_set_uint32(DEVICE(system_flash), "num-blocks",
+ size / FLASH_SECTOR_SIZE);
+ qdev_init_nofail(DEVICE(system_flash));
+ sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0,
+ 0x100000000ULL - total_size);
- phys_addr -= size;
-
- /* pflash_cfi01_register() creates a deep copy of the name */
- snprintf(name, sizeof name, "system.flash%d", unit);
- system_flash = pflash_cfi01_register(phys_addr, NULL /* qdev */, name,
- size, blk, sector_size,
- size >> sector_bits,
- 1 /* width */,
- 0x0000 /* id0 */,
- 0x0000 /* id1 */,
- 0x0000 /* id2 */,
- 0x0000 /* id3 */,
- 0 /* be */);
- if (unit == 0) {
+ if (i == 0) {
flash_mem = pflash_cfi01_get_memory(system_flash);
pc_isa_bios_init(rom_memory, flash_mem, size);
@@ -240,24 +264,63 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
bios);
}
-void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
+void pc_system_firmware_init(PCMachineState *pcms,
+ MemoryRegion *rom_memory)
{
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+ int i;
DriveInfo *pflash_drv;
+ BlockBackend *pflash_blk[ARRAY_SIZE(pcms->flash)];
+ Location loc;
- pflash_drv = drive_get(IF_PFLASH, 0, 0);
-
- if (isapc_ram_fw || pflash_drv == NULL) {
- /* When a pflash drive is not found, use rom-mode */
- old_pc_system_rom_init(rom_memory, isapc_ram_fw);
+ if (!pcmc->pci_enabled) {
+ old_pc_system_rom_init(rom_memory, true);
return;
}
- if (kvm_enabled() && !kvm_readonly_mem_enabled()) {
- /* Older KVM cannot execute from device memory. So, flash memory
- * cannot be used unless the readonly memory kvm capability is present. */
- fprintf(stderr, "qemu: pflash with kvm requires KVM readonly memory support\n");
- exit(1);
+ /* Map legacy -drive if=pflash to machine properties */
+ for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
+ pflash_blk[i] = pflash_cfi01_get_blk(pcms->flash[i]);
+ pflash_drv = drive_get(IF_PFLASH, 0, i);
+ if (!pflash_drv) {
+ continue;
+ }
+ loc_push_none(&loc);
+ qemu_opts_loc_restore(pflash_drv->opts);
+ if (pflash_blk[i]) {
+ error_report("clashes with -machine");
+ exit(1);
+ }
+ pflash_blk[i] = blk_by_legacy_dinfo(pflash_drv);
+ qdev_prop_set_drive(DEVICE(pcms->flash[i]),
+ "drive", pflash_blk[i], &error_fatal);
+ loc_pop(&loc);
+ }
+
+ /* Reject gaps */
+ for (i = 1; i < ARRAY_SIZE(pcms->flash); i++) {
+ if (pflash_blk[i] && !pflash_blk[i - 1]) {
+ error_report("pflash%d requires pflash%d", i, i - 1);
+ exit(1);
+ }
+ }
+
+ if (!pflash_blk[0]) {
+ /* Machine property pflash0 not set, use ROM mode */
+ old_pc_system_rom_init(rom_memory, false);
+ } else {
+ if (kvm_enabled() && !kvm_readonly_mem_enabled()) {
+ /*
+ * Older KVM cannot execute from device memory. So, flash
+ * memory cannot be used unless the readonly memory kvm
+ * capability is present.
+ */
+ error_report("pflash with kvm requires KVM readonly memory support");
+ exit(1);
+ }
+
+ pc_system_flash_map(pcms, rom_memory);
}
- pc_system_flash_init(rom_memory);
+ pc_system_flash_cleanup_unused(pcms);
}
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 77244fc384..cae1b76fde 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -30,7 +30,7 @@ vtd_iotlb_cc_hit(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32
vtd_iotlb_cc_update(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32_t gen1, uint32_t gen2) "IOTLB context update bus 0x%"PRIx8" devfn 0x%"PRIx8" high 0x%"PRIx64" low 0x%"PRIx64" gen %"PRIu32" -> gen %"PRIu32
vtd_iotlb_reset(const char *reason) "IOTLB reset (reason: %s)"
vtd_fault_disabled(void) "Fault processing disabled for context entry"
-vtd_replay_ce_valid(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t domain, uint64_t hi, uint64_t lo) "replay valid context device %02"PRIx8":%02"PRIx8".%02"PRIx8" domain 0x%"PRIx16" hi 0x%"PRIx64" lo 0x%"PRIx64
+vtd_replay_ce_valid(const char *mode, uint8_t bus, uint8_t dev, uint8_t fn, uint16_t domain, uint64_t hi, uint64_t lo) "%s: replay valid context device %02"PRIx8":%02"PRIx8".%02"PRIx8" domain 0x%"PRIx16" hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_replay_ce_invalid(uint8_t bus, uint8_t dev, uint8_t fn) "replay invalid context device %02"PRIx8":%02"PRIx8".%02"PRIx8
vtd_page_walk_level(uint64_t addr, uint32_t level, uint64_t start, uint64_t end) "walk (base=0x%"PRIx64", level=%"PRIu32") iova range 0x%"PRIx64" - 0x%"PRIx64
vtd_page_walk_one(uint16_t domain, uint64_t iova, uint64_t gpa, uint64_t mask, int perm) "domain 0x%"PRIu16" iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64" perm %d"
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
index 2eb3cb9518..41731619bb 100644
--- a/hw/input/tsc210x.c
+++ b/hw/input/tsc210x.c
@@ -318,7 +318,7 @@ static void tsc2102_audio_output_update(TSC210xState *s)
fmt.endianness = 0;
fmt.nchannels = 2;
fmt.freq = s->codec.tx_rate;
- fmt.fmt = AUD_FMT_S16;
+ 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);
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 301a8e972d..df712c3e6c 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -39,7 +39,7 @@ obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
obj-$(CONFIG_XIVE) += xive.o
obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o
-obj-$(CONFIG_POWERNV) += xics_pnv.o
+obj-$(CONFIG_POWERNV) += xics_pnv.o pnv_xive.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
obj-$(CONFIG_S390_FLIC) += s390_flic.o
obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
new file mode 100644
index 0000000000..bb0877cbdf
--- /dev/null
+++ b/hw/intc/pnv_xive.c
@@ -0,0 +1,1753 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2019, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#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 "monitor/monitor.h"
+#include "hw/ppc/fdt.h"
+#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_core.h"
+#include "hw/ppc/pnv_xscom.h"
+#include "hw/ppc/pnv_xive.h"
+#include "hw/ppc/xive_regs.h"
+#include "hw/ppc/ppc.h"
+
+#include <libfdt.h>
+
+#include "pnv_xive_regs.h"
+
+#define XIVE_DEBUG
+
+/*
+ * Virtual structures table (VST)
+ */
+#define SBE_PER_BYTE 4
+
+typedef struct XiveVstInfo {
+ const char *name;
+ uint32_t size;
+ uint32_t max_blocks;
+} XiveVstInfo;
+
+static const XiveVstInfo vst_infos[] = {
+ [VST_TSEL_IVT] = { "EAT", sizeof(XiveEAS), 16 },
+ [VST_TSEL_SBE] = { "SBE", 1, 16 },
+ [VST_TSEL_EQDT] = { "ENDT", sizeof(XiveEND), 16 },
+ [VST_TSEL_VPDT] = { "VPDT", sizeof(XiveNVT), 32 },
+
+ /*
+ * Interrupt fifo backing store table (not modeled) :
+ *
+ * 0 - IPI,
+ * 1 - HWD,
+ * 2 - First escalate,
+ * 3 - Second escalate,
+ * 4 - Redistribution,
+ * 5 - IPI cascaded queue ?
+ */
+ [VST_TSEL_IRQ] = { "IRQ", 1, 6 },
+};
+
+#define xive_error(xive, fmt, ...) \
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n", \
+ (xive)->chip->chip_id, ## __VA_ARGS__);
+
+/*
+ * QEMU version of the GETFIELD/SETFIELD macros
+ *
+ * TODO: It might be better to use the existing extract64() and
+ * deposit64() but this means that all the register definitions will
+ * change and become incompatible with the ones found in skiboot.
+ *
+ * Keep it as it is for now until we find a common ground.
+ */
+static inline uint64_t GETFIELD(uint64_t mask, uint64_t word)
+{
+ return (word & mask) >> ctz64(mask);
+}
+
+static inline uint64_t SETFIELD(uint64_t mask, uint64_t word,
+ uint64_t value)
+{
+ return (word & ~mask) | ((value << ctz64(mask)) & mask);
+}
+
+/*
+ * Remote access to controllers. HW uses MMIOs. For now, a simple scan
+ * of the chips is good enough.
+ *
+ * TODO: Block scope support
+ */
+static PnvXive *pnv_xive_get_ic(uint8_t blk)
+{
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+ int i;
+
+ for (i = 0; i < pnv->num_chips; i++) {
+ Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
+ PnvXive *xive = &chip9->xive;
+
+ if (xive->chip->chip_id == blk) {
+ return xive;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * VST accessors for SBE, EAT, ENDT, NVT
+ *
+ * Indirect VST tables are arrays of VSDs pointing to a page (of same
+ * size). Each page is a direct VST table.
+ */
+
+#define XIVE_VSD_SIZE 8
+
+/* Indirect page size can be 4K, 64K, 2M, 16M. */
+static uint64_t pnv_xive_vst_page_size_allowed(uint32_t page_shift)
+{
+ return page_shift == 12 || page_shift == 16 ||
+ page_shift == 21 || page_shift == 24;
+}
+
+static uint64_t pnv_xive_vst_size(uint64_t vsd)
+{
+ uint64_t vst_tsize = 1ull << (GETFIELD(VSD_TSIZE, vsd) + 12);
+
+ /*
+ * Read the first descriptor to get the page size of the indirect
+ * table.
+ */
+ if (VSD_INDIRECT & vsd) {
+ uint32_t nr_pages = vst_tsize / XIVE_VSD_SIZE;
+ uint32_t page_shift;
+
+ vsd = ldq_be_dma(&address_space_memory, vsd & VSD_ADDRESS_MASK);
+ page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
+
+ if (!pnv_xive_vst_page_size_allowed(page_shift)) {
+ return 0;
+ }
+
+ return nr_pages * (1ull << page_shift);
+ }
+
+ return vst_tsize;
+}
+
+static uint64_t pnv_xive_vst_addr_direct(PnvXive *xive, uint32_t type,
+ uint64_t vsd, uint32_t idx)
+{
+ const XiveVstInfo *info = &vst_infos[type];
+ uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
+
+ return vst_addr + idx * info->size;
+}
+
+static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
+ uint64_t vsd, uint32_t idx)
+{
+ const XiveVstInfo *info = &vst_infos[type];
+ uint64_t vsd_addr;
+ uint32_t vsd_idx;
+ uint32_t page_shift;
+ uint32_t vst_per_page;
+
+ /* Get the page size of the indirect table. */
+ vsd_addr = vsd & VSD_ADDRESS_MASK;
+ vsd = ldq_be_dma(&address_space_memory, vsd_addr);
+
+ if (!(vsd & VSD_ADDRESS_MASK)) {
+ xive_error(xive, "VST: invalid %s entry %x !?", info->name, 0);
+ return 0;
+ }
+
+ page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
+
+ if (!pnv_xive_vst_page_size_allowed(page_shift)) {
+ xive_error(xive, "VST: invalid %s page shift %d", info->name,
+ page_shift);
+ return 0;
+ }
+
+ vst_per_page = (1ull << page_shift) / info->size;
+ vsd_idx = idx / vst_per_page;
+
+ /* Load the VSD we are looking for, if not already done */
+ if (vsd_idx) {
+ vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
+ vsd = ldq_be_dma(&address_space_memory, vsd_addr);
+
+ if (!(vsd & VSD_ADDRESS_MASK)) {
+ xive_error(xive, "VST: invalid %s entry %x !?", info->name, 0);
+ return 0;
+ }
+
+ /*
+ * Check that the pages have a consistent size across the
+ * indirect table
+ */
+ if (page_shift != GETFIELD(VSD_TSIZE, vsd) + 12) {
+ xive_error(xive, "VST: %s entry %x indirect page size differ !?",
+ info->name, idx);
+ return 0;
+ }
+ }
+
+ return pnv_xive_vst_addr_direct(xive, type, vsd, (idx % vst_per_page));
+}
+
+static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk,
+ uint32_t idx)
+{
+ const XiveVstInfo *info = &vst_infos[type];
+ uint64_t vsd;
+ uint32_t idx_max;
+
+ if (blk >= info->max_blocks) {
+ xive_error(xive, "VST: invalid block id %d for VST %s %d !?",
+ blk, info->name, idx);
+ return 0;
+ }
+
+ vsd = xive->vsds[type][blk];
+
+ /* Remote VST access */
+ if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
+ xive = pnv_xive_get_ic(blk);
+
+ return xive ? pnv_xive_vst_addr(xive, type, blk, idx) : 0;
+ }
+
+ idx_max = pnv_xive_vst_size(vsd) / info->size - 1;
+ if (idx > idx_max) {
+#ifdef XIVE_DEBUG
+ xive_error(xive, "VST: %s entry %x/%x out of range [ 0 .. %x ] !?",
+ info->name, blk, idx, idx_max);
+#endif
+ return 0;
+ }
+
+ if (VSD_INDIRECT & vsd) {
+ return pnv_xive_vst_addr_indirect(xive, type, vsd, idx);
+ }
+
+ return pnv_xive_vst_addr_direct(xive, type, vsd, idx);
+}
+
+static int pnv_xive_vst_read(PnvXive *xive, uint32_t type, uint8_t blk,
+ uint32_t idx, void *data)
+{
+ const XiveVstInfo *info = &vst_infos[type];
+ uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
+
+ if (!addr) {
+ return -1;
+ }
+
+ cpu_physical_memory_read(addr, data, info->size);
+ return 0;
+}
+
+#define XIVE_VST_WORD_ALL -1
+
+static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk,
+ uint32_t idx, void *data, uint32_t word_number)
+{
+ const XiveVstInfo *info = &vst_infos[type];
+ uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
+
+ if (!addr) {
+ return -1;
+ }
+
+ if (word_number == XIVE_VST_WORD_ALL) {
+ cpu_physical_memory_write(addr, data, info->size);
+ } else {
+ cpu_physical_memory_write(addr + word_number * 4,
+ data + word_number * 4, 4);
+ }
+ return 0;
+}
+
+static int pnv_xive_get_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+ XiveEND *end)
+{
+ return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end);
+}
+
+static int pnv_xive_write_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+ XiveEND *end, uint8_t word_number)
+{
+ return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end,
+ word_number);
+}
+
+static int pnv_xive_end_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+{
+ int i;
+ uint64_t eqc_watch[4];
+
+ for (i = 0; i < ARRAY_SIZE(eqc_watch); i++) {
+ eqc_watch[i] = cpu_to_be64(xive->regs[(VC_EQC_CWATCH_DAT0 >> 3) + i]);
+ }
+
+ return pnv_xive_vst_write(xive, VST_TSEL_EQDT, blk, idx, eqc_watch,
+ XIVE_VST_WORD_ALL);
+}
+
+static int pnv_xive_get_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+ XiveNVT *nvt)
+{
+ return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt);
+}
+
+static int pnv_xive_write_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+ XiveNVT *nvt, uint8_t word_number)
+{
+ return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt,
+ word_number);
+}
+
+static int pnv_xive_nvt_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+{
+ int i;
+ uint64_t vpc_watch[8];
+
+ for (i = 0; i < ARRAY_SIZE(vpc_watch); i++) {
+ vpc_watch[i] = cpu_to_be64(xive->regs[(PC_VPC_CWATCH_DAT0 >> 3) + i]);
+ }
+
+ return pnv_xive_vst_write(xive, VST_TSEL_VPDT, blk, idx, vpc_watch,
+ XIVE_VST_WORD_ALL);
+}
+
+static int pnv_xive_get_eas(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+ XiveEAS *eas)
+{
+ PnvXive *xive = PNV_XIVE(xrtr);
+
+ if (pnv_xive_get_ic(blk) != xive) {
+ xive_error(xive, "VST: EAS %x is remote !?", XIVE_SRCNO(blk, idx));
+ return -1;
+ }
+
+ return pnv_xive_vst_read(xive, VST_TSEL_IVT, blk, idx, eas);
+}
+
+static int pnv_xive_eas_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+{
+ /* All done. */
+ return 0;
+}
+
+static XiveTCTX *pnv_xive_get_tctx(XiveRouter *xrtr, CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ XiveTCTX *tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc);
+ PnvXive *xive = NULL;
+ CPUPPCState *env = &cpu->env;
+ int pir = env->spr_cb[SPR_PIR].default_value;
+
+ /*
+ * Perform an extra check on the HW thread enablement.
+ *
+ * The TIMA is shared among the chips and to identify the chip
+ * from which the access is being done, we extract the chip id
+ * from the PIR.
+ */
+ xive = pnv_xive_get_ic((pir >> 8) & 0xf);
+ if (!xive) {
+ return NULL;
+ }
+
+ if (!(xive->regs[PC_THREAD_EN_REG0 >> 3] & PPC_BIT(pir & 0x3f))) {
+ xive_error(PNV_XIVE(xrtr), "IC: CPU %x is not enabled", pir);
+ }
+
+ return tctx;
+}
+
+/*
+ * The internal sources (IPIs) of the interrupt controller have no
+ * knowledge of the XIVE chip on which they reside. Encode the block
+ * id in the source interrupt number before forwarding the source
+ * event notification to the Router. This is required on a multichip
+ * system.
+ */
+static void pnv_xive_notify(XiveNotifier *xn, uint32_t srcno)
+{
+ PnvXive *xive = PNV_XIVE(xn);
+ uint8_t blk = xive->chip->chip_id;
+
+ xive_router_notify(xn, XIVE_SRCNO(blk, srcno));
+}
+
+/*
+ * XIVE helpers
+ */
+
+static uint64_t pnv_xive_vc_size(PnvXive *xive)
+{
+ return (~xive->regs[CQ_VC_BARM >> 3] + 1) & CQ_VC_BARM_MASK;
+}
+
+static uint64_t pnv_xive_edt_shift(PnvXive *xive)
+{
+ return ctz64(pnv_xive_vc_size(xive) / XIVE_TABLE_EDT_MAX);
+}
+
+static uint64_t pnv_xive_pc_size(PnvXive *xive)
+{
+ return (~xive->regs[CQ_PC_BARM >> 3] + 1) & CQ_PC_BARM_MASK;
+}
+
+static uint32_t pnv_xive_nr_ipis(PnvXive *xive)
+{
+ uint8_t blk = xive->chip->chip_id;
+
+ return pnv_xive_vst_size(xive->vsds[VST_TSEL_SBE][blk]) * SBE_PER_BYTE;
+}
+
+static uint32_t pnv_xive_nr_ends(PnvXive *xive)
+{
+ uint8_t blk = xive->chip->chip_id;
+
+ return pnv_xive_vst_size(xive->vsds[VST_TSEL_EQDT][blk])
+ / vst_infos[VST_TSEL_EQDT].size;
+}
+
+/*
+ * EDT Table
+ *
+ * The Virtualization Controller MMIO region containing the IPI ESB
+ * pages and END ESB pages is sub-divided into "sets" which map
+ * portions of the VC region to the different ESB pages. It is
+ * configured at runtime through the EDT "Domain Table" to let the
+ * firmware decide how to split the VC address space between IPI ESB
+ * pages and END ESB pages.
+ */
+
+/*
+ * Computes the overall size of the IPI or the END ESB pages
+ */
+static uint64_t pnv_xive_edt_size(PnvXive *xive, uint64_t type)
+{
+ uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
+ uint64_t size = 0;
+ int i;
+
+ for (i = 0; i < XIVE_TABLE_EDT_MAX; i++) {
+ uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
+
+ if (edt_type == type) {
+ size += edt_size;
+ }
+ }
+
+ return size;
+}
+
+/*
+ * Maps an offset of the VC region in the IPI or END region using the
+ * layout defined by the EDT "Domaine Table"
+ */
+static uint64_t pnv_xive_edt_offset(PnvXive *xive, uint64_t vc_offset,
+ uint64_t type)
+{
+ int i;
+ uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
+ uint64_t edt_offset = vc_offset;
+
+ for (i = 0; i < XIVE_TABLE_EDT_MAX && (i * edt_size) < vc_offset; i++) {
+ uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
+
+ if (edt_type != type) {
+ edt_offset -= edt_size;
+ }
+ }
+
+ return edt_offset;
+}
+
+static void pnv_xive_edt_resize(PnvXive *xive)
+{
+ uint64_t ipi_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_IPI);
+ uint64_t end_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_EQ);
+
+ memory_region_set_size(&xive->ipi_edt_mmio, ipi_edt_size);
+ memory_region_add_subregion(&xive->ipi_mmio, 0, &xive->ipi_edt_mmio);
+
+ memory_region_set_size(&xive->end_edt_mmio, end_edt_size);
+ memory_region_add_subregion(&xive->end_mmio, 0, &xive->end_edt_mmio);
+}
+
+/*
+ * XIVE Table configuration. Only EDT is supported.
+ */
+static int pnv_xive_table_set_data(PnvXive *xive, uint64_t val)
+{
+ uint64_t tsel = xive->regs[CQ_TAR >> 3] & CQ_TAR_TSEL;
+ uint8_t tsel_index = GETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3]);
+ uint64_t *xive_table;
+ uint8_t max_index;
+
+ switch (tsel) {
+ case CQ_TAR_TSEL_BLK:
+ max_index = ARRAY_SIZE(xive->blk);
+ xive_table = xive->blk;
+ break;
+ case CQ_TAR_TSEL_MIG:
+ max_index = ARRAY_SIZE(xive->mig);
+ xive_table = xive->mig;
+ break;
+ case CQ_TAR_TSEL_EDT:
+ max_index = ARRAY_SIZE(xive->edt);
+ xive_table = xive->edt;
+ break;
+ case CQ_TAR_TSEL_VDT:
+ max_index = ARRAY_SIZE(xive->vdt);
+ xive_table = xive->vdt;
+ break;
+ default:
+ xive_error(xive, "IC: invalid table %d", (int) tsel);
+ return -1;
+ }
+
+ if (tsel_index >= max_index) {
+ xive_error(xive, "IC: invalid index %d", (int) tsel_index);
+ return -1;
+ }
+
+ xive_table[tsel_index] = val;
+
+ if (xive->regs[CQ_TAR >> 3] & CQ_TAR_TBL_AUTOINC) {
+ xive->regs[CQ_TAR >> 3] =
+ SETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3], ++tsel_index);
+ }
+
+ /*
+ * EDT configuration is complete. Resize the MMIO windows exposing
+ * the IPI and the END ESBs in the VC region.
+ */
+ if (tsel == CQ_TAR_TSEL_EDT && tsel_index == ARRAY_SIZE(xive->edt)) {
+ pnv_xive_edt_resize(xive);
+ }
+
+ return 0;
+}
+
+/*
+ * Virtual Structure Tables (VST) configuration
+ */
+static void pnv_xive_vst_set_exclusive(PnvXive *xive, uint8_t type,
+ uint8_t blk, uint64_t vsd)
+{
+ XiveENDSource *end_xsrc = &xive->end_source;
+ XiveSource *xsrc = &xive->ipi_source;
+ const XiveVstInfo *info = &vst_infos[type];
+ uint32_t page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
+ uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
+
+ /* Basic checks */
+
+ if (VSD_INDIRECT & vsd) {
+ if (!(xive->regs[VC_GLOBAL_CONFIG >> 3] & VC_GCONF_INDIRECT)) {
+ xive_error(xive, "VST: %s indirect tables are not enabled",
+ info->name);
+ return;
+ }
+
+ if (!pnv_xive_vst_page_size_allowed(page_shift)) {
+ xive_error(xive, "VST: invalid %s page shift %d", info->name,
+ page_shift);
+ return;
+ }
+ }
+
+ if (!QEMU_IS_ALIGNED(vst_addr, 1ull << page_shift)) {
+ xive_error(xive, "VST: %s table address 0x%"PRIx64" is not aligned with"
+ " page shift %d", info->name, vst_addr, page_shift);
+ return;
+ }
+
+ /* Record the table configuration (in SRAM on HW) */
+ xive->vsds[type][blk] = vsd;
+
+ /* Now tune the models with the configuration provided by the FW */
+
+ switch (type) {
+ case VST_TSEL_IVT: /* Nothing to be done */
+ break;
+
+ case VST_TSEL_EQDT:
+ /*
+ * Backing store pages for the END. Compute the number of ENDs
+ * provisioned by FW and resize the END ESB window accordingly.
+ */
+ memory_region_set_size(&end_xsrc->esb_mmio, pnv_xive_nr_ends(xive) *
+ (1ull << (end_xsrc->esb_shift + 1)));
+ memory_region_add_subregion(&xive->end_edt_mmio, 0,
+ &end_xsrc->esb_mmio);
+ break;
+
+ case VST_TSEL_SBE:
+ /*
+ * Backing store pages for the source PQ bits. The model does
+ * not use these PQ bits backed in RAM because the XiveSource
+ * model has its own. Compute the number of IRQs provisioned
+ * by FW and resize the IPI ESB window accordingly.
+ */
+ memory_region_set_size(&xsrc->esb_mmio, pnv_xive_nr_ipis(xive) *
+ (1ull << xsrc->esb_shift));
+ memory_region_add_subregion(&xive->ipi_edt_mmio, 0, &xsrc->esb_mmio);
+ break;
+
+ case VST_TSEL_VPDT: /* Not modeled */
+ case VST_TSEL_IRQ: /* Not modeled */
+ /*
+ * These tables contains the backing store pages for the
+ * interrupt fifos of the VC sub-engine in case of overflow.
+ */
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+/*
+ * Both PC and VC sub-engines are configured as each use the Virtual
+ * Structure Tables : SBE, EAS, END and NVT.
+ */
+static void pnv_xive_vst_set_data(PnvXive *xive, uint64_t vsd, bool pc_engine)
+{
+ uint8_t mode = GETFIELD(VSD_MODE, vsd);
+ uint8_t type = GETFIELD(VST_TABLE_SELECT,
+ xive->regs[VC_VSD_TABLE_ADDR >> 3]);
+ uint8_t blk = GETFIELD(VST_TABLE_BLOCK,
+ xive->regs[VC_VSD_TABLE_ADDR >> 3]);
+ uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
+
+ if (type > VST_TSEL_IRQ) {
+ xive_error(xive, "VST: invalid table type %d", type);
+ return;
+ }
+
+ if (blk >= vst_infos[type].max_blocks) {
+ xive_error(xive, "VST: invalid block id %d for"
+ " %s table", blk, vst_infos[type].name);
+ return;
+ }
+
+ /*
+ * Only take the VC sub-engine configuration into account because
+ * the XiveRouter model combines both VC and PC sub-engines
+ */
+ if (pc_engine) {
+ return;
+ }
+
+ if (!vst_addr) {
+ xive_error(xive, "VST: invalid %s table address", vst_infos[type].name);
+ return;
+ }
+
+ switch (mode) {
+ case VSD_MODE_FORWARD:
+ xive->vsds[type][blk] = vsd;
+ break;
+
+ case VSD_MODE_EXCLUSIVE:
+ pnv_xive_vst_set_exclusive(xive, type, blk, vsd);
+ break;
+
+ default:
+ xive_error(xive, "VST: unsupported table mode %d", mode);
+ return;
+ }
+}
+
+/*
+ * Interrupt controller MMIO region. The layout is compatible between
+ * 4K and 64K pages :
+ *
+ * Page 0 sub-engine BARs
+ * 0x000 - 0x3FF IC registers
+ * 0x400 - 0x7FF PC registers
+ * 0x800 - 0xFFF VC registers
+ *
+ * Page 1 Notify page (writes only)
+ * 0x000 - 0x7FF HW interrupt triggers (PSI, PHB)
+ * 0x800 - 0xFFF forwards and syncs
+ *
+ * Page 2 LSI Trigger page (writes only) (not modeled)
+ * Page 3 LSI SB EOI page (reads only) (not modeled)
+ *
+ * Page 4-7 indirect TIMA
+ */
+
+/*
+ * IC - registers MMIO
+ */
+static void pnv_xive_ic_reg_write(void *opaque, hwaddr offset,
+ uint64_t val, unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+ MemoryRegion *sysmem = get_system_memory();
+ uint32_t reg = offset >> 3;
+ bool is_chip0 = xive->chip->chip_id == 0;
+
+ switch (offset) {
+
+ /*
+ * XIVE CQ (PowerBus bridge) settings
+ */
+ case CQ_MSGSND: /* msgsnd for doorbells */
+ case CQ_FIRMASK_OR: /* FIR error reporting */
+ break;
+ case CQ_PBI_CTL:
+ if (val & CQ_PBI_PC_64K) {
+ xive->pc_shift = 16;
+ }
+ if (val & CQ_PBI_VC_64K) {
+ xive->vc_shift = 16;
+ }
+ break;
+ case CQ_CFG_PB_GEN: /* PowerBus General Configuration */
+ /*
+ * TODO: CQ_INT_ADDR_OPT for 1-block-per-chip mode
+ */
+ break;
+
+ /*
+ * XIVE Virtualization Controller settings
+ */
+ case VC_GLOBAL_CONFIG:
+ break;
+
+ /*
+ * XIVE Presenter Controller settings
+ */
+ case PC_GLOBAL_CONFIG:
+ /*
+ * PC_GCONF_CHIPID_OVR
+ * Overrides Int command Chip ID with the Chip ID field (DEBUG)
+ */
+ break;
+ case PC_TCTXT_CFG:
+ /*
+ * TODO: block group support
+ *
+ * PC_TCTXT_CFG_BLKGRP_EN
+ * PC_TCTXT_CFG_HARD_CHIPID_BLK :
+ * Moves the chipid into block field for hardwired CAM compares.
+ * Block offset value is adjusted to 0b0..01 & ThrdId
+ *
+ * Will require changes in xive_presenter_tctx_match(). I am
+ * not sure how to handle that yet.
+ */
+
+ /* Overrides hardwired chip ID with the chip ID field */
+ if (val & PC_TCTXT_CHIPID_OVERRIDE) {
+ xive->tctx_chipid = GETFIELD(PC_TCTXT_CHIPID, val);
+ }
+ break;
+ case PC_TCTXT_TRACK:
+ /*
+ * PC_TCTXT_TRACK_EN:
+ * enable block tracking and exchange of block ownership
+ * information between Interrupt controllers
+ */
+ break;
+
+ /*
+ * Misc settings
+ */
+ case VC_SBC_CONFIG: /* Store EOI configuration */
+ /*
+ * Configure store EOI if required by firwmare (skiboot has removed
+ * support recently though)
+ */
+ if (val & (VC_SBC_CONF_CPLX_CIST | VC_SBC_CONF_CIST_BOTH)) {
+ object_property_set_int(OBJECT(&xive->ipi_source),
+ XIVE_SRC_STORE_EOI, "flags", &error_fatal);
+ }
+ break;
+
+ case VC_EQC_CONFIG: /* TODO: silent escalation */
+ case VC_AIB_TX_ORDER_TAG2: /* relax ordering */
+ break;
+
+ /*
+ * XIVE BAR settings (XSCOM only)
+ */
+ case CQ_RST_CTL:
+ /* bit4: resets all BAR registers */
+ break;
+
+ case CQ_IC_BAR: /* IC BAR. 8 pages */
+ xive->ic_shift = val & CQ_IC_BAR_64K ? 16 : 12;
+ if (!(val & CQ_IC_BAR_VALID)) {
+ xive->ic_base = 0;
+ if (xive->regs[reg] & CQ_IC_BAR_VALID) {
+ memory_region_del_subregion(&xive->ic_mmio,
+ &xive->ic_reg_mmio);
+ memory_region_del_subregion(&xive->ic_mmio,
+ &xive->ic_notify_mmio);
+ memory_region_del_subregion(&xive->ic_mmio,
+ &xive->ic_lsi_mmio);
+ memory_region_del_subregion(&xive->ic_mmio,
+ &xive->tm_indirect_mmio);
+
+ memory_region_del_subregion(sysmem, &xive->ic_mmio);
+ }
+ } else {
+ xive->ic_base = val & ~(CQ_IC_BAR_VALID | CQ_IC_BAR_64K);
+ if (!(xive->regs[reg] & CQ_IC_BAR_VALID)) {
+ memory_region_add_subregion(sysmem, xive->ic_base,
+ &xive->ic_mmio);
+
+ memory_region_add_subregion(&xive->ic_mmio, 0,
+ &xive->ic_reg_mmio);
+ memory_region_add_subregion(&xive->ic_mmio,
+ 1ul << xive->ic_shift,
+ &xive->ic_notify_mmio);
+ memory_region_add_subregion(&xive->ic_mmio,
+ 2ul << xive->ic_shift,
+ &xive->ic_lsi_mmio);
+ memory_region_add_subregion(&xive->ic_mmio,
+ 4ull << xive->ic_shift,
+ &xive->tm_indirect_mmio);
+ }
+ }
+ break;
+
+ case CQ_TM1_BAR: /* TM BAR. 4 pages. Map only once */
+ case CQ_TM2_BAR: /* second TM BAR. for hotplug. Not modeled */
+ xive->tm_shift = val & CQ_TM_BAR_64K ? 16 : 12;
+ if (!(val & CQ_TM_BAR_VALID)) {
+ xive->tm_base = 0;
+ if (xive->regs[reg] & CQ_TM_BAR_VALID && is_chip0) {
+ memory_region_del_subregion(sysmem, &xive->tm_mmio);
+ }
+ } else {
+ xive->tm_base = val & ~(CQ_TM_BAR_VALID | CQ_TM_BAR_64K);
+ if (!(xive->regs[reg] & CQ_TM_BAR_VALID) && is_chip0) {
+ memory_region_add_subregion(sysmem, xive->tm_base,
+ &xive->tm_mmio);
+ }
+ }
+ break;
+
+ case CQ_PC_BARM:
+ xive->regs[reg] = val;
+ memory_region_set_size(&xive->pc_mmio, pnv_xive_pc_size(xive));
+ break;
+ case CQ_PC_BAR: /* From 32M to 512G */
+ if (!(val & CQ_PC_BAR_VALID)) {
+ xive->pc_base = 0;
+ if (xive->regs[reg] & CQ_PC_BAR_VALID) {
+ memory_region_del_subregion(sysmem, &xive->pc_mmio);
+ }
+ } else {
+ xive->pc_base = val & ~(CQ_PC_BAR_VALID);
+ if (!(xive->regs[reg] & CQ_PC_BAR_VALID)) {
+ memory_region_add_subregion(sysmem, xive->pc_base,
+ &xive->pc_mmio);
+ }
+ }
+ break;
+
+ case CQ_VC_BARM:
+ xive->regs[reg] = val;
+ memory_region_set_size(&xive->vc_mmio, pnv_xive_vc_size(xive));
+ break;
+ case CQ_VC_BAR: /* From 64M to 4TB */
+ if (!(val & CQ_VC_BAR_VALID)) {
+ xive->vc_base = 0;
+ if (xive->regs[reg] & CQ_VC_BAR_VALID) {
+ memory_region_del_subregion(sysmem, &xive->vc_mmio);
+ }
+ } else {
+ xive->vc_base = val & ~(CQ_VC_BAR_VALID);
+ if (!(xive->regs[reg] & CQ_VC_BAR_VALID)) {
+ memory_region_add_subregion(sysmem, xive->vc_base,
+ &xive->vc_mmio);
+ }
+ }
+ break;
+
+ /*
+ * XIVE Table settings.
+ */
+ case CQ_TAR: /* Table Address */
+ break;
+ case CQ_TDR: /* Table Data */
+ pnv_xive_table_set_data(xive, val);
+ break;
+
+ /*
+ * XIVE VC & PC Virtual Structure Table settings
+ */
+ case VC_VSD_TABLE_ADDR:
+ case PC_VSD_TABLE_ADDR: /* Virtual table selector */
+ break;
+ case VC_VSD_TABLE_DATA: /* Virtual table setting */
+ case PC_VSD_TABLE_DATA:
+ pnv_xive_vst_set_data(xive, val, offset == PC_VSD_TABLE_DATA);
+ break;
+
+ /*
+ * Interrupt fifo overflow in memory backing store (Not modeled)
+ */
+ case VC_IRQ_CONFIG_IPI:
+ case VC_IRQ_CONFIG_HW:
+ case VC_IRQ_CONFIG_CASCADE1:
+ case VC_IRQ_CONFIG_CASCADE2:
+ case VC_IRQ_CONFIG_REDIST:
+ case VC_IRQ_CONFIG_IPI_CASC:
+ break;
+
+ /*
+ * XIVE hardware thread enablement
+ */
+ case PC_THREAD_EN_REG0: /* Physical Thread Enable */
+ case PC_THREAD_EN_REG1: /* Physical Thread Enable (fused core) */
+ break;
+
+ case PC_THREAD_EN_REG0_SET:
+ xive->regs[PC_THREAD_EN_REG0 >> 3] |= val;
+ break;
+ case PC_THREAD_EN_REG1_SET:
+ xive->regs[PC_THREAD_EN_REG1 >> 3] |= val;
+ break;
+ case PC_THREAD_EN_REG0_CLR:
+ xive->regs[PC_THREAD_EN_REG0 >> 3] &= ~val;
+ break;
+ case PC_THREAD_EN_REG1_CLR:
+ xive->regs[PC_THREAD_EN_REG1 >> 3] &= ~val;
+ break;
+
+ /*
+ * Indirect TIMA access set up. Defines the PIR of the HW thread
+ * to use.
+ */
+ case PC_TCTXT_INDIR0 ... PC_TCTXT_INDIR3:
+ break;
+
+ /*
+ * XIVE PC & VC cache updates for EAS, NVT and END
+ */
+ case VC_IVC_SCRUB_MASK:
+ break;
+ case VC_IVC_SCRUB_TRIG:
+ pnv_xive_eas_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val),
+ GETFIELD(VC_SCRUB_OFFSET, val));
+ break;
+
+ case VC_EQC_SCRUB_MASK:
+ case VC_EQC_CWATCH_SPEC:
+ case VC_EQC_CWATCH_DAT0 ... VC_EQC_CWATCH_DAT3:
+ break;
+ case VC_EQC_SCRUB_TRIG:
+ pnv_xive_end_update(xive, GETFIELD(VC_SCRUB_BLOCK_ID, val),
+ GETFIELD(VC_SCRUB_OFFSET, val));
+ break;
+
+ case PC_VPC_SCRUB_MASK:
+ case PC_VPC_CWATCH_SPEC:
+ case PC_VPC_CWATCH_DAT0 ... PC_VPC_CWATCH_DAT7:
+ break;
+ case PC_VPC_SCRUB_TRIG:
+ pnv_xive_nvt_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val),
+ GETFIELD(PC_SCRUB_OFFSET, val));
+ break;
+
+
+ /*
+ * XIVE PC & VC cache invalidation
+ */
+ case PC_AT_KILL:
+ break;
+ case VC_AT_MACRO_KILL:
+ break;
+ case PC_AT_KILL_MASK:
+ case VC_AT_MACRO_KILL_MASK:
+ break;
+
+ default:
+ xive_error(xive, "IC: invalid write to reg=0x%"HWADDR_PRIx, offset);
+ return;
+ }
+
+ xive->regs[reg] = val;
+}
+
+static uint64_t pnv_xive_ic_reg_read(void *opaque, hwaddr offset, unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+ uint64_t val = 0;
+ uint32_t reg = offset >> 3;
+
+ switch (offset) {
+ case CQ_CFG_PB_GEN:
+ case CQ_IC_BAR:
+ case CQ_TM1_BAR:
+ case CQ_TM2_BAR:
+ case CQ_PC_BAR:
+ case CQ_PC_BARM:
+ case CQ_VC_BAR:
+ case CQ_VC_BARM:
+ case CQ_TAR:
+ case CQ_TDR:
+ case CQ_PBI_CTL:
+
+ case PC_TCTXT_CFG:
+ case PC_TCTXT_TRACK:
+ case PC_TCTXT_INDIR0:
+ case PC_TCTXT_INDIR1:
+ case PC_TCTXT_INDIR2:
+ case PC_TCTXT_INDIR3:
+ case PC_GLOBAL_CONFIG:
+
+ case PC_VPC_SCRUB_MASK:
+ case PC_VPC_CWATCH_SPEC:
+ case PC_VPC_CWATCH_DAT0:
+ case PC_VPC_CWATCH_DAT1:
+ case PC_VPC_CWATCH_DAT2:
+ case PC_VPC_CWATCH_DAT3:
+ case PC_VPC_CWATCH_DAT4:
+ case PC_VPC_CWATCH_DAT5:
+ case PC_VPC_CWATCH_DAT6:
+ case PC_VPC_CWATCH_DAT7:
+
+ case VC_GLOBAL_CONFIG:
+ case VC_AIB_TX_ORDER_TAG2:
+
+ case VC_IRQ_CONFIG_IPI:
+ case VC_IRQ_CONFIG_HW:
+ case VC_IRQ_CONFIG_CASCADE1:
+ case VC_IRQ_CONFIG_CASCADE2:
+ case VC_IRQ_CONFIG_REDIST:
+ case VC_IRQ_CONFIG_IPI_CASC:
+
+ case VC_EQC_SCRUB_MASK:
+ case VC_EQC_CWATCH_DAT0:
+ case VC_EQC_CWATCH_DAT1:
+ case VC_EQC_CWATCH_DAT2:
+ case VC_EQC_CWATCH_DAT3:
+
+ case VC_EQC_CWATCH_SPEC:
+ case VC_IVC_SCRUB_MASK:
+ case VC_SBC_CONFIG:
+ case VC_AT_MACRO_KILL_MASK:
+ case VC_VSD_TABLE_ADDR:
+ case PC_VSD_TABLE_ADDR:
+ case VC_VSD_TABLE_DATA:
+ case PC_VSD_TABLE_DATA:
+ case PC_THREAD_EN_REG0:
+ case PC_THREAD_EN_REG1:
+ val = xive->regs[reg];
+ break;
+
+ /*
+ * XIVE hardware thread enablement
+ */
+ case PC_THREAD_EN_REG0_SET:
+ case PC_THREAD_EN_REG0_CLR:
+ val = xive->regs[PC_THREAD_EN_REG0 >> 3];
+ break;
+ case PC_THREAD_EN_REG1_SET:
+ case PC_THREAD_EN_REG1_CLR:
+ val = xive->regs[PC_THREAD_EN_REG1 >> 3];
+ break;
+
+ case CQ_MSGSND: /* Identifies which cores have msgsnd enabled. */
+ val = 0xffffff0000000000;
+ break;
+
+ /*
+ * XIVE PC & VC cache updates for EAS, NVT and END
+ */
+ case PC_VPC_SCRUB_TRIG:
+ case VC_IVC_SCRUB_TRIG:
+ case VC_EQC_SCRUB_TRIG:
+ xive->regs[reg] &= ~VC_SCRUB_VALID;
+ val = xive->regs[reg];
+ break;
+
+ /*
+ * XIVE PC & VC cache invalidation
+ */
+ case PC_AT_KILL:
+ xive->regs[reg] &= ~PC_AT_KILL_VALID;
+ val = xive->regs[reg];
+ break;
+ case VC_AT_MACRO_KILL:
+ xive->regs[reg] &= ~VC_KILL_VALID;
+ val = xive->regs[reg];
+ break;
+
+ /*
+ * XIVE synchronisation
+ */
+ case VC_EQC_CONFIG:
+ val = VC_EQC_SYNC_MASK;
+ break;
+
+ default:
+ xive_error(xive, "IC: invalid read reg=0x%"HWADDR_PRIx, offset);
+ }
+
+ return val;
+}
+
+static const MemoryRegionOps pnv_xive_ic_reg_ops = {
+ .read = pnv_xive_ic_reg_read,
+ .write = pnv_xive_ic_reg_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+/*
+ * IC - Notify MMIO port page (write only)
+ */
+#define PNV_XIVE_FORWARD_IPI 0x800 /* Forward IPI */
+#define PNV_XIVE_FORWARD_HW 0x880 /* Forward HW */
+#define PNV_XIVE_FORWARD_OS_ESC 0x900 /* Forward OS escalation */
+#define PNV_XIVE_FORWARD_HW_ESC 0x980 /* Forward Hyp escalation */
+#define PNV_XIVE_FORWARD_REDIS 0xa00 /* Forward Redistribution */
+#define PNV_XIVE_RESERVED5 0xa80 /* Cache line 5 PowerBUS operation */
+#define PNV_XIVE_RESERVED6 0xb00 /* Cache line 6 PowerBUS operation */
+#define PNV_XIVE_RESERVED7 0xb80 /* Cache line 7 PowerBUS operation */
+
+/* VC synchronisation */
+#define PNV_XIVE_SYNC_IPI 0xc00 /* Sync IPI */
+#define PNV_XIVE_SYNC_HW 0xc80 /* Sync HW */
+#define PNV_XIVE_SYNC_OS_ESC 0xd00 /* Sync OS escalation */
+#define PNV_XIVE_SYNC_HW_ESC 0xd80 /* Sync Hyp escalation */
+#define PNV_XIVE_SYNC_REDIS 0xe00 /* Sync Redistribution */
+
+/* PC synchronisation */
+#define PNV_XIVE_SYNC_PULL 0xe80 /* Sync pull context */
+#define PNV_XIVE_SYNC_PUSH 0xf00 /* Sync push context */
+#define PNV_XIVE_SYNC_VPC 0xf80 /* Sync remove VPC store */
+
+static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
+{
+ /*
+ * Forward the source event notification directly to the Router.
+ * The source interrupt number should already be correctly encoded
+ * with the chip block id by the sending device (PHB, PSI).
+ */
+ xive_router_notify(XIVE_NOTIFIER(xive), val);
+}
+
+static void pnv_xive_ic_notify_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+
+ /* VC: HW triggers */
+ switch (addr) {
+ case 0x000 ... 0x7FF:
+ pnv_xive_ic_hw_trigger(opaque, addr, val);
+ break;
+
+ /* VC: Forwarded IRQs */
+ case PNV_XIVE_FORWARD_IPI:
+ case PNV_XIVE_FORWARD_HW:
+ case PNV_XIVE_FORWARD_OS_ESC:
+ case PNV_XIVE_FORWARD_HW_ESC:
+ case PNV_XIVE_FORWARD_REDIS:
+ /* TODO: forwarded IRQs. Should be like HW triggers */
+ xive_error(xive, "IC: forwarded at @0x%"HWADDR_PRIx" IRQ 0x%"PRIx64,
+ addr, val);
+ break;
+
+ /* VC syncs */
+ case PNV_XIVE_SYNC_IPI:
+ case PNV_XIVE_SYNC_HW:
+ case PNV_XIVE_SYNC_OS_ESC:
+ case PNV_XIVE_SYNC_HW_ESC:
+ case PNV_XIVE_SYNC_REDIS:
+ break;
+
+ /* PC syncs */
+ case PNV_XIVE_SYNC_PULL:
+ case PNV_XIVE_SYNC_PUSH:
+ case PNV_XIVE_SYNC_VPC:
+ break;
+
+ default:
+ xive_error(xive, "IC: invalid notify write @%"HWADDR_PRIx, addr);
+ }
+}
+
+static uint64_t pnv_xive_ic_notify_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+
+ /* loads are invalid */
+ xive_error(xive, "IC: invalid notify read @%"HWADDR_PRIx, addr);
+ return -1;
+}
+
+static const MemoryRegionOps pnv_xive_ic_notify_ops = {
+ .read = pnv_xive_ic_notify_read,
+ .write = pnv_xive_ic_notify_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+/*
+ * IC - LSI MMIO handlers (not modeled)
+ */
+
+static void pnv_xive_ic_lsi_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+
+ xive_error(xive, "IC: LSI invalid write @%"HWADDR_PRIx, addr);
+}
+
+static uint64_t pnv_xive_ic_lsi_read(void *opaque, hwaddr addr, unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+
+ xive_error(xive, "IC: LSI invalid read @%"HWADDR_PRIx, addr);
+ return -1;
+}
+
+static const MemoryRegionOps pnv_xive_ic_lsi_ops = {
+ .read = pnv_xive_ic_lsi_read,
+ .write = pnv_xive_ic_lsi_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+/*
+ * IC - Indirect TIMA MMIO handlers
+ */
+
+/*
+ * When the TIMA is accessed from the indirect page, the thread id
+ * (PIR) has to be configured in the IC registers before. This is used
+ * for resets and for debug purpose also.
+ */
+static XiveTCTX *pnv_xive_get_indirect_tctx(PnvXive *xive)
+{
+ uint64_t tctxt_indir = xive->regs[PC_TCTXT_INDIR0 >> 3];
+ PowerPCCPU *cpu = NULL;
+ int pir;
+
+ if (!(tctxt_indir & PC_TCTXT_INDIR_VALID)) {
+ xive_error(xive, "IC: no indirect TIMA access in progress");
+ return NULL;
+ }
+
+ pir = GETFIELD(PC_TCTXT_INDIR_THRDID, tctxt_indir) & 0xff;
+ cpu = ppc_get_vcpu_by_pir(pir);
+ if (!cpu) {
+ xive_error(xive, "IC: invalid PIR %x for indirect access", pir);
+ return NULL;
+ }
+
+ /* Check that HW thread is XIVE enabled */
+ if (!(xive->regs[PC_THREAD_EN_REG0 >> 3] & PPC_BIT(pir & 0x3f))) {
+ xive_error(xive, "IC: CPU %x is not enabled", pir);
+ }
+
+ return XIVE_TCTX(pnv_cpu_state(cpu)->intc);
+}
+
+static void xive_tm_indirect_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
+
+ xive_tctx_tm_write(tctx, offset, value, size);
+}
+
+static uint64_t xive_tm_indirect_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
+
+ return xive_tctx_tm_read(tctx, offset, size);
+}
+
+static const MemoryRegionOps xive_tm_indirect_ops = {
+ .read = xive_tm_indirect_read,
+ .write = xive_tm_indirect_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
+/*
+ * Interrupt controller XSCOM region.
+ */
+static uint64_t pnv_xive_xscom_read(void *opaque, hwaddr addr, unsigned size)
+{
+ switch (addr >> 3) {
+ case X_VC_EQC_CONFIG:
+ /* FIXME (skiboot): This is the only XSCOM load. Bizarre. */
+ return VC_EQC_SYNC_MASK;
+ default:
+ return pnv_xive_ic_reg_read(opaque, addr, size);
+ }
+}
+
+static void pnv_xive_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ pnv_xive_ic_reg_write(opaque, addr, val, size);
+}
+
+static const MemoryRegionOps pnv_xive_xscom_ops = {
+ .read = pnv_xive_xscom_read,
+ .write = pnv_xive_xscom_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ }
+};
+
+/*
+ * Virtualization Controller MMIO region containing the IPI and END ESB pages
+ */
+static uint64_t pnv_xive_vc_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+ uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
+ uint64_t edt_type = 0;
+ uint64_t edt_offset;
+ MemTxResult result;
+ AddressSpace *edt_as = NULL;
+ uint64_t ret = -1;
+
+ if (edt_index < XIVE_TABLE_EDT_MAX) {
+ edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
+ }
+
+ switch (edt_type) {
+ case CQ_TDR_EDT_IPI:
+ edt_as = &xive->ipi_as;
+ break;
+ case CQ_TDR_EDT_EQ:
+ edt_as = &xive->end_as;
+ break;
+ default:
+ xive_error(xive, "VC: invalid EDT type for read @%"HWADDR_PRIx, offset);
+ return -1;
+ }
+
+ /* Remap the offset for the targeted address space */
+ edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
+
+ ret = address_space_ldq(edt_as, edt_offset, MEMTXATTRS_UNSPECIFIED,
+ &result);
+
+ if (result != MEMTX_OK) {
+ xive_error(xive, "VC: %s read failed at @0x%"HWADDR_PRIx " -> @0x%"
+ HWADDR_PRIx, edt_type == CQ_TDR_EDT_IPI ? "IPI" : "END",
+ offset, edt_offset);
+ return -1;
+ }
+
+ return ret;
+}
+
+static void pnv_xive_vc_write(void *opaque, hwaddr offset,
+ uint64_t val, unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+ uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
+ uint64_t edt_type = 0;
+ uint64_t edt_offset;
+ MemTxResult result;
+ AddressSpace *edt_as = NULL;
+
+ if (edt_index < XIVE_TABLE_EDT_MAX) {
+ edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
+ }
+
+ switch (edt_type) {
+ case CQ_TDR_EDT_IPI:
+ edt_as = &xive->ipi_as;
+ break;
+ case CQ_TDR_EDT_EQ:
+ edt_as = &xive->end_as;
+ break;
+ default:
+ xive_error(xive, "VC: invalid EDT type for write @%"HWADDR_PRIx,
+ offset);
+ return;
+ }
+
+ /* Remap the offset for the targeted address space */
+ edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
+
+ address_space_stq(edt_as, edt_offset, val, MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ xive_error(xive, "VC: write failed at @0x%"HWADDR_PRIx, edt_offset);
+ }
+}
+
+static const MemoryRegionOps pnv_xive_vc_ops = {
+ .read = pnv_xive_vc_read,
+ .write = pnv_xive_vc_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+/*
+ * Presenter Controller MMIO region. The Virtualization Controller
+ * updates the IPB in the NVT table when required. Not modeled.
+ */
+static uint64_t pnv_xive_pc_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+
+ xive_error(xive, "PC: invalid read @%"HWADDR_PRIx, addr);
+ return -1;
+}
+
+static void pnv_xive_pc_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ PnvXive *xive = PNV_XIVE(opaque);
+
+ xive_error(xive, "PC: invalid write to VC @%"HWADDR_PRIx, addr);
+}
+
+static const MemoryRegionOps pnv_xive_pc_ops = {
+ .read = pnv_xive_pc_read,
+ .write = pnv_xive_pc_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon)
+{
+ XiveRouter *xrtr = XIVE_ROUTER(xive);
+ uint8_t blk = xive->chip->chip_id;
+ uint32_t srcno0 = XIVE_SRCNO(blk, 0);
+ uint32_t nr_ipis = pnv_xive_nr_ipis(xive);
+ uint32_t nr_ends = pnv_xive_nr_ends(xive);
+ XiveEAS eas;
+ XiveEND end;
+ int i;
+
+ monitor_printf(mon, "XIVE[%x] Source %08x .. %08x\n", blk, srcno0,
+ srcno0 + nr_ipis - 1);
+ xive_source_pic_print_info(&xive->ipi_source, srcno0, mon);
+
+ monitor_printf(mon, "XIVE[%x] EAT %08x .. %08x\n", blk, srcno0,
+ srcno0 + nr_ipis - 1);
+ for (i = 0; i < nr_ipis; i++) {
+ if (xive_router_get_eas(xrtr, blk, i, &eas)) {
+ break;
+ }
+ if (!xive_eas_is_masked(&eas)) {
+ xive_eas_pic_print_info(&eas, i, mon);
+ }
+ }
+
+ monitor_printf(mon, "XIVE[%x] ENDT %08x .. %08x\n", blk, 0, nr_ends - 1);
+ for (i = 0; i < nr_ends; i++) {
+ if (xive_router_get_end(xrtr, blk, i, &end)) {
+ break;
+ }
+ xive_end_pic_print_info(&end, i, mon);
+ }
+}
+
+static void pnv_xive_reset(void *dev)
+{
+ PnvXive *xive = PNV_XIVE(dev);
+ XiveSource *xsrc = &xive->ipi_source;
+ XiveENDSource *end_xsrc = &xive->end_source;
+
+ /*
+ * Use the PnvChip id to identify the XIVE interrupt controller.
+ * It can be overriden by configuration at runtime.
+ */
+ xive->tctx_chipid = xive->chip->chip_id;
+
+ /* Default page size (Should be changed at runtime to 64k) */
+ xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
+
+ /* Clear subregions */
+ if (memory_region_is_mapped(&xsrc->esb_mmio)) {
+ memory_region_del_subregion(&xive->ipi_edt_mmio, &xsrc->esb_mmio);
+ }
+
+ if (memory_region_is_mapped(&xive->ipi_edt_mmio)) {
+ memory_region_del_subregion(&xive->ipi_mmio, &xive->ipi_edt_mmio);
+ }
+
+ if (memory_region_is_mapped(&end_xsrc->esb_mmio)) {
+ memory_region_del_subregion(&xive->end_edt_mmio, &end_xsrc->esb_mmio);
+ }
+
+ if (memory_region_is_mapped(&xive->end_edt_mmio)) {
+ memory_region_del_subregion(&xive->end_mmio, &xive->end_edt_mmio);
+ }
+}
+
+static void pnv_xive_init(Object *obj)
+{
+ PnvXive *xive = PNV_XIVE(obj);
+
+ object_initialize_child(obj, "ipi_source", &xive->ipi_source,
+ sizeof(xive->ipi_source), TYPE_XIVE_SOURCE,
+ &error_abort, NULL);
+ object_initialize_child(obj, "end_source", &xive->end_source,
+ sizeof(xive->end_source), TYPE_XIVE_END_SOURCE,
+ &error_abort, NULL);
+}
+
+/*
+ * Maximum number of IRQs and ENDs supported by HW
+ */
+#define PNV_XIVE_NR_IRQS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
+#define PNV_XIVE_NR_ENDS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
+
+static void pnv_xive_realize(DeviceState *dev, Error **errp)
+{
+ PnvXive *xive = PNV_XIVE(dev);
+ XiveSource *xsrc = &xive->ipi_source;
+ XiveENDSource *end_xsrc = &xive->end_source;
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = object_property_get_link(OBJECT(dev), "chip", &local_err);
+ if (!obj) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'chip' not found: ");
+ return;
+ }
+
+ /* The PnvChip id identifies the XIVE interrupt controller. */
+ xive->chip = PNV_CHIP(obj);
+
+ /*
+ * The XiveSource and XiveENDSource objects are realized with the
+ * maximum allowed HW configuration. The ESB MMIO regions will be
+ * resized dynamically when the controller is configured by the FW
+ * to limit accesses to resources not provisioned.
+ */
+ object_property_set_int(OBJECT(xsrc), PNV_XIVE_NR_IRQS, "nr-irqs",
+ &error_fatal);
+ object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(xive),
+ &error_fatal);
+ object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ object_property_set_int(OBJECT(end_xsrc), PNV_XIVE_NR_ENDS, "nr-ends",
+ &error_fatal);
+ object_property_add_const_link(OBJECT(end_xsrc), "xive", OBJECT(xive),
+ &error_fatal);
+ object_property_set_bool(OBJECT(end_xsrc), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* Default page size. Generally changed at runtime to 64k */
+ xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
+
+ /* XSCOM region, used for initial configuration of the BARs */
+ memory_region_init_io(&xive->xscom_regs, OBJECT(dev), &pnv_xive_xscom_ops,
+ xive, "xscom-xive", PNV9_XSCOM_XIVE_SIZE << 3);
+
+ /* Interrupt controller MMIO regions */
+ memory_region_init(&xive->ic_mmio, OBJECT(dev), "xive-ic",
+ PNV9_XIVE_IC_SIZE);
+
+ memory_region_init_io(&xive->ic_reg_mmio, OBJECT(dev), &pnv_xive_ic_reg_ops,
+ xive, "xive-ic-reg", 1 << xive->ic_shift);
+ memory_region_init_io(&xive->ic_notify_mmio, OBJECT(dev),
+ &pnv_xive_ic_notify_ops,
+ xive, "xive-ic-notify", 1 << xive->ic_shift);
+
+ /* The Pervasive LSI trigger and EOI pages (not modeled) */
+ memory_region_init_io(&xive->ic_lsi_mmio, OBJECT(dev), &pnv_xive_ic_lsi_ops,
+ xive, "xive-ic-lsi", 2 << xive->ic_shift);
+
+ /* Thread Interrupt Management Area (Indirect) */
+ memory_region_init_io(&xive->tm_indirect_mmio, OBJECT(dev),
+ &xive_tm_indirect_ops,
+ xive, "xive-tima-indirect", PNV9_XIVE_TM_SIZE);
+ /*
+ * Overall Virtualization Controller MMIO region containing the
+ * IPI ESB pages and END ESB pages. The layout is defined by the
+ * EDT "Domain table" and the accesses are dispatched using
+ * address spaces for each.
+ */
+ memory_region_init_io(&xive->vc_mmio, OBJECT(xive), &pnv_xive_vc_ops, xive,
+ "xive-vc", PNV9_XIVE_VC_SIZE);
+
+ memory_region_init(&xive->ipi_mmio, OBJECT(xive), "xive-vc-ipi",
+ PNV9_XIVE_VC_SIZE);
+ address_space_init(&xive->ipi_as, &xive->ipi_mmio, "xive-vc-ipi");
+ memory_region_init(&xive->end_mmio, OBJECT(xive), "xive-vc-end",
+ PNV9_XIVE_VC_SIZE);
+ address_space_init(&xive->end_as, &xive->end_mmio, "xive-vc-end");
+
+ /*
+ * The MMIO windows exposing the IPI ESBs and the END ESBs in the
+ * VC region. Their size is configured by the FW in the EDT table.
+ */
+ memory_region_init(&xive->ipi_edt_mmio, OBJECT(xive), "xive-vc-ipi-edt", 0);
+ memory_region_init(&xive->end_edt_mmio, OBJECT(xive), "xive-vc-end-edt", 0);
+
+ /* Presenter Controller MMIO region (not modeled) */
+ memory_region_init_io(&xive->pc_mmio, OBJECT(xive), &pnv_xive_pc_ops, xive,
+ "xive-pc", PNV9_XIVE_PC_SIZE);
+
+ /* Thread Interrupt Management Area (Direct) */
+ memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops,
+ xive, "xive-tima", PNV9_XIVE_TM_SIZE);
+
+ qemu_register_reset(pnv_xive_reset, dev);
+}
+
+static int pnv_xive_dt_xscom(PnvXScomInterface *dev, void *fdt,
+ int xscom_offset)
+{
+ const char compat[] = "ibm,power9-xive-x";
+ char *name;
+ int offset;
+ uint32_t lpc_pcba = PNV9_XSCOM_XIVE_BASE;
+ uint32_t reg[] = {
+ cpu_to_be32(lpc_pcba),
+ cpu_to_be32(PNV9_XSCOM_XIVE_SIZE)
+ };
+
+ name = g_strdup_printf("xive@%x", lpc_pcba);
+ offset = fdt_add_subnode(fdt, xscom_offset, name);
+ _FDT(offset);
+ g_free(name);
+
+ _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+ _FDT((fdt_setprop(fdt, offset, "compatible", compat,
+ sizeof(compat))));
+ return 0;
+}
+
+static 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),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_xive_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
+ XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
+ XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
+
+ xdc->dt_xscom = pnv_xive_dt_xscom;
+
+ dc->desc = "PowerNV XIVE Interrupt Controller";
+ dc->realize = pnv_xive_realize;
+ dc->props = pnv_xive_properties;
+
+ xrc->get_eas = pnv_xive_get_eas;
+ xrc->get_end = pnv_xive_get_end;
+ xrc->write_end = pnv_xive_write_end;
+ xrc->get_nvt = pnv_xive_get_nvt;
+ xrc->write_nvt = pnv_xive_write_nvt;
+ xrc->get_tctx = pnv_xive_get_tctx;
+
+ xnc->notify = pnv_xive_notify;
+};
+
+static const TypeInfo pnv_xive_info = {
+ .name = TYPE_PNV_XIVE,
+ .parent = TYPE_XIVE_ROUTER,
+ .instance_init = pnv_xive_init,
+ .instance_size = sizeof(PnvXive),
+ .class_init = pnv_xive_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_PNV_XSCOM_INTERFACE },
+ { }
+ }
+};
+
+static void pnv_xive_register_types(void)
+{
+ type_register_static(&pnv_xive_info);
+}
+
+type_init(pnv_xive_register_types)
diff --git a/hw/intc/pnv_xive_regs.h b/hw/intc/pnv_xive_regs.h
new file mode 100644
index 0000000000..c78f030c02
--- /dev/null
+++ b/hw/intc/pnv_xive_regs.h
@@ -0,0 +1,248 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * 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.
+ */
+
+#ifndef PPC_PNV_XIVE_REGS_H
+#define PPC_PNV_XIVE_REGS_H
+
+/* IC register offsets 0x0 - 0x400 */
+#define CQ_SWI_CMD_HIST 0x020
+#define CQ_SWI_CMD_POLL 0x028
+#define CQ_SWI_CMD_BCAST 0x030
+#define CQ_SWI_CMD_ASSIGN 0x038
+#define CQ_SWI_CMD_BLK_UPD 0x040
+#define CQ_SWI_RSP 0x048
+#define CQ_CFG_PB_GEN 0x050
+#define CQ_INT_ADDR_OPT PPC_BITMASK(14, 15)
+#define CQ_MSGSND 0x058
+#define CQ_CNPM_SEL 0x078
+#define CQ_IC_BAR 0x080
+#define CQ_IC_BAR_VALID PPC_BIT(0)
+#define CQ_IC_BAR_64K PPC_BIT(1)
+#define CQ_TM1_BAR 0x90
+#define CQ_TM2_BAR 0x0a0
+#define CQ_TM_BAR_VALID PPC_BIT(0)
+#define CQ_TM_BAR_64K PPC_BIT(1)
+#define CQ_PC_BAR 0x0b0
+#define CQ_PC_BAR_VALID PPC_BIT(0)
+#define CQ_PC_BARM 0x0b8
+#define CQ_PC_BARM_MASK PPC_BITMASK(26, 38)
+#define CQ_VC_BAR 0x0c0
+#define CQ_VC_BAR_VALID PPC_BIT(0)
+#define CQ_VC_BARM 0x0c8
+#define CQ_VC_BARM_MASK PPC_BITMASK(21, 37)
+#define CQ_TAR 0x0f0
+#define CQ_TAR_TBL_AUTOINC PPC_BIT(0)
+#define CQ_TAR_TSEL PPC_BITMASK(12, 15)
+#define CQ_TAR_TSEL_BLK PPC_BIT(12)
+#define CQ_TAR_TSEL_MIG PPC_BIT(13)
+#define CQ_TAR_TSEL_VDT PPC_BIT(14)
+#define CQ_TAR_TSEL_EDT PPC_BIT(15)
+#define CQ_TAR_TSEL_INDEX PPC_BITMASK(26, 31)
+#define CQ_TDR 0x0f8
+#define CQ_TDR_VDT_VALID PPC_BIT(0)
+#define CQ_TDR_VDT_BLK PPC_BITMASK(11, 15)
+#define CQ_TDR_VDT_INDEX PPC_BITMASK(28, 31)
+#define CQ_TDR_EDT_TYPE PPC_BITMASK(0, 1)
+#define CQ_TDR_EDT_INVALID 0
+#define CQ_TDR_EDT_IPI 1
+#define CQ_TDR_EDT_EQ 2
+#define CQ_TDR_EDT_BLK PPC_BITMASK(12, 15)
+#define CQ_TDR_EDT_INDEX PPC_BITMASK(26, 31)
+#define CQ_PBI_CTL 0x100
+#define CQ_PBI_PC_64K PPC_BIT(5)
+#define CQ_PBI_VC_64K PPC_BIT(6)
+#define CQ_PBI_LNX_TRIG PPC_BIT(7)
+#define CQ_PBI_FORCE_TM_LOCAL PPC_BIT(22)
+#define CQ_PBO_CTL 0x108
+#define CQ_AIB_CTL 0x110
+#define CQ_RST_CTL 0x118
+#define CQ_FIRMASK 0x198
+#define CQ_FIRMASK_AND 0x1a0
+#define CQ_FIRMASK_OR 0x1a8
+
+/* PC LBS1 register offsets 0x400 - 0x800 */
+#define PC_TCTXT_CFG 0x400
+#define PC_TCTXT_CFG_BLKGRP_EN PPC_BIT(0)
+#define PC_TCTXT_CFG_TARGET_EN PPC_BIT(1)
+#define PC_TCTXT_CFG_LGS_EN PPC_BIT(2)
+#define PC_TCTXT_CFG_STORE_ACK PPC_BIT(3)
+#define PC_TCTXT_CFG_HARD_CHIPID_BLK PPC_BIT(8)
+#define PC_TCTXT_CHIPID_OVERRIDE PPC_BIT(9)
+#define PC_TCTXT_CHIPID PPC_BITMASK(12, 15)
+#define PC_TCTXT_INIT_AGE PPC_BITMASK(30, 31)
+#define PC_TCTXT_TRACK 0x408
+#define PC_TCTXT_TRACK_EN PPC_BIT(0)
+#define PC_TCTXT_INDIR0 0x420
+#define PC_TCTXT_INDIR_VALID PPC_BIT(0)
+#define PC_TCTXT_INDIR_THRDID PPC_BITMASK(9, 15)
+#define PC_TCTXT_INDIR1 0x428
+#define PC_TCTXT_INDIR2 0x430
+#define PC_TCTXT_INDIR3 0x438
+#define PC_THREAD_EN_REG0 0x440
+#define PC_THREAD_EN_REG0_SET 0x448
+#define PC_THREAD_EN_REG0_CLR 0x450
+#define PC_THREAD_EN_REG1 0x460
+#define PC_THREAD_EN_REG1_SET 0x468
+#define PC_THREAD_EN_REG1_CLR 0x470
+#define PC_GLOBAL_CONFIG 0x480
+#define PC_GCONF_INDIRECT PPC_BIT(32)
+#define PC_GCONF_CHIPID_OVR PPC_BIT(40)
+#define PC_GCONF_CHIPID PPC_BITMASK(44, 47)
+#define PC_VSD_TABLE_ADDR 0x488
+#define PC_VSD_TABLE_DATA 0x490
+#define PC_AT_KILL 0x4b0
+#define PC_AT_KILL_VALID PPC_BIT(0)
+#define PC_AT_KILL_BLOCK_ID PPC_BITMASK(27, 31)
+#define PC_AT_KILL_OFFSET PPC_BITMASK(48, 60)
+#define PC_AT_KILL_MASK 0x4b8
+
+/* PC LBS2 register offsets */
+#define PC_VPC_CACHE_ENABLE 0x708
+#define PC_VPC_CACHE_EN_MASK PPC_BITMASK(0, 31)
+#define PC_VPC_SCRUB_TRIG 0x710
+#define PC_VPC_SCRUB_MASK 0x718
+#define PC_SCRUB_VALID PPC_BIT(0)
+#define PC_SCRUB_WANT_DISABLE PPC_BIT(1)
+#define PC_SCRUB_WANT_INVAL PPC_BIT(2)
+#define PC_SCRUB_BLOCK_ID PPC_BITMASK(27, 31)
+#define PC_SCRUB_OFFSET PPC_BITMASK(45, 63)
+#define PC_VPC_CWATCH_SPEC 0x738
+#define PC_VPC_CWATCH_CONFLICT PPC_BIT(0)
+#define PC_VPC_CWATCH_FULL PPC_BIT(8)
+#define PC_VPC_CWATCH_BLOCKID PPC_BITMASK(27, 31)
+#define PC_VPC_CWATCH_OFFSET PPC_BITMASK(45, 63)
+#define PC_VPC_CWATCH_DAT0 0x740
+#define PC_VPC_CWATCH_DAT1 0x748
+#define PC_VPC_CWATCH_DAT2 0x750
+#define PC_VPC_CWATCH_DAT3 0x758
+#define PC_VPC_CWATCH_DAT4 0x760
+#define PC_VPC_CWATCH_DAT5 0x768
+#define PC_VPC_CWATCH_DAT6 0x770
+#define PC_VPC_CWATCH_DAT7 0x778
+
+/* VC0 register offsets 0x800 - 0xFFF */
+#define VC_GLOBAL_CONFIG 0x800
+#define VC_GCONF_INDIRECT PPC_BIT(32)
+#define VC_VSD_TABLE_ADDR 0x808
+#define VC_VSD_TABLE_DATA 0x810
+#define VC_IVE_ISB_BLOCK_MODE 0x818
+#define VC_EQD_BLOCK_MODE 0x820
+#define VC_VPS_BLOCK_MODE 0x828
+#define VC_IRQ_CONFIG_IPI 0x840
+#define VC_IRQ_CONFIG_MEMB_EN PPC_BIT(45)
+#define VC_IRQ_CONFIG_MEMB_SZ PPC_BITMASK(46, 51)
+#define VC_IRQ_CONFIG_HW 0x848
+#define VC_IRQ_CONFIG_CASCADE1 0x850
+#define VC_IRQ_CONFIG_CASCADE2 0x858
+#define VC_IRQ_CONFIG_REDIST 0x860
+#define VC_IRQ_CONFIG_IPI_CASC 0x868
+#define VC_AIB_TX_ORDER_TAG2_REL_TF PPC_BIT(20)
+#define VC_AIB_TX_ORDER_TAG2 0x890
+#define VC_AT_MACRO_KILL 0x8b0
+#define VC_AT_MACRO_KILL_MASK 0x8b8
+#define VC_KILL_VALID PPC_BIT(0)
+#define VC_KILL_TYPE PPC_BITMASK(14, 15)
+#define VC_KILL_IRQ 0
+#define VC_KILL_IVC 1
+#define VC_KILL_SBC 2
+#define VC_KILL_EQD 3
+#define VC_KILL_BLOCK_ID PPC_BITMASK(27, 31)
+#define VC_KILL_OFFSET PPC_BITMASK(48, 60)
+#define VC_EQC_CACHE_ENABLE 0x908
+#define VC_EQC_CACHE_EN_MASK PPC_BITMASK(0, 15)
+#define VC_EQC_SCRUB_TRIG 0x910
+#define VC_EQC_SCRUB_MASK 0x918
+#define VC_EQC_CONFIG 0x920
+#define X_VC_EQC_CONFIG 0x214 /* XSCOM register */
+#define VC_EQC_CONF_SYNC_IPI PPC_BIT(32)
+#define VC_EQC_CONF_SYNC_HW PPC_BIT(33)
+#define VC_EQC_CONF_SYNC_ESC1 PPC_BIT(34)
+#define VC_EQC_CONF_SYNC_ESC2 PPC_BIT(35)
+#define VC_EQC_CONF_SYNC_REDI PPC_BIT(36)
+#define VC_EQC_CONF_EQP_INTERLEAVE PPC_BIT(38)
+#define VC_EQC_CONF_ENABLE_END_s_BIT PPC_BIT(39)
+#define VC_EQC_CONF_ENABLE_END_u_BIT PPC_BIT(40)
+#define VC_EQC_CONF_ENABLE_END_c_BIT PPC_BIT(41)
+#define VC_EQC_CONF_ENABLE_MORE_QSZ PPC_BIT(42)
+#define VC_EQC_CONF_SKIP_ESCALATE PPC_BIT(43)
+#define VC_EQC_CWATCH_SPEC 0x928
+#define VC_EQC_CWATCH_CONFLICT PPC_BIT(0)
+#define VC_EQC_CWATCH_FULL PPC_BIT(8)
+#define VC_EQC_CWATCH_BLOCKID PPC_BITMASK(28, 31)
+#define VC_EQC_CWATCH_OFFSET PPC_BITMASK(40, 63)
+#define VC_EQC_CWATCH_DAT0 0x930
+#define VC_EQC_CWATCH_DAT1 0x938
+#define VC_EQC_CWATCH_DAT2 0x940
+#define VC_EQC_CWATCH_DAT3 0x948
+#define VC_IVC_SCRUB_TRIG 0x990
+#define VC_IVC_SCRUB_MASK 0x998
+#define VC_SBC_SCRUB_TRIG 0xa10
+#define VC_SBC_SCRUB_MASK 0xa18
+#define VC_SCRUB_VALID PPC_BIT(0)
+#define VC_SCRUB_WANT_DISABLE PPC_BIT(1)
+#define VC_SCRUB_WANT_INVAL PPC_BIT(2) /* EQC and SBC only */
+#define VC_SCRUB_BLOCK_ID PPC_BITMASK(28, 31)
+#define VC_SCRUB_OFFSET PPC_BITMASK(40, 63)
+#define VC_IVC_CACHE_ENABLE 0x988
+#define VC_IVC_CACHE_EN_MASK PPC_BITMASK(0, 15)
+#define VC_SBC_CACHE_ENABLE 0xa08
+#define VC_SBC_CACHE_EN_MASK PPC_BITMASK(0, 15)
+#define VC_IVC_CACHE_SCRUB_TRIG 0x990
+#define VC_IVC_CACHE_SCRUB_MASK 0x998
+#define VC_SBC_CACHE_ENABLE 0xa08
+#define VC_SBC_CACHE_SCRUB_TRIG 0xa10
+#define VC_SBC_CACHE_SCRUB_MASK 0xa18
+#define VC_SBC_CONFIG 0xa20
+#define VC_SBC_CONF_CPLX_CIST PPC_BIT(44)
+#define VC_SBC_CONF_CIST_BOTH PPC_BIT(45)
+#define VC_SBC_CONF_NO_UPD_PRF PPC_BIT(59)
+
+/* VC1 register offsets */
+
+/* VSD Table address register definitions (shared) */
+#define VST_ADDR_AUTOINC PPC_BIT(0)
+#define VST_TABLE_SELECT PPC_BITMASK(13, 15)
+#define VST_TSEL_IVT 0
+#define VST_TSEL_SBE 1
+#define VST_TSEL_EQDT 2
+#define VST_TSEL_VPDT 3
+#define VST_TSEL_IRQ 4 /* VC only */
+#define VST_TABLE_BLOCK PPC_BITMASK(27, 31)
+
+/* Number of queue overflow pages */
+#define VC_QUEUE_OVF_COUNT 6
+
+/*
+ * Bits in a VSD entry.
+ *
+ * Note: the address is naturally aligned, we don't use a PPC_BITMASK,
+ * but just a mask to apply to the address before OR'ing it in.
+ *
+ * Note: VSD_FIRMWARE is a SW bit ! It hijacks an unused bit in the
+ * VSD and is only meant to be used in indirect mode !
+ */
+#define VSD_MODE PPC_BITMASK(0, 1)
+#define VSD_MODE_SHARED 1
+#define VSD_MODE_EXCLUSIVE 2
+#define VSD_MODE_FORWARD 3
+#define VSD_ADDRESS_MASK 0x0ffffffffffff000ull
+#define VSD_MIGRATION_REG PPC_BITMASK(52, 55)
+#define VSD_INDIRECT PPC_BIT(56)
+#define VSD_TSIZE PPC_BITMASK(59, 63)
+#define VSD_FIRMWARE PPC_BIT(2) /* Read warning above */
+
+#define VC_EQC_SYNC_MASK \
+ (VC_EQC_CONF_SYNC_IPI | \
+ VC_EQC_CONF_SYNC_HW | \
+ VC_EQC_CONF_SYNC_ESC1 | \
+ VC_EQC_CONF_SYNC_ESC2 | \
+ VC_EQC_CONF_SYNC_REDI)
+
+
+#endif /* PPC_PNV_XIVE_REGS_H */
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index e0e5cb5d8e..097f88d460 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -117,7 +117,7 @@ static int spapr_xive_target_to_end(uint32_t target, uint8_t prio,
* On sPAPR machines, use a simplified output for the XIVE END
* structure dumping only the information related to the OS EQ.
*/
-static void spapr_xive_end_pic_print_info(sPAPRXive *xive, XiveEND *end,
+static void spapr_xive_end_pic_print_info(SpaprXive *xive, XiveEND *end,
Monitor *mon)
{
uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
@@ -135,7 +135,7 @@ static void spapr_xive_end_pic_print_info(sPAPRXive *xive, XiveEND *end,
monitor_printf(mon, "]");
}
-void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon)
+void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon)
{
XiveSource *xsrc = &xive->source;
int i;
@@ -173,14 +173,14 @@ void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon)
}
}
-static void spapr_xive_map_mmio(sPAPRXive *xive)
+static void spapr_xive_map_mmio(SpaprXive *xive)
{
sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->vc_base);
sysbus_mmio_map(SYS_BUS_DEVICE(xive), 1, xive->end_base);
sysbus_mmio_map(SYS_BUS_DEVICE(xive), 2, xive->tm_base);
}
-void spapr_xive_mmio_set_enabled(sPAPRXive *xive, bool enable)
+void spapr_xive_mmio_set_enabled(SpaprXive *xive, bool enable)
{
memory_region_set_enabled(&xive->source.esb_mmio, enable);
memory_region_set_enabled(&xive->tm_mmio, enable);
@@ -216,7 +216,7 @@ static void spapr_xive_end_reset(XiveEND *end)
static void spapr_xive_reset(void *dev)
{
- sPAPRXive *xive = SPAPR_XIVE(dev);
+ SpaprXive *xive = SPAPR_XIVE(dev);
int i;
/*
@@ -242,7 +242,7 @@ static void spapr_xive_reset(void *dev)
static void spapr_xive_instance_init(Object *obj)
{
- sPAPRXive *xive = SPAPR_XIVE(obj);
+ SpaprXive *xive = SPAPR_XIVE(obj);
object_initialize_child(obj, "source", &xive->source, sizeof(xive->source),
TYPE_XIVE_SOURCE, &error_abort, NULL);
@@ -254,7 +254,7 @@ static void spapr_xive_instance_init(Object *obj)
static void spapr_xive_realize(DeviceState *dev, Error **errp)
{
- sPAPRXive *xive = SPAPR_XIVE(dev);
+ SpaprXive *xive = SPAPR_XIVE(dev);
XiveSource *xsrc = &xive->source;
XiveENDSource *end_xsrc = &xive->end_source;
Error *local_err = NULL;
@@ -325,7 +325,7 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp)
static int spapr_xive_get_eas(XiveRouter *xrtr, uint8_t eas_blk,
uint32_t eas_idx, XiveEAS *eas)
{
- sPAPRXive *xive = SPAPR_XIVE(xrtr);
+ SpaprXive *xive = SPAPR_XIVE(xrtr);
if (eas_idx >= xive->nr_irqs) {
return -1;
@@ -338,7 +338,7 @@ static int spapr_xive_get_eas(XiveRouter *xrtr, uint8_t eas_blk,
static int spapr_xive_get_end(XiveRouter *xrtr,
uint8_t end_blk, uint32_t end_idx, XiveEND *end)
{
- sPAPRXive *xive = SPAPR_XIVE(xrtr);
+ SpaprXive *xive = SPAPR_XIVE(xrtr);
if (end_idx >= xive->nr_ends) {
return -1;
@@ -352,7 +352,7 @@ static int spapr_xive_write_end(XiveRouter *xrtr, uint8_t end_blk,
uint32_t end_idx, XiveEND *end,
uint8_t word_number)
{
- sPAPRXive *xive = SPAPR_XIVE(xrtr);
+ SpaprXive *xive = SPAPR_XIVE(xrtr);
if (end_idx >= xive->nr_ends) {
return -1;
@@ -432,20 +432,20 @@ static const VMStateDescription vmstate_spapr_xive = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_UINT32_EQUAL(nr_irqs, sPAPRXive, NULL),
- VMSTATE_STRUCT_VARRAY_POINTER_UINT32(eat, sPAPRXive, nr_irqs,
+ VMSTATE_UINT32_EQUAL(nr_irqs, SpaprXive, NULL),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(eat, SpaprXive, nr_irqs,
vmstate_spapr_xive_eas, XiveEAS),
- VMSTATE_STRUCT_VARRAY_POINTER_UINT32(endt, sPAPRXive, nr_ends,
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(endt, SpaprXive, nr_ends,
vmstate_spapr_xive_end, XiveEND),
VMSTATE_END_OF_LIST()
},
};
static 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_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_END_OF_LIST(),
};
@@ -471,7 +471,7 @@ static const TypeInfo spapr_xive_info = {
.name = TYPE_SPAPR_XIVE,
.parent = TYPE_XIVE_ROUTER,
.instance_init = spapr_xive_instance_init,
- .instance_size = sizeof(sPAPRXive),
+ .instance_size = sizeof(SpaprXive),
.class_init = spapr_xive_class_init,
};
@@ -482,7 +482,7 @@ static void spapr_xive_register_types(void)
type_init(spapr_xive_register_types)
-bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi)
+bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi)
{
XiveSource *xsrc = &xive->source;
@@ -497,7 +497,7 @@ bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi)
return true;
}
-bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn)
+bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn)
{
if (lisn >= xive->nr_irqs) {
return false;
@@ -576,11 +576,11 @@ static bool spapr_xive_priority_is_reserved(uint8_t priority)
#define SPAPR_XIVE_SRC_STORE_EOI PPC_BIT(63) /* Store EOI support */
static target_ulong h_int_get_source_info(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
XiveSource *xsrc = &xive->source;
target_ulong flags = args[0];
target_ulong lisn = args[1];
@@ -686,11 +686,11 @@ static target_ulong h_int_get_source_info(PowerPCCPU *cpu,
#define SPAPR_XIVE_SRC_MASK PPC_BIT(63)
static target_ulong h_int_set_source_config(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
XiveEAS eas, new_eas;
target_ulong flags = args[0];
target_ulong lisn = args[1];
@@ -783,11 +783,11 @@ out:
* equivalent to the LISN if not changed by H_INT_SET_SOURCE_CONFIG)
*/
static target_ulong h_int_get_source_config(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
target_ulong flags = args[0];
target_ulong lisn = args[1];
XiveEAS eas;
@@ -856,11 +856,11 @@ static target_ulong h_int_get_source_config(PowerPCCPU *cpu,
* - R5: Power of 2 page size of the notification page
*/
static target_ulong h_int_get_queue_info(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
XiveENDSource *end_xsrc = &xive->end_source;
target_ulong flags = args[0];
target_ulong target = args[1];
@@ -942,11 +942,11 @@ static target_ulong h_int_get_queue_info(PowerPCCPU *cpu,
#define SPAPR_XIVE_END_ALWAYS_NOTIFY PPC_BIT(63)
static target_ulong h_int_set_queue_config(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
target_ulong flags = args[0];
target_ulong target = args[1];
target_ulong priority = args[2];
@@ -1095,11 +1095,11 @@ out:
#define SPAPR_XIVE_END_DEBUG PPC_BIT(63)
static target_ulong h_int_get_queue_config(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
target_ulong flags = args[0];
target_ulong target = args[1];
target_ulong priority = args[2];
@@ -1187,7 +1187,7 @@ static target_ulong h_int_get_queue_config(PowerPCCPU *cpu,
* - None
*/
static target_ulong h_int_set_os_reporting_line(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
@@ -1223,7 +1223,7 @@ static target_ulong h_int_set_os_reporting_line(PowerPCCPU *cpu,
* - R4: The logical real address of the reporting line if set, else -1
*/
static target_ulong h_int_get_os_reporting_line(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
@@ -1266,11 +1266,11 @@ static target_ulong h_int_get_os_reporting_line(PowerPCCPU *cpu,
#define SPAPR_XIVE_ESB_STORE PPC_BIT(63)
static target_ulong h_int_esb(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
XiveEAS eas;
target_ulong flags = args[0];
target_ulong lisn = args[1];
@@ -1334,11 +1334,11 @@ static target_ulong h_int_esb(PowerPCCPU *cpu,
* - None
*/
static target_ulong h_int_sync(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
XiveEAS eas;
target_ulong flags = args[0];
target_ulong lisn = args[1];
@@ -1388,11 +1388,11 @@ static target_ulong h_int_sync(PowerPCCPU *cpu,
* - None
*/
static target_ulong h_int_reset(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
target_ulong flags = args[0];
if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
@@ -1407,7 +1407,7 @@ static target_ulong h_int_reset(PowerPCCPU *cpu,
return H_SUCCESS;
}
-void spapr_xive_hcall_init(sPAPRMachineState *spapr)
+void spapr_xive_hcall_init(SpaprMachineState *spapr)
{
spapr_register_hypercall(H_INT_GET_SOURCE_INFO, h_int_get_source_info);
spapr_register_hypercall(H_INT_SET_SOURCE_CONFIG, h_int_set_source_config);
@@ -1424,10 +1424,10 @@ void spapr_xive_hcall_init(sPAPRMachineState *spapr)
spapr_register_hypercall(H_INT_RESET, h_int_reset);
}
-void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+void spapr_dt_xive(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
uint32_t phandle)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
int node;
uint64_t timas[2 * 2];
/* Interrupt number ranges for the IPIs */
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index c6e1b630a4..78a252e6df 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -291,7 +291,7 @@ void ics_kvm_set_irq(ICSState *ics, int srcno, int val)
}
}
-static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_dummy(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
@@ -300,7 +300,7 @@ static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr,
__func__);
}
-int xics_kvm_init(sPAPRMachineState *spapr, Error **errp)
+int xics_kvm_init(SpaprMachineState *spapr, Error **errp)
{
int rc;
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index 53bda6661b..607e1c167b 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -41,7 +41,7 @@
* Guest interfaces
*/
-static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_cppr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong cppr = args[0];
@@ -50,7 +50,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_ipi(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong mfrr = args[1];
@@ -64,7 +64,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_xirr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
@@ -73,7 +73,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_xirr_x(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
@@ -83,7 +83,7 @@ static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_eoi(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong xirr = args[0];
@@ -92,7 +92,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_ipoll(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
uint32_t mfrr;
@@ -104,7 +104,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
@@ -137,7 +137,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_get_xive(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
@@ -167,7 +167,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 2, ics->irqs[srcno].priority);
}
-static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_int_off(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
@@ -198,7 +198,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
@@ -230,7 +230,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-void xics_spapr_init(sPAPRMachineState *spapr)
+void xics_spapr_init(SpaprMachineState *spapr)
{
/* Registration of global state belongs into realize */
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
@@ -246,7 +246,7 @@ void xics_spapr_init(sPAPRMachineState *spapr)
spapr_register_hypercall(H_IPOLL, h_ipoll);
}
-void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
uint32_t phandle)
{
uint32_t interrupt_server_ranges_prop[] = {
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index daa7badc84..a0b87001da 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -54,6 +54,8 @@ 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();
}
@@ -88,7 +90,16 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
uint8_t *regs = &tctx->regs[ring];
if (regs[TM_PIPR] < regs[TM_CPPR]) {
- regs[TM_NSR] |= exception_mask(ring);
+ switch (ring) {
+ case TM_QW1_OS:
+ regs[TM_NSR] |= TM_QW1_NSR_EO;
+ break;
+ case TM_QW3_HV_PHYS:
+ regs[TM_NSR] |= (TM_QW3_NSR_HE_PHYS << 6);
+ break;
+ default:
+ g_assert_not_reached();
+ }
qemu_irq_raise(tctx->output);
}
}
@@ -109,6 +120,38 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
* XIVE Thread Interrupt Management Area (TIMA)
*/
+static void xive_tm_set_hv_cppr(XiveTCTX *tctx, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ xive_tctx_set_cppr(tctx, TM_QW3_HV_PHYS, value & 0xff);
+}
+
+static uint64_t xive_tm_ack_hv_reg(XiveTCTX *tctx, hwaddr offset, unsigned size)
+{
+ return xive_tctx_accept(tctx, TM_QW3_HV_PHYS);
+}
+
+static uint64_t xive_tm_pull_pool_ctx(XiveTCTX *tctx, hwaddr offset,
+ unsigned size)
+{
+ uint64_t ret;
+
+ ret = tctx->regs[TM_QW2_HV_POOL + TM_WORD2] & TM_QW2W2_POOL_CAM;
+ tctx->regs[TM_QW2_HV_POOL + TM_WORD2] &= ~TM_QW2W2_POOL_CAM;
+ return ret;
+}
+
+static void xive_tm_vt_push(XiveTCTX *tctx, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] = value & 0xff;
+}
+
+static uint64_t xive_tm_vt_poll(XiveTCTX *tctx, hwaddr offset, unsigned size)
+{
+ return tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] & 0xff;
+}
+
/*
* Define an access map for each page of the TIMA that we will use in
* the memory region ops to filter values when doing loads and stores
@@ -288,10 +331,16 @@ static const XiveTmOp xive_tm_operations[] = {
* effects
*/
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, 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_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 },
};
static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write)
@@ -317,14 +366,13 @@ static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write)
/*
* TIMA MMIO handlers
*/
-static void xive_tm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
+void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
+ unsigned size)
{
- XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
const XiveTmOp *xto;
/*
- * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
+ * TODO: check V bit in Q[0-3]W2
*/
/*
@@ -356,13 +404,12 @@ static void xive_tm_write(void *opaque, hwaddr offset,
xive_tm_raw_write(tctx, offset, value, size);
}
-static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
+uint64_t xive_tctx_tm_read(XiveTCTX *tctx, hwaddr offset, unsigned size)
{
- XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
const XiveTmOp *xto;
/*
- * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
+ * TODO: check V bit in Q[0-3]W2
*/
/*
@@ -392,6 +439,21 @@ static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
return xive_tm_raw_read(tctx, offset, size);
}
+static void xive_tm_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
+
+ xive_tctx_tm_write(tctx, offset, value, size);
+}
+
+static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
+{
+ XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
+
+ return xive_tctx_tm_read(tctx, offset, size);
+}
+
const MemoryRegionOps xive_tm_ops = {
.read = xive_tm_read,
.write = xive_tm_write,
@@ -459,6 +521,8 @@ static void xive_tctx_reset(void *dev)
*/
tctx->regs[TM_QW1_OS + TM_PIPR] =
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]);
}
static void xive_tctx_realize(DeviceState *dev, Error **errp)
@@ -1113,6 +1177,30 @@ XiveTCTX *xive_router_get_tctx(XiveRouter *xrtr, CPUState *cs)
}
/*
+ * By default on P9, the HW CAM line (23bits) is hardwired to :
+ *
+ * 0x000||0b1||4Bit chip number||7Bit Thread number.
+ *
+ * When the block grouping is enabled, the CAM line is changed to :
+ *
+ * 4Bit chip number||0x001||7Bit Thread number.
+ */
+static uint32_t hw_cam_line(uint8_t chip_id, uint8_t tid)
+{
+ return 1 << 11 | (chip_id & 0xf) << 7 | (tid & 0x7f);
+}
+
+static bool xive_presenter_tctx_match_hw(XiveTCTX *tctx,
+ uint8_t nvt_blk, uint32_t nvt_idx)
+{
+ CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
+ uint32_t pir = env->spr_cb[SPR_PIR].default_value;
+
+ return hw_cam_line((pir >> 8) & 0xf, pir & 0x7f) ==
+ hw_cam_line(nvt_blk, nvt_idx);
+}
+
+/*
* The thread context register words are in big-endian format.
*/
static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
@@ -1120,6 +1208,7 @@ static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
bool cam_ignore, uint32_t logic_serv)
{
uint32_t cam = xive_nvt_cam_line(nvt_blk, nvt_idx);
+ uint32_t qw3w2 = xive_tctx_word2(&tctx->regs[TM_QW3_HV_PHYS]);
uint32_t qw2w2 = xive_tctx_word2(&tctx->regs[TM_QW2_HV_POOL]);
uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
uint32_t qw0w2 = xive_tctx_word2(&tctx->regs[TM_QW0_USER]);
@@ -1142,7 +1231,11 @@ static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
/* F=0 & i=0: Specific NVT notification */
- /* TODO (PowerNV) : PHYS ring */
+ /* PHYS ring */
+ if ((be32_to_cpu(qw3w2) & TM_QW3W2_VT) &&
+ xive_presenter_tctx_match_hw(tctx, nvt_blk, nvt_idx)) {
+ return TM_QW3_HV_PHYS;
+ }
/* HV POOL ring */
if ((be32_to_cpu(qw2w2) & TM_QW2W2_VP) &&
@@ -1362,7 +1455,7 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
/* TODO: Auto EOI. */
}
-static void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
+void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
{
XiveRouter *xrtr = XIVE_ROUTER(xn);
uint8_t eas_blk = XIVE_SRCNO_BLOCK(lisn);
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index e692b9fdc1..ac44aa53be 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -805,6 +805,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
* pc_q35_init()
*/
dc->user_creatable = false;
+ hc->pre_plug = ich9_pm_device_pre_plug_cb;
hc->plug = ich9_pm_device_plug_cb;
hc->unplug_request = ich9_pm_device_unplug_request_cb;
hc->unplug = ich9_pm_device_unplug_cb;
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
index 599e0d4923..b820c9114b 100644
--- a/hw/lm32/lm32_boards.c
+++ b/hw/lm32/lm32_boards.c
@@ -113,9 +113,9 @@ static void lm32_evr_init(MachineState *machine)
dinfo = drive_get(IF_PFLASH, 0, 0);
/* Spansion S29NS128P */
- pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size,
+ pflash_cfi02_register(flash_base, "lm32_evr.flash", flash_size,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size, flash_size / flash_sector_size,
+ flash_sector_size,
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
/* create irq lines */
@@ -206,9 +206,9 @@ static void lm32_uclinux_init(MachineState *machine)
dinfo = drive_get(IF_PFLASH, 0, 0);
/* Spansion S29NS128P */
- pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size,
+ pflash_cfi02_register(flash_base, "lm32_uclinux.flash", flash_size,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size, flash_size / flash_sector_size,
+ flash_sector_size,
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
/* create irq lines */
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
index 538f33b946..689e633199 100644
--- a/hw/lm32/milkymist.c
+++ b/hw/lm32/milkymist.c
@@ -120,10 +120,9 @@ milkymist_init(MachineState *machine)
dinfo = drive_get(IF_PFLASH, 0, 0);
/* Numonyx JS28F256J3F105 */
- pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size,
+ pflash_cfi01_register(flash_base, "milkymist.flash", flash_size,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size, flash_size / flash_sector_size,
- 2, 0x00, 0x89, 0x00, 0x1d, 1);
+ flash_sector_size, 2, 0x00, 0x89, 0x00, 0x1d, 1);
/* create irq lines */
env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index 18048d3555..a907604116 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -106,11 +106,9 @@ petalogix_ml605_init(MachineState *machine)
dinfo = drive_get(IF_PFLASH, 0, 0);
/* 5th parameter 2 means bank-width
* 10th paremeter 0 means little-endian */
- pflash_cfi01_register(FLASH_BASEADDR,
- NULL, "petalogix_ml605.flash", FLASH_SIZE,
+ pflash_cfi01_register(FLASH_BASEADDR, "petalogix_ml605.flash", FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- 64 * KiB, FLASH_SIZE >> 16,
- 2, 0x89, 0x18, 0x0000, 0x0, 0);
+ 64 * KiB, 2, 0x89, 0x18, 0x0000, 0x0, 0);
dev = qdev_create(NULL, "xlnx.xps-intc");
diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c
index a0edaf867c..88ce570f9a 100644
--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c
+++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c
@@ -87,10 +87,9 @@ petalogix_s3adsp1800_init(MachineState *machine)
dinfo = drive_get(IF_PFLASH, 0, 0);
pflash_cfi01_register(FLASH_BASEADDR,
- NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE,
+ "petalogix_s3adsp1800.flash", FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- 64 * KiB, FLASH_SIZE >> 16,
- 1, 0x89, 0x18, 0x0000, 0x0, 1);
+ 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1);
dev = qdev_create(NULL, "xlnx.xps-intc");
qdev_prop_set_uint32(dev, "kind-of-intr",
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 39aef4b6db..439665ab45 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -58,8 +58,6 @@
#include "exec/semihost.h"
#include "hw/mips/cps.h"
-//#define DEBUG_BOARD_INIT
-
#define ENVP_ADDR 0x80002000l
#define ENVP_NB_ENTRIES 16
#define ENVP_ENTRY_SIZE 256
@@ -1189,13 +1187,12 @@ void mips_malta_init(MachineState *machine)
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
char *filename;
- pflash_t *fl;
+ PFlashCFI01 *fl;
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *ram_high = g_new(MemoryRegion, 1);
MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1);
MemoryRegion *ram_low_postio;
MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1);
- target_long bios_size = FLASH_SIZE;
const size_t smbus_eeprom_size = 8 * 256;
uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
int64_t kernel_entry, bootloader_run_addr;
@@ -1208,7 +1205,6 @@ void mips_malta_init(MachineState *machine)
DriveInfo *dinfo;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
int fl_idx = 0;
- int fl_sectors = bios_size >> 16;
int be;
DeviceState *dev = qdev_create(NULL, TYPE_MIPS_MALTA);
@@ -1265,18 +1261,10 @@ void mips_malta_init(MachineState *machine)
/* Load firmware in flash / BIOS. */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
-#ifdef DEBUG_BOARD_INIT
- if (dinfo) {
- printf("Register parallel flash %d size " TARGET_FMT_lx " at "
- "addr %08llx '%s' %x\n",
- fl_idx, bios_size, FLASH_ADDRESS,
- blk_name(dinfo->bdrv), fl_sectors);
- }
-#endif
- fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios",
- BIOS_SIZE,
+ fl = pflash_cfi01_register(FLASH_ADDRESS, "mips_malta.bios",
+ FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- 65536, fl_sectors,
+ 65536,
4, 0x0000, 0x0000, 0x0000, 0x0000, be);
bios = pflash_cfi01_get_memory(fl);
fl_idx++;
@@ -1312,6 +1300,7 @@ void mips_malta_init(MachineState *machine)
bootloader_run_addr, kernel_entry);
}
} else {
+ target_long bios_size = FLASH_SIZE;
/* The flash region isn't executable from a KVM guest */
if (kvm_enabled()) {
error_report("KVM enabled but no -kernel argument was specified. "
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index a015a6d14e..93dbf76bb4 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -235,10 +235,9 @@ void mips_r4k_init(MachineState *machine)
load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
} else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) {
uint32_t mips_rom = 0x00400000;
- if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom,
+ if (!pflash_cfi01_register(0x1fc00000, "mips_r4k.bios", mips_rom,
blk_by_legacy_dinfo(dinfo),
- sector_len, mips_rom / sector_len,
- 4, 0, 0, 0, 0, be)) {
+ sector_len, 4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");
}
} else if (!qtest_enabled()) {
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index d239e4bd7d..63ba3929e9 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -84,7 +84,7 @@ typedef uint64_t vlan_bd_t;
#define TYPE_VIO_SPAPR_VLAN_DEVICE "spapr-vlan"
#define VIO_SPAPR_VLAN_DEVICE(obj) \
- OBJECT_CHECK(VIOsPAPRVLANDevice, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE)
+ OBJECT_CHECK(SpaprVioVlan, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE)
#define RX_POOL_MAX_BDS 4096
#define RX_MAX_POOLS 5
@@ -95,8 +95,8 @@ typedef struct {
vlan_bd_t bds[RX_POOL_MAX_BDS];
} RxBufPool;
-typedef struct VIOsPAPRVLANDevice {
- VIOsPAPRDevice sdev;
+typedef struct SpaprVioVlan {
+ SpaprVioDevice sdev;
NICConf nicconf;
NICState *nic;
MACAddr perm_mac;
@@ -107,11 +107,11 @@ typedef struct VIOsPAPRVLANDevice {
QEMUTimer *rxp_timer;
uint32_t compat_flags; /* Compatibility flags for migration */
RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */
-} VIOsPAPRVLANDevice;
+} SpaprVioVlan;
static int spapr_vlan_can_receive(NetClientState *nc)
{
- VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
+ SpaprVioVlan *dev = qemu_get_nic_opaque(nc);
return (dev->isopen && dev->rx_bufs > 0);
}
@@ -123,7 +123,7 @@ static int spapr_vlan_can_receive(NetClientState *nc)
* suitable receive buffer available. This function is used to increase
* this counter by one.
*/
-static void spapr_vlan_record_dropped_rx_frame(VIOsPAPRVLANDevice *dev)
+static void spapr_vlan_record_dropped_rx_frame(SpaprVioVlan *dev)
{
uint64_t cnt;
@@ -134,7 +134,7 @@ static void spapr_vlan_record_dropped_rx_frame(VIOsPAPRVLANDevice *dev)
/**
* Get buffer descriptor from one of our receive buffer pools
*/
-static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev,
+static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(SpaprVioVlan *dev,
size_t size)
{
vlan_bd_t bd;
@@ -168,7 +168,7 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev,
* Get buffer descriptor from the receive buffer list page that has been
* supplied by the guest with the H_REGISTER_LOGICAL_LAN call
*/
-static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev,
+static vlan_bd_t spapr_vlan_get_rx_bd_from_page(SpaprVioVlan *dev,
size_t size)
{
int buf_ptr = dev->use_buf_ptr;
@@ -203,8 +203,8 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev,
static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
size_t size)
{
- VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
- VIOsPAPRDevice *sdev = VIO_SPAPR_DEVICE(dev);
+ SpaprVioVlan *dev = qemu_get_nic_opaque(nc);
+ SpaprVioDevice *sdev = VIO_SPAPR_DEVICE(dev);
vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
vlan_bd_t bd;
uint64_t handle;
@@ -280,7 +280,7 @@ static NetClientInfo net_spapr_vlan_info = {
static void spapr_vlan_flush_rx_queue(void *opaque)
{
- VIOsPAPRVLANDevice *dev = opaque;
+ SpaprVioVlan *dev = opaque;
qemu_flush_queued_packets(qemu_get_queue(dev->nic));
}
@@ -296,9 +296,9 @@ static void spapr_vlan_reset_rx_pool(RxBufPool *rxp)
memset(rxp->bds, 0, sizeof(rxp->bds));
}
-static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
+static void spapr_vlan_reset(SpaprVioDevice *sdev)
{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
int i;
dev->buf_list = 0;
@@ -316,9 +316,9 @@ static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
}
-static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
+static void spapr_vlan_realize(SpaprVioDevice *sdev, Error **errp)
{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
@@ -334,7 +334,7 @@ static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
static void spapr_vlan_instance_init(Object *obj)
{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(obj);
int i;
device_add_bootindex_property(obj, &dev->nicconf.bootindex,
@@ -351,7 +351,7 @@ static void spapr_vlan_instance_init(Object *obj)
static void spapr_vlan_instance_finalize(Object *obj)
{
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(obj);
int i;
if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
@@ -367,7 +367,7 @@ static void spapr_vlan_instance_finalize(Object *obj)
}
}
-void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
+void spapr_vlan_create(SpaprVioBus *bus, NICInfo *nd)
{
DeviceState *dev;
@@ -378,9 +378,9 @@ void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
qdev_init_nofail(dev);
}
-static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+static int spapr_vlan_devnode(SpaprVioDevice *dev, void *fdt, int node_off)
{
- VIOsPAPRVLANDevice *vdev = VIO_SPAPR_VLAN_DEVICE(dev);
+ SpaprVioVlan *vdev = VIO_SPAPR_VLAN_DEVICE(dev);
uint8_t padded_mac[8] = {0, 0};
int ret;
@@ -415,7 +415,7 @@ static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
return 0;
}
-static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
+static int check_bd(SpaprVioVlan *dev, vlan_bd_t bd,
target_ulong alignment)
{
if ((VLAN_BD_ADDR(bd) % alignment)
@@ -434,7 +434,7 @@ static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
}
static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
@@ -442,8 +442,8 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
target_ulong buf_list = args[1];
target_ulong rec_queue = args[2];
target_ulong filter_list = args[3];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ SpaprVioDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
vlan_bd_t filter_list_bd;
if (!dev) {
@@ -500,12 +500,12 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
static target_ulong h_free_logical_lan(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ SpaprVioDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
if (!dev) {
return H_PARAMETER;
@@ -539,7 +539,7 @@ static int rx_pool_size_compare(const void *p1, const void *p2)
* Search for a matching buffer pool with exact matching size,
* or return -1 if no matching pool has been found.
*/
-static int spapr_vlan_get_rx_pool_id(VIOsPAPRVLANDevice *dev, int size)
+static int spapr_vlan_get_rx_pool_id(SpaprVioVlan *dev, int size)
{
int pool;
@@ -555,7 +555,7 @@ static int spapr_vlan_get_rx_pool_id(VIOsPAPRVLANDevice *dev, int size)
/**
* Enqueuing receive buffer by adding it to one of our receive buffer pools
*/
-static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev,
+static target_long spapr_vlan_add_rxbuf_to_pool(SpaprVioVlan *dev,
target_ulong buf)
{
int size = VLAN_BD_LEN(buf);
@@ -602,7 +602,7 @@ static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev,
* This is the old way of enqueuing receive buffers: Add it to the rx queue
* page that has been supplied by the guest (which is quite limited in size).
*/
-static target_long spapr_vlan_add_rxbuf_to_page(VIOsPAPRVLANDevice *dev,
+static target_long spapr_vlan_add_rxbuf_to_page(SpaprVioVlan *dev,
target_ulong buf)
{
vlan_bd_t bd;
@@ -628,14 +628,14 @@ static target_long spapr_vlan_add_rxbuf_to_page(VIOsPAPRVLANDevice *dev,
}
static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong reg = args[0];
target_ulong buf = args[1];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ SpaprVioDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
target_long ret;
trace_spapr_vlan_h_add_logical_lan_buffer(reg, buf);
@@ -678,14 +678,14 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
}
static target_ulong h_send_logical_lan(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
target_ulong *bufs = args + 1;
target_ulong continue_token = args[7];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ SpaprVioDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
unsigned total_len;
uint8_t *lbuf, *p;
int i, nbufs;
@@ -745,11 +745,11 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu,
return H_SUCCESS;
}
-static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
return H_PARAMETER;
@@ -759,14 +759,14 @@ static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
static target_ulong h_change_logical_lan_mac(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong reg = args[0];
target_ulong macaddr = args[1];
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ SpaprVioDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioVlan *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
int i;
for (i = 0; i < ETH_ALEN; i++) {
@@ -780,16 +780,16 @@ static target_ulong h_change_logical_lan_mac(PowerPCCPU *cpu,
}
static Property spapr_vlan_properties[] = {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
- DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
- DEFINE_PROP_BIT("use-rx-buffer-pools", VIOsPAPRVLANDevice,
+ 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)
{
- VIOsPAPRVLANDevice *dev = opaque;
+ SpaprVioVlan *dev = opaque;
return (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) != 0;
}
@@ -813,7 +813,7 @@ static const VMStateDescription vmstate_rx_pools = {
.minimum_version_id = 1,
.needed = spapr_vlan_rx_buffer_pools_needed,
.fields = (VMStateField[]) {
- VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(rx_pool, VIOsPAPRVLANDevice,
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(rx_pool, SpaprVioVlan,
RX_MAX_POOLS, 1,
vmstate_rx_buffer_pool, RxBufPool),
VMSTATE_END_OF_LIST()
@@ -825,14 +825,14 @@ static const VMStateDescription vmstate_spapr_llan = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVLANDevice),
+ VMSTATE_SPAPR_VIO(sdev, SpaprVioVlan),
/* LLAN state */
- VMSTATE_BOOL(isopen, VIOsPAPRVLANDevice),
- VMSTATE_UINT64(buf_list, VIOsPAPRVLANDevice),
- VMSTATE_UINT32(add_buf_ptr, VIOsPAPRVLANDevice),
- VMSTATE_UINT32(use_buf_ptr, VIOsPAPRVLANDevice),
- VMSTATE_UINT32(rx_bufs, VIOsPAPRVLANDevice),
- VMSTATE_UINT64(rxq_ptr, VIOsPAPRVLANDevice),
+ VMSTATE_BOOL(isopen, SpaprVioVlan),
+ VMSTATE_UINT64(buf_list, SpaprVioVlan),
+ VMSTATE_UINT32(add_buf_ptr, SpaprVioVlan),
+ VMSTATE_UINT32(use_buf_ptr, SpaprVioVlan),
+ VMSTATE_UINT32(rx_bufs, SpaprVioVlan),
+ VMSTATE_UINT64(rxq_ptr, SpaprVioVlan),
VMSTATE_END_OF_LIST()
},
@@ -845,7 +845,7 @@ static const VMStateDescription vmstate_spapr_llan = {
static void spapr_vlan_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->realize = spapr_vlan_realize;
k->reset = spapr_vlan_reset;
@@ -863,7 +863,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
static const TypeInfo spapr_vlan_info = {
.name = TYPE_VIO_SPAPR_VLAN_DEVICE,
.parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(VIOsPAPRVLANDevice),
+ .instance_size = sizeof(SpaprVioVlan),
.class_init = spapr_vlan_class_init,
.instance_init = spapr_vlan_instance_init,
.instance_finalize = spapr_vlan_instance_finalize,
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 7fdf04adc9..5c3a46ce6f 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -85,7 +85,7 @@ static char *read_splashfile(char *filename, gsize *file_sizep,
}
/* check magic ID */
- filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff;
+ filehead = lduw_le_p(content);
if (filehead == 0xd8ff) {
file_type = JPG_FILE;
} else if (filehead == 0x4d42) {
@@ -96,7 +96,7 @@ static char *read_splashfile(char *filename, gsize *file_sizep,
/* check BMP bpp */
if (file_type == BMP_FILE) {
- bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff;
+ bmp_bpp = lduw_le_p(&content[28]);
if (bmp_bpp != 24) {
goto error;
}
@@ -161,15 +161,14 @@ static void fw_cfg_bootsplash(FWCfgState *s)
}
g_free(boot_splash_filedata);
boot_splash_filedata = (uint8_t *)file_data;
- boot_splash_filedata_size = file_size;
/* insert data */
if (file_type == JPG_FILE) {
fw_cfg_add_file(s, "bootsplash.jpg",
- boot_splash_filedata, boot_splash_filedata_size);
+ boot_splash_filedata, file_size);
} else {
fw_cfg_add_file(s, "bootsplash.bmp",
- boot_splash_filedata, boot_splash_filedata_size);
+ boot_splash_filedata, file_size);
}
g_free(filename);
}
diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c
index bed1557d83..c98c7576e6 100644
--- a/hw/nvram/spapr_nvram.c
+++ b/hw/nvram/spapr_nvram.c
@@ -36,28 +36,28 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
-typedef struct sPAPRNVRAM {
- VIOsPAPRDevice sdev;
+typedef struct SpaprNvram {
+ SpaprVioDevice sdev;
uint32_t size;
uint8_t *buf;
BlockBackend *blk;
VMChangeStateEntry *vmstate;
-} sPAPRNVRAM;
+} SpaprNvram;
#define TYPE_VIO_SPAPR_NVRAM "spapr-nvram"
#define VIO_SPAPR_NVRAM(obj) \
- OBJECT_CHECK(sPAPRNVRAM, (obj), TYPE_VIO_SPAPR_NVRAM)
+ OBJECT_CHECK(SpaprNvram, (obj), TYPE_VIO_SPAPR_NVRAM)
#define MIN_NVRAM_SIZE (8 * KiB)
#define DEFAULT_NVRAM_SIZE (64 * KiB)
#define MAX_NVRAM_SIZE (1 * MiB)
-static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_nvram_fetch(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- sPAPRNVRAM *nvram = spapr->nvram;
+ SpaprNvram *nvram = spapr->nvram;
hwaddr offset, buffer, len;
void *membuf;
@@ -93,12 +93,12 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 1, len);
}
-static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_nvram_store(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- sPAPRNVRAM *nvram = spapr->nvram;
+ SpaprNvram *nvram = spapr->nvram;
hwaddr offset, buffer, len;
int alen;
void *membuf;
@@ -139,9 +139,9 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 1, (alen < 0) ? 0 : alen);
}
-static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
+static void spapr_nvram_realize(SpaprVioDevice *dev, Error **errp)
{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
+ SpaprNvram *nvram = VIO_SPAPR_NVRAM(dev);
int ret;
if (nvram->blk) {
@@ -193,16 +193,16 @@ static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
}
-static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+static int spapr_nvram_devnode(SpaprVioDevice *dev, void *fdt, int node_off)
{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
+ SpaprNvram *nvram = VIO_SPAPR_NVRAM(dev);
return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
}
static int spapr_nvram_pre_load(void *opaque)
{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
+ SpaprNvram *nvram = VIO_SPAPR_NVRAM(opaque);
g_free(nvram->buf);
nvram->buf = NULL;
@@ -213,7 +213,7 @@ static int spapr_nvram_pre_load(void *opaque)
static void postload_update_cb(void *opaque, int running, RunState state)
{
- sPAPRNVRAM *nvram = opaque;
+ SpaprNvram *nvram = opaque;
/* This is called after bdrv_invalidate_cache_all. */
@@ -225,7 +225,7 @@ static void postload_update_cb(void *opaque, int running, RunState state)
static int spapr_nvram_post_load(void *opaque, int version_id)
{
- sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
+ SpaprNvram *nvram = VIO_SPAPR_NVRAM(opaque);
if (nvram->blk) {
nvram->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
@@ -242,22 +242,22 @@ static const VMStateDescription vmstate_spapr_nvram = {
.pre_load = spapr_nvram_pre_load,
.post_load = spapr_nvram_post_load,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(size, sPAPRNVRAM),
- VMSTATE_VBUFFER_ALLOC_UINT32(buf, sPAPRNVRAM, 1, NULL, size),
+ VMSTATE_UINT32(size, SpaprNvram),
+ VMSTATE_VBUFFER_ALLOC_UINT32(buf, SpaprNvram, 1, NULL, size),
VMSTATE_END_OF_LIST()
},
};
static Property spapr_nvram_properties[] = {
- DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
- DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, blk),
+ 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)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->realize = spapr_nvram_realize;
k->devnode = spapr_nvram_devnode;
@@ -274,7 +274,7 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data)
static const TypeInfo spapr_nvram_type_info = {
.name = TYPE_VIO_SPAPR_NVRAM,
.parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(sPAPRNVRAM),
+ .instance_size = sizeof(SpaprNvram),
.class_init = spapr_nvram_class_init,
};
diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
index 9766edb445..26bda73eae 100644
--- a/hw/pci-bridge/gen_pcie_root_port.c
+++ b/hw/pci-bridge/gen_pcie_root_port.c
@@ -20,6 +20,9 @@
OBJECT_CHECK(GenPCIERootPort, (obj), TYPE_GEN_PCIE_ROOT_PORT)
#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100
+#define GEN_PCIE_ROOT_PORT_ACS_OFFSET \
+ (GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF)
+
#define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1
typedef struct GenPCIERootPort {
@@ -149,6 +152,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data)
rpc->interrupts_init = gen_rp_interrupts_init;
rpc->interrupts_uninit = gen_rp_interrupts_uninit;
rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
+ rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET;
}
static const TypeInfo gen_rp_dev_info = {
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index 34ad76743c..e94d918b6d 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -47,6 +47,7 @@ static void rp_reset(DeviceState *qdev)
pcie_cap_deverr_reset(d);
pcie_cap_slot_reset(d);
pcie_cap_arifwd_reset(d);
+ pcie_acs_reset(d);
pcie_aer_root_reset(d);
pci_bridge_reset(qdev);
pci_bridge_disable_base_limit(d);
@@ -106,6 +107,9 @@ static void rp_realize(PCIDevice *d, Error **errp)
pcie_aer_root_init(d);
rp_aer_vector_update(d);
+ if (rpc->acs_offset) {
+ pcie_acs_init(d, rpc->acs_offset);
+ }
return;
err:
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 640f678773..cf1ca30f93 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -914,3 +914,41 @@ void pcie_ats_init(PCIDevice *dev, uint16_t offset)
pci_set_word(dev->wmask + dev->exp.ats_cap + PCI_ATS_CTRL, 0x800f);
}
+
+/* ACS (Access Control Services) */
+void pcie_acs_init(PCIDevice *dev, uint16_t offset)
+{
+ bool is_downstream = pci_is_express_downstream_port(dev);
+ uint16_t cap_bits = 0;
+
+ /* For endpoints, only multifunction devs may have an ACS capability: */
+ assert(is_downstream ||
+ (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) ||
+ PCI_FUNC(dev->devfn));
+
+ pcie_add_capability(dev, PCI_EXT_CAP_ID_ACS, PCI_ACS_VER, offset,
+ PCI_ACS_SIZEOF);
+ dev->exp.acs_cap = offset;
+
+ if (is_downstream) {
+ /*
+ * Downstream ports must implement SV, TB, RR, CR, UF, and DT (with
+ * caveats on the latter four that we ignore for simplicity).
+ * Endpoints may also implement a subset of ACS capabilities,
+ * but these are optional if the endpoint does not support
+ * peer-to-peer between functions and thus omitted here.
+ */
+ cap_bits = PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
+ PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT;
+ }
+
+ pci_set_word(dev->config + offset + PCI_ACS_CAP, cap_bits);
+ pci_set_word(dev->wmask + offset + PCI_ACS_CTRL, cap_bits);
+}
+
+void pcie_acs_reset(PCIDevice *dev)
+{
+ if (dev->exp.acs_cap) {
+ pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, 0);
+ }
+}
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 7553f674c9..beb2efd694 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -42,6 +42,7 @@
#include "qemu/error-report.h"
#include "hw/platform-bus.h"
#include "hw/net/fsl_etsec/etsec.h"
+#include "hw/i2c/i2c.h"
#define EPAPR_MAGIC (0x45504150)
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
@@ -63,7 +64,10 @@
#define MPC8544_PCI_REGS_SIZE 0x1000ULL
#define MPC8544_UTIL_OFFSET 0xe0000ULL
#define MPC8XXX_GPIO_OFFSET 0x000FF000ULL
+#define MPC8544_I2C_REGS_OFFSET 0x3000ULL
#define MPC8XXX_GPIO_IRQ 47
+#define MPC8544_I2C_IRQ 43
+#define RTC_REGS_OFFSET 0x68
struct boot_info
{
@@ -161,6 +165,39 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
g_free(poweroff);
}
+static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
+{
+ int offset = RTC_REGS_OFFSET;
+
+ gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
+ qemu_fdt_add_subnode(fdt, rtc);
+ qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
+ qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
+ qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
+
+ g_free(rtc);
+}
+
+static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
+ const char *alias)
+{
+ hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
+ int irq0 = MPC8544_I2C_IRQ;
+
+ gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
+ qemu_fdt_add_subnode(fdt, i2c);
+ qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
+ qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
+ qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
+ 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_string(fdt, "/aliases", alias, i2c);
+
+ g_free(i2c);
+}
+
+
typedef struct PlatformDevtreeData {
void *fdt;
const char *mpic;
@@ -464,6 +501,12 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
soc, mpic, "serial0", 0, true);
}
+ /* i2c */
+ dt_i2c_create(fdt, soc, mpic, "i2c");
+
+ dt_rtc_create(fdt, "i2c", "rtc");
+
+
gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
MPC8544_UTIL_OFFSET);
qemu_fdt_add_subnode(fdt, gutil);
@@ -812,6 +855,7 @@ void ppce500_init(MachineState *machine)
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
PPCE500CCSRState *ccsr;
+ I2CBus *i2c;
irqs = g_new0(IrqLines, smp_cpus);
for (i = 0; i < smp_cpus; i++) {
@@ -887,6 +931,16 @@ void ppce500_init(MachineState *machine)
0, qdev_get_gpio_in(mpicdev, 42), 399193,
serial_hd(1), DEVICE_BIG_ENDIAN);
}
+ /* I2C */
+ dev = qdev_create(NULL, "mpc-i2c");
+ s = SYS_BUS_DEVICE(dev);
+ qdev_init_nofail(dev);
+ 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_create_slave(i2c, "ds1338", RTC_REGS_OFFSET);
+
/* General Utility device */
dev = qdev_create(NULL, "mpc8544-guts");
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 97e8817145..02d8559621 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -547,11 +547,11 @@ static char *core99_fw_dev_path(FWPathProvider *p, BusState *bus,
return g_strdup("cdrom");
}
- return g_strdup("hd");
+ return g_strdup("disk");
}
if (!strcmp(object_get_typename(OBJECT(dev)), "ide-hd")) {
- return g_strdup("hd");
+ return g_strdup("disk");
}
if (!strcmp(object_get_typename(OBJECT(dev)), "ide-cd")) {
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index cc1e463466..460cbc7923 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -402,11 +402,11 @@ static char *heathrow_fw_dev_path(FWPathProvider *p, BusState *bus,
return g_strdup("cdrom");
}
- return g_strdup("hd");
+ return g_strdup("disk");
}
if (!strcmp(object_get_typename(OBJECT(dev)), "ide-hd")) {
- return g_strdup("hd");
+ return g_strdup("disk");
}
if (!strcmp(object_get_typename(OBJECT(dev)), "ide-cd")) {
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 3d5dfef220..8be4d4cbf7 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -267,7 +267,7 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
g_free(reg);
}
-static void pnv_dt_chip(PnvChip *chip, void *fdt)
+static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
{
const char *typename = pnv_chip_core_typename(chip);
size_t typesize = object_type_get_instance_size(typename);
@@ -289,6 +289,27 @@ static void pnv_dt_chip(PnvChip *chip, void *fdt)
}
}
+static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
+{
+ const char *typename = pnv_chip_core_typename(chip);
+ size_t typesize = object_type_get_instance_size(typename);
+ int i;
+
+ pnv_dt_xscom(chip, fdt, 0);
+
+ for (i = 0; i < chip->nr_cores; i++) {
+ PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
+
+ pnv_dt_core(chip, pnv_core, fdt);
+ }
+
+ if (chip->ram_size) {
+ pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
+ }
+
+ pnv_dt_lpc(chip, fdt, 0);
+}
+
static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
{
uint32_t io_base = d->ioport_id;
@@ -398,24 +419,12 @@ static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
return 0;
}
-static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
-{
- char *name;
- int offset;
-
- name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
- (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
- offset = fdt_path_offset(fdt, name);
- g_free(name);
- return offset;
-}
-
/* The default LPC bus of a multichip system is on chip 0. It's
* recognized by the firmware (skiboot) using a "primary" property.
*/
static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
{
- int isa_offset = pnv_chip_isa_offset(pnv->chips[0], fdt);
+ int isa_offset = fdt_path_offset(fdt, pnv->chips[0]->dt_isa_nodename);
ForeachPopulateArgs args = {
.fdt = fdt,
.offset = isa_offset,
@@ -429,6 +438,16 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
&args);
}
+static void pnv_dt_power_mgt(void *fdt)
+{
+ int off;
+
+ off = fdt_add_subnode(fdt, 0, "ibm,opal");
+ off = fdt_add_subnode(fdt, off, "power-mgt");
+
+ _FDT(fdt_setprop_cell(fdt, off, "ibm,enabled-stop-levels", 0xc0000000));
+}
+
static void *pnv_dt_create(MachineState *machine)
{
const char plat_compat[] = "qemu,powernv\0ibm,powernv";
@@ -474,7 +493,7 @@ static void *pnv_dt_create(MachineState *machine)
/* Populate device tree for each chip */
for (i = 0; i < pnv->num_chips; i++) {
- pnv_dt_chip(pnv->chips[i], fdt);
+ PNV_CHIP_GET_CLASS(pnv->chips[i])->dt_populate(pnv->chips[i], fdt);
}
/* Populate ISA devices on chip 0 */
@@ -484,6 +503,11 @@ static void *pnv_dt_create(MachineState *machine)
pnv_dt_bmc_sensors(pnv->bmc, fdt);
}
+ /* Create an extra node for power management on Power9 */
+ if (pnv_is_power9(pnv)) {
+ pnv_dt_power_mgt(fdt);
+ }
+
return fdt;
}
@@ -540,7 +564,8 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
{
- return NULL;
+ Pnv9Chip *chip9 = PNV9_CHIP(chip);
+ return pnv_lpc_isa_create(&chip9->lpc, false, errp);
}
static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
@@ -548,6 +573,21 @@ static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
}
+static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
+{
+ Pnv8Chip *chip8 = PNV8_CHIP(chip);
+
+ ics_pic_print_info(&chip8->psi.ics, mon);
+}
+
+static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
+{
+ Pnv9Chip *chip9 = PNV9_CHIP(chip);
+
+ pnv_xive_pic_print_info(&chip9->xive, mon);
+ pnv_psi_pic_print_info(&chip9->psi, mon);
+}
+
static void pnv_init(MachineState *machine)
{
PnvMachineState *pnv = PNV_MACHINE(machine);
@@ -684,7 +724,7 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
return;
}
- pnv_cpu->icp = ICP(obj);
+ pnv_cpu->intc = obj;
}
/*
@@ -705,7 +745,23 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
Error **errp)
{
- return;
+ Pnv9Chip *chip9 = PNV9_CHIP(chip);
+ Error *local_err = NULL;
+ Object *obj;
+ PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
+
+ /*
+ * The core creates its interrupt presenter but the XIVE interrupt
+ * controller object is initialized afterwards. Hopefully, it's
+ * only used at runtime.
+ */
+ obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(&chip9->xive), errp);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ pnv_cpu->intc = obj;
}
/* Allowed core identifiers on a POWER8 Processor Chip :
@@ -739,17 +795,17 @@ static void pnv_chip_power8_instance_init(Object *obj)
Pnv8Chip *chip8 = PNV8_CHIP(obj);
object_initialize_child(obj, "psi", &chip8->psi, sizeof(chip8->psi),
- TYPE_PNV_PSI, &error_abort, NULL);
+ TYPE_PNV8_PSI, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip8->psi), "xics",
OBJECT(qdev_get_machine()), &error_abort);
object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc),
- TYPE_PNV_LPC, &error_abort, NULL);
+ TYPE_PNV8_LPC, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
OBJECT(&chip8->psi), &error_abort);
object_initialize_child(obj, "occ", &chip8->occ, sizeof(chip8->occ),
- TYPE_PNV_OCC, &error_abort, NULL);
+ TYPE_PNV8_OCC, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip8->occ), "psi",
OBJECT(&chip8->psi), &error_abort);
}
@@ -791,6 +847,7 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
PnvChip *chip = PNV_CHIP(dev);
Pnv8Chip *chip8 = PNV8_CHIP(dev);
+ Pnv8Psi *psi8 = &chip8->psi;
Error *local_err = NULL;
pcc->parent_realize(dev, &local_err);
@@ -807,13 +864,18 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
error_propagate(errp, local_err);
return;
}
- pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip8->psi.xscom_regs);
+ pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE,
+ &PNV_PSI(psi8)->xscom_regs);
/* Create LPC controller */
object_property_set_bool(OBJECT(&chip8->lpc), true, "realized",
&error_fatal);
pnv_xscom_add_subregion(chip, PNV_XSCOM_LPC_BASE, &chip8->lpc.xscom_regs);
+ chip->dt_isa_nodename = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
+ (uint64_t) PNV_XSCOM_BASE(chip),
+ PNV_XSCOM_LPC_BASE);
+
/* Interrupt Management Area. This is the memory region holding
* all the Interrupt Control Presenter (ICP) registers */
pnv_chip_icp_realize(chip8, &local_err);
@@ -842,6 +904,8 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
k->core_pir = pnv_chip_core_pir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->isa_create = pnv_chip_power8_isa_create;
+ k->dt_populate = pnv_chip_power8_dt_populate;
+ k->pic_print_info = pnv_chip_power8_pic_print_info;
k->xscom_base = 0x003fc0000000000ull;
dc->desc = "PowerNV Chip POWER8E";
@@ -860,6 +924,8 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
k->core_pir = pnv_chip_core_pir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->isa_create = pnv_chip_power8_isa_create;
+ k->dt_populate = pnv_chip_power8_dt_populate;
+ k->pic_print_info = pnv_chip_power8_pic_print_info;
k->xscom_base = 0x003fc0000000000ull;
dc->desc = "PowerNV Chip POWER8";
@@ -878,6 +944,8 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
k->core_pir = pnv_chip_core_pir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->isa_create = pnv_chip_power8nvl_isa_create;
+ k->dt_populate = pnv_chip_power8_dt_populate;
+ k->pic_print_info = pnv_chip_power8_pic_print_info;
k->xscom_base = 0x003fc0000000000ull;
dc->desc = "PowerNV Chip POWER8NVL";
@@ -887,11 +955,65 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
static void pnv_chip_power9_instance_init(Object *obj)
{
+ Pnv9Chip *chip9 = PNV9_CHIP(obj);
+
+ object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive),
+ TYPE_PNV_XIVE, &error_abort, NULL);
+ object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
+ &error_abort);
+
+ object_initialize_child(obj, "psi", &chip9->psi, sizeof(chip9->psi),
+ TYPE_PNV9_PSI, &error_abort, NULL);
+ object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
+ &error_abort);
+
+ object_initialize_child(obj, "lpc", &chip9->lpc, sizeof(chip9->lpc),
+ TYPE_PNV9_LPC, &error_abort, NULL);
+ object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
+ OBJECT(&chip9->psi), &error_abort);
+
+ object_initialize_child(obj, "occ", &chip9->occ, sizeof(chip9->occ),
+ TYPE_PNV9_OCC, &error_abort, NULL);
+ object_property_add_const_link(OBJECT(&chip9->occ), "psi",
+ OBJECT(&chip9->psi), &error_abort);
+}
+
+static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
+{
+ PnvChip *chip = PNV_CHIP(chip9);
+ const char *typename = pnv_chip_core_typename(chip);
+ size_t typesize = object_type_get_instance_size(typename);
+ int i;
+
+ chip9->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4);
+ chip9->quads = g_new0(PnvQuad, chip9->nr_quads);
+
+ for (i = 0; i < chip9->nr_quads; i++) {
+ char eq_name[32];
+ PnvQuad *eq = &chip9->quads[i];
+ PnvCore *pnv_core = PNV_CORE(chip->cores + (i * 4) * typesize);
+ int core_id = CPU_CORE(pnv_core)->core_id;
+
+ object_initialize(eq, sizeof(*eq), TYPE_PNV_QUAD);
+ snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id);
+
+ object_property_add_child(OBJECT(chip), eq_name, OBJECT(eq),
+ &error_fatal);
+ object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal);
+ object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal);
+ object_unref(OBJECT(eq));
+
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id),
+ &eq->xscom_regs);
+ }
}
static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
+ Pnv9Chip *chip9 = PNV9_CHIP(dev);
+ PnvChip *chip = PNV_CHIP(dev);
+ Pnv9Psi *psi9 = &chip9->psi;
Error *local_err = NULL;
pcc->parent_realize(dev, &local_err);
@@ -899,6 +1021,61 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
error_propagate(errp, local_err);
return;
}
+
+ pnv_chip_quad_realize(chip9, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* XIVE interrupt controller (POWER9) */
+ object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
+ "ic-bar", &error_fatal);
+ object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_VC_BASE(chip),
+ "vc-bar", &error_fatal);
+ object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_PC_BASE(chip),
+ "pc-bar", &error_fatal);
+ object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_TM_BASE(chip),
+ "tm-bar", &error_fatal);
+ object_property_set_bool(OBJECT(&chip9->xive), true, "realized",
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
+ &chip9->xive.xscom_regs);
+
+ /* Processor Service Interface (PSI) Host Bridge */
+ object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
+ "bar", &error_fatal);
+ object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
+ &PNV_PSI(psi9)->xscom_regs);
+
+ /* LPC */
+ object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
+ &chip9->lpc.xscom_regs);
+
+ chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
+ (uint64_t) PNV9_LPCM_BASE(chip));
+
+ /* Create the simplified OCC model */
+ object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
}
static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
@@ -912,6 +1089,8 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
k->core_pir = pnv_chip_core_pir_p9;
k->intc_create = pnv_chip_power9_intc_create;
k->isa_create = pnv_chip_power9_isa_create;
+ k->dt_populate = pnv_chip_power9_dt_populate;
+ k->pic_print_info = pnv_chip_power9_pic_print_info;
k->xscom_base = 0x00603fc00000000ull;
dc->desc = "PowerNV Chip POWER9";
@@ -1007,7 +1186,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
if (!pnv_chip_is_power9(chip)) {
xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
} else {
- xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid);
+ xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
}
pnv_xscom_add_subregion(chip, xscom_core_base,
@@ -1082,27 +1261,11 @@ static void pnv_ics_resend(XICSFabric *xi)
}
}
-static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
-{
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
-
- if (env->spr_cb[SPR_PIR].default_value == pir) {
- return cpu;
- }
- }
-
- return NULL;
-}
-
static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
{
PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
- return cpu ? pnv_cpu_state(cpu)->icp : NULL;
+ return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL;
}
static void pnv_pic_print_info(InterruptStatsProvider *obj,
@@ -1115,12 +1278,15 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
- icp_pic_print_info(pnv_cpu_state(cpu)->icp, mon);
+ if (pnv_chip_is_power9(pnv->chips[0])) {
+ xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), mon);
+ } else {
+ icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
+ }
}
for (i = 0; i < pnv->num_chips; i++) {
- Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
- ics_pic_print_info(&chip8->psi.ics, mon);
+ PNV_CHIP_GET_CLASS(pnv->chips[i])->pic_print_info(pnv->chips[i], mon);
}
}
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 7c806da720..5feeed6bc4 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -60,8 +60,8 @@ static void pnv_cpu_reset(void *opaque)
#define PNV_XSCOM_EX_DTS_RESULT0 0x50000
#define PNV_XSCOM_EX_DTS_RESULT1 0x50001
-static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
- unsigned int width)
+static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
{
uint32_t offset = addr >> 3;
uint64_t val = 0;
@@ -82,16 +82,74 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
return val;
}
-static void pnv_core_xscom_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned int width)
+static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int width)
{
qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
addr);
}
-static const MemoryRegionOps pnv_core_xscom_ops = {
- .read = pnv_core_xscom_read,
- .write = pnv_core_xscom_write,
+static const MemoryRegionOps pnv_core_power8_xscom_ops = {
+ .read = pnv_core_power8_xscom_read,
+ .write = pnv_core_power8_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+
+/*
+ * POWER9 core controls
+ */
+#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
+#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
+
+static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+ uint64_t val = 0;
+
+ /* The result should be 38 C */
+ switch (offset) {
+ case PNV_XSCOM_EX_DTS_RESULT0:
+ val = 0x26f024f023f0000ull;
+ break;
+ case PNV_XSCOM_EX_DTS_RESULT1:
+ val = 0x24f000000000000ull;
+ break;
+ case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
+ case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
+ val = 0x0;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
+ addr);
+ }
+
+ return val;
+}
+
+static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+
+ switch (offset) {
+ case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
+ case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
+ addr);
+ }
+}
+
+static const MemoryRegionOps pnv_core_power9_xscom_ops = {
+ .read = pnv_core_power9_xscom_read,
+ .write = pnv_core_power9_xscom_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
@@ -138,6 +196,7 @@ static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp)
static void pnv_core_realize(DeviceState *dev, Error **errp)
{
PnvCore *pc = PNV_CORE(OBJECT(dev));
+ PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
CPUCore *cc = CPU_CORE(OBJECT(dev));
const char *typename = pnv_core_cpu_typename(pc);
Error *local_err = NULL;
@@ -180,7 +239,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
}
snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
- pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), &pnv_core_xscom_ops,
+ pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
pc, name, PNV_XSCOM_EX_SIZE);
return;
@@ -198,7 +257,7 @@ static void pnv_unrealize_vcpu(PowerPCCPU *cpu)
PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
qemu_unregister_reset(pnv_cpu_reset, cpu);
- object_unparent(OBJECT(pnv_cpu_state(cpu)->icp));
+ object_unparent(OBJECT(pnv_cpu_state(cpu)->intc));
cpu_remove_sync(CPU(cpu));
cpu->machine_data = NULL;
g_free(pnv_cpu);
@@ -222,6 +281,20 @@ static Property pnv_core_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
+{
+ PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
+
+ pcc->xscom_ops = &pnv_core_power8_xscom_ops;
+}
+
+static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
+{
+ PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
+
+ pcc->xscom_ops = &pnv_core_power9_xscom_ops;
+}
+
static void pnv_core_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -231,10 +304,11 @@ static void pnv_core_class_init(ObjectClass *oc, void *data)
dc->props = pnv_core_properties;
}
-#define DEFINE_PNV_CORE_TYPE(cpu_model) \
+#define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
{ \
.parent = TYPE_PNV_CORE, \
.name = PNV_CORE_TYPE_NAME(cpu_model), \
+ .class_init = pnv_core_##family##_class_init, \
}
static const TypeInfo pnv_core_infos[] = {
@@ -246,10 +320,97 @@ static const TypeInfo pnv_core_infos[] = {
.class_init = pnv_core_class_init,
.abstract = true,
},
- DEFINE_PNV_CORE_TYPE("power8e_v2.1"),
- DEFINE_PNV_CORE_TYPE("power8_v2.0"),
- DEFINE_PNV_CORE_TYPE("power8nvl_v1.0"),
- DEFINE_PNV_CORE_TYPE("power9_v2.0"),
+ DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
+ DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
+ DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
+ DEFINE_PNV_CORE_TYPE(power9, "power9_v2.0"),
};
DEFINE_TYPES(pnv_core_infos)
+
+/*
+ * POWER9 Quads
+ */
+
+#define P9X_EX_NCU_SPEC_BAR 0x11010
+
+static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+ uint64_t val = -1;
+
+ switch (offset) {
+ case P9X_EX_NCU_SPEC_BAR:
+ case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
+ offset);
+ }
+
+ return val;
+}
+
+static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+
+ switch (offset) {
+ case P9X_EX_NCU_SPEC_BAR:
+ case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
+ offset);
+ }
+}
+
+static const MemoryRegionOps pnv_quad_xscom_ops = {
+ .read = pnv_quad_xscom_read,
+ .write = pnv_quad_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void pnv_quad_realize(DeviceState *dev, Error **errp)
+{
+ PnvQuad *eq = PNV_QUAD(dev);
+ char name[32];
+
+ snprintf(name, sizeof(name), "xscom-quad.%d", eq->id);
+ pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops,
+ eq, name, PNV9_XSCOM_EQ_SIZE);
+}
+
+static Property pnv_quad_properties[] = {
+ DEFINE_PROP_UINT32("id", PnvQuad, id, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_quad_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = pnv_quad_realize;
+ dc->props = pnv_quad_properties;
+}
+
+static const TypeInfo pnv_quad_info = {
+ .name = TYPE_PNV_QUAD,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PnvQuad),
+ .class_init = pnv_quad_class_init,
+};
+
+static void pnv_core_register_types(void)
+{
+ type_register_static(&pnv_quad_info);
+}
+
+type_init(pnv_core_register_types)
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 172a915cfc..641e2046db 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -39,6 +39,8 @@ enum {
};
/* OPB Master LS registers */
+#define OPB_MASTER_LS_ROUTE0 0x8
+#define OPB_MASTER_LS_ROUTE1 0xC
#define OPB_MASTER_LS_IRQ_STAT 0x50
#define OPB_MASTER_IRQ_LPC 0x00000800
#define OPB_MASTER_LS_IRQ_MASK 0x54
@@ -89,10 +91,11 @@ enum {
#define LPC_FW_OPB_SIZE 0x10000000
#define LPC_OPB_REGS_OPB_ADDR 0xc0010000
-#define LPC_OPB_REGS_OPB_SIZE 0x00002000
+#define LPC_OPB_REGS_OPB_SIZE 0x00000060
+#define LPC_OPB_REGS_OPBA_ADDR 0xc0011000
+#define LPC_OPB_REGS_OPBA_SIZE 0x00000008
#define LPC_HC_REGS_OPB_ADDR 0xc0012000
-#define LPC_HC_REGS_OPB_SIZE 0x00001000
-
+#define LPC_HC_REGS_OPB_SIZE 0x00000100
static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
{
@@ -117,6 +120,100 @@ static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
return 0;
}
+/* POWER9 only */
+int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset)
+{
+ const char compat[] = "ibm,power9-lpcm-opb\0simple-bus";
+ const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc";
+ char *name;
+ int offset, lpcm_offset;
+ uint64_t lpcm_addr = PNV9_LPCM_BASE(chip);
+ uint32_t opb_ranges[8] = { 0,
+ cpu_to_be32(lpcm_addr >> 32),
+ cpu_to_be32((uint32_t)lpcm_addr),
+ cpu_to_be32(PNV9_LPCM_SIZE / 2),
+ cpu_to_be32(PNV9_LPCM_SIZE / 2),
+ cpu_to_be32(lpcm_addr >> 32),
+ cpu_to_be32(PNV9_LPCM_SIZE / 2),
+ cpu_to_be32(PNV9_LPCM_SIZE / 2),
+ };
+ uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32),
+ cpu_to_be32((uint32_t)lpcm_addr),
+ cpu_to_be32(PNV9_LPCM_SIZE >> 32),
+ cpu_to_be32((uint32_t)PNV9_LPCM_SIZE),
+ };
+ uint32_t reg[2];
+
+ /*
+ * OPB bus
+ */
+ name = g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr);
+ lpcm_offset = fdt_add_subnode(fdt, root_offset, name);
+ _FDT(lpcm_offset);
+ g_free(name);
+
+ _FDT((fdt_setprop(fdt, lpcm_offset, "reg", opb_reg, sizeof(opb_reg))));
+ _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1)));
+ _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1)));
+ _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(compat))));
+ _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_id)));
+ _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", opb_ranges,
+ sizeof(opb_ranges))));
+
+ /*
+ * OPB Master registers
+ */
+ name = g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR);
+ offset = fdt_add_subnode(fdt, lpcm_offset, name);
+ _FDT(offset);
+ g_free(name);
+
+ reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR);
+ reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE);
+ _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+ _FDT((fdt_setprop_string(fdt, offset, "compatible",
+ "ibm,power9-lpcm-opb-master")));
+
+ /*
+ * OPB arbitrer registers
+ */
+ name = g_strdup_printf("opb-arbitrer@%x", LPC_OPB_REGS_OPBA_ADDR);
+ offset = fdt_add_subnode(fdt, lpcm_offset, name);
+ _FDT(offset);
+ g_free(name);
+
+ reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR);
+ reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE);
+ _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+ _FDT((fdt_setprop_string(fdt, offset, "compatible",
+ "ibm,power9-lpcm-opb-arbiter")));
+
+ /*
+ * LPC Host Controller registers
+ */
+ name = g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR);
+ offset = fdt_add_subnode(fdt, lpcm_offset, name);
+ _FDT(offset);
+ g_free(name);
+
+ reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR);
+ reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE);
+ _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+ _FDT((fdt_setprop_string(fdt, offset, "compatible",
+ "ibm,power9-lpc-controller")));
+
+ name = g_strdup_printf("lpc@0");
+ offset = fdt_add_subnode(fdt, lpcm_offset, name);
+ _FDT(offset);
+ g_free(name);
+ _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
+ _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
+ _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat,
+ sizeof(lpc_compat))));
+
+ return 0;
+}
+
/*
* These read/write handlers of the OPB address space should be common
* with the P9 LPC Controller which uses direct MMIOs.
@@ -241,9 +338,78 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
+static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+ PnvLpcController *lpc = PNV_LPC(opaque);
+ uint64_t val = 0;
+ uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
+ MemTxResult result;
+
+ switch (size) {
+ case 4:
+ val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
+ &result);
+ break;
+ case 1:
+ val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
+ &result);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
+ HWADDR_PRIx " invalid size %d\n", addr, size);
+ return 0;
+ }
+
+ if (result != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
+ HWADDR_PRIx "\n", addr);
+ }
+
+ return val;
+}
+
+static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvLpcController *lpc = PNV_LPC(opaque);
+ uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
+ MemTxResult result;
+
+ switch (size) {
+ case 4:
+ address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
+ &result);
+ break;
+ case 1:
+ address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
+ &result);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
+ HWADDR_PRIx " invalid size %d\n", addr, size);
+ return;
+ }
+
+ if (result != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
+ HWADDR_PRIx "\n", addr);
+ }
+}
+
+static const MemoryRegionOps pnv_lpc_mmio_ops = {
+ .read = pnv_lpc_mmio_read,
+ .write = pnv_lpc_mmio_write,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
{
bool lpc_to_opb_irq = false;
+ PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc);
/* Update LPC controller to OPB line */
if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
@@ -266,7 +432,7 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
/* Reflect the interrupt */
- pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_LPC_I2C, lpc->opb_irq_stat != 0);
+ pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0);
}
static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
@@ -294,7 +460,7 @@ static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
val = lpc->lpc_hc_error_addr;
break;
default:
- qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
+ qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%"
HWADDR_PRIx "\n", addr);
}
return val;
@@ -332,7 +498,7 @@ static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val,
case LPC_HC_ERROR_ADDRESS:
break;
default:
- qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
+ qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%"
HWADDR_PRIx "\n", addr);
}
}
@@ -357,6 +523,12 @@ static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size)
uint64_t val = 0xfffffffffffffffful;
switch (addr) {
+ case OPB_MASTER_LS_ROUTE0: /* TODO */
+ val = lpc->opb_irq_route0;
+ break;
+ case OPB_MASTER_LS_ROUTE1: /* TODO */
+ val = lpc->opb_irq_route1;
+ break;
case OPB_MASTER_LS_IRQ_STAT:
val = lpc->opb_irq_stat;
break;
@@ -370,7 +542,7 @@ static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size)
val = lpc->opb_irq_input;
break;
default:
- qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
+ qemu_log_mask(LOG_UNIMP, "OPBM: read on unimplemented register: 0x%"
HWADDR_PRIx "\n", addr);
}
@@ -383,6 +555,12 @@ static void opb_master_write(void *opaque, hwaddr addr,
PnvLpcController *lpc = opaque;
switch (addr) {
+ case OPB_MASTER_LS_ROUTE0: /* TODO */
+ lpc->opb_irq_route0 = val;
+ break;
+ case OPB_MASTER_LS_ROUTE1: /* TODO */
+ lpc->opb_irq_route1 = val;
+ break;
case OPB_MASTER_LS_IRQ_STAT:
lpc->opb_irq_stat &= ~val;
pnv_lpc_eval_irqs(lpc);
@@ -399,8 +577,8 @@ static void opb_master_write(void *opaque, hwaddr addr,
/* Read only */
break;
default:
- qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
- HWADDR_PRIx "\n", addr);
+ qemu_log_mask(LOG_UNIMP, "OPBM: write on unimplemented register: 0x%"
+ HWADDR_PRIx " val=0x%08"PRIx64"\n", addr, val);
}
}
@@ -418,11 +596,102 @@ static const MemoryRegionOps opb_master_ops = {
},
};
+static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp)
+{
+ PnvLpcController *lpc = PNV_LPC(dev);
+ PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
+ Error *local_err = NULL;
+
+ plc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* P8 uses a XSCOM region for LPC registers */
+ pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(lpc),
+ &pnv_lpc_xscom_ops, lpc, "xscom-lpc",
+ PNV_XSCOM_LPC_SIZE);
+}
+
+static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
+ PnvLpcClass *plc = PNV_LPC_CLASS(klass);
+
+ dc->desc = "PowerNV LPC Controller POWER8";
+
+ xdc->dt_xscom = pnv_lpc_dt_xscom;
+
+ plc->psi_irq = PSIHB_IRQ_LPC_I2C;
+
+ device_class_set_parent_realize(dc, pnv_lpc_power8_realize,
+ &plc->parent_realize);
+}
+
+static const TypeInfo pnv_lpc_power8_info = {
+ .name = TYPE_PNV8_LPC,
+ .parent = TYPE_PNV_LPC,
+ .instance_size = sizeof(PnvLpcController),
+ .class_init = pnv_lpc_power8_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_PNV_XSCOM_INTERFACE },
+ { }
+ }
+};
+
+static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
+{
+ PnvLpcController *lpc = PNV_LPC(dev);
+ PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
+ Error *local_err = NULL;
+
+ plc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* P9 uses a MMIO region */
+ memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
+ lpc, "lpcm", PNV9_LPCM_SIZE);
+}
+
+static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PnvLpcClass *plc = PNV_LPC_CLASS(klass);
+
+ dc->desc = "PowerNV LPC Controller POWER9";
+
+ plc->psi_irq = PSIHB9_IRQ_LPCHC;
+
+ device_class_set_parent_realize(dc, pnv_lpc_power9_realize,
+ &plc->parent_realize);
+}
+
+static const TypeInfo pnv_lpc_power9_info = {
+ .name = TYPE_PNV9_LPC,
+ .parent = TYPE_PNV_LPC,
+ .instance_size = sizeof(PnvLpcController),
+ .class_init = pnv_lpc_power9_class_init,
+};
+
static void pnv_lpc_realize(DeviceState *dev, Error **errp)
{
PnvLpcController *lpc = PNV_LPC(dev);
Object *obj;
- Error *error = NULL;
+ Error *local_err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
+ if (!obj) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'psi' not found: ");
+ return;
+ }
+ /* The LPC controller needs PSI to generate interrupts */
+ lpc->psi = PNV_PSI(obj);
/* Reg inits */
lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B;
@@ -462,46 +731,29 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
"lpc-hc", LPC_HC_REGS_OPB_SIZE);
memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
&lpc->lpc_hc_regs);
-
- /* XScom region for LPC registers */
- pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(dev),
- &pnv_lpc_xscom_ops, lpc, "xscom-lpc",
- PNV_XSCOM_LPC_SIZE);
-
- /* get PSI object from chip */
- obj = object_property_get_link(OBJECT(dev), "psi", &error);
- if (!obj) {
- error_setg(errp, "%s: required link 'psi' not found: %s",
- __func__, error_get_pretty(error));
- return;
- }
- lpc->psi = PNV_PSI(obj);
}
static void pnv_lpc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
-
- xdc->dt_xscom = pnv_lpc_dt_xscom;
dc->realize = pnv_lpc_realize;
+ dc->desc = "PowerNV LPC Controller";
}
static const TypeInfo pnv_lpc_info = {
.name = TYPE_PNV_LPC,
.parent = TYPE_DEVICE,
- .instance_size = sizeof(PnvLpcController),
.class_init = pnv_lpc_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_PNV_XSCOM_INTERFACE },
- { }
- }
+ .class_size = sizeof(PnvLpcClass),
+ .abstract = true,
};
static void pnv_lpc_register_types(void)
{
type_register_static(&pnv_lpc_info);
+ type_register_static(&pnv_lpc_power8_info);
+ type_register_static(&pnv_lpc_power9_info);
}
type_init(pnv_lpc_register_types)
diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
index 04880f26d6..fdd9296e1b 100644
--- a/hw/ppc/pnv_occ.c
+++ b/hw/ppc/pnv_occ.c
@@ -34,15 +34,17 @@
static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
{
bool irq_state;
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
val &= 0xffff000000000000ull;
occ->occmisc = val;
irq_state = !!(val >> 63);
- pnv_psi_irq_set(occ->psi, PSIHB_IRQ_OCC, irq_state);
+ pnv_psi_irq_set(occ->psi, poc->psi_irq, irq_state);
}
-static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
+static uint64_t pnv_occ_power8_xscom_read(void *opaque, hwaddr addr,
+ unsigned size)
{
PnvOCC *occ = PNV_OCC(opaque);
uint32_t offset = addr >> 3;
@@ -54,13 +56,13 @@ static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
break;
default:
qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
- HWADDR_PRIx "\n", addr);
+ HWADDR_PRIx "\n", addr >> 3);
}
return val;
}
-static void pnv_occ_xscom_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
+static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
{
PnvOCC *occ = PNV_OCC(opaque);
uint32_t offset = addr >> 3;
@@ -77,13 +79,13 @@ static void pnv_occ_xscom_write(void *opaque, hwaddr addr,
break;
default:
qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
- HWADDR_PRIx "\n", addr);
+ HWADDR_PRIx "\n", addr >> 3);
}
}
-static const MemoryRegionOps pnv_occ_xscom_ops = {
- .read = pnv_occ_xscom_read,
- .write = pnv_occ_xscom_write,
+static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
+ .read = pnv_occ_power8_xscom_read,
+ .write = pnv_occ_power8_xscom_write,
.valid.min_access_size = 8,
.valid.max_access_size = 8,
.impl.min_access_size = 8,
@@ -91,27 +93,113 @@ static const MemoryRegionOps pnv_occ_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
+static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
+{
+ PnvOCCClass *poc = PNV_OCC_CLASS(klass);
+
+ poc->xscom_size = PNV_XSCOM_OCC_SIZE;
+ poc->xscom_ops = &pnv_occ_power8_xscom_ops;
+ poc->psi_irq = PSIHB_IRQ_OCC;
+}
+
+static const TypeInfo pnv_occ_power8_type_info = {
+ .name = TYPE_PNV8_OCC,
+ .parent = TYPE_PNV_OCC,
+ .instance_size = sizeof(PnvOCC),
+ .class_init = pnv_occ_power8_class_init,
+};
+
+#define P9_OCB_OCI_OCCMISC 0x6080
+#define P9_OCB_OCI_OCCMISC_CLEAR 0x6081
+#define P9_OCB_OCI_OCCMISC_OR 0x6082
+
+
+static uint64_t pnv_occ_power9_xscom_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ PnvOCC *occ = PNV_OCC(opaque);
+ uint32_t offset = addr >> 3;
+ uint64_t val = 0;
+
+ switch (offset) {
+ case P9_OCB_OCI_OCCMISC:
+ val = occ->occmisc;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
+ HWADDR_PRIx "\n", addr >> 3);
+ }
+ return val;
+}
+
+static void pnv_occ_power9_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvOCC *occ = PNV_OCC(opaque);
+ uint32_t offset = addr >> 3;
+
+ switch (offset) {
+ case P9_OCB_OCI_OCCMISC_CLEAR:
+ pnv_occ_set_misc(occ, 0);
+ break;
+ case P9_OCB_OCI_OCCMISC_OR:
+ pnv_occ_set_misc(occ, occ->occmisc | val);
+ break;
+ case P9_OCB_OCI_OCCMISC:
+ pnv_occ_set_misc(occ, val);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
+ HWADDR_PRIx "\n", addr >> 3);
+ }
+}
+
+static const MemoryRegionOps pnv_occ_power9_xscom_ops = {
+ .read = pnv_occ_power9_xscom_read,
+ .write = pnv_occ_power9_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
+{
+ PnvOCCClass *poc = PNV_OCC_CLASS(klass);
+
+ poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
+ poc->xscom_ops = &pnv_occ_power9_xscom_ops;
+ poc->psi_irq = PSIHB9_IRQ_OCC;
+}
+
+static const TypeInfo pnv_occ_power9_type_info = {
+ .name = TYPE_PNV9_OCC,
+ .parent = TYPE_PNV_OCC,
+ .instance_size = sizeof(PnvOCC),
+ .class_init = pnv_occ_power9_class_init,
+};
static void pnv_occ_realize(DeviceState *dev, Error **errp)
{
PnvOCC *occ = PNV_OCC(dev);
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
Object *obj;
- Error *error = NULL;
+ Error *local_err = NULL;
occ->occmisc = 0;
- /* get PSI object from chip */
- obj = object_property_get_link(OBJECT(dev), "psi", &error);
+ obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
if (!obj) {
- error_setg(errp, "%s: required link 'psi' not found: %s",
- __func__, error_get_pretty(error));
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'psi' not found: ");
return;
}
occ->psi = PNV_PSI(obj);
/* XScom region for OCC registers */
- pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), &pnv_occ_xscom_ops,
- occ, "xscom-occ", PNV_XSCOM_OCC_SIZE);
+ pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
+ occ, "xscom-occ", poc->xscom_size);
}
static void pnv_occ_class_init(ObjectClass *klass, void *data)
@@ -119,6 +207,7 @@ static void pnv_occ_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pnv_occ_realize;
+ dc->desc = "PowerNV OCC Controller";
}
static const TypeInfo pnv_occ_type_info = {
@@ -126,11 +215,15 @@ static const TypeInfo pnv_occ_type_info = {
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvOCC),
.class_init = pnv_occ_class_init,
+ .class_size = sizeof(PnvOCCClass),
+ .abstract = true,
};
static void pnv_occ_register_types(void)
{
type_register_static(&pnv_occ_type_info);
+ type_register_static(&pnv_occ_power8_type_info);
+ type_register_static(&pnv_occ_power9_type_info);
}
-type_init(pnv_occ_register_types)
+type_init(pnv_occ_register_types);
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 44bc0cbf58..5a923e4151 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -22,6 +22,7 @@
#include "target/ppc/cpu.h"
#include "qemu/log.h"
#include "qapi/error.h"
+#include "monitor/monitor.h"
#include "exec/address-spaces.h"
@@ -114,12 +115,18 @@
#define PSIHB_BAR_MASK 0x0003fffffff00000ull
#define PSIHB_FSPBAR_MASK 0x0003ffff00000000ull
+#define PSIHB9_BAR_MASK 0x00fffffffff00000ull
+#define PSIHB9_FSPBAR_MASK 0x00ffffff00000000ull
+
+#define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
+
static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
{
+ PnvPsiClass *ppc = PNV_PSI_GET_CLASS(psi);
MemoryRegion *sysmem = get_system_memory();
uint64_t old = psi->regs[PSIHB_XSCOM_BAR];
- psi->regs[PSIHB_XSCOM_BAR] = bar & (PSIHB_BAR_MASK | PSIHB_BAR_EN);
+ psi->regs[PSIHB_XSCOM_BAR] = bar & (ppc->bar_mask | PSIHB_BAR_EN);
/* Update MR, always remove it first */
if (old & PSIHB_BAR_EN) {
@@ -128,7 +135,7 @@ static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
/* Then add it back if needed */
if (bar & PSIHB_BAR_EN) {
- uint64_t addr = bar & PSIHB_BAR_MASK;
+ uint64_t addr = bar & ppc->bar_mask;
memory_region_add_subregion(sysmem, addr, &psi->regs_mr);
}
}
@@ -152,7 +159,7 @@ static void pnv_psi_set_cr(PnvPsi *psi, uint64_t cr)
static void pnv_psi_set_irsn(PnvPsi *psi, uint64_t val)
{
- ICSState *ics = &psi->ics;
+ ICSState *ics = &PNV8_PSI(psi)->ics;
/* In this model we ignore the up/down enable bits for now
* as SW doesn't use them (other than setting them at boot).
@@ -205,7 +212,12 @@ static const uint64_t stat_bits[] = {
[PSIHB_IRQ_EXTERNAL] = PSIHB_IRQ_STAT_EXT,
};
-void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state)
+void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state)
+{
+ PNV_PSI_GET_CLASS(psi)->irq_set(psi, irq, state);
+}
+
+static void pnv_psi_power8_irq_set(PnvPsi *psi, int irq, bool state)
{
uint32_t xivr_reg;
uint32_t stat_reg;
@@ -260,7 +272,7 @@ void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state)
static void pnv_psi_set_xivr(PnvPsi *psi, uint32_t reg, uint64_t val)
{
- ICSState *ics = &psi->ics;
+ ICSState *ics = &PNV8_PSI(psi)->ics;
uint16_t server;
uint8_t prio;
uint8_t src;
@@ -323,7 +335,7 @@ static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio)
val = psi->regs[offset];
break;
default:
- qemu_log_mask(LOG_UNIMP, "PSI: read at Ox%" PRIx32 "\n", offset);
+ qemu_log_mask(LOG_UNIMP, "PSI: read at 0x%" PRIx32 "\n", offset);
}
return val;
}
@@ -382,7 +394,7 @@ static void pnv_psi_reg_write(PnvPsi *psi, uint32_t offset, uint64_t val,
pnv_psi_set_irsn(psi, val);
break;
default:
- qemu_log_mask(LOG_UNIMP, "PSI: write at Ox%" PRIx32 "\n", offset);
+ qemu_log_mask(LOG_UNIMP, "PSI: write at 0x%" PRIx32 "\n", offset);
}
}
@@ -392,13 +404,13 @@ static void pnv_psi_reg_write(PnvPsi *psi, uint32_t offset, uint64_t val,
*/
static uint64_t pnv_psi_mmio_read(void *opaque, hwaddr addr, unsigned size)
{
- return pnv_psi_reg_read(opaque, (addr >> 3) + PSIHB_XSCOM_BAR, true);
+ return pnv_psi_reg_read(opaque, PSIHB_REG(addr), true);
}
static void pnv_psi_mmio_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
- pnv_psi_reg_write(opaque, (addr >> 3) + PSIHB_XSCOM_BAR, val, true);
+ pnv_psi_reg_write(opaque, PSIHB_REG(addr), val, true);
}
static const MemoryRegionOps psi_mmio_ops = {
@@ -440,11 +452,20 @@ static const MemoryRegionOps pnv_psi_xscom_ops = {
}
};
-static void pnv_psi_init(Object *obj)
+static void pnv_psi_reset(void *dev)
{
- PnvPsi *psi = PNV_PSI(obj);
+ PnvPsi *psi = PNV_PSI(dev);
+
+ memset(psi->regs, 0x0, sizeof(psi->regs));
- object_initialize_child(obj, "ics-psi", &psi->ics, sizeof(psi->ics),
+ psi->regs[PSIHB_XSCOM_BAR] = psi->bar | PSIHB_BAR_EN;
+}
+
+static void pnv_psi_power8_instance_init(Object *obj)
+{
+ Pnv8Psi *psi8 = PNV8_PSI(obj);
+
+ object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics),
TYPE_ICS_SIMPLE, &error_abort, NULL);
}
@@ -457,10 +478,10 @@ static const uint8_t irq_to_xivr[] = {
PSIHB_XSCOM_XIVR_EXT,
};
-static void pnv_psi_realize(DeviceState *dev, Error **errp)
+static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
{
PnvPsi *psi = PNV_PSI(dev);
- ICSState *ics = &psi->ics;
+ ICSState *ics = &PNV8_PSI(psi)->ics;
Object *obj;
Error *err = NULL;
unsigned int i;
@@ -509,30 +530,38 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
psi->regs[xivr] = PSIHB_XIVR_PRIO_MSK |
((uint64_t) i << PSIHB_XIVR_SRC_SH);
}
+
+ qemu_register_reset(pnv_psi_reset, dev);
}
+static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
+static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
+
static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
{
- const char compat[] = "ibm,power8-psihb-x\0ibm,psihb-x";
+ PnvPsiClass *ppc = PNV_PSI_GET_CLASS(dev);
char *name;
int offset;
- uint32_t lpc_pcba = PNV_XSCOM_PSIHB_BASE;
uint32_t reg[] = {
- cpu_to_be32(lpc_pcba),
- cpu_to_be32(PNV_XSCOM_PSIHB_SIZE)
+ cpu_to_be32(ppc->xscom_pcba),
+ cpu_to_be32(ppc->xscom_size)
};
- name = g_strdup_printf("psihb@%x", lpc_pcba);
+ name = g_strdup_printf("psihb@%x", ppc->xscom_pcba);
offset = fdt_add_subnode(fdt, xscom_offset, name);
_FDT(offset);
g_free(name);
- _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
-
- _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
- _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
- _FDT((fdt_setprop(fdt, offset, "compatible", compat,
- sizeof(compat))));
+ _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
+ _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
+ _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
+ if (ppc->chip_type == PNV_CHIP_POWER9) {
+ _FDT(fdt_setprop(fdt, offset, "compatible", compat_p9,
+ sizeof(compat_p9)));
+ } else {
+ _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
+ sizeof(compat_p8)));
+ }
return 0;
}
@@ -542,6 +571,331 @@ static Property pnv_psi_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static void pnv_psi_power8_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
+
+ dc->desc = "PowerNV PSI Controller POWER8";
+ dc->realize = pnv_psi_power8_realize;
+
+ ppc->chip_type = PNV_CHIP_POWER8;
+ ppc->xscom_pcba = PNV_XSCOM_PSIHB_BASE;
+ ppc->xscom_size = PNV_XSCOM_PSIHB_SIZE;
+ ppc->bar_mask = PSIHB_BAR_MASK;
+ ppc->irq_set = pnv_psi_power8_irq_set;
+}
+
+static const TypeInfo pnv_psi_power8_info = {
+ .name = TYPE_PNV8_PSI,
+ .parent = TYPE_PNV_PSI,
+ .instance_size = sizeof(Pnv8Psi),
+ .instance_init = pnv_psi_power8_instance_init,
+ .class_init = pnv_psi_power8_class_init,
+};
+
+
+/* Common registers */
+
+#define PSIHB9_CR 0x20
+#define PSIHB9_SEMR 0x28
+
+/* P9 registers */
+
+#define PSIHB9_INTERRUPT_CONTROL 0x58
+#define PSIHB9_IRQ_METHOD PPC_BIT(0)
+#define PSIHB9_IRQ_RESET PPC_BIT(1)
+#define PSIHB9_ESB_CI_BASE 0x60
+#define PSIHB9_ESB_CI_VALID 1
+#define PSIHB9_ESB_NOTIF_ADDR 0x68
+#define PSIHB9_ESB_NOTIF_VALID 1
+#define PSIHB9_IVT_OFFSET 0x70
+#define PSIHB9_IVT_OFF_SHIFT 32
+
+#define PSIHB9_IRQ_LEVEL 0x78 /* assertion */
+#define PSIHB9_IRQ_LEVEL_PSI PPC_BIT(0)
+#define PSIHB9_IRQ_LEVEL_OCC PPC_BIT(1)
+#define PSIHB9_IRQ_LEVEL_FSI PPC_BIT(2)
+#define PSIHB9_IRQ_LEVEL_LPCHC PPC_BIT(3)
+#define PSIHB9_IRQ_LEVEL_LOCAL_ERR PPC_BIT(4)
+#define PSIHB9_IRQ_LEVEL_GLOBAL_ERR PPC_BIT(5)
+#define PSIHB9_IRQ_LEVEL_TPM PPC_BIT(6)
+#define PSIHB9_IRQ_LEVEL_LPC_SIRQ1 PPC_BIT(7)
+#define PSIHB9_IRQ_LEVEL_LPC_SIRQ2 PPC_BIT(8)
+#define PSIHB9_IRQ_LEVEL_LPC_SIRQ3 PPC_BIT(9)
+#define PSIHB9_IRQ_LEVEL_LPC_SIRQ4 PPC_BIT(10)
+#define PSIHB9_IRQ_LEVEL_SBE_I2C PPC_BIT(11)
+#define PSIHB9_IRQ_LEVEL_DIO PPC_BIT(12)
+#define PSIHB9_IRQ_LEVEL_PSU PPC_BIT(13)
+#define PSIHB9_IRQ_LEVEL_I2C_C PPC_BIT(14)
+#define PSIHB9_IRQ_LEVEL_I2C_D PPC_BIT(15)
+#define PSIHB9_IRQ_LEVEL_I2C_E PPC_BIT(16)
+#define PSIHB9_IRQ_LEVEL_SBE PPC_BIT(19)
+
+#define PSIHB9_IRQ_STAT 0x80 /* P bit */
+#define PSIHB9_IRQ_STAT_PSI PPC_BIT(0)
+#define PSIHB9_IRQ_STAT_OCC PPC_BIT(1)
+#define PSIHB9_IRQ_STAT_FSI PPC_BIT(2)
+#define PSIHB9_IRQ_STAT_LPCHC PPC_BIT(3)
+#define PSIHB9_IRQ_STAT_LOCAL_ERR PPC_BIT(4)
+#define PSIHB9_IRQ_STAT_GLOBAL_ERR PPC_BIT(5)
+#define PSIHB9_IRQ_STAT_TPM PPC_BIT(6)
+#define PSIHB9_IRQ_STAT_LPC_SIRQ1 PPC_BIT(7)
+#define PSIHB9_IRQ_STAT_LPC_SIRQ2 PPC_BIT(8)
+#define PSIHB9_IRQ_STAT_LPC_SIRQ3 PPC_BIT(9)
+#define PSIHB9_IRQ_STAT_LPC_SIRQ4 PPC_BIT(10)
+#define PSIHB9_IRQ_STAT_SBE_I2C PPC_BIT(11)
+#define PSIHB9_IRQ_STAT_DIO PPC_BIT(12)
+#define PSIHB9_IRQ_STAT_PSU PPC_BIT(13)
+
+static void pnv_psi_notify(XiveNotifier *xf, uint32_t srcno)
+{
+ PnvPsi *psi = PNV_PSI(xf);
+ uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)];
+ bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID;
+ uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID;
+
+ uint32_t offset =
+ (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
+ uint64_t lisn = cpu_to_be64(offset + srcno);
+
+ if (valid) {
+ cpu_physical_memory_write(notify_addr, &lisn, sizeof(lisn));
+ }
+}
+
+static uint64_t pnv_psi_p9_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+ PnvPsi *psi = PNV_PSI(opaque);
+ uint32_t reg = PSIHB_REG(addr);
+ uint64_t val = -1;
+
+ switch (addr) {
+ case PSIHB9_CR:
+ case PSIHB9_SEMR:
+ /* FSP stuff */
+ case PSIHB9_INTERRUPT_CONTROL:
+ case PSIHB9_ESB_CI_BASE:
+ case PSIHB9_ESB_NOTIF_ADDR:
+ case PSIHB9_IVT_OFFSET:
+ val = psi->regs[reg];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "PSI: read at 0x%" PRIx64 "\n", addr);
+ }
+
+ return val;
+}
+
+static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvPsi *psi = PNV_PSI(opaque);
+ Pnv9Psi *psi9 = PNV9_PSI(psi);
+ uint32_t reg = PSIHB_REG(addr);
+ MemoryRegion *sysmem = get_system_memory();
+
+ switch (addr) {
+ case PSIHB9_CR:
+ case PSIHB9_SEMR:
+ /* FSP stuff */
+ break;
+ case PSIHB9_INTERRUPT_CONTROL:
+ if (val & PSIHB9_IRQ_RESET) {
+ device_reset(DEVICE(&psi9->source));
+ }
+ psi->regs[reg] = val;
+ break;
+
+ case PSIHB9_ESB_CI_BASE:
+ if (!(val & PSIHB9_ESB_CI_VALID)) {
+ if (psi->regs[reg] & PSIHB9_ESB_CI_VALID) {
+ memory_region_del_subregion(sysmem, &psi9->source.esb_mmio);
+ }
+ } else {
+ if (!(psi->regs[reg] & PSIHB9_ESB_CI_VALID)) {
+ memory_region_add_subregion(sysmem,
+ val & ~PSIHB9_ESB_CI_VALID,
+ &psi9->source.esb_mmio);
+ }
+ }
+ psi->regs[reg] = val;
+ break;
+
+ case PSIHB9_ESB_NOTIF_ADDR:
+ psi->regs[reg] = val;
+ break;
+ case PSIHB9_IVT_OFFSET:
+ psi->regs[reg] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "PSI: write at 0x%" PRIx64 "\n", addr);
+ }
+}
+
+static const MemoryRegionOps pnv_psi_p9_mmio_ops = {
+ .read = pnv_psi_p9_mmio_read,
+ .write = pnv_psi_p9_mmio_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+static uint64_t pnv_psi_p9_xscom_read(void *opaque, hwaddr addr, unsigned size)
+{
+ /* No read are expected */
+ qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom read at 0x%" PRIx64 "\n", addr);
+ return -1;
+}
+
+static void pnv_psi_p9_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvPsi *psi = PNV_PSI(opaque);
+
+ /* XSCOM is only used to set the PSIHB MMIO region */
+ switch (addr >> 3) {
+ case PSIHB_XSCOM_BAR:
+ pnv_psi_set_bar(psi, val);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom write at 0x%" PRIx64 "\n",
+ addr);
+ }
+}
+
+static const MemoryRegionOps pnv_psi_p9_xscom_ops = {
+ .read = pnv_psi_p9_xscom_read,
+ .write = pnv_psi_p9_xscom_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ }
+};
+
+static void pnv_psi_power9_irq_set(PnvPsi *psi, int irq, bool state)
+{
+ uint32_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)];
+
+ if (irq > PSIHB9_NUM_IRQS) {
+ qemu_log_mask(LOG_GUEST_ERROR, "PSI: Unsupported irq %d\n", irq);
+ return;
+ }
+
+ if (irq_method & PSIHB9_IRQ_METHOD) {
+ qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n");
+ return;
+ }
+
+ /* Update LSI levels */
+ if (state) {
+ psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= PPC_BIT(irq);
+ } else {
+ psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~PPC_BIT(irq);
+ }
+
+ qemu_set_irq(psi->qirqs[irq], state);
+}
+
+static void pnv_psi_power9_reset(void *dev)
+{
+ Pnv9Psi *psi = PNV9_PSI(dev);
+
+ pnv_psi_reset(dev);
+
+ if (memory_region_is_mapped(&psi->source.esb_mmio)) {
+ memory_region_del_subregion(get_system_memory(), &psi->source.esb_mmio);
+ }
+}
+
+static void pnv_psi_power9_instance_init(Object *obj)
+{
+ Pnv9Psi *psi = PNV9_PSI(obj);
+
+ object_initialize_child(obj, "source", &psi->source, sizeof(psi->source),
+ TYPE_XIVE_SOURCE, &error_abort, NULL);
+}
+
+static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
+{
+ PnvPsi *psi = PNV_PSI(dev);
+ XiveSource *xsrc = &PNV9_PSI(psi)->source;
+ Error *local_err = NULL;
+ int i;
+
+ /* This is the only device with 4k ESB pages */
+ object_property_set_int(OBJECT(xsrc), XIVE_ESB_4K, "shift",
+ &error_fatal);
+ object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs",
+ &error_fatal);
+ object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(psi),
+ &error_fatal);
+ object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ for (i = 0; i < xsrc->nr_irqs; i++) {
+ xive_source_irq_set_lsi(xsrc, i);
+ }
+
+ psi->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
+
+ /* XSCOM region for PSI registers */
+ pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_p9_xscom_ops,
+ psi, "xscom-psi", PNV9_XSCOM_PSIHB_SIZE);
+
+ /* MMIO region for PSI registers */
+ memory_region_init_io(&psi->regs_mr, OBJECT(dev), &pnv_psi_p9_mmio_ops, psi,
+ "psihb", PNV9_PSIHB_SIZE);
+
+ pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
+
+ qemu_register_reset(pnv_psi_power9_reset, dev);
+}
+
+static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
+ XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
+
+ dc->desc = "PowerNV PSI Controller POWER9";
+ dc->realize = pnv_psi_power9_realize;
+
+ ppc->chip_type = PNV_CHIP_POWER9;
+ ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
+ ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
+ ppc->bar_mask = PSIHB9_BAR_MASK;
+ ppc->irq_set = pnv_psi_power9_irq_set;
+
+ xfc->notify = pnv_psi_notify;
+}
+
+static const TypeInfo pnv_psi_power9_info = {
+ .name = TYPE_PNV9_PSI,
+ .parent = TYPE_PNV_PSI,
+ .instance_size = sizeof(Pnv9Psi),
+ .instance_init = pnv_psi_power9_instance_init,
+ .class_init = pnv_psi_power9_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_XIVE_NOTIFIER },
+ { },
+ },
+};
+
static void pnv_psi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -549,7 +903,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
xdc->dt_xscom = pnv_psi_dt_xscom;
- dc->realize = pnv_psi_realize;
+ dc->desc = "PowerNV PSI Controller";
dc->props = pnv_psi_properties;
}
@@ -557,8 +911,9 @@ static const TypeInfo pnv_psi_info = {
.name = TYPE_PNV_PSI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(PnvPsi),
- .instance_init = pnv_psi_init,
.class_init = pnv_psi_class_init,
+ .class_size = sizeof(PnvPsiClass),
+ .abstract = true,
.interfaces = (InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
@@ -568,6 +923,20 @@ static const TypeInfo pnv_psi_info = {
static void pnv_psi_register_types(void)
{
type_register_static(&pnv_psi_info);
+ type_register_static(&pnv_psi_power8_info);
+ type_register_static(&pnv_psi_power9_info);
}
-type_init(pnv_psi_register_types)
+type_init(pnv_psi_register_types);
+
+void pnv_psi_pic_print_info(Pnv9Psi *psi9, Monitor *mon)
+{
+ PnvPsi *psi = PNV_PSI(psi9);
+
+ uint32_t offset =
+ (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
+
+ monitor_printf(mon, "PSIHB Source %08x .. %08x\n",
+ offset, offset + psi9->source.nr_irqs - 1);
+ xive_source_pic_print_info(&psi9->source, offset, mon);
+}
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index 46fae41f32..c285ef514e 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -64,11 +64,21 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
switch (pcba) {
case 0xf000f:
return PNV_CHIP_GET_CLASS(chip)->chip_cfam_id;
+ case 0x18002: /* ECID2 */
+ return 0;
+
case 0x1010c00: /* PIBAM FIR */
case 0x1010c03: /* PIBAM FIR MASK */
- case 0x2020007: /* ADU stuff */
- case 0x2020009: /* ADU stuff */
- case 0x202000f: /* ADU stuff */
+
+ /* P9 xscom reset */
+ case 0x0090018: /* Receive status reg */
+ case 0x0090012: /* log register */
+ case 0x0090013: /* error register */
+
+ /* P8 xscom reset */
+ case 0x2020007: /* ADU stuff, log register */
+ case 0x2020009: /* ADU stuff, error register */
+ case 0x202000f: /* ADU stuff, receive status register*/
return 0;
case 0x2013f00: /* PBA stuff */
case 0x2013f01: /* PBA stuff */
@@ -100,9 +110,20 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val)
case 0x1010c03: /* PIBAM FIR MASK */
case 0x1010c04: /* PIBAM FIR MASK */
case 0x1010c05: /* PIBAM FIR MASK */
- case 0x2020007: /* ADU stuff */
- case 0x2020009: /* ADU stuff */
- case 0x202000f: /* ADU stuff */
+ /* P9 xscom reset */
+ case 0x0090018: /* Receive status reg */
+ case 0x0090012: /* log register */
+ case 0x0090013: /* error register */
+
+ /* P8 xscom reset */
+ case 0x2020007: /* ADU stuff, log register */
+ case 0x2020009: /* ADU stuff, error register */
+ case 0x202000f: /* ADU stuff, receive status register*/
+
+ case 0x2013028: /* CAPP stuff */
+ case 0x201302a: /* CAPP stuff */
+ case 0x2013801: /* CAPP stuff */
+ case 0x2013802: /* CAPP stuff */
return true;
default:
return false;
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index d1e3d4cd20..49d57469fb 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -744,11 +744,10 @@ bool ppc_decr_clear_on_delivery(CPUPPCState *env)
return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
}
-static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
+static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
{
ppc_tb_t *tb_env = env->tb_env;
- uint32_t decr;
- int64_t diff;
+ int64_t decr, diff;
diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (diff >= 0) {
@@ -758,27 +757,49 @@ static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
} else {
decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND);
}
- LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
+ LOG_TB("%s: %016" PRIx64 "\n", __func__, decr);
return decr;
}
-uint32_t cpu_ppc_load_decr (CPUPPCState *env)
+target_ulong cpu_ppc_load_decr(CPUPPCState *env)
{
ppc_tb_t *tb_env = env->tb_env;
+ uint64_t decr;
if (kvm_enabled()) {
return env->spr[SPR_DECR];
}
- return _cpu_ppc_load_decr(env, tb_env->decr_next);
+ decr = _cpu_ppc_load_decr(env, tb_env->decr_next);
+
+ /*
+ * If large decrementer is enabled then the decrementer is signed extened
+ * to 64 bits, otherwise it is a 32 bit value.
+ */
+ if (env->spr[SPR_LPCR] & LPCR_LD) {
+ return decr;
+ }
+ return (uint32_t) decr;
}
-uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
+target_ulong cpu_ppc_load_hdecr(CPUPPCState *env)
{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
ppc_tb_t *tb_env = env->tb_env;
+ uint64_t hdecr;
+
+ hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next);
- return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
+ /*
+ * If we have a large decrementer (POWER9 or later) then hdecr is sign
+ * extended to 64 bits, otherwise it is 32 bits.
+ */
+ if (pcc->lrg_decr_bits > 32) {
+ return hdecr;
+ }
+ return (uint32_t) hdecr;
}
uint64_t cpu_ppc_load_purr (CPUPPCState *env)
@@ -832,13 +853,22 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
QEMUTimer *timer,
void (*raise_excp)(void *),
void (*lower_excp)(PowerPCCPU *),
- uint32_t decr, uint32_t value)
+ target_ulong decr, target_ulong value,
+ int nr_bits)
{
CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env = env->tb_env;
uint64_t now, next;
+ bool negative;
- LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
+ /* Truncate value to decr_width and sign extend for simplicity */
+ value &= ((1ULL << nr_bits) - 1);
+ negative = !!(value & (1ULL << (nr_bits - 1)));
+ if (negative) {
+ value |= (0xFFFFFFFFULL << nr_bits);
+ }
+
+ LOG_TB("%s: " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__,
decr, value);
if (kvm_enabled()) {
@@ -860,15 +890,15 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
* an edge interrupt, so raise it here too.
*/
if ((value < 3) ||
- ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
- ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
- && !(decr & 0x80000000))) {
+ ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && negative) ||
+ ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && negative
+ && !(decr & (1ULL << (nr_bits - 1))))) {
(*raise_excp)(cpu);
return;
}
/* On MSB level based systems a 0 for the MSB stops interrupt delivery */
- if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
+ if (!negative && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
(*lower_excp)(cpu);
}
@@ -881,21 +911,27 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
timer_mod(timer, next);
}
-static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
- uint32_t value)
+static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr,
+ target_ulong value, int nr_bits)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
- value);
+ value, nr_bits);
}
-void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
+void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ int nr_bits = 32;
+
+ if (env->spr[SPR_LPCR] & LPCR_LD) {
+ nr_bits = pcc->lrg_decr_bits;
+ }
- _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
+ _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits);
}
static void cpu_ppc_decr_cb(void *opaque)
@@ -905,23 +941,25 @@ static void cpu_ppc_decr_cb(void *opaque)
cpu_ppc_decr_excp(cpu);
}
-static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
- uint32_t value)
+static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr,
+ target_ulong value, int nr_bits)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
if (tb_env->hdecr_timer != NULL) {
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
- hdecr, value);
+ hdecr, value, nr_bits);
}
}
-void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
+void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
+ _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value,
+ pcc->lrg_decr_bits);
}
static void cpu_ppc_hdecr_cb(void *opaque)
@@ -951,8 +989,8 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
* if a decrementer exception is pending when it enables msr_ee at startup,
* it's not ready to handle it...
*/
- _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
- _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
+ _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
+ _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32);
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
}
@@ -1454,3 +1492,19 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
break;
}
}
+
+PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ if (env->spr_cb[SPR_PIR].default_value == pir) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index f47b15f10e..13318a9faf 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -48,8 +48,6 @@
#define USE_FLASH_BIOS
-//#define DEBUG_BOARD_INIT
-
/*****************************************************************************/
/* PPC405EP reference board (IBM) */
/* Standalone board with:
@@ -158,7 +156,7 @@ static void ref405ep_init(MachineState *machine)
target_ulong kernel_base, initrd_base;
long kernel_size, initrd_size;
int linux_boot;
- int fl_idx, fl_sectors, len;
+ int len;
DriveInfo *dinfo;
MemoryRegion *sysmem = get_system_memory();
@@ -171,9 +169,6 @@ static void ref405ep_init(MachineState *machine)
ram_bases[1] = 0x00000000;
ram_sizes[1] = 0x00000000;
ram_size = 128 * MiB;
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register cpu\n", __func__);
-#endif
env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
33333333, &pic, kernel_filename == NULL ? 0 : 1);
/* allocate SRAM */
@@ -182,35 +177,19 @@ static void ref405ep_init(MachineState *machine)
&error_fatal);
memory_region_add_subregion(sysmem, 0xFFF00000, sram);
/* allocate and load BIOS */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register BIOS\n", __func__);
-#endif
- fl_idx = 0;
#ifdef USE_FLASH_BIOS
- dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+ dinfo = drive_get(IF_PFLASH, 0, 0);
if (dinfo) {
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
-
- bios_size = blk_getlength(blk);
- fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size %lx"
- " at addr %lx '%s' %d\n",
- fl_idx, bios_size, -bios_size,
- blk_name(blk), fl_sectors);
-#endif
+ bios_size = 8 * MiB;
pflash_cfi02_register((uint32_t)(-bios_size),
- NULL, "ef405ep.bios", bios_size,
- blk, 65536, fl_sectors, 1,
+ "ef405ep.bios", bios_size,
+ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
+ 64 * KiB, 1,
2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
1);
- fl_idx++;
} else
#endif
{
-#ifdef DEBUG_BOARD_INIT
- printf("Load BIOS from file\n");
-#endif
bios = g_new(MemoryRegion, 1);
memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE,
&error_fatal);
@@ -239,21 +218,12 @@ static void ref405ep_init(MachineState *machine)
memory_region_set_readonly(bios, true);
}
/* Register FPGA */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register FPGA\n", __func__);
-#endif
ref405ep_fpga_init(sysmem, 0xF0300000);
/* Register NVRAM */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register NVRAM\n", __func__);
-#endif
m48t59_init(NULL, 0xF0000000, 0, 8192, 1968, 8);
/* Load kernel */
linux_boot = (kernel_filename != NULL);
if (linux_boot) {
-#ifdef DEBUG_BOARD_INIT
- printf("%s: load kernel\n", __func__);
-#endif
memset(&bd, 0, sizeof(bd));
bd.bi_memstart = 0x00000000;
bd.bi_memsize = ram_size;
@@ -325,10 +295,6 @@ static void ref405ep_init(MachineState *machine)
initrd_size = 0;
bdloc = 0;
}
-#ifdef DEBUG_BOARD_INIT
- printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
- printf("%s: Done\n", __func__);
-#endif
}
static void ref405ep_class_init(ObjectClass *oc, void *data)
@@ -455,7 +421,7 @@ static void taihu_405ep_init(MachineState *machine)
target_ulong kernel_base, initrd_base;
long kernel_size, initrd_size;
int linux_boot;
- int fl_idx, fl_sectors;
+ int fl_idx;
DriveInfo *dinfo;
/* RAM is soldered to the board so the size cannot be changed */
@@ -473,43 +439,24 @@ static void taihu_405ep_init(MachineState *machine)
memory_region_init_alias(&ram_memories[1], NULL,
"taihu_405ep.ram-1", ram, ram_bases[1],
ram_sizes[1]);
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register cpu\n", __func__);
-#endif
ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
33333333, &pic, kernel_filename == NULL ? 0 : 1);
/* allocate and load BIOS */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register BIOS\n", __func__);
-#endif
fl_idx = 0;
#if defined(USE_FLASH_BIOS)
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
if (dinfo) {
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
-
- bios_size = blk_getlength(blk);
- /* XXX: should check that size is 2MB */
- // bios_size = 2 * 1024 * 1024;
- fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size %lx"
- " at addr %lx '%s' %d\n",
- fl_idx, bios_size, -bios_size,
- blk_name(blk), fl_sectors);
-#endif
- pflash_cfi02_register((uint32_t)(-bios_size),
- NULL, "taihu_405ep.bios", bios_size,
- blk, 65536, fl_sectors, 1,
+ bios_size = 2 * MiB;
+ pflash_cfi02_register(0xFFE00000,
+ "taihu_405ep.bios", bios_size,
+ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
+ 64 * KiB, 1,
4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
1);
fl_idx++;
} else
#endif
{
-#ifdef DEBUG_BOARD_INIT
- printf("Load BIOS from file\n");
-#endif
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
bios = g_new(MemoryRegion, 1);
@@ -536,35 +483,19 @@ static void taihu_405ep_init(MachineState *machine)
/* Register Linux flash */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
if (dinfo) {
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
-
- bios_size = blk_getlength(blk);
- /* XXX: should check that size is 32MB */
bios_size = 32 * MiB;
- fl_sectors = (bios_size + 65535) >> 16;
-#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size %lx"
- " at addr " TARGET_FMT_lx " '%s'\n",
- fl_idx, bios_size, (target_ulong)0xfc000000,
- blk_name(blk));
-#endif
- pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size,
- blk, 65536, fl_sectors, 1,
+ pflash_cfi02_register(0xfc000000, "taihu_405ep.flash", bios_size,
+ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
+ 64 * KiB, 1,
4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
1);
fl_idx++;
}
/* Register CLPD & LCD display */
-#ifdef DEBUG_BOARD_INIT
- printf("%s: register CPLD\n", __func__);
-#endif
taihu_cpld_init(sysmem, 0x50100000);
/* Load kernel */
linux_boot = (kernel_filename != NULL);
if (linux_boot) {
-#ifdef DEBUG_BOARD_INIT
- printf("%s: load kernel\n", __func__);
-#endif
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image_targphys(kernel_filename, kernel_base,
@@ -593,9 +524,6 @@ static void taihu_405ep_init(MachineState *machine)
initrd_base = 0;
initrd_size = 0;
}
-#ifdef DEBUG_BOARD_INIT
- printf("%s: Done\n", __func__);
-#endif
}
static void taihu_class_init(ObjectClass *oc, void *data)
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index d455c4bd07..fbcddc5b00 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -91,32 +91,42 @@ struct boot_info {
static int sam460ex_load_uboot(void)
{
+ /*
+ * This first creates 1MiB of flash memory mapped at the end of
+ * the 32-bit address space (0xFFF00000..0xFFFFFFFF).
+ *
+ * If_PFLASH unit 0 is defined, the flash memory is initialized
+ * from that block backend.
+ *
+ * Else, it's initialized to zero. And then 512KiB of ROM get
+ * mapped on top of its second half (0xFFF80000..0xFFFFFFFF),
+ * initialized from u-boot-sam460-20100605.bin.
+ *
+ * This doesn't smell right.
+ *
+ * The physical hardware appears to have 512KiB flash memory.
+ *
+ * TODO Figure out what we really need here, and clean this up.
+ */
+
DriveInfo *dinfo;
- BlockBackend *blk = NULL;
- hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32);
- long bios_size = FLASH_SIZE;
- int fl_sectors;
dinfo = drive_get(IF_PFLASH, 0, 0);
- if (dinfo) {
- blk = blk_by_legacy_dinfo(dinfo);
- bios_size = blk_getlength(blk);
- }
- fl_sectors = (bios_size + 65535) >> 16;
-
- if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size,
- blk, 64 * KiB, fl_sectors,
- 1, 0x89, 0x18, 0x0000, 0x0, 1)) {
+ if (!pflash_cfi01_register(FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32),
+ "sam460ex.flash", FLASH_SIZE,
+ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
+ 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1)) {
error_report("Error registering flash memory");
/* XXX: return an error instead? */
exit(1);
}
- if (!blk) {
+ if (!dinfo) {
/*error_report("No flash image given with the 'pflash' parameter,"
" using default u-boot image");*/
- base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32);
- rom_add_file_fixed(UBOOT_FILENAME, base, -1);
+ rom_add_file_fixed(UBOOT_FILENAME,
+ UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32),
+ -1);
}
return 0;
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 9e01226e18..6c16d6cfaf 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -29,6 +29,7 @@
#include "qapi/visitor.h"
#include "sysemu/sysemu.h"
#include "sysemu/numa.h"
+#include "sysemu/qtest.h"
#include "hw/hw.h"
#include "qemu/log.h"
#include "hw/fw-path-provider.h"
@@ -102,13 +103,13 @@
* all and one to identify thread 0 of a VCORE. Any change to the first one
* is likely to have an impact on the second one, so let's keep them close.
*/
-static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index)
+static int spapr_vcpu_id(SpaprMachineState *spapr, int cpu_index)
{
assert(spapr->vsmt);
return
(cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
}
-static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
+static bool spapr_is_thread0_in_vcore(SpaprMachineState *spapr,
PowerPCCPU *cpu)
{
assert(spapr->vsmt);
@@ -149,7 +150,7 @@ static void pre_2_10_vmstate_unregister_dummy_icp(int i)
(void *)(uintptr_t) i);
}
-int spapr_max_server_number(sPAPRMachineState *spapr)
+int spapr_max_server_number(SpaprMachineState *spapr)
{
assert(spapr->vsmt);
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
@@ -204,7 +205,7 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
}
/* Populate the "ibm,pa-features" property */
-static void spapr_populate_pa_features(sPAPRMachineState *spapr,
+static void spapr_populate_pa_features(SpaprMachineState *spapr,
PowerPCCPU *cpu,
void *fdt, int offset,
bool legacy_guest)
@@ -283,7 +284,7 @@ static void spapr_populate_pa_features(sPAPRMachineState *spapr,
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
}
-static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
+static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr)
{
int ret = 0, offset, cpus_offset;
CPUState *cs;
@@ -386,7 +387,7 @@ static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
return off;
}
-static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
+static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt)
{
MachineState *machine = MACHINE(spapr);
hwaddr mem_start, node_size;
@@ -438,7 +439,7 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
}
static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
- sPAPRMachineState *spapr)
+ SpaprMachineState *spapr)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
@@ -454,7 +455,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
uint32_t vcpus_per_socket = smp_threads * smp_cores;
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
int drc_index;
uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
int i;
@@ -557,9 +558,17 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
pcc->radix_page_info->count *
sizeof(radix_AP_encodings[0]))));
}
+
+ /*
+ * We set this property to let the guest know that it can use the large
+ * decrementer and its width in bits.
+ */
+ if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
+ _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
+ pcc->lrg_decr_bits)));
}
-static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
+static void spapr_populate_cpus_dt_node(void *fdt, SpaprMachineState *spapr)
{
CPUState **rev;
CPUState *cs;
@@ -683,7 +692,7 @@ spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
}
/* ibm,dynamic-memory-v2 */
-static int spapr_populate_drmem_v2(sPAPRMachineState *spapr, void *fdt,
+static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt,
int offset, MemoryDeviceInfoList *dimms)
{
MachineState *machine = MACHINE(spapr);
@@ -695,7 +704,7 @@ static int spapr_populate_drmem_v2(sPAPRMachineState *spapr, void *fdt,
uint64_t mem_end = machine->device_memory->base +
memory_region_size(&machine->device_memory->mr);
uint32_t node, buf_len, nr_entries = 0;
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
DrconfCellQueue *elem, *next;
MemoryDeviceInfoList *info;
QSIMPLEQ_HEAD(, DrconfCellQueue) drconf_queue
@@ -768,7 +777,7 @@ static int spapr_populate_drmem_v2(sPAPRMachineState *spapr, void *fdt,
}
/* ibm,dynamic-memory */
-static int spapr_populate_drmem_v1(sPAPRMachineState *spapr, void *fdt,
+static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
int offset, MemoryDeviceInfoList *dimms)
{
MachineState *machine = MACHINE(spapr);
@@ -792,7 +801,7 @@ static int spapr_populate_drmem_v1(sPAPRMachineState *spapr, void *fdt,
uint32_t *dynamic_memory = cur_index;
if (i >= device_lmb_start) {
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB, i);
g_assert(drc);
@@ -837,7 +846,7 @@ static int spapr_populate_drmem_v1(sPAPRMachineState *spapr, void *fdt,
* Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
* of this device tree node.
*/
-static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
+static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
{
MachineState *machine = MACHINE(spapr);
int ret, i, offset;
@@ -908,10 +917,10 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
return ret;
}
-static int spapr_dt_cas_updates(sPAPRMachineState *spapr, void *fdt,
- sPAPROptionVector *ov5_updates)
+static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
+ SpaprOptionVector *ov5_updates)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
int ret = 0, offset;
/* Generate ibm,dynamic-reconfiguration-memory node if required */
@@ -957,12 +966,12 @@ static bool spapr_hotplugged_dev_before_cas(void)
return false;
}
-int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
+int spapr_h_cas_compose_response(SpaprMachineState *spapr,
target_ulong addr, target_ulong size,
- sPAPROptionVector *ov5_updates)
+ SpaprOptionVector *ov5_updates)
{
void *fdt, *fdt_skel;
- sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
+ SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
if (spapr_hotplugged_dev_before_cas()) {
return 1;
@@ -1011,7 +1020,7 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
return 0;
}
-static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
+static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
{
int rtas;
GString *hypertas = g_string_sized_new(256);
@@ -1100,7 +1109,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
* and the XIVE features that the guest may request and thus the valid
* values for bytes 23..26 of option vector 5:
*/
-static void spapr_dt_ov5_platform_support(sPAPRMachineState *spapr, void *fdt,
+static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
int chosen)
{
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
@@ -1136,7 +1145,7 @@ static void spapr_dt_ov5_platform_support(sPAPRMachineState *spapr, void *fdt,
val, sizeof(val)));
}
-static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
+static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
{
MachineState *machine = MACHINE(spapr);
int chosen;
@@ -1202,7 +1211,7 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
g_free(bootlist);
}
-static void spapr_dt_hypervisor(sPAPRMachineState *spapr, void *fdt)
+static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
{
/* The /hypervisor node isn't in PAPR - this is a hack to allow PR
* KVM to work under pHyp with some guest co-operation */
@@ -1225,14 +1234,14 @@ static void spapr_dt_hypervisor(sPAPRMachineState *spapr, void *fdt)
}
}
-static void *spapr_build_fdt(sPAPRMachineState *spapr)
+static void *spapr_build_fdt(SpaprMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
int ret;
void *fdt;
- sPAPRPHBState *phb;
+ SpaprPhbState *phb;
char *buf;
fdt = g_malloc0(FDT_MAX_SIZE);
@@ -1430,7 +1439,7 @@ void spapr_set_all_lpcrs(target_ulong value, target_ulong mask)
static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
/* Copy PATE1:GR into PATE0:HR */
entry->dw0 = spapr->patb_entry & PATE0_HR;
@@ -1446,7 +1455,7 @@ static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry)
/*
* Get the fd to access the kernel htab, re-opening it if necessary
*/
-static int get_htab_fd(sPAPRMachineState *spapr)
+static int get_htab_fd(SpaprMachineState *spapr)
{
Error *local_err = NULL;
@@ -1462,7 +1471,7 @@ static int get_htab_fd(sPAPRMachineState *spapr)
return spapr->htab_fd;
}
-void close_htab_fd(sPAPRMachineState *spapr)
+void close_htab_fd(SpaprMachineState *spapr)
{
if (spapr->htab_fd >= 0) {
close(spapr->htab_fd);
@@ -1472,14 +1481,14 @@ void close_htab_fd(sPAPRMachineState *spapr)
static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
}
static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
assert(kvm_enabled());
@@ -1493,7 +1502,7 @@ static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
hwaddr ptex, int n)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
if (!spapr->htab) {
@@ -1516,7 +1525,7 @@ static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
const ppc_hash_pte64_t *hptes,
hwaddr ptex, int n)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
if (!spapr->htab) {
g_free((void *)hptes);
@@ -1528,7 +1537,7 @@ static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
uint64_t pte0, uint64_t pte1)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
hwaddr offset = ptex * HASH_PTE_SIZE_64;
if (!spapr->htab) {
@@ -1569,7 +1578,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
return shift;
}
-void spapr_free_hpt(sPAPRMachineState *spapr)
+void spapr_free_hpt(SpaprMachineState *spapr)
{
g_free(spapr->htab);
spapr->htab = NULL;
@@ -1577,7 +1586,7 @@ void spapr_free_hpt(sPAPRMachineState *spapr)
close_htab_fd(spapr);
}
-void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
+void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
Error **errp)
{
long rc;
@@ -1623,10 +1632,11 @@ void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
}
}
/* We're setting up a hash table, so that means we're not radix */
+ spapr->patb_entry = 0;
spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
}
-void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr)
+void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr)
{
int hpt_shift;
@@ -1650,8 +1660,8 @@ void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr)
static int spapr_reset_drcs(Object *child, void *opaque)
{
- sPAPRDRConnector *drc =
- (sPAPRDRConnector *) object_dynamic_cast(child,
+ SpaprDrc *drc =
+ (SpaprDrc *) object_dynamic_cast(child,
TYPE_SPAPR_DR_CONNECTOR);
if (drc) {
@@ -1664,7 +1674,7 @@ static int spapr_reset_drcs(Object *child, void *opaque)
static void spapr_machine_reset(void)
{
MachineState *machine = MACHINE(qdev_get_machine());
- sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
+ SpaprMachineState *spapr = SPAPR_MACHINE(machine);
PowerPCCPU *first_ppc_cpu;
uint32_t rtas_limit;
hwaddr rtas_addr, fdt_addr;
@@ -1711,6 +1721,16 @@ static void spapr_machine_reset(void)
*/
spapr_irq_reset(spapr, &error_fatal);
+ /*
+ * There is no CAS under qtest. Simulate one to please the code that
+ * depends on spapr->ov5_cas. This is especially needed to test device
+ * unplug, so we do that before resetting the DRCs.
+ */
+ if (qtest_enabled()) {
+ spapr_ovec_cleanup(spapr->ov5_cas);
+ spapr->ov5_cas = spapr_ovec_clone(spapr->ov5);
+ }
+
/* DRC reset may cause a device to be unplugged. This will cause troubles
* if this device is used by another device (eg, a running vhost backend
* will crash QEMU if the DIMM holding the vring goes away). To avoid such
@@ -1759,7 +1779,7 @@ static void spapr_machine_reset(void)
spapr->cas_reboot = false;
}
-static void spapr_create_nvram(sPAPRMachineState *spapr)
+static void spapr_create_nvram(SpaprMachineState *spapr)
{
DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
@@ -1771,10 +1791,10 @@ static void spapr_create_nvram(sPAPRMachineState *spapr)
qdev_init_nofail(dev);
- spapr->nvram = (struct sPAPRNVRAM *)dev;
+ spapr->nvram = (struct SpaprNvram *)dev;
}
-static void spapr_rtc_create(sPAPRMachineState *spapr)
+static void spapr_rtc_create(SpaprMachineState *spapr)
{
object_initialize_child(OBJECT(spapr), "rtc",
&spapr->rtc, sizeof(spapr->rtc), TYPE_SPAPR_RTC,
@@ -1818,7 +1838,7 @@ static int spapr_pre_load(void *opaque)
static int spapr_post_load(void *opaque, int version_id)
{
- sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
+ SpaprMachineState *spapr = (SpaprMachineState *)opaque;
int err = 0;
err = spapr_caps_post_migration(spapr);
@@ -1885,7 +1905,7 @@ static bool version_before_3(void *opaque, int version_id)
static bool spapr_pending_events_needed(void *opaque)
{
- sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
+ SpaprMachineState *spapr = (SpaprMachineState *)opaque;
return !QTAILQ_EMPTY(&spapr->pending_events);
}
@@ -1894,9 +1914,9 @@ static const VMStateDescription vmstate_spapr_event_entry = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(summary, sPAPREventLogEntry),
- VMSTATE_UINT32(extended_length, sPAPREventLogEntry),
- VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, sPAPREventLogEntry, 0,
+ VMSTATE_UINT32(summary, SpaprEventLogEntry),
+ VMSTATE_UINT32(extended_length, SpaprEventLogEntry),
+ VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, SpaprEventLogEntry, 0,
NULL, extended_length),
VMSTATE_END_OF_LIST()
},
@@ -1908,21 +1928,21 @@ static const VMStateDescription vmstate_spapr_pending_events = {
.minimum_version_id = 1,
.needed = spapr_pending_events_needed,
.fields = (VMStateField[]) {
- VMSTATE_QTAILQ_V(pending_events, sPAPRMachineState, 1,
- vmstate_spapr_event_entry, sPAPREventLogEntry, next),
+ VMSTATE_QTAILQ_V(pending_events, SpaprMachineState, 1,
+ vmstate_spapr_event_entry, SpaprEventLogEntry, next),
VMSTATE_END_OF_LIST()
},
};
static bool spapr_ov5_cas_needed(void *opaque)
{
- sPAPRMachineState *spapr = opaque;
- sPAPROptionVector *ov5_mask = spapr_ovec_new();
- sPAPROptionVector *ov5_legacy = spapr_ovec_new();
- sPAPROptionVector *ov5_removed = spapr_ovec_new();
+ SpaprMachineState *spapr = opaque;
+ SpaprOptionVector *ov5_mask = spapr_ovec_new();
+ SpaprOptionVector *ov5_legacy = spapr_ovec_new();
+ SpaprOptionVector *ov5_removed = spapr_ovec_new();
bool cas_needed;
- /* Prior to the introduction of sPAPROptionVector, we had two option
+ /* Prior to the introduction of SpaprOptionVector, we had two option
* vectors we dealt with: OV5_FORM1_AFFINITY, and OV5_DRCONF_MEMORY.
* Both of these options encode machine topology into the device-tree
* in such a way that the now-booted OS should still be able to interact
@@ -1972,15 +1992,15 @@ static const VMStateDescription vmstate_spapr_ov5_cas = {
.minimum_version_id = 1,
.needed = spapr_ov5_cas_needed,
.fields = (VMStateField[]) {
- VMSTATE_STRUCT_POINTER_V(ov5_cas, sPAPRMachineState, 1,
- vmstate_spapr_ovec, sPAPROptionVector),
+ VMSTATE_STRUCT_POINTER_V(ov5_cas, SpaprMachineState, 1,
+ vmstate_spapr_ovec, SpaprOptionVector),
VMSTATE_END_OF_LIST()
},
};
static bool spapr_patb_entry_needed(void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
return !!spapr->patb_entry;
}
@@ -1991,14 +2011,14 @@ static const VMStateDescription vmstate_spapr_patb_entry = {
.minimum_version_id = 1,
.needed = spapr_patb_entry_needed,
.fields = (VMStateField[]) {
- VMSTATE_UINT64(patb_entry, sPAPRMachineState),
+ VMSTATE_UINT64(patb_entry, SpaprMachineState),
VMSTATE_END_OF_LIST()
},
};
static bool spapr_irq_map_needed(void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
}
@@ -2009,21 +2029,21 @@ static const VMStateDescription vmstate_spapr_irq_map = {
.minimum_version_id = 1,
.needed = spapr_irq_map_needed,
.fields = (VMStateField[]) {
- VMSTATE_BITMAP(irq_map, sPAPRMachineState, 0, irq_map_nr),
+ VMSTATE_BITMAP(irq_map, SpaprMachineState, 0, irq_map_nr),
VMSTATE_END_OF_LIST()
},
};
static bool spapr_dtb_needed(void *opaque)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
return smc->update_dt_enabled;
}
static int spapr_dtb_pre_load(void *opaque)
{
- sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
+ SpaprMachineState *spapr = (SpaprMachineState *)opaque;
g_free(spapr->fdt_blob);
spapr->fdt_blob = NULL;
@@ -2039,9 +2059,9 @@ static const VMStateDescription vmstate_spapr_dtb = {
.needed = spapr_dtb_needed,
.pre_load = spapr_dtb_pre_load,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(fdt_initial_size, sPAPRMachineState),
- VMSTATE_UINT32(fdt_size, sPAPRMachineState),
- VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, sPAPRMachineState, 0, NULL,
+ VMSTATE_UINT32(fdt_initial_size, SpaprMachineState),
+ VMSTATE_UINT32(fdt_size, SpaprMachineState),
+ VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL,
fdt_size),
VMSTATE_END_OF_LIST()
},
@@ -2059,9 +2079,9 @@ static const VMStateDescription vmstate_spapr = {
VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
/* RTC offset */
- VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3),
+ VMSTATE_UINT64_TEST(rtc_offset, SpaprMachineState, version_before_3),
- VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
+ VMSTATE_PPC_TIMEBASE_V(tb, SpaprMachineState, 2),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
@@ -2077,13 +2097,15 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_irq_map,
&vmstate_spapr_cap_nested_kvm_hv,
&vmstate_spapr_dtb,
+ &vmstate_spapr_cap_large_decr,
+ &vmstate_spapr_cap_ccf_assist,
NULL
}
};
static int htab_save_setup(QEMUFile *f, void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
/* "Iteration" header */
if (!spapr->htab_shift) {
@@ -2105,7 +2127,7 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
return 0;
}
-static void htab_save_chunk(QEMUFile *f, sPAPRMachineState *spapr,
+static void htab_save_chunk(QEMUFile *f, SpaprMachineState *spapr,
int chunkstart, int n_valid, int n_invalid)
{
qemu_put_be32(f, chunkstart);
@@ -2122,7 +2144,7 @@ static void htab_save_end_marker(QEMUFile *f)
qemu_put_be16(f, 0);
}
-static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
+static void htab_save_first_pass(QEMUFile *f, SpaprMachineState *spapr,
int64_t max_ns)
{
bool has_timeout = max_ns != -1;
@@ -2170,7 +2192,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
spapr->htab_save_index = index;
}
-static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
+static int htab_save_later_pass(QEMUFile *f, SpaprMachineState *spapr,
int64_t max_ns)
{
bool final = max_ns < 0;
@@ -2248,7 +2270,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
static int htab_save_iterate(QEMUFile *f, void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
int fd;
int rc = 0;
@@ -2285,7 +2307,7 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
static int htab_save_complete(QEMUFile *f, void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
int fd;
/* Iteration header */
@@ -2325,7 +2347,7 @@ static int htab_save_complete(QEMUFile *f, void *opaque)
static int htab_load(QEMUFile *f, void *opaque, int version_id)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
uint32_t section_hdr;
int fd = -1;
Error *local_err = NULL;
@@ -2415,7 +2437,7 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
static void htab_save_cleanup(void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
close_htab_fd(spapr);
}
@@ -2435,7 +2457,7 @@ static void spapr_boot_set(void *opaque, const char *boot_device,
machine->boot_order = g_strdup(boot_device);
}
-static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
+static void spapr_create_lmb_dr_connectors(SpaprMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
@@ -2502,7 +2524,7 @@ static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
return &ms->possible_cpus->cpus[index];
}
-static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
+static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp)
{
Error *local_err = NULL;
bool vsmt_user = !!spapr->vsmt;
@@ -2574,11 +2596,11 @@ out:
error_propagate(errp, local_err);
}
-static void spapr_init_cpus(sPAPRMachineState *spapr)
+static void spapr_init_cpus(SpaprMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
- sPAPRMachineClass *smc = SPAPR_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;
int boot_cores_nr = smp_cpus / smp_threads;
@@ -2657,8 +2679,8 @@ static PCIHostState *spapr_create_default_phb(void)
/* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
+ SpaprMachineState *spapr = SPAPR_MACHINE(machine);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
PCIHostState *phb;
@@ -2800,6 +2822,9 @@ static void spapr_machine_init(MachineState *machine)
/* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
kvmppc_enable_clear_ref_mod_hcalls();
+
+ /* Enable H_PAGE_INIT */
+ kvmppc_enable_h_page_init();
}
/* allocate RAM */
@@ -3051,7 +3076,7 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
#define CAST(type, obj, name) \
((type *)object_dynamic_cast(OBJECT(obj), (name)))
SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE);
- sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
+ SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
if (d) {
@@ -3131,14 +3156,14 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
static char *spapr_get_kvm_type(Object *obj, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
return g_strdup(spapr->kvm_type);
}
static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
g_free(spapr->kvm_type);
spapr->kvm_type = g_strdup(value);
@@ -3146,7 +3171,7 @@ static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
return spapr->use_hotplug_event_source;
}
@@ -3154,7 +3179,7 @@ static bool spapr_get_modern_hotplug_events(Object *obj, Error **errp)
static void spapr_set_modern_hotplug_events(Object *obj, bool value,
Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
spapr->use_hotplug_event_source = value;
}
@@ -3166,7 +3191,7 @@ static bool spapr_get_msix_emulation(Object *obj, Error **errp)
static char *spapr_get_resize_hpt(Object *obj, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
switch (spapr->resize_hpt) {
case SPAPR_RESIZE_HPT_DEFAULT:
@@ -3183,7 +3208,7 @@ static char *spapr_get_resize_hpt(Object *obj, Error **errp)
static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
if (strcmp(value, "default") == 0) {
spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT;
@@ -3212,7 +3237,7 @@ static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
static char *spapr_get_ic_mode(Object *obj, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
if (spapr->irq == &spapr_irq_xics_legacy) {
return g_strdup("legacy");
@@ -3228,7 +3253,7 @@ static char *spapr_get_ic_mode(Object *obj, Error **errp)
static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
error_setg(errp, "This machine only uses the legacy XICS backend, don't pass ic-mode");
@@ -3249,14 +3274,14 @@ static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
static char *spapr_get_host_model(Object *obj, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
return g_strdup(spapr->host_model);
}
static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
g_free(spapr->host_model);
spapr->host_model = g_strdup(value);
@@ -3264,14 +3289,14 @@ static void spapr_set_host_model(Object *obj, const char *value, Error **errp)
static char *spapr_get_host_serial(Object *obj, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
return g_strdup(spapr->host_serial);
}
static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
g_free(spapr->host_serial);
spapr->host_serial = g_strdup(value);
@@ -3279,8 +3304,8 @@ static void spapr_set_host_serial(Object *obj, const char *value, Error **errp)
static void spapr_instance_init(Object *obj)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
spapr->htab_fd = -1;
spapr->use_hotplug_event_source = true;
@@ -3337,7 +3362,7 @@ static void spapr_instance_init(Object *obj)
static void spapr_machine_finalizefn(Object *obj)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
g_free(spapr->kvm_type);
}
@@ -3357,7 +3382,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
}
}
-int spapr_lmb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp)
{
uint64_t addr;
@@ -3374,7 +3399,7 @@ int spapr_lmb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
bool dedicated_hp_event_source, Error **errp)
{
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
int i;
uint64_t addr = addr_start;
@@ -3423,7 +3448,7 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
Error *local_err = NULL;
- sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
+ SpaprMachineState *ms = SPAPR_MACHINE(hotplug_dev);
PCDIMMDevice *dimm = PC_DIMM(dev);
uint64_t size, addr;
@@ -3457,8 +3482,8 @@ out:
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);
+ const SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev);
+ SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
PCDIMMDevice *dimm = PC_DIMM(dev);
Error *local_err = NULL;
uint64_t size;
@@ -3494,16 +3519,16 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp);
}
-struct sPAPRDIMMState {
+struct SpaprDimmState {
PCDIMMDevice *dimm;
uint32_t nr_lmbs;
- QTAILQ_ENTRY(sPAPRDIMMState) next;
+ QTAILQ_ENTRY(SpaprDimmState) next;
};
-static sPAPRDIMMState *spapr_pending_dimm_unplugs_find(sPAPRMachineState *s,
+static SpaprDimmState *spapr_pending_dimm_unplugs_find(SpaprMachineState *s,
PCDIMMDevice *dimm)
{
- sPAPRDIMMState *dimm_state = NULL;
+ SpaprDimmState *dimm_state = NULL;
QTAILQ_FOREACH(dimm_state, &s->pending_dimm_unplugs, next) {
if (dimm_state->dimm == dimm) {
@@ -3513,11 +3538,11 @@ static sPAPRDIMMState *spapr_pending_dimm_unplugs_find(sPAPRMachineState *s,
return dimm_state;
}
-static sPAPRDIMMState *spapr_pending_dimm_unplugs_add(sPAPRMachineState *spapr,
+static SpaprDimmState *spapr_pending_dimm_unplugs_add(SpaprMachineState *spapr,
uint32_t nr_lmbs,
PCDIMMDevice *dimm)
{
- sPAPRDIMMState *ds = NULL;
+ SpaprDimmState *ds = NULL;
/*
* If this request is for a DIMM whose removal had failed earlier
@@ -3527,7 +3552,7 @@ static sPAPRDIMMState *spapr_pending_dimm_unplugs_add(sPAPRMachineState *spapr,
*/
ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
if (!ds) {
- ds = g_malloc0(sizeof(sPAPRDIMMState));
+ ds = g_malloc0(sizeof(SpaprDimmState));
ds->nr_lmbs = nr_lmbs;
ds->dimm = dimm;
QTAILQ_INSERT_HEAD(&spapr->pending_dimm_unplugs, ds, next);
@@ -3535,17 +3560,17 @@ static sPAPRDIMMState *spapr_pending_dimm_unplugs_add(sPAPRMachineState *spapr,
return ds;
}
-static void spapr_pending_dimm_unplugs_remove(sPAPRMachineState *spapr,
- sPAPRDIMMState *dimm_state)
+static void spapr_pending_dimm_unplugs_remove(SpaprMachineState *spapr,
+ SpaprDimmState *dimm_state)
{
QTAILQ_REMOVE(&spapr->pending_dimm_unplugs, dimm_state, next);
g_free(dimm_state);
}
-static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms,
+static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
PCDIMMDevice *dimm)
{
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm),
&error_abort);
uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
@@ -3574,8 +3599,8 @@ static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms,
void spapr_lmb_release(DeviceState *dev)
{
HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
- sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
- sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
+ SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_ctrl);
+ SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
/* This information will get lost if a migration occurs
* during the unplug process. In this case recover it. */
@@ -3600,8 +3625,8 @@ void spapr_lmb_release(DeviceState *dev)
static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
- sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
+ SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
+ SpaprDimmState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev));
pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev));
object_property_set_bool(OBJECT(dev), false, "realized", NULL);
@@ -3611,13 +3636,13 @@ static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
+ SpaprMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
Error *local_err = NULL;
PCDIMMDevice *dimm = PC_DIMM(dev);
uint32_t nr_lmbs;
uint64_t size, addr_start, addr;
int i;
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
@@ -3674,12 +3699,12 @@ 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);
+ 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));
+ SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
int i;
for (i = 0; i < cc->nr_threads; i++) {
@@ -3698,9 +3723,9 @@ static
void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
int index;
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
CPUCore *cc = CPU_CORE(dev);
if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
@@ -3722,10 +3747,10 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
spapr_hotplug_req_remove_by_index(drc);
}
-int spapr_core_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp)
{
- sPAPRCPUCore *core = SPAPR_CPU_CORE(drc->dev);
+ SpaprCpuCore *core = SPAPR_CPU_CORE(drc->dev);
CPUState *cs = CPU(core->threads[0]);
PowerPCCPU *cpu = POWERPC_CPU(cs);
DeviceClass *dc = DEVICE_GET_CLASS(cs);
@@ -3746,13 +3771,13 @@ int spapr_core_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_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));
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprCpuCore *core = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
CPUState *cs;
- sPAPRDRConnector *drc;
+ SpaprDrc *drc;
Error *local_err = NULL;
CPUArchId *core_slot;
int index;
@@ -3855,10 +3880,10 @@ out:
error_propagate(errp, local_err);
}
-int spapr_phb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp)
{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(drc->dev);
int intc_phandle;
intc_phandle = spapr_irq_get_phandle(spapr, spapr->fdt_blob, errp);
@@ -3881,9 +3906,9 @@ int spapr_phb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
const unsigned windows_supported = spapr_phb_windows_supported(sphb);
if (dev->hotplugged && !smc->dr_phb_enabled) {
@@ -3909,10 +3934,10 @@ static void spapr_phb_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
static void spapr_phb_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
- sPAPRDRConnector *drc;
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
+ SpaprDrc *drc;
bool hotplugged = spapr_drc_hotplugged(dev);
Error *local_err = NULL;
@@ -3953,8 +3978,8 @@ static void spapr_phb_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
- sPAPRDRConnector *drc;
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(dev);
+ SpaprDrc *drc;
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PHB, sphb->index);
assert(drc);
@@ -3992,9 +4017,9 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- sPAPRMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ SpaprMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
MachineClass *mc = MACHINE_GET_CLASS(sms);
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
@@ -4101,7 +4126,7 @@ static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
return machine->possible_cpus;
}
-static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
+static void spapr_phb_placement(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns, Error **errp)
@@ -4153,14 +4178,14 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
+ SpaprMachineState *spapr = SPAPR_MACHINE(dev);
return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
}
static void spapr_ics_resend(XICSFabric *dev)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
+ SpaprMachineState *spapr = SPAPR_MACHINE(dev);
ics_resend(spapr->ics);
}
@@ -4175,7 +4200,7 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
static void spapr_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
spapr->irq->print_info(spapr, mon);
}
@@ -4187,7 +4212,7 @@ int spapr_get_vcpu_id(PowerPCCPU *cpu)
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
int vcpu_id;
vcpu_id = spapr_vcpu_id(spapr, cpu_index);
@@ -4221,7 +4246,7 @@ PowerPCCPU *spapr_find_cpu(int vcpu_id)
static void spapr_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
@@ -4286,11 +4311,13 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
- smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
- smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
- smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
+ 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_WORKAROUND;
smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
+ smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
+ smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
spapr_caps_add_properties(smc, &error_abort);
smc->irq = &spapr_irq_xics;
smc->dr_phb_enabled = true;
@@ -4300,10 +4327,10 @@ static const TypeInfo spapr_machine_info = {
.name = TYPE_SPAPR_MACHINE,
.parent = TYPE_MACHINE,
.abstract = true,
- .instance_size = sizeof(sPAPRMachineState),
+ .instance_size = sizeof(SpaprMachineState),
.instance_init = spapr_instance_init,
.instance_finalize = spapr_machine_finalizefn,
- .class_size = sizeof(sPAPRMachineClass),
+ .class_size = sizeof(SpaprMachineClass),
.class_init = spapr_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
@@ -4353,7 +4380,7 @@ DEFINE_SPAPR_MACHINE(4_0, "4.0", true);
*/
static void spapr_machine_3_1_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
static GlobalProperty compat[] = {
{ TYPE_SPAPR_MACHINE, "host-model", "passthrough" },
{ TYPE_SPAPR_MACHINE, "host-serial", "passthrough" },
@@ -4366,6 +4393,10 @@ static void spapr_machine_3_1_class_options(MachineClass *mc)
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
smc->update_dt_enabled = false;
smc->dr_phb_enabled = false;
+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
+ smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
}
DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
@@ -4376,7 +4407,7 @@ DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
static void spapr_machine_3_0_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_3_1_class_options(mc);
compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
@@ -4392,7 +4423,7 @@ DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
*/
static void spapr_machine_2_12_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(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" },
@@ -4414,7 +4445,7 @@ DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_2_12_class_options(mc);
smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
@@ -4430,7 +4461,7 @@ DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
static void spapr_machine_2_11_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_2_12_class_options(mc);
smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
@@ -4457,7 +4488,7 @@ DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
static void spapr_machine_2_9_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
static GlobalProperty compat[] = {
{ TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
};
@@ -4494,7 +4525,7 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
* pseries-2.7
*/
-static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
+static void 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)
@@ -4545,7 +4576,7 @@ static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
static void spapr_machine_2_7_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(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", },
@@ -4587,7 +4618,7 @@ DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
static void spapr_machine_2_5_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
static GlobalProperty compat[] = {
{ "spapr-vlan", "use-rx-buffer-pools", "off" },
};
@@ -4606,7 +4637,7 @@ DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
static void spapr_machine_2_4_class_options(MachineClass *mc)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_2_5_class_options(mc);
smc->dr_lmb_enabled = false;
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 64f98ae68d..edc5ed0e0c 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -31,10 +31,11 @@
#include "target/ppc/mmu-hash64.h"
#include "cpu-models.h"
#include "kvm_ppc.h"
+#include "sysemu/qtest.h"
#include "hw/ppc/spapr.h"
-typedef struct sPAPRCapPossible {
+typedef struct SpaprCapPossible {
int num; /* size of vals array below */
const char *help; /* help text for vals */
/*
@@ -46,9 +47,9 @@ typedef struct sPAPRCapPossible {
* point is observed
*/
const char *vals[];
-} sPAPRCapPossible;
+} SpaprCapPossible;
-typedef struct sPAPRCapabilityInfo {
+typedef struct SpaprCapabilityInfo {
const char *name;
const char *description;
int index;
@@ -58,18 +59,18 @@ typedef struct sPAPRCapabilityInfo {
ObjectPropertyAccessor *set;
const char *type;
/* Possible values if this is a custom string type */
- sPAPRCapPossible *possible;
+ SpaprCapPossible *possible;
/* Make sure the virtual hardware can support this capability */
- void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
- void (*cpu_apply)(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+ void (*apply)(SpaprMachineState *spapr, uint8_t val, Error **errp);
+ void (*cpu_apply)(SpaprMachineState *spapr, PowerPCCPU *cpu,
uint8_t val, Error **errp);
-} sPAPRCapabilityInfo;
+} SpaprCapabilityInfo;
static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRCapabilityInfo *cap = opaque;
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
visit_type_bool(v, name, &value, errp);
@@ -78,8 +79,8 @@ static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRCapabilityInfo *cap = opaque;
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
bool value;
Error *local_err = NULL;
@@ -97,8 +98,8 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRCapabilityInfo *cap = opaque;
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
char *val = NULL;
uint8_t value = spapr_get_cap(spapr, cap->index);
@@ -116,8 +117,8 @@ static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRCapabilityInfo *cap = opaque;
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
Error *local_err = NULL;
uint8_t i;
char *val;
@@ -149,8 +150,8 @@ out:
static void spapr_cap_get_pagesize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRCapabilityInfo *cap = opaque;
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
uint8_t val = spapr_get_cap(spapr, cap->index);
uint64_t pagesize = (1ULL << val);
@@ -160,8 +161,8 @@ static void spapr_cap_get_pagesize(Object *obj, Visitor *v, const char *name,
static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRCapabilityInfo *cap = opaque;
- sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ SpaprCapabilityInfo *cap = opaque;
+ SpaprMachineState *spapr = SPAPR_MACHINE(obj);
uint64_t pagesize;
uint8_t val;
Error *local_err = NULL;
@@ -182,7 +183,7 @@ static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name,
spapr->eff.caps[cap->index] = val;
}
-static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
+static void cap_htm_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
{
if (!val) {
/* TODO: We don't support disabling htm yet */
@@ -198,7 +199,7 @@ static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
}
}
-static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
+static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
CPUPPCState *env = &cpu->env;
@@ -215,7 +216,7 @@ static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
}
}
-static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
+static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
CPUPPCState *env = &cpu->env;
@@ -229,83 +230,97 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
}
}
-sPAPRCapPossible cap_cfpc_possible = {
+SpaprCapPossible cap_cfpc_possible = {
.num = 3,
.vals = {"broken", "workaround", "fixed"},
.help = "broken - no protection, workaround - workaround available,"
" fixed - fixed in hardware",
};
-static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
+static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val,
Error **errp)
{
+ Error *local_err = NULL;
uint8_t kvm_val = kvmppc_get_cap_safe_cache();
if (tcg_enabled() && val) {
- /* TODO - for now only allow broken for TCG */
- error_setg(errp,
-"Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
+ /* TCG only supports broken, allow other values and print a warning */
+ error_setg(&local_err,
+ "TCG doesn't support requested feature, cap-cfpc=%s",
+ cap_cfpc_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
cap_cfpc_possible.vals[kvm_val]);
}
+
+ if (local_err != NULL)
+ warn_report_err(local_err);
}
-sPAPRCapPossible cap_sbbc_possible = {
+SpaprCapPossible cap_sbbc_possible = {
.num = 3,
.vals = {"broken", "workaround", "fixed"},
.help = "broken - no protection, workaround - workaround available,"
" fixed - fixed in hardware",
};
-static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
+static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val,
Error **errp)
{
+ Error *local_err = NULL;
uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check();
if (tcg_enabled() && val) {
- /* TODO - for now only allow broken for TCG */
- error_setg(errp,
-"Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
+ /* TCG only supports broken, allow other values and print a warning */
+ error_setg(&local_err,
+ "TCG doesn't support requested feature, cap-sbbc=%s",
+ cap_sbbc_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
cap_sbbc_possible.vals[kvm_val]);
}
+
+ if (local_err != NULL)
+ warn_report_err(local_err);
}
-sPAPRCapPossible cap_ibs_possible = {
- .num = 4,
+SpaprCapPossible cap_ibs_possible = {
+ .num = 5,
/* Note workaround only maintained for compatibility */
- .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"},
- .help = "broken - no protection, fixed-ibs - indirect branch serialisation,"
- " fixed-ccd - cache count disabled",
+ .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd", "fixed-na"},
+ .help = "broken - no protection, workaround - count cache flush"
+ ", fixed-ibs - indirect branch serialisation,"
+ " fixed-ccd - cache count disabled,"
+ " fixed-na - fixed in hardware (no longer applicable)",
};
-static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
+static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr,
uint8_t val, Error **errp)
{
+ Error *local_err = NULL;
uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch();
- if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
- error_setg(errp,
-"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s",
- cap_ibs_possible.vals[kvm_val]);
- } else if (tcg_enabled() && val) {
- /* TODO - for now only allow broken for TCG */
- error_setg(errp,
-"Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
- } else if (kvm_enabled() && val && (val != kvm_val)) {
+ if (tcg_enabled() && val) {
+ /* TCG only supports broken, allow other values and print a warning */
+ error_setg(&local_err,
+ "TCG doesn't support requested feature, cap-ibs=%s",
+ cap_ibs_possible.vals[val]);
+ } else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
cap_ibs_possible.vals[kvm_val]);
}
+
+ if (local_err != NULL) {
+ warn_report_err(local_err);
+ }
}
#define VALUE_DESC_TRISTATE " (broken, workaround, fixed)"
-void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize,
+void spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize,
Error **errp)
{
hwaddr maxpagesize = (1ULL << spapr->eff.caps[SPAPR_CAP_HPT_MAXPAGESIZE]);
@@ -322,7 +337,7 @@ void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize,
}
}
-static void cap_hpt_maxpagesize_apply(sPAPRMachineState *spapr,
+static void cap_hpt_maxpagesize_apply(SpaprMachineState *spapr,
uint8_t val, Error **errp)
{
if (val < 12) {
@@ -359,7 +374,7 @@ static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift,
return true;
}
-static void cap_hpt_maxpagesize_cpu_apply(sPAPRMachineState *spapr,
+static void cap_hpt_maxpagesize_cpu_apply(SpaprMachineState *spapr,
PowerPCCPU *cpu,
uint8_t val, Error **errp)
{
@@ -368,7 +383,7 @@ static void cap_hpt_maxpagesize_cpu_apply(sPAPRMachineState *spapr,
ppc_hash64_filter_pagesizes(cpu, spapr_pagesize_cb, &maxshift);
}
-static void cap_nested_kvm_hv_apply(sPAPRMachineState *spapr,
+static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr,
uint8_t val, Error **errp)
{
if (!val) {
@@ -390,7 +405,75 @@ static void cap_nested_kvm_hv_apply(sPAPRMachineState *spapr,
}
}
-sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
+static void cap_large_decr_apply(SpaprMachineState *spapr,
+ uint8_t val, Error **errp)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+
+ if (!val) {
+ return; /* Disabled by default */
+ }
+
+ if (tcg_enabled()) {
+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0,
+ spapr->max_compat_pvr)) {
+ error_setg(errp,
+ "Large decrementer only supported on POWER9, try -cpu POWER9");
+ return;
+ }
+ } else if (kvm_enabled()) {
+ int kvm_nr_bits = kvmppc_get_cap_large_decr();
+
+ if (!kvm_nr_bits) {
+ error_setg(errp,
+ "No large decrementer support, try cap-large-decr=off");
+ } else if (pcc->lrg_decr_bits != kvm_nr_bits) {
+ error_setg(errp,
+"KVM large decrementer size (%d) differs to model (%d), try -cap-large-decr=off",
+ kvm_nr_bits, pcc->lrg_decr_bits);
+ }
+ }
+}
+
+static void cap_large_decr_cpu_apply(SpaprMachineState *spapr,
+ PowerPCCPU *cpu,
+ uint8_t val, Error **errp)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong lpcr = env->spr[SPR_LPCR];
+
+ if (kvm_enabled()) {
+ if (kvmppc_enable_cap_large_decr(cpu, val)) {
+ error_setg(errp,
+ "No large decrementer support, try cap-large-decr=off");
+ }
+ }
+
+ if (val) {
+ lpcr |= LPCR_LD;
+ } else {
+ lpcr &= ~LPCR_LD;
+ }
+ ppc_store_lpcr(cpu, lpcr);
+}
+
+static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val,
+ Error **errp)
+{
+ uint8_t kvm_val = kvmppc_get_cap_count_cache_flush_assist();
+
+ if (tcg_enabled() && val) {
+ /* TODO - for now only allow broken for TCG */
+ error_setg(errp,
+"Requested count cache flush assist capability level not supported by tcg, try cap-ccf-assist=off");
+ } else if (kvm_enabled() && (val > kvm_val)) {
+ error_setg(errp,
+"Requested count cache flush assist capability level not supported by kvm, try cap-ccf-assist=off");
+ }
+}
+
+SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
[SPAPR_CAP_HTM] = {
.name = "htm",
.description = "Allow Hardware Transactional Memory (HTM)",
@@ -441,7 +524,8 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
[SPAPR_CAP_IBS] = {
.name = "ibs",
.description =
- "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)",
+ "Indirect Branch Speculation (broken, workaround, fixed-ibs,"
+ "fixed-ccd, fixed-na)",
.index = SPAPR_CAP_IBS,
.get = spapr_cap_get_string,
.set = spapr_cap_set_string,
@@ -468,16 +552,40 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.type = "bool",
.apply = cap_nested_kvm_hv_apply,
},
+ [SPAPR_CAP_LARGE_DECREMENTER] = {
+ .name = "large-decr",
+ .description = "Allow Large Decrementer",
+ .index = SPAPR_CAP_LARGE_DECREMENTER,
+ .get = spapr_cap_get_bool,
+ .set = spapr_cap_set_bool,
+ .type = "bool",
+ .apply = cap_large_decr_apply,
+ .cpu_apply = cap_large_decr_cpu_apply,
+ },
+ [SPAPR_CAP_CCF_ASSIST] = {
+ .name = "ccf-assist",
+ .description = "Count Cache Flush Assist via HW Instruction",
+ .index = SPAPR_CAP_CCF_ASSIST,
+ .get = spapr_cap_get_bool,
+ .set = spapr_cap_set_bool,
+ .type = "bool",
+ .apply = cap_ccf_assist_apply,
+ },
};
-static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
+static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
const char *cputype)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- sPAPRCapabilities caps;
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ SpaprCapabilities caps;
caps = smc->default_caps;
+ 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;
+ }
+
if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_07,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
@@ -514,7 +622,7 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
int spapr_caps_pre_load(void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
/* Set to default so we can tell if this came in with the migration */
spapr->mig = spapr->def;
@@ -523,7 +631,7 @@ int spapr_caps_pre_load(void *opaque)
int spapr_caps_pre_save(void *opaque)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
spapr->mig = spapr->eff;
return 0;
@@ -533,12 +641,12 @@ int spapr_caps_pre_save(void *opaque)
* caps specific one. Otherwise it wouldn't be called when the source
* caps are all defaults, which could still conflict with overridden
* caps on the destination */
-int spapr_caps_post_migration(sPAPRMachineState *spapr)
+int spapr_caps_post_migration(SpaprMachineState *spapr)
{
int i;
bool ok = true;
- sPAPRCapabilities dstcaps = spapr->eff;
- sPAPRCapabilities srccaps;
+ SpaprCapabilities dstcaps = spapr->eff;
+ SpaprCapabilities srccaps;
srccaps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type);
for (i = 0; i < SPAPR_CAP_NUM; i++) {
@@ -549,7 +657,7 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr)
}
for (i = 0; i < SPAPR_CAP_NUM; i++) {
- sPAPRCapabilityInfo *info = &capability_table[i];
+ SpaprCapabilityInfo *info = &capability_table[i];
if (srccaps.caps[i] > dstcaps.caps[i]) {
error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)",
@@ -570,7 +678,7 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr)
#define SPAPR_CAP_MIG_STATE(sname, cap) \
static bool spapr_cap_##sname##_needed(void *opaque) \
{ \
- sPAPRMachineState *spapr = opaque; \
+ SpaprMachineState *spapr = opaque; \
\
return spapr->cmd_line_caps[cap] && \
(spapr->eff.caps[cap] != \
@@ -584,7 +692,7 @@ const VMStateDescription vmstate_spapr_cap_##sname = { \
.needed = spapr_cap_##sname##_needed, \
.fields = (VMStateField[]) { \
VMSTATE_UINT8(mig.caps[cap], \
- sPAPRMachineState), \
+ SpaprMachineState), \
VMSTATE_END_OF_LIST() \
}, \
}
@@ -596,10 +704,12 @@ SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC);
SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC);
SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS);
SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV);
+SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER);
+SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST);
-void spapr_caps_init(sPAPRMachineState *spapr)
+void spapr_caps_init(SpaprMachineState *spapr)
{
- sPAPRCapabilities default_caps;
+ SpaprCapabilities default_caps;
int i;
/* Compute the actual set of caps we should run with */
@@ -615,12 +725,12 @@ void spapr_caps_init(sPAPRMachineState *spapr)
}
}
-void spapr_caps_apply(sPAPRMachineState *spapr)
+void spapr_caps_apply(SpaprMachineState *spapr)
{
int i;
for (i = 0; i < SPAPR_CAP_NUM; i++) {
- sPAPRCapabilityInfo *info = &capability_table[i];
+ SpaprCapabilityInfo *info = &capability_table[i];
/*
* If the apply function can't set the desired level and thinks it's
@@ -630,12 +740,12 @@ void spapr_caps_apply(sPAPRMachineState *spapr)
}
}
-void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu)
+void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu)
{
int i;
for (i = 0; i < SPAPR_CAP_NUM; i++) {
- sPAPRCapabilityInfo *info = &capability_table[i];
+ SpaprCapabilityInfo *info = &capability_table[i];
/*
* If the apply function can't set the desired level and thinks it's
@@ -647,14 +757,14 @@ void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu)
}
}
-void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
+void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp)
{
Error *local_err = NULL;
ObjectClass *klass = OBJECT_CLASS(smc);
int i;
for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
- sPAPRCapabilityInfo *cap = &capability_table[i];
+ SpaprCapabilityInfo *cap = &capability_table[i];
const char *name = g_strdup_printf("cap-%s", cap->name);
char *desc;
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index ef6cbb9c29..f04e06cdf6 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -28,7 +28,7 @@ static void spapr_cpu_reset(void *opaque)
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
target_ulong lpcr;
cpu_reset(cs);
@@ -116,7 +116,7 @@ const char *spapr_get_cpu_core_type(const char *cpu_type)
static bool slb_shadow_needed(void *opaque)
{
- sPAPRCPUState *spapr_cpu = opaque;
+ SpaprCpuState *spapr_cpu = opaque;
return spapr_cpu->slb_shadow_addr != 0;
}
@@ -127,15 +127,15 @@ static const VMStateDescription vmstate_spapr_cpu_slb_shadow = {
.minimum_version_id = 1,
.needed = slb_shadow_needed,
.fields = (VMStateField[]) {
- VMSTATE_UINT64(slb_shadow_addr, sPAPRCPUState),
- VMSTATE_UINT64(slb_shadow_size, sPAPRCPUState),
+ VMSTATE_UINT64(slb_shadow_addr, SpaprCpuState),
+ VMSTATE_UINT64(slb_shadow_size, SpaprCpuState),
VMSTATE_END_OF_LIST()
}
};
static bool dtl_needed(void *opaque)
{
- sPAPRCPUState *spapr_cpu = opaque;
+ SpaprCpuState *spapr_cpu = opaque;
return spapr_cpu->dtl_addr != 0;
}
@@ -146,15 +146,15 @@ static const VMStateDescription vmstate_spapr_cpu_dtl = {
.minimum_version_id = 1,
.needed = dtl_needed,
.fields = (VMStateField[]) {
- VMSTATE_UINT64(dtl_addr, sPAPRCPUState),
- VMSTATE_UINT64(dtl_size, sPAPRCPUState),
+ VMSTATE_UINT64(dtl_addr, SpaprCpuState),
+ VMSTATE_UINT64(dtl_size, SpaprCpuState),
VMSTATE_END_OF_LIST()
}
};
static bool vpa_needed(void *opaque)
{
- sPAPRCPUState *spapr_cpu = opaque;
+ SpaprCpuState *spapr_cpu = opaque;
return spapr_cpu->vpa_addr != 0;
}
@@ -165,7 +165,7 @@ static const VMStateDescription vmstate_spapr_cpu_vpa = {
.minimum_version_id = 1,
.needed = vpa_needed,
.fields = (VMStateField[]) {
- VMSTATE_UINT64(vpa_addr, sPAPRCPUState),
+ VMSTATE_UINT64(vpa_addr, SpaprCpuState),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
@@ -188,7 +188,7 @@ static const VMStateDescription vmstate_spapr_cpu_state = {
}
};
-static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
+static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc)
{
if (!sc->pre_3_0_migration) {
vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
@@ -206,7 +206,7 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
{
- sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
+ SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
int i;
@@ -216,8 +216,8 @@ static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
g_free(sc->threads);
}
-static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- sPAPRCPUCore *sc, Error **errp)
+static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ SpaprCpuCore *sc, Error **errp)
{
CPUPPCState *env = &cpu->env;
CPUState *cs = CPU(cpu);
@@ -256,9 +256,9 @@ error:
error_propagate(errp, local_err);
}
-static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
+static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
{
- sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc);
+ SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc);
CPUCore *cc = CPU_CORE(sc);
Object *obj;
char *id;
@@ -285,7 +285,7 @@ static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
goto err;
}
- cpu->machine_data = g_new0(sPAPRCPUState, 1);
+ cpu->machine_data = g_new0(SpaprCpuState, 1);
object_unref(obj);
return cpu;
@@ -296,9 +296,9 @@ err:
return NULL;
}
-static void spapr_delete_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
+static void spapr_delete_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc)
{
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
cpu->machine_data = NULL;
g_free(spapr_cpu);
@@ -310,10 +310,10 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
/* We don't use SPAPR_MACHINE() in order to exit gracefully if the user
* tries to add a sPAPR CPU core to a non-pseries machine.
*/
- sPAPRMachineState *spapr =
- (sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(),
+ SpaprMachineState *spapr =
+ (SpaprMachineState *) object_dynamic_cast(qdev_get_machine(),
TYPE_SPAPR_MACHINE);
- sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
+ SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(OBJECT(dev));
Error *local_err = NULL;
int i, j;
@@ -352,8 +352,8 @@ err:
}
static 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,
+ 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()
};
@@ -361,7 +361,7 @@ static Property spapr_cpu_core_properties[] = {
static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
+ SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
dc->realize = spapr_cpu_core_realize;
dc->unrealize = spapr_cpu_core_unrealize;
@@ -382,8 +382,8 @@ static const TypeInfo spapr_cpu_core_type_infos[] = {
.name = TYPE_SPAPR_CPU_CORE,
.parent = TYPE_CPU_CORE,
.abstract = true,
- .instance_size = sizeof(sPAPRCPUCore),
- .class_size = sizeof(sPAPRCPUCoreClass),
+ .instance_size = sizeof(SpaprCpuCore),
+ .class_size = sizeof(SpaprCpuCoreClass),
},
DEFINE_SPAPR_CPU_CORE_TYPE("970_v2.2"),
DEFINE_SPAPR_CPU_CORE_TYPE("970mp_v1.0"),
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 2943cf47d4..597f236b9c 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -29,16 +29,16 @@
#define DRC_INDEX_TYPE_SHIFT 28
#define DRC_INDEX_ID_MASK ((1ULL << DRC_INDEX_TYPE_SHIFT) - 1)
-sPAPRDRConnectorType spapr_drc_type(sPAPRDRConnector *drc)
+SpaprDrcType spapr_drc_type(SpaprDrc *drc)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
return 1 << drck->typeshift;
}
-uint32_t spapr_drc_index(sPAPRDRConnector *drc)
+uint32_t spapr_drc_index(SpaprDrc *drc)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
/* no set format for a drc index: it only needs to be globally
* unique. this is how we encode the DRC type on bare-metal
@@ -48,7 +48,7 @@ uint32_t spapr_drc_index(sPAPRDRConnector *drc)
| (drc->id & DRC_INDEX_ID_MASK);
}
-static uint32_t drc_isolate_physical(sPAPRDRConnector *drc)
+static uint32_t drc_isolate_physical(SpaprDrc *drc)
{
switch (drc->state) {
case SPAPR_DRC_STATE_PHYSICAL_POWERON:
@@ -72,7 +72,7 @@ static uint32_t drc_isolate_physical(sPAPRDRConnector *drc)
return RTAS_OUT_SUCCESS;
}
-static uint32_t drc_unisolate_physical(sPAPRDRConnector *drc)
+static uint32_t drc_unisolate_physical(SpaprDrc *drc)
{
switch (drc->state) {
case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE:
@@ -99,7 +99,7 @@ static uint32_t drc_unisolate_physical(sPAPRDRConnector *drc)
return RTAS_OUT_SUCCESS;
}
-static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
+static uint32_t drc_isolate_logical(SpaprDrc *drc)
{
switch (drc->state) {
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
@@ -146,7 +146,7 @@ static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
return RTAS_OUT_SUCCESS;
}
-static uint32_t drc_unisolate_logical(sPAPRDRConnector *drc)
+static uint32_t drc_unisolate_logical(SpaprDrc *drc)
{
switch (drc->state) {
case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
@@ -170,7 +170,7 @@ static uint32_t drc_unisolate_logical(sPAPRDRConnector *drc)
return RTAS_OUT_SUCCESS;
}
-static uint32_t drc_set_usable(sPAPRDRConnector *drc)
+static uint32_t drc_set_usable(SpaprDrc *drc)
{
switch (drc->state) {
case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
@@ -202,7 +202,7 @@ static uint32_t drc_set_usable(sPAPRDRConnector *drc)
return RTAS_OUT_SUCCESS;
}
-static uint32_t drc_set_unusable(sPAPRDRConnector *drc)
+static uint32_t drc_set_unusable(SpaprDrc *drc)
{
switch (drc->state) {
case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
@@ -226,9 +226,9 @@ static uint32_t drc_set_unusable(sPAPRDRConnector *drc)
return RTAS_OUT_SUCCESS;
}
-static const char *spapr_drc_name(sPAPRDRConnector *drc)
+static const char *spapr_drc_name(SpaprDrc *drc)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
/* human-readable name for a DRC to encode into the DT
* description. this is mainly only used within a guest in place
@@ -261,7 +261,7 @@ static const char *spapr_drc_name(sPAPRDRConnector *drc)
* based on the current allocation/indicator/power states
* for the DR connector.
*/
-static sPAPRDREntitySense physical_entity_sense(sPAPRDRConnector *drc)
+static SpaprDREntitySense physical_entity_sense(SpaprDrc *drc)
{
/* this assumes all PCI devices are assigned to a 'live insertion'
* power domain, where QEMU manages power state automatically as
@@ -272,7 +272,7 @@ static sPAPRDREntitySense physical_entity_sense(sPAPRDRConnector *drc)
: SPAPR_DR_ENTITY_SENSE_EMPTY;
}
-static sPAPRDREntitySense logical_entity_sense(sPAPRDRConnector *drc)
+static SpaprDREntitySense logical_entity_sense(SpaprDrc *drc)
{
switch (drc->state) {
case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
@@ -290,7 +290,7 @@ static sPAPRDREntitySense logical_entity_sense(sPAPRDRConnector *drc)
static void prop_get_index(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
uint32_t value = spapr_drc_index(drc);
visit_type_uint32(v, name, &value, errp);
}
@@ -298,7 +298,7 @@ static void prop_get_index(Object *obj, Visitor *v, const char *name,
static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
QNull *null = NULL;
Error *err = NULL;
int fdt_offset_next, fdt_offset, fdt_depth;
@@ -374,7 +374,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
} while (fdt_depth != 0);
}
-void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, Error **errp)
+void spapr_drc_attach(SpaprDrc *drc, DeviceState *d, Error **errp)
{
trace_spapr_drc_attach(spapr_drc_index(drc));
@@ -393,9 +393,9 @@ void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, Error **errp)
NULL, 0, NULL);
}
-static void spapr_drc_release(sPAPRDRConnector *drc)
+static void spapr_drc_release(SpaprDrc *drc)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
drck->release(drc->dev);
@@ -407,9 +407,9 @@ static void spapr_drc_release(sPAPRDRConnector *drc)
drc->dev = NULL;
}
-void spapr_drc_detach(sPAPRDRConnector *drc)
+void spapr_drc_detach(SpaprDrc *drc)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
trace_spapr_drc_detach(spapr_drc_index(drc));
@@ -425,9 +425,9 @@ void spapr_drc_detach(sPAPRDRConnector *drc)
spapr_drc_release(drc);
}
-void spapr_drc_reset(sPAPRDRConnector *drc)
+void spapr_drc_reset(SpaprDrc *drc)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
trace_spapr_drc_reset(spapr_drc_index(drc));
@@ -456,8 +456,8 @@ void spapr_drc_reset(sPAPRDRConnector *drc)
bool spapr_drc_needed(void *opaque)
{
- sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque;
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrc *drc = (SpaprDrc *)opaque;
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
/* If no dev is plugged in there is no need to migrate the DRC state */
if (!drc->dev) {
@@ -477,14 +477,14 @@ static const VMStateDescription vmstate_spapr_drc = {
.minimum_version_id = 1,
.needed = spapr_drc_needed,
.fields = (VMStateField []) {
- VMSTATE_UINT32(state, sPAPRDRConnector),
+ VMSTATE_UINT32(state, SpaprDrc),
VMSTATE_END_OF_LIST()
}
};
static void realize(DeviceState *d, Error **errp)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
Object *root_container;
gchar *link_name;
gchar *child_name;
@@ -517,7 +517,7 @@ static void realize(DeviceState *d, Error **errp)
static void unrealize(DeviceState *d, Error **errp)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
Object *root_container;
gchar *name;
@@ -529,10 +529,10 @@ static void unrealize(DeviceState *d, Error **errp)
g_free(name);
}
-sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
+SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
uint32_t id)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(object_new(type));
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(object_new(type));
char *prop_name;
drc->id = id;
@@ -549,8 +549,8 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
static void spapr_dr_connector_instance_init(Object *obj)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
object_property_add_uint32_ptr(obj, "id", &drc->id, NULL);
object_property_add(obj, "index", "uint32", prop_get_index,
@@ -574,8 +574,8 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
static bool drc_physical_needed(void *opaque)
{
- sPAPRDRCPhysical *drcp = (sPAPRDRCPhysical *)opaque;
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(drcp);
+ SpaprDrcPhysical *drcp = (SpaprDrcPhysical *)opaque;
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(drcp);
if ((drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_ACTIVE))
|| (!drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_INACTIVE))) {
@@ -590,15 +590,15 @@ static const VMStateDescription vmstate_spapr_drc_physical = {
.minimum_version_id = 1,
.needed = drc_physical_needed,
.fields = (VMStateField []) {
- VMSTATE_UINT32(dr_indicator, sPAPRDRCPhysical),
+ VMSTATE_UINT32(dr_indicator, SpaprDrcPhysical),
VMSTATE_END_OF_LIST()
}
};
static void drc_physical_reset(void *opaque)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(opaque);
- sPAPRDRCPhysical *drcp = SPAPR_DRC_PHYSICAL(drc);
+ SpaprDrc *drc = SPAPR_DR_CONNECTOR(opaque);
+ SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(drc);
if (drc->dev) {
drcp->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE;
@@ -609,7 +609,7 @@ static void drc_physical_reset(void *opaque)
static void realize_physical(DeviceState *d, Error **errp)
{
- sPAPRDRCPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
+ SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
Error *local_err = NULL;
realize(d, &local_err);
@@ -625,7 +625,7 @@ static void realize_physical(DeviceState *d, Error **errp)
static void unrealize_physical(DeviceState *d, Error **errp)
{
- sPAPRDRCPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
+ SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
Error *local_err = NULL;
unrealize(d, &local_err);
@@ -641,7 +641,7 @@ static void unrealize_physical(DeviceState *d, Error **errp)
static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
{
DeviceClass *dk = DEVICE_CLASS(k);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
dk->realize = realize_physical;
dk->unrealize = unrealize_physical;
@@ -654,7 +654,7 @@ static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
drck->dr_entity_sense = logical_entity_sense;
drck->isolate = drc_isolate_logical;
@@ -665,7 +665,7 @@ static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU;
drck->typename = "CPU";
@@ -676,7 +676,7 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI;
drck->typename = "28";
@@ -687,7 +687,7 @@ static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB;
drck->typename = "MEM";
@@ -698,7 +698,7 @@ static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
static void spapr_drc_phb_class_init(ObjectClass *k, void *data)
{
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB;
drck->typename = "PHB";
@@ -710,9 +710,9 @@ static void spapr_drc_phb_class_init(ObjectClass *k, void *data)
static const TypeInfo spapr_dr_connector_info = {
.name = TYPE_SPAPR_DR_CONNECTOR,
.parent = TYPE_DEVICE,
- .instance_size = sizeof(sPAPRDRConnector),
+ .instance_size = sizeof(SpaprDrc),
.instance_init = spapr_dr_connector_instance_init,
- .class_size = sizeof(sPAPRDRConnectorClass),
+ .class_size = sizeof(SpaprDrcClass),
.class_init = spapr_dr_connector_class_init,
.abstract = true,
};
@@ -720,7 +720,7 @@ static const TypeInfo spapr_dr_connector_info = {
static const TypeInfo spapr_drc_physical_info = {
.name = TYPE_SPAPR_DRC_PHYSICAL,
.parent = TYPE_SPAPR_DR_CONNECTOR,
- .instance_size = sizeof(sPAPRDRCPhysical),
+ .instance_size = sizeof(SpaprDrcPhysical),
.class_init = spapr_drc_physical_class_init,
.abstract = true,
};
@@ -753,13 +753,13 @@ static const TypeInfo spapr_drc_lmb_info = {
static const TypeInfo spapr_drc_phb_info = {
.name = TYPE_SPAPR_DRC_PHB,
.parent = TYPE_SPAPR_DRC_LOGICAL,
- .instance_size = sizeof(sPAPRDRConnector),
+ .instance_size = sizeof(SpaprDrc),
.class_init = spapr_drc_phb_class_init,
};
/* helper functions for external users */
-sPAPRDRConnector *spapr_drc_by_index(uint32_t index)
+SpaprDrc *spapr_drc_by_index(uint32_t index)
{
Object *obj;
gchar *name;
@@ -771,9 +771,9 @@ sPAPRDRConnector *spapr_drc_by_index(uint32_t index)
return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
}
-sPAPRDRConnector *spapr_drc_by_id(const char *type, uint32_t id)
+SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id)
{
- sPAPRDRConnectorClass *drck
+ SpaprDrcClass *drck
= SPAPR_DR_CONNECTOR_CLASS(object_class_by_name(type));
return spapr_drc_by_index(drck->typeshift << DRC_INDEX_TYPE_SHIFT
@@ -787,7 +787,7 @@ sPAPRDRConnector *spapr_drc_by_id(const char *type, uint32_t id)
* @path: path in the DT to generate properties
* @owner: parent Object/DeviceState for which to generate DRC
* descriptions for
- * @drc_type_mask: mask of sPAPRDRConnectorType values corresponding
+ * @drc_type_mask: mask of SpaprDrcType values corresponding
* to the types of DRCs to generate entries for
*
* generate OF properties to describe DRC topology/indices to guests
@@ -826,8 +826,8 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
object_property_iter_init(&iter, root_container);
while ((prop = object_property_iter_next(&iter))) {
Object *obj;
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
+ SpaprDrc *drc;
+ SpaprDrcClass *drck;
uint32_t drc_index, drc_power_domain;
if (!strstart(prop->type, "link<", NULL)) {
@@ -918,8 +918,8 @@ out:
static uint32_t rtas_set_isolation_state(uint32_t idx, uint32_t state)
{
- sPAPRDRConnector *drc = spapr_drc_by_index(idx);
- sPAPRDRConnectorClass *drck;
+ SpaprDrc *drc = spapr_drc_by_index(idx);
+ SpaprDrcClass *drck;
if (!drc) {
return RTAS_OUT_NO_SUCH_INDICATOR;
@@ -943,7 +943,7 @@ static uint32_t rtas_set_isolation_state(uint32_t idx, uint32_t state)
static uint32_t rtas_set_allocation_state(uint32_t idx, uint32_t state)
{
- sPAPRDRConnector *drc = spapr_drc_by_index(idx);
+ SpaprDrc *drc = spapr_drc_by_index(idx);
if (!drc || !object_dynamic_cast(OBJECT(drc), TYPE_SPAPR_DRC_LOGICAL)) {
return RTAS_OUT_NO_SUCH_INDICATOR;
@@ -965,7 +965,7 @@ static uint32_t rtas_set_allocation_state(uint32_t idx, uint32_t state)
static uint32_t rtas_set_dr_indicator(uint32_t idx, uint32_t state)
{
- sPAPRDRConnector *drc = spapr_drc_by_index(idx);
+ SpaprDrc *drc = spapr_drc_by_index(idx);
if (!drc || !object_dynamic_cast(OBJECT(drc), TYPE_SPAPR_DRC_PHYSICAL)) {
return RTAS_OUT_NO_SUCH_INDICATOR;
@@ -982,7 +982,7 @@ static uint32_t rtas_set_dr_indicator(uint32_t idx, uint32_t state)
return RTAS_OUT_SUCCESS;
}
-static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_set_indicator(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
@@ -1017,7 +1017,7 @@ out:
rtas_st(rets, 0, ret);
}
-static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_get_sensor_state(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
@@ -1025,8 +1025,8 @@ static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t sensor_type;
uint32_t sensor_index;
uint32_t sensor_state = 0;
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
+ SpaprDrc *drc;
+ SpaprDrcClass *drck;
uint32_t ret = RTAS_OUT_SUCCESS;
if (nargs != 2 || nret != 2) {
@@ -1079,7 +1079,7 @@ static void configure_connector_st(target_ulong addr, target_ulong offset,
}
static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
@@ -1087,9 +1087,9 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
uint64_t wa_addr;
uint64_t wa_offset;
uint32_t drc_index;
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
- sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
+ SpaprDrc *drc;
+ SpaprDrcClass *drck;
+ SpaprDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
int rc;
if (nargs != 2 || nret != 1) {
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index ab9a1f0063..ae0f093f59 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -229,18 +229,18 @@ static const char * const event_names[EVENT_CLASS_MAX] = {
[EVENT_CLASS_IO] = "ibm,io-events",
};
-struct sPAPREventSource {
+struct SpaprEventSource {
int irq;
uint32_t mask;
bool enabled;
};
-static sPAPREventSource *spapr_event_sources_new(void)
+static SpaprEventSource *spapr_event_sources_new(void)
{
- return g_new0(sPAPREventSource, EVENT_CLASS_MAX);
+ return g_new0(SpaprEventSource, EVENT_CLASS_MAX);
}
-static void spapr_event_sources_register(sPAPREventSource *event_sources,
+static void spapr_event_sources_register(SpaprEventSource *event_sources,
EventClassIndex index, int irq)
{
/* we only support 1 irq per event class at the moment */
@@ -251,8 +251,8 @@ static void spapr_event_sources_register(sPAPREventSource *event_sources,
event_sources[index].enabled = true;
}
-static const sPAPREventSource *
-spapr_event_sources_get_source(sPAPREventSource *event_sources,
+static const SpaprEventSource *
+spapr_event_sources_get_source(SpaprEventSource *event_sources,
EventClassIndex index)
{
g_assert(index < EVENT_CLASS_MAX);
@@ -261,11 +261,11 @@ spapr_event_sources_get_source(sPAPREventSource *event_sources,
return &event_sources[index];
}
-void spapr_dt_events(sPAPRMachineState *spapr, void *fdt)
+void spapr_dt_events(SpaprMachineState *spapr, void *fdt)
{
uint32_t irq_ranges[EVENT_CLASS_MAX * 2];
int i, count = 0, event_sources;
- sPAPREventSource *events = spapr->event_sources;
+ SpaprEventSource *events = spapr->event_sources;
g_assert(events);
@@ -274,7 +274,7 @@ void spapr_dt_events(sPAPRMachineState *spapr, void *fdt)
for (i = 0, count = 0; i < EVENT_CLASS_MAX; i++) {
int node_offset;
uint32_t interrupts[2];
- const sPAPREventSource *source =
+ const SpaprEventSource *source =
spapr_event_sources_get_source(events, i);
const char *source_name = event_names[i];
@@ -298,10 +298,10 @@ void spapr_dt_events(sPAPRMachineState *spapr, void *fdt)
irq_ranges, count * sizeof(uint32_t))));
}
-static const sPAPREventSource *
-rtas_event_log_to_source(sPAPRMachineState *spapr, int log_type)
+static const SpaprEventSource *
+rtas_event_log_to_source(SpaprMachineState *spapr, int log_type)
{
- const sPAPREventSource *source;
+ const SpaprEventSource *source;
g_assert(spapr->event_sources);
@@ -325,9 +325,9 @@ rtas_event_log_to_source(sPAPRMachineState *spapr, int log_type)
return source;
}
-static int rtas_event_log_to_irq(sPAPRMachineState *spapr, int log_type)
+static int rtas_event_log_to_irq(SpaprMachineState *spapr, int log_type)
{
- const sPAPREventSource *source;
+ const SpaprEventSource *source;
source = rtas_event_log_to_source(spapr, log_type);
g_assert(source);
@@ -336,24 +336,24 @@ static int rtas_event_log_to_irq(sPAPRMachineState *spapr, int log_type)
return source->irq;
}
-static uint32_t spapr_event_log_entry_type(sPAPREventLogEntry *entry)
+static uint32_t spapr_event_log_entry_type(SpaprEventLogEntry *entry)
{
return entry->summary & RTAS_LOG_TYPE_MASK;
}
-static void rtas_event_log_queue(sPAPRMachineState *spapr,
- sPAPREventLogEntry *entry)
+static void rtas_event_log_queue(SpaprMachineState *spapr,
+ SpaprEventLogEntry *entry)
{
QTAILQ_INSERT_TAIL(&spapr->pending_events, entry, next);
}
-static sPAPREventLogEntry *rtas_event_log_dequeue(sPAPRMachineState *spapr,
+static SpaprEventLogEntry *rtas_event_log_dequeue(SpaprMachineState *spapr,
uint32_t event_mask)
{
- sPAPREventLogEntry *entry = NULL;
+ SpaprEventLogEntry *entry = NULL;
QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
- const sPAPREventSource *source =
+ const SpaprEventSource *source =
rtas_event_log_to_source(spapr,
spapr_event_log_entry_type(entry));
@@ -371,11 +371,11 @@ static sPAPREventLogEntry *rtas_event_log_dequeue(sPAPRMachineState *spapr,
static bool rtas_event_log_contains(uint32_t event_mask)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPREventLogEntry *entry = NULL;
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprEventLogEntry *entry = NULL;
QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
- const sPAPREventSource *source =
+ const SpaprEventSource *source =
rtas_event_log_to_source(spapr,
spapr_event_log_entry_type(entry));
@@ -401,7 +401,7 @@ static void spapr_init_v6hdr(struct rtas_event_log_v6 *v6hdr)
static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
int section_count)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
struct tm tm;
int year;
@@ -424,15 +424,15 @@ static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
static void spapr_powerdown_req(Notifier *n, void *opaque)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPREventLogEntry *entry;
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprEventLogEntry *entry;
struct rtas_event_log_v6 *v6hdr;
struct rtas_event_log_v6_maina *maina;
struct rtas_event_log_v6_mainb *mainb;
struct rtas_event_log_v6_epow *epow;
struct epow_extended_log *new_epow;
- entry = g_new(sPAPREventLogEntry, 1);
+ entry = g_new(SpaprEventLogEntry, 1);
new_epow = g_malloc0(sizeof(*new_epow));
entry->extended_log = new_epow;
@@ -473,18 +473,18 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
}
static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
- sPAPRDRConnectorType drc_type,
+ SpaprDrcType drc_type,
union drc_identifier *drc_id)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPREventLogEntry *entry;
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprEventLogEntry *entry;
struct hp_extended_log *new_hp;
struct rtas_event_log_v6 *v6hdr;
struct rtas_event_log_v6_maina *maina;
struct rtas_event_log_v6_mainb *mainb;
struct rtas_event_log_v6_hp *hp;
- entry = g_new(sPAPREventLogEntry, 1);
+ entry = g_new(SpaprEventLogEntry, 1);
new_hp = g_malloc0(sizeof(struct hp_extended_log));
entry->extended_log = new_hp;
@@ -558,9 +558,9 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_HOTPLUG)));
}
-void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
+void spapr_hotplug_req_add_by_index(SpaprDrc *drc)
{
- sPAPRDRConnectorType drc_type = spapr_drc_type(drc);
+ SpaprDrcType drc_type = spapr_drc_type(drc);
union drc_identifier drc_id;
drc_id.index = spapr_drc_index(drc);
@@ -568,9 +568,9 @@ void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
RTAS_LOG_V6_HP_ACTION_ADD, drc_type, &drc_id);
}
-void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc)
+void spapr_hotplug_req_remove_by_index(SpaprDrc *drc)
{
- sPAPRDRConnectorType drc_type = spapr_drc_type(drc);
+ SpaprDrcType drc_type = spapr_drc_type(drc);
union drc_identifier drc_id;
drc_id.index = spapr_drc_index(drc);
@@ -578,7 +578,7 @@ void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc)
RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, &drc_id);
}
-void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_add_by_count(SpaprDrcType drc_type,
uint32_t count)
{
union drc_identifier drc_id;
@@ -588,7 +588,7 @@ void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
RTAS_LOG_V6_HP_ACTION_ADD, drc_type, &drc_id);
}
-void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_remove_by_count(SpaprDrcType drc_type,
uint32_t count)
{
union drc_identifier drc_id;
@@ -598,7 +598,7 @@ void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, &drc_id);
}
-void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_add_by_count_indexed(SpaprDrcType drc_type,
uint32_t count, uint32_t index)
{
union drc_identifier drc_id;
@@ -609,7 +609,7 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
RTAS_LOG_V6_HP_ACTION_ADD, drc_type, &drc_id);
}
-void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_remove_by_count_indexed(SpaprDrcType drc_type,
uint32_t count, uint32_t index)
{
union drc_identifier drc_id;
@@ -620,14 +620,14 @@ void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, &drc_id);
}
-static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void check_exception(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
uint32_t mask, buf, len, event_len;
uint64_t xinfo;
- sPAPREventLogEntry *event;
+ SpaprEventLogEntry *event;
struct rtas_error_log header;
int i;
@@ -671,7 +671,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
*/
for (i = 0; i < EVENT_CLASS_MAX; i++) {
if (rtas_event_log_contains(EVENT_CLASS_MASK(i))) {
- const sPAPREventSource *source =
+ const SpaprEventSource *source =
spapr_event_sources_get_source(spapr->event_sources, i);
g_assert(source->enabled);
@@ -685,7 +685,7 @@ out_no_events:
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
}
-static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void event_scan(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -697,9 +697,9 @@ static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
}
-void spapr_clear_pending_events(sPAPRMachineState *spapr)
+void spapr_clear_pending_events(SpaprMachineState *spapr)
{
- sPAPREventLogEntry *entry = NULL, *next_entry;
+ SpaprEventLogEntry *entry = NULL, *next_entry;
QTAILQ_FOREACH_SAFE(entry, &spapr->pending_events, next, next_entry) {
QTAILQ_REMOVE(&spapr->pending_events, entry, next);
@@ -708,7 +708,7 @@ void spapr_clear_pending_events(sPAPRMachineState *spapr)
}
}
-void spapr_events_init(sPAPRMachineState *spapr)
+void spapr_events_init(SpaprMachineState *spapr)
{
int epow_irq = SPAPR_IRQ_EPOW;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 476bad6271..0761e10142 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -34,7 +34,7 @@ static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
return true;
}
-static bool is_ram_address(sPAPRMachineState *spapr, hwaddr addr)
+static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr)
{
MachineState *machine = MACHINE(spapr);
DeviceMemoryState *dms = machine->device_memory;
@@ -50,7 +50,7 @@ static bool is_ram_address(sPAPRMachineState *spapr, hwaddr addr)
return false;
}
-static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
@@ -160,7 +160,7 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
return REMOVE_SUCCESS;
}
-static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
@@ -208,7 +208,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
#define H_BULK_REMOVE_MAX_BATCH 4
-static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
@@ -260,7 +260,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return rc;
}
-static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
@@ -299,7 +299,7 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
@@ -328,7 +328,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-struct sPAPRPendingHPT {
+struct SpaprPendingHpt {
/* These fields are read-only after initialization */
int shift;
QemuThread thread;
@@ -342,7 +342,7 @@ struct sPAPRPendingHPT {
void *hpt;
};
-static void free_pending_hpt(sPAPRPendingHPT *pending)
+static void free_pending_hpt(SpaprPendingHpt *pending)
{
if (pending->hpt) {
qemu_vfree(pending->hpt);
@@ -353,7 +353,7 @@ static void free_pending_hpt(sPAPRPendingHPT *pending)
static void *hpt_prepare_thread(void *opaque)
{
- sPAPRPendingHPT *pending = opaque;
+ SpaprPendingHpt *pending = opaque;
size_t size = 1ULL << pending->shift;
pending->hpt = qemu_memalign(size, size);
@@ -379,9 +379,9 @@ static void *hpt_prepare_thread(void *opaque)
}
/* Must be called with BQL held */
-static void cancel_hpt_prepare(sPAPRMachineState *spapr)
+static void cancel_hpt_prepare(SpaprMachineState *spapr)
{
- sPAPRPendingHPT *pending = spapr->pending_hpt;
+ SpaprPendingHpt *pending = spapr->pending_hpt;
/* Let the thread know it's cancelled */
spapr->pending_hpt = NULL;
@@ -438,13 +438,13 @@ static target_ulong resize_hpt_convert_rc(int ret)
}
static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong flags = args[0];
int shift = args[1];
- sPAPRPendingHPT *pending = spapr->pending_hpt;
+ SpaprPendingHpt *pending = spapr->pending_hpt;
uint64_t current_ram_size;
int rc;
@@ -503,7 +503,7 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
/* start new prepare */
- pending = g_new0(sPAPRPendingHPT, 1);
+ pending = g_new0(SpaprPendingHpt, 1);
pending->shift = shift;
pending->ret = H_HARDWARE;
@@ -672,7 +672,7 @@ static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data)
}
}
-static void push_sregs_to_kvm_pr(sPAPRMachineState *spapr)
+static void push_sregs_to_kvm_pr(SpaprMachineState *spapr)
{
CPUState *cs;
@@ -691,13 +691,13 @@ static void push_sregs_to_kvm_pr(sPAPRMachineState *spapr)
}
static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong flags = args[0];
target_ulong shift = args[1];
- sPAPRPendingHPT *pending = spapr->pending_hpt;
+ SpaprPendingHpt *pending = spapr->pending_hpt;
int rc;
size_t newsize;
@@ -759,7 +759,7 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
return rc;
}
-static target_ulong h_set_sprg0(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
cpu_synchronize_state(CPU(cpu));
@@ -768,7 +768,7 @@ static target_ulong h_set_sprg0(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_dabr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
if (!has_spr(cpu, SPR_DABR)) {
@@ -786,7 +786,7 @@ static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_set_xdabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_xdabr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong dabrx = args[1];
@@ -807,7 +807,7 @@ static target_ulong h_set_xdabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_page_init(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_page_init(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
@@ -882,7 +882,7 @@ static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
uint16_t size;
uint8_t tmp;
@@ -918,7 +918,7 @@ static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa)
static target_ulong deregister_vpa(PowerPCCPU *cpu, target_ulong vpa)
{
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
if (spapr_cpu->slb_shadow_addr) {
return H_RESOURCE;
@@ -934,7 +934,7 @@ static target_ulong deregister_vpa(PowerPCCPU *cpu, target_ulong vpa)
static target_ulong register_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
{
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
uint32_t size;
if (addr == 0) {
@@ -963,7 +963,7 @@ static target_ulong register_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
static target_ulong deregister_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
{
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
spapr_cpu->slb_shadow_addr = 0;
spapr_cpu->slb_shadow_size = 0;
@@ -972,7 +972,7 @@ static target_ulong deregister_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
static target_ulong register_dtl(PowerPCCPU *cpu, target_ulong addr)
{
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
uint32_t size;
if (addr == 0) {
@@ -998,7 +998,7 @@ static target_ulong register_dtl(PowerPCCPU *cpu, target_ulong addr)
static target_ulong deregister_dtl(PowerPCCPU *cpu, target_ulong addr)
{
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
spapr_cpu->dtl_addr = 0;
spapr_cpu->dtl_size = 0;
@@ -1006,7 +1006,7 @@ static target_ulong deregister_dtl(PowerPCCPU *cpu, target_ulong addr)
return H_SUCCESS;
}
-static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_register_vpa(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
@@ -1049,7 +1049,7 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return ret;
}
-static target_ulong h_cede(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
@@ -1065,7 +1065,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_rtas(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_rtas(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong rtas_r3 = args[0];
@@ -1077,7 +1077,7 @@ static target_ulong h_rtas(PowerPCCPU *cpu, sPAPRMachineState *spapr,
nret, rtas_r3 + 12 + 4*nargs);
}
-static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_load(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
@@ -1101,7 +1101,7 @@ static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_PARAMETER;
}
-static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_store(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
@@ -1127,7 +1127,7 @@ static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_PARAMETER;
}
-static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_memop(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
@@ -1196,14 +1196,14 @@ static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_icbi(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
/* Nothing to do on emulation, KVM will trap this in the kernel */
return H_SUCCESS;
}
-static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_dcbf(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
/* Nothing to do on emulation, KVM will trap this in the kernel */
@@ -1263,7 +1263,7 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
return H_SUCCESS;
}
-static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_mode(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong resource = args[1];
@@ -1282,7 +1282,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return ret;
}
-static target_ulong h_clean_slb(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_clean_slb(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
qemu_log_mask(LOG_UNIMP, "Unimplemented SPAPR hcall 0x"TARGET_FMT_lx"%s\n",
@@ -1290,7 +1290,7 @@ static target_ulong h_clean_slb(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_FUNCTION;
}
-static target_ulong h_invalidate_pid(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_invalidate_pid(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
qemu_log_mask(LOG_UNIMP, "Unimplemented SPAPR hcall 0x"TARGET_FMT_lx"%s\n",
@@ -1298,7 +1298,7 @@ static target_ulong h_invalidate_pid(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_FUNCTION;
}
-static void spapr_check_setup_free_hpt(sPAPRMachineState *spapr,
+static void spapr_check_setup_free_hpt(SpaprMachineState *spapr,
uint64_t patbe_old, uint64_t patbe_new)
{
/*
@@ -1331,7 +1331,7 @@ static void spapr_check_setup_free_hpt(sPAPRMachineState *spapr,
#define FLAG_GTSE 0x01
static target_ulong h_register_process_table(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
@@ -1339,6 +1339,7 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
target_ulong proc_tbl = args[1];
target_ulong page_size = args[2];
target_ulong table_size = args[3];
+ target_ulong update_lpcr = 0;
uint64_t cproc;
if (flags & ~FLAGS_MASK) { /* Check no reserved bits are set */
@@ -1394,10 +1395,13 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
spapr->patb_entry = cproc; /* Save new process table */
/* Update the UPRT, HR and GTSE bits in the LPCR for all cpus */
- spapr_set_all_lpcrs(((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ?
- (LPCR_UPRT | LPCR_HR) : 0) |
- ((flags & FLAG_GTSE) ? LPCR_GTSE : 0),
- LPCR_UPRT | LPCR_HR | LPCR_GTSE);
+ if (flags & FLAG_RADIX) /* Radix must use process tables, also set HR */
+ update_lpcr |= (LPCR_UPRT | LPCR_HR);
+ else if (flags & FLAG_HASH_PROC_TBL) /* Hash with process tables */
+ update_lpcr |= LPCR_UPRT;
+ if (flags & FLAG_GTSE) /* Guest translation shootdown enable */
+ update_lpcr |= FLAG_GTSE;
+ spapr_set_all_lpcrs(update_lpcr, LPCR_UPRT | LPCR_HR | LPCR_GTSE);
if (kvm_enabled()) {
return kvmppc_configure_v3_mmu(cpu, flags & FLAG_RADIX,
@@ -1410,7 +1414,7 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
#define H_SIGNAL_SYS_RESET_ALLBUTSELF -2
static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_long target = args[0];
@@ -1445,7 +1449,7 @@ static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
}
}
-static uint32_t cas_check_pvr(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+static uint32_t cas_check_pvr(SpaprMachineState *spapr, PowerPCCPU *cpu,
target_ulong *addr, bool *raw_mode_supported,
Error **errp)
{
@@ -1496,7 +1500,7 @@ static uint32_t cas_check_pvr(sPAPRMachineState *spapr, PowerPCCPU *cpu,
}
static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
@@ -1504,7 +1508,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
target_ulong addr = ppc64_phys_to_real(args[0]);
target_ulong ov_table;
uint32_t cas_pvr;
- sPAPROptionVector *ov1_guest, *ov5_guest, *ov5_cas_old, *ov5_updates;
+ SpaprOptionVector *ov1_guest, *ov5_guest, *ov5_cas_old, *ov5_updates;
bool guest_radix;
Error *local_err = NULL;
bool raw_mode_supported = false;
@@ -1647,7 +1651,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
}
static target_ulong h_home_node_associativity(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
@@ -1683,7 +1687,7 @@ static target_ulong h_home_node_associativity(PowerPCCPU *cpu,
}
static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
@@ -1693,6 +1697,8 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
uint8_t safe_cache = spapr_get_cap(spapr, SPAPR_CAP_CFPC);
uint8_t safe_bounds_check = spapr_get_cap(spapr, SPAPR_CAP_SBBC);
uint8_t safe_indirect_branch = spapr_get_cap(spapr, SPAPR_CAP_IBS);
+ uint8_t count_cache_flush_assist = spapr_get_cap(spapr,
+ SPAPR_CAP_CCF_ASSIST);
switch (safe_cache) {
case SPAPR_CAP_WORKAROUND:
@@ -1723,12 +1729,20 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
}
switch (safe_indirect_branch) {
+ case SPAPR_CAP_FIXED_NA:
+ break;
case SPAPR_CAP_FIXED_CCD:
characteristics |= H_CPU_CHAR_CACHE_COUNT_DIS;
break;
case SPAPR_CAP_FIXED_IBS:
characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED;
break;
+ case SPAPR_CAP_WORKAROUND:
+ behaviour |= H_CPU_BEHAV_FLUSH_COUNT_CACHE;
+ if (count_cache_flush_assist) {
+ characteristics |= H_CPU_CHAR_BCCTR_FLUSH_ASSIST;
+ }
+ break;
default: /* broken */
assert(safe_indirect_branch == SPAPR_CAP_BROKEN);
break;
@@ -1739,13 +1753,13 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
return H_SUCCESS;
}
-static target_ulong h_update_dt(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_update_dt(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong dt = ppc64_phys_to_real(args[0]);
struct fdt_header hdr = { 0 };
unsigned cb;
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
void *fdt;
cpu_physical_memory_read(dt, &hdr, sizeof(hdr));
@@ -1804,7 +1818,7 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
target_ulong *args)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
if ((opcode <= MAX_HCALL_OPCODE)
&& ((opcode & 0x3) == 0)) {
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 37e98f9321..5aff4d5a05 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -32,7 +32,7 @@
#include <libfdt.h>
-enum sPAPRTCEAccess {
+enum SpaprTceAccess {
SPAPR_TCE_FAULT = 0,
SPAPR_TCE_RO = 1,
SPAPR_TCE_WO = 2,
@@ -42,11 +42,11 @@ enum sPAPRTCEAccess {
#define IOMMU_PAGE_SIZE(shift) (1ULL << (shift))
#define IOMMU_PAGE_MASK(shift) (~(IOMMU_PAGE_SIZE(shift) - 1))
-static QLIST_HEAD(, sPAPRTCETable) spapr_tce_tables;
+static QLIST_HEAD(, SpaprTceTable) spapr_tce_tables;
-sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn)
+SpaprTceTable *spapr_tce_find_by_liobn(target_ulong liobn)
{
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
if (liobn & 0xFFFFFFFF00000000ULL) {
hcall_dprintf("Request for out-of-bounds LIOBN 0x" TARGET_FMT_lx "\n",
@@ -115,7 +115,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
IOMMUAccessFlags flag,
int iommu_idx)
{
- sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
+ SpaprTceTable *tcet = container_of(iommu, SpaprTceTable, iommu);
uint64_t tce;
IOMMUTLBEntry ret = {
.target_as = &address_space_memory,
@@ -141,9 +141,39 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
return ret;
}
+static void spapr_tce_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
+{
+ MemoryRegion *mr = MEMORY_REGION(iommu_mr);
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+ hwaddr addr, granularity;
+ IOMMUTLBEntry iotlb;
+ SpaprTceTable *tcet = container_of(iommu_mr, SpaprTceTable, iommu);
+
+ if (tcet->skipping_replay) {
+ return;
+ }
+
+ granularity = memory_region_iommu_get_min_page_size(iommu_mr);
+
+ for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
+ iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, n->iommu_idx);
+ if (iotlb.perm != IOMMU_NONE) {
+ n->notify(n, &iotlb);
+ }
+
+ /*
+ * if (2^64 - MR size) < granularity, it's possible to get an
+ * infinite loop here. This should catch such a wraparound.
+ */
+ if ((addr + granularity) < addr) {
+ break;
+ }
+ }
+}
+
static int spapr_tce_table_pre_save(void *opaque)
{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
+ SpaprTceTable *tcet = SPAPR_TCE_TABLE(opaque);
tcet->mig_table = tcet->table;
tcet->mig_nb_table = tcet->nb_table;
@@ -156,7 +186,7 @@ static int spapr_tce_table_pre_save(void *opaque)
static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
{
- sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
+ SpaprTceTable *tcet = container_of(iommu, SpaprTceTable, iommu);
return 1ULL << tcet->page_shift;
}
@@ -164,7 +194,7 @@ static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
static int spapr_tce_get_attr(IOMMUMemoryRegion *iommu,
enum IOMMUMemoryRegionAttr attr, void *data)
{
- sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
+ SpaprTceTable *tcet = container_of(iommu, SpaprTceTable, iommu);
if (attr == IOMMU_ATTR_SPAPR_TCE_FD && kvmppc_has_cap_spapr_vfio()) {
*(int *) data = tcet->fd;
@@ -178,7 +208,7 @@ static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old,
IOMMUNotifierFlag new)
{
- struct sPAPRTCETable *tbl = container_of(iommu, sPAPRTCETable, iommu);
+ struct SpaprTceTable *tbl = container_of(iommu, SpaprTceTable, iommu);
if (old == IOMMU_NOTIFIER_NONE && new != IOMMU_NOTIFIER_NONE) {
spapr_tce_set_need_vfio(tbl, true);
@@ -189,7 +219,7 @@ static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
static int spapr_tce_table_post_load(void *opaque, int version_id)
{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
+ SpaprTceTable *tcet = SPAPR_TCE_TABLE(opaque);
uint32_t old_nb_table = tcet->nb_table;
uint64_t old_bus_offset = tcet->bus_offset;
uint32_t old_page_shift = tcet->page_shift;
@@ -223,7 +253,7 @@ static int spapr_tce_table_post_load(void *opaque, int version_id)
static bool spapr_tce_table_ex_needed(void *opaque)
{
- sPAPRTCETable *tcet = opaque;
+ SpaprTceTable *tcet = opaque;
return tcet->bus_offset || tcet->page_shift != 0xC;
}
@@ -234,8 +264,8 @@ static const VMStateDescription vmstate_spapr_tce_table_ex = {
.minimum_version_id = 1,
.needed = spapr_tce_table_ex_needed,
.fields = (VMStateField[]) {
- VMSTATE_UINT64(bus_offset, sPAPRTCETable),
- VMSTATE_UINT32(page_shift, sPAPRTCETable),
+ VMSTATE_UINT64(bus_offset, SpaprTceTable),
+ VMSTATE_UINT32(page_shift, SpaprTceTable),
VMSTATE_END_OF_LIST()
},
};
@@ -248,12 +278,12 @@ static const VMStateDescription vmstate_spapr_tce_table = {
.post_load = spapr_tce_table_post_load,
.fields = (VMStateField []) {
/* Sanity check */
- VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable, NULL),
+ VMSTATE_UINT32_EQUAL(liobn, SpaprTceTable, NULL),
/* IOMMU state */
- VMSTATE_UINT32(mig_nb_table, sPAPRTCETable),
- VMSTATE_BOOL(bypass, sPAPRTCETable),
- VMSTATE_VARRAY_UINT32_ALLOC(mig_table, sPAPRTCETable, mig_nb_table, 0,
+ VMSTATE_UINT32(mig_nb_table, SpaprTceTable),
+ VMSTATE_BOOL(bypass, SpaprTceTable),
+ VMSTATE_VARRAY_UINT32_ALLOC(mig_table, SpaprTceTable, mig_nb_table, 0,
vmstate_info_uint64, uint64_t),
VMSTATE_END_OF_LIST()
@@ -266,7 +296,7 @@ static const VMStateDescription vmstate_spapr_tce_table = {
static void spapr_tce_table_realize(DeviceState *dev, Error **errp)
{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
+ SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev);
Object *tcetobj = OBJECT(tcet);
gchar *tmp;
@@ -288,7 +318,7 @@ static void spapr_tce_table_realize(DeviceState *dev, Error **errp)
tcet);
}
-void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio)
+void spapr_tce_set_need_vfio(SpaprTceTable *tcet, bool need_vfio)
{
size_t table_size = tcet->nb_table * sizeof(uint64_t);
uint64_t *oldtable;
@@ -317,9 +347,9 @@ void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio)
tcet->fd = newfd;
}
-sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
+SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
{
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
gchar *tmp;
if (spapr_tce_find_by_liobn(liobn)) {
@@ -341,7 +371,7 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
return tcet;
}
-void spapr_tce_table_enable(sPAPRTCETable *tcet,
+void spapr_tce_table_enable(SpaprTceTable *tcet,
uint32_t page_shift, uint64_t bus_offset,
uint32_t nb_table)
{
@@ -366,7 +396,7 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet,
MEMORY_REGION(&tcet->iommu));
}
-void spapr_tce_table_disable(sPAPRTCETable *tcet)
+void spapr_tce_table_disable(SpaprTceTable *tcet)
{
if (!tcet->nb_table) {
return;
@@ -385,7 +415,7 @@ void spapr_tce_table_disable(sPAPRTCETable *tcet)
static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
+ SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev);
vmstate_unregister(DEVICE(tcet), &vmstate_spapr_tce_table, tcet);
@@ -394,14 +424,14 @@ static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
spapr_tce_table_disable(tcet);
}
-MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet)
+MemoryRegion *spapr_tce_get_iommu(SpaprTceTable *tcet)
{
return &tcet->root;
}
static void spapr_tce_reset(DeviceState *dev)
{
- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
+ SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev);
size_t table_size = tcet->nb_table * sizeof(uint64_t);
if (tcet->nb_table) {
@@ -409,7 +439,7 @@ static void spapr_tce_reset(DeviceState *dev)
}
}
-static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba,
target_ulong tce)
{
IOMMUTLBEntry entry;
@@ -435,7 +465,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
}
static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
int i;
@@ -445,7 +475,7 @@ static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
target_ulong tce_list = args[2];
target_ulong npages = args[3];
target_ulong ret = H_PARAMETER, tce = 0;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+ SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
CPUState *cs = CPU(cpu);
hwaddr page_mask, page_size;
@@ -480,7 +510,7 @@ static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
return ret;
}
-static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_stuff_tce(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
int i;
@@ -489,7 +519,7 @@ static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong tce_value = args[2];
target_ulong npages = args[3];
target_ulong ret = H_PARAMETER;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+ SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
hwaddr page_mask, page_size;
if (!tcet) {
@@ -519,14 +549,14 @@ static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return ret;
}
-static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_put_tce(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong liobn = args[0];
target_ulong ioba = args[1];
target_ulong tce = args[2];
target_ulong ret = H_PARAMETER;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+ SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
if (tcet) {
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
@@ -544,7 +574,7 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return ret;
}
-static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+static target_ulong get_tce_emu(SpaprTceTable *tcet, target_ulong ioba,
target_ulong *tce)
{
unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift;
@@ -560,14 +590,14 @@ static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
return H_SUCCESS;
}
-static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_get_tce(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong liobn = args[0];
target_ulong ioba = args[1];
target_ulong tce = 0;
target_ulong ret = H_PARAMETER;
- sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+ SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
if (tcet) {
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
@@ -619,7 +649,7 @@ int spapr_dma_dt(void *fdt, int node_off, const char *propname,
}
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
- sPAPRTCETable *tcet)
+ SpaprTceTable *tcet)
{
if (!tcet) {
return 0;
@@ -650,7 +680,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
static TypeInfo spapr_tce_table_info = {
.name = TYPE_SPAPR_TCE_TABLE,
.parent = TYPE_DEVICE,
- .instance_size = sizeof(sPAPRTCETable),
+ .instance_size = sizeof(SpaprTceTable),
.class_init = spapr_tce_table_class_init,
};
@@ -659,6 +689,7 @@ static void spapr_iommu_memory_region_class_init(ObjectClass *klass, void *data)
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = spapr_tce_translate_iommu;
+ imrc->replay = spapr_tce_replay;
imrc->get_min_page_size = spapr_tce_get_min_page_size;
imrc->notify_flag_changed = spapr_tce_notify_flag_changed;
imrc->get_attr = spapr_tce_get_attr;
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index 4145079d7f..253e4de7fd 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -20,13 +20,13 @@
#include "trace.h"
-void spapr_irq_msi_init(sPAPRMachineState *spapr, uint32_t nr_msis)
+void spapr_irq_msi_init(SpaprMachineState *spapr, uint32_t nr_msis)
{
spapr->irq_map_nr = nr_msis;
spapr->irq_map = bitmap_new(spapr->irq_map_nr);
}
-int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
+int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align,
Error **errp)
{
int irq;
@@ -51,12 +51,12 @@ int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
return irq + SPAPR_IRQ_MSI;
}
-void spapr_irq_msi_free(sPAPRMachineState *spapr, int irq, uint32_t num)
+void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num)
{
bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num);
}
-void spapr_irq_msi_reset(sPAPRMachineState *spapr)
+void spapr_irq_msi_reset(SpaprMachineState *spapr)
{
bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr);
}
@@ -66,7 +66,7 @@ void spapr_irq_msi_reset(sPAPRMachineState *spapr)
* XICS IRQ backend.
*/
-static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
+static ICSState *spapr_ics_create(SpaprMachineState *spapr,
int nr_irqs, Error **errp)
{
Error *local_err = NULL;
@@ -92,7 +92,7 @@ error:
return NULL;
}
-static void spapr_irq_init_xics(sPAPRMachineState *spapr, int nr_irqs,
+static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
MachineState *machine = MACHINE(spapr);
@@ -126,7 +126,7 @@ error:
#define ICS_IRQ_FREE(ics, srcno) \
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
-static int spapr_irq_claim_xics(sPAPRMachineState *spapr, int irq, bool lsi,
+static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
ICSState *ics = spapr->ics;
@@ -147,7 +147,7 @@ static int spapr_irq_claim_xics(sPAPRMachineState *spapr, int irq, bool lsi,
return 0;
}
-static void spapr_irq_free_xics(sPAPRMachineState *spapr, int irq, int num)
+static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num)
{
ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset;
@@ -164,7 +164,7 @@ static void spapr_irq_free_xics(sPAPRMachineState *spapr, int irq, int num)
}
}
-static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq)
+static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq)
{
ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset;
@@ -176,7 +176,7 @@ static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq)
return NULL;
}
-static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
+static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon)
{
CPUState *cs;
@@ -189,12 +189,12 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
ics_pic_print_info(spapr->ics, mon);
}
-static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr,
+static void spapr_irq_cpu_intc_create_xics(SpaprMachineState *spapr,
PowerPCCPU *cpu, Error **errp)
{
Error *local_err = NULL;
Object *obj;
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
obj = icp_create(OBJECT(cpu), TYPE_ICP, XICS_FABRIC(spapr),
&local_err);
@@ -206,7 +206,7 @@ static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr,
spapr_cpu->icp = ICP(obj);
}
-static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id)
+static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id)
{
if (!kvm_irqchip_in_kernel()) {
CPUState *cs;
@@ -220,17 +220,17 @@ static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id)
static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
ics_simple_set_irq(spapr->ics, srcno, val);
}
-static void spapr_irq_reset_xics(sPAPRMachineState *spapr, Error **errp)
+static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp)
{
/* TODO: create the KVM XICS device */
}
-static const char *spapr_irq_get_nodename_xics(sPAPRMachineState *spapr)
+static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr)
{
return XICS_NODENAME;
}
@@ -239,7 +239,7 @@ static const char *spapr_irq_get_nodename_xics(sPAPRMachineState *spapr)
#define SPAPR_IRQ_XICS_NR_MSIS \
(XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI)
-sPAPRIrq spapr_irq_xics = {
+SpaprIrq spapr_irq_xics = {
.nr_irqs = SPAPR_IRQ_XICS_NR_IRQS,
.nr_msis = SPAPR_IRQ_XICS_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_LEGACY,
@@ -260,7 +260,7 @@ sPAPRIrq spapr_irq_xics = {
/*
* XIVE IRQ backend.
*/
-static void spapr_irq_init_xive(sPAPRMachineState *spapr, int nr_irqs,
+static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
MachineState *machine = MACHINE(spapr);
@@ -294,7 +294,7 @@ static void spapr_irq_init_xive(sPAPRMachineState *spapr, int nr_irqs,
spapr_xive_hcall_init(spapr);
}
-static int spapr_irq_claim_xive(sPAPRMachineState *spapr, int irq, bool lsi,
+static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) {
@@ -304,7 +304,7 @@ static int spapr_irq_claim_xive(sPAPRMachineState *spapr, int irq, bool lsi,
return 0;
}
-static void spapr_irq_free_xive(sPAPRMachineState *spapr, int irq, int num)
+static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num)
{
int i;
@@ -313,9 +313,9 @@ static void spapr_irq_free_xive(sPAPRMachineState *spapr, int irq, int num)
}
}
-static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq)
+static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq)
{
- sPAPRXive *xive = spapr->xive;
+ SpaprXive *xive = spapr->xive;
if (irq >= xive->nr_irqs) {
return NULL;
@@ -327,7 +327,7 @@ static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq)
return spapr->qirqs[irq];
}
-static void spapr_irq_print_info_xive(sPAPRMachineState *spapr,
+static void spapr_irq_print_info_xive(SpaprMachineState *spapr,
Monitor *mon)
{
CPUState *cs;
@@ -341,12 +341,12 @@ static void spapr_irq_print_info_xive(sPAPRMachineState *spapr,
spapr_xive_pic_print_info(spapr->xive, mon);
}
-static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr,
+static void spapr_irq_cpu_intc_create_xive(SpaprMachineState *spapr,
PowerPCCPU *cpu, Error **errp)
{
Error *local_err = NULL;
Object *obj;
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err);
if (local_err) {
@@ -363,12 +363,12 @@ static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr,
spapr_xive_set_tctx_os_cam(spapr_cpu->tctx);
}
-static int spapr_irq_post_load_xive(sPAPRMachineState *spapr, int version_id)
+static int spapr_irq_post_load_xive(SpaprMachineState *spapr, int version_id)
{
return 0;
}
-static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp)
+static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp)
{
CPUState *cs;
@@ -385,12 +385,12 @@ static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp)
static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
xive_source_set_irq(&spapr->xive->source, srcno, val);
}
-static const char *spapr_irq_get_nodename_xive(sPAPRMachineState *spapr)
+static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr)
{
return spapr->xive->nodename;
}
@@ -403,7 +403,7 @@ static const char *spapr_irq_get_nodename_xive(sPAPRMachineState *spapr)
#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000
#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI)
-sPAPRIrq spapr_irq_xive = {
+SpaprIrq spapr_irq_xive = {
.nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS,
.nr_msis = SPAPR_IRQ_XIVE_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_EXPLOIT,
@@ -434,13 +434,13 @@ sPAPRIrq spapr_irq_xive = {
* Returns the sPAPR IRQ backend negotiated by CAS. XICS is the
* default.
*/
-static sPAPRIrq *spapr_irq_current(sPAPRMachineState *spapr)
+static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr)
{
return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ?
&spapr_irq_xive : &spapr_irq_xics;
}
-static void spapr_irq_init_dual(sPAPRMachineState *spapr, int nr_irqs,
+static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
MachineState *machine = MACHINE(spapr);
@@ -464,7 +464,7 @@ static void spapr_irq_init_dual(sPAPRMachineState *spapr, int nr_irqs,
}
}
-static int spapr_irq_claim_dual(sPAPRMachineState *spapr, int irq, bool lsi,
+static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
Error *local_err = NULL;
@@ -485,30 +485,30 @@ static int spapr_irq_claim_dual(sPAPRMachineState *spapr, int irq, bool lsi,
return ret;
}
-static void spapr_irq_free_dual(sPAPRMachineState *spapr, int irq, int num)
+static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num)
{
spapr_irq_xics.free(spapr, irq, num);
spapr_irq_xive.free(spapr, irq, num);
}
-static qemu_irq spapr_qirq_dual(sPAPRMachineState *spapr, int irq)
+static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq)
{
return spapr_irq_current(spapr)->qirq(spapr, irq);
}
-static void spapr_irq_print_info_dual(sPAPRMachineState *spapr, Monitor *mon)
+static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon)
{
spapr_irq_current(spapr)->print_info(spapr, mon);
}
-static void spapr_irq_dt_populate_dual(sPAPRMachineState *spapr,
+static void spapr_irq_dt_populate_dual(SpaprMachineState *spapr,
uint32_t nr_servers, void *fdt,
uint32_t phandle)
{
spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle);
}
-static void spapr_irq_cpu_intc_create_dual(sPAPRMachineState *spapr,
+static void spapr_irq_cpu_intc_create_dual(SpaprMachineState *spapr,
PowerPCCPU *cpu, Error **errp)
{
Error *local_err = NULL;
@@ -522,7 +522,7 @@ static void spapr_irq_cpu_intc_create_dual(sPAPRMachineState *spapr,
spapr_irq_xics.cpu_intc_create(spapr, cpu, errp);
}
-static int spapr_irq_post_load_dual(sPAPRMachineState *spapr, int version_id)
+static int spapr_irq_post_load_dual(SpaprMachineState *spapr, int version_id)
{
/*
* Force a reset of the XIVE backend after migration. The machine
@@ -535,7 +535,7 @@ static int spapr_irq_post_load_dual(sPAPRMachineState *spapr, int version_id)
return spapr_irq_current(spapr)->post_load(spapr, version_id);
}
-static void spapr_irq_reset_dual(sPAPRMachineState *spapr, Error **errp)
+static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp)
{
/*
* Deactivate the XIVE MMIOs. The XIVE backend will reenable them
@@ -548,12 +548,12 @@ static void spapr_irq_reset_dual(sPAPRMachineState *spapr, Error **errp)
static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val)
{
- sPAPRMachineState *spapr = opaque;
+ SpaprMachineState *spapr = opaque;
spapr_irq_current(spapr)->set_irq(spapr, srcno, val);
}
-static const char *spapr_irq_get_nodename_dual(sPAPRMachineState *spapr)
+static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr)
{
return spapr_irq_current(spapr)->get_nodename(spapr);
}
@@ -564,7 +564,7 @@ static const char *spapr_irq_get_nodename_dual(sPAPRMachineState *spapr)
#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000
#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI)
-sPAPRIrq spapr_irq_dual = {
+SpaprIrq spapr_irq_dual = {
.nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS,
.nr_msis = SPAPR_IRQ_DUAL_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_BOTH,
@@ -585,7 +585,7 @@ sPAPRIrq spapr_irq_dual = {
/*
* sPAPR IRQ frontend routines for devices
*/
-void spapr_irq_init(sPAPRMachineState *spapr, Error **errp)
+void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
{
MachineState *machine = MACHINE(spapr);
@@ -611,34 +611,34 @@ void spapr_irq_init(sPAPRMachineState *spapr, Error **errp)
spapr->irq->nr_irqs);
}
-int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
+int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp)
{
return spapr->irq->claim(spapr, irq, lsi, errp);
}
-void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
+void spapr_irq_free(SpaprMachineState *spapr, int irq, int num)
{
spapr->irq->free(spapr, irq, num);
}
-qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
+qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq)
{
return spapr->irq->qirq(spapr, irq);
}
-int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id)
+int spapr_irq_post_load(SpaprMachineState *spapr, int version_id)
{
return spapr->irq->post_load(spapr, version_id);
}
-void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp)
+void spapr_irq_reset(SpaprMachineState *spapr, Error **errp)
{
if (spapr->irq->reset) {
spapr->irq->reset(spapr, errp);
}
}
-int spapr_irq_get_phandle(sPAPRMachineState *spapr, void *fdt, Error **errp)
+int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp)
{
const char *nodename = spapr->irq->get_nodename(spapr);
int offset, phandle;
@@ -684,7 +684,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)
return -1;
}
-int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
+int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp)
{
ICSState *ics = spapr->ics;
int first = -1;
@@ -716,7 +716,7 @@ int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
#define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400
-sPAPRIrq spapr_irq_xics_legacy = {
+SpaprIrq spapr_irq_xics_legacy = {
.nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
.nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
.ov5 = SPAPR_OV5_XIVE_LEGACY,
diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c
index 12510b236a..a65b7c7da9 100644
--- a/hw/ppc/spapr_ovec.c
+++ b/hw/ppc/spapr_ovec.c
@@ -16,7 +16,6 @@
#include "qemu/bitmap.h"
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
-#include "sysemu/qtest.h"
#include "trace.h"
#include <libfdt.h>
@@ -27,7 +26,7 @@
* allows us to more safely make assumptions about the bitmap size and
* simplify the calling code somewhat
*/
-struct sPAPROptionVector {
+struct SpaprOptionVector {
unsigned long *bitmap;
int32_t bitmap_size; /* only used for migration */
};
@@ -37,25 +36,25 @@ const VMStateDescription vmstate_spapr_ovec = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_BITMAP(bitmap, sPAPROptionVector, 1, bitmap_size),
+ VMSTATE_BITMAP(bitmap, SpaprOptionVector, 1, bitmap_size),
VMSTATE_END_OF_LIST()
}
};
-sPAPROptionVector *spapr_ovec_new(void)
+SpaprOptionVector *spapr_ovec_new(void)
{
- sPAPROptionVector *ov;
+ SpaprOptionVector *ov;
- ov = g_new0(sPAPROptionVector, 1);
+ ov = g_new0(SpaprOptionVector, 1);
ov->bitmap = bitmap_new(OV_MAXBITS);
ov->bitmap_size = OV_MAXBITS;
return ov;
}
-sPAPROptionVector *spapr_ovec_clone(sPAPROptionVector *ov_orig)
+SpaprOptionVector *spapr_ovec_clone(SpaprOptionVector *ov_orig)
{
- sPAPROptionVector *ov;
+ SpaprOptionVector *ov;
g_assert(ov_orig);
@@ -65,9 +64,9 @@ sPAPROptionVector *spapr_ovec_clone(sPAPROptionVector *ov_orig)
return ov;
}
-void spapr_ovec_intersect(sPAPROptionVector *ov,
- sPAPROptionVector *ov1,
- sPAPROptionVector *ov2)
+void spapr_ovec_intersect(SpaprOptionVector *ov,
+ SpaprOptionVector *ov1,
+ SpaprOptionVector *ov2)
{
g_assert(ov);
g_assert(ov1);
@@ -77,9 +76,9 @@ void spapr_ovec_intersect(sPAPROptionVector *ov,
}
/* returns true if options bits were removed, false otherwise */
-bool spapr_ovec_diff(sPAPROptionVector *ov,
- sPAPROptionVector *ov_old,
- sPAPROptionVector *ov_new)
+bool spapr_ovec_diff(SpaprOptionVector *ov,
+ SpaprOptionVector *ov_old,
+ SpaprOptionVector *ov_new)
{
unsigned long *change_mask = bitmap_new(OV_MAXBITS);
unsigned long *removed_bits = bitmap_new(OV_MAXBITS);
@@ -103,7 +102,7 @@ bool spapr_ovec_diff(sPAPROptionVector *ov,
return bits_were_removed;
}
-void spapr_ovec_cleanup(sPAPROptionVector *ov)
+void spapr_ovec_cleanup(SpaprOptionVector *ov)
{
if (ov) {
g_free(ov->bitmap);
@@ -111,7 +110,7 @@ void spapr_ovec_cleanup(sPAPROptionVector *ov)
}
}
-void spapr_ovec_set(sPAPROptionVector *ov, long bitnr)
+void spapr_ovec_set(SpaprOptionVector *ov, long bitnr)
{
g_assert(ov);
g_assert(bitnr < OV_MAXBITS);
@@ -119,7 +118,7 @@ void spapr_ovec_set(sPAPROptionVector *ov, long bitnr)
set_bit(bitnr, ov->bitmap);
}
-void spapr_ovec_clear(sPAPROptionVector *ov, long bitnr)
+void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr)
{
g_assert(ov);
g_assert(bitnr < OV_MAXBITS);
@@ -127,16 +126,11 @@ void spapr_ovec_clear(sPAPROptionVector *ov, long bitnr)
clear_bit(bitnr, ov->bitmap);
}
-bool spapr_ovec_test(sPAPROptionVector *ov, long bitnr)
+bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr)
{
g_assert(ov);
g_assert(bitnr < OV_MAXBITS);
- /* support memory unplug for qtest */
- if (qtest_enabled() && bitnr == OV5_HP_EVT) {
- return true;
- }
-
return test_bit(bitnr, ov->bitmap) ? true : false;
}
@@ -184,9 +178,9 @@ static target_ulong vector_addr(target_ulong table_addr, int vector)
return table_addr;
}
-sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector)
+SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector)
{
- sPAPROptionVector *ov;
+ SpaprOptionVector *ov;
target_ulong addr;
uint16_t vector_len;
int i;
@@ -216,7 +210,7 @@ sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector)
}
int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
- sPAPROptionVector *ov, const char *name)
+ SpaprOptionVector *ov, const char *name)
{
uint8_t vec[OV_MAXBYTES + 1];
uint16_t vec_len;
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 69059c36eb..20915d2b3c 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -61,9 +61,9 @@
#define RTAS_TYPE_MSI 1
#define RTAS_TYPE_MSIX 2
-sPAPRPHBState *spapr_pci_find_phb(sPAPRMachineState *spapr, uint64_t buid)
+SpaprPhbState *spapr_pci_find_phb(SpaprMachineState *spapr, uint64_t buid)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
QLIST_FOREACH(sphb, &spapr->phbs, list) {
if (sphb->buid != buid) {
@@ -75,10 +75,10 @@ sPAPRPHBState *spapr_pci_find_phb(sPAPRMachineState *spapr, uint64_t buid)
return NULL;
}
-PCIDevice *spapr_pci_find_dev(sPAPRMachineState *spapr, uint64_t buid,
+PCIDevice *spapr_pci_find_dev(SpaprMachineState *spapr, uint64_t buid,
uint32_t config_addr)
{
- sPAPRPHBState *sphb = spapr_pci_find_phb(spapr, buid);
+ SpaprPhbState *sphb = spapr_pci_find_phb(spapr, buid);
PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
int bus_num = (config_addr >> 16) & 0xFF;
int devfn = (config_addr >> 8) & 0xFF;
@@ -96,7 +96,7 @@ static uint32_t rtas_pci_cfgaddr(uint32_t arg)
return ((arg >> 20) & 0xf00) | (arg & 0xff);
}
-static void finish_read_pci_config(sPAPRMachineState *spapr, uint64_t buid,
+static void finish_read_pci_config(SpaprMachineState *spapr, uint64_t buid,
uint32_t addr, uint32_t size,
target_ulong rets)
{
@@ -126,7 +126,7 @@ static void finish_read_pci_config(sPAPRMachineState *spapr, uint64_t buid,
rtas_st(rets, 1, val);
}
-static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -146,7 +146,7 @@ static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
finish_read_pci_config(spapr, buid, addr, size, rets);
}
-static void rtas_read_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_read_pci_config(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -164,7 +164,7 @@ static void rtas_read_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
finish_read_pci_config(spapr, 0, addr, size, rets);
}
-static void finish_write_pci_config(sPAPRMachineState *spapr, uint64_t buid,
+static void finish_write_pci_config(SpaprMachineState *spapr, uint64_t buid,
uint32_t addr, uint32_t size,
uint32_t val, target_ulong rets)
{
@@ -192,7 +192,7 @@ static void finish_write_pci_config(sPAPRMachineState *spapr, uint64_t buid,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -213,7 +213,7 @@ static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
finish_write_pci_config(spapr, buid, addr, size, val, rets);
}
-static void rtas_write_pci_config(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_write_pci_config(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -262,12 +262,12 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
}
}
-static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
uint32_t config_addr = rtas_ld(args, 0);
uint64_t buid = rtas_ldq(args, 1);
unsigned int func = rtas_ld(args, 3);
@@ -275,14 +275,14 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
unsigned int seq_num = rtas_ld(args, 5);
unsigned int ret_intr_type;
unsigned int irq, max_irqs = 0;
- sPAPRPHBState *phb = NULL;
+ SpaprPhbState *phb = NULL;
PCIDevice *pdev = NULL;
spapr_pci_msi *msi;
int *config_addr_key;
Error *err = NULL;
int i;
- /* Fins sPAPRPHBState */
+ /* Fins SpaprPhbState */
phb = spapr_pci_find_phb(spapr, buid);
if (phb) {
pdev = spapr_pci_find_dev(spapr, buid, config_addr);
@@ -439,7 +439,7 @@ out:
}
static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs,
target_ulong args,
@@ -449,11 +449,11 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
uint32_t config_addr = rtas_ld(args, 0);
uint64_t buid = rtas_ldq(args, 1);
unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
- sPAPRPHBState *phb = NULL;
+ SpaprPhbState *phb = NULL;
PCIDevice *pdev = NULL;
spapr_pci_msi *msi;
- /* Find sPAPRPHBState */
+ /* Find SpaprPhbState */
phb = spapr_pci_find_phb(spapr, buid);
if (phb) {
pdev = spapr_pci_find_dev(spapr, buid, config_addr);
@@ -480,12 +480,12 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
}
static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
uint32_t addr, option;
uint64_t buid;
int ret;
@@ -516,12 +516,12 @@ param_error_exit:
}
static void rtas_ibm_get_config_addr_info2(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
PCIDevice *pdev;
uint32_t addr, option;
uint64_t buid;
@@ -570,12 +570,12 @@ param_error_exit:
}
static void rtas_ibm_read_slot_reset_state2(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
uint64_t buid;
int state, ret;
@@ -612,12 +612,12 @@ param_error_exit:
}
static void rtas_ibm_set_slot_reset(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
uint32_t option;
uint64_t buid;
int ret;
@@ -646,12 +646,12 @@ param_error_exit:
}
static void rtas_ibm_configure_pe(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
uint64_t buid;
int ret;
@@ -679,12 +679,12 @@ param_error_exit:
/* To support it later */
static void rtas_ibm_slot_error_detail(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
int option;
uint64_t buid;
@@ -741,7 +741,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
* Here we use the number returned by pci_spapr_map_irq to find a
* corresponding qemu_irq.
*/
- sPAPRPHBState *phb = opaque;
+ SpaprPhbState *phb = opaque;
trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq);
qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
@@ -749,7 +749,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin)
{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(opaque);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(opaque);
PCIINTxRoute route;
route.mode = PCI_INTX_ENABLED;
@@ -766,7 +766,7 @@ static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin)
static void spapr_msi_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
uint32_t irq = data;
trace_spapr_pci_msi_write(addr, data, irq);
@@ -786,12 +786,12 @@ static const MemoryRegionOps spapr_msi_ops = {
*/
static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
{
- sPAPRPHBState *phb = opaque;
+ SpaprPhbState *phb = opaque;
return &phb->iommu_as;
}
-static char *spapr_phb_vfio_get_loc_code(sPAPRPHBState *sphb, PCIDevice *pdev)
+static char *spapr_phb_vfio_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev)
{
char *path = NULL, *buf = NULL, *host = NULL;
@@ -822,7 +822,7 @@ err_out:
return NULL;
}
-static char *spapr_phb_get_loc_code(sPAPRPHBState *sphb, PCIDevice *pdev)
+static char *spapr_phb_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev)
{
char *buf;
const char *devtype = "qemu";
@@ -1249,11 +1249,11 @@ static gchar *pci_get_node_name(PCIDevice *dev)
}
}
-static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
+static uint32_t spapr_phb_get_pci_drc_index(SpaprPhbState *phb,
PCIDevice *pdev);
static void spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
- sPAPRPHBState *sphb)
+ SpaprPhbState *sphb)
{
ResourceProps rp;
bool is_bridge = false;
@@ -1358,7 +1358,7 @@ static void spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
}
/* create OF node for pci device and required OF DT properties */
-static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
+static int spapr_create_pci_child_dt(SpaprPhbState *phb, PCIDevice *dev,
void *fdt, int node_offset)
{
int offset;
@@ -1382,7 +1382,7 @@ void spapr_phb_remove_pci_device_cb(DeviceState *dev)
object_unparent(OBJECT(dev));
}
-static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb,
+static SpaprDrc *spapr_phb_get_pci_func_drc(SpaprPhbState *phb,
uint32_t busnr,
int32_t devfn)
{
@@ -1390,17 +1390,17 @@ static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb,
(phb->index << 16) | (busnr << 8) | devfn);
}
-static sPAPRDRConnector *spapr_phb_get_pci_drc(sPAPRPHBState *phb,
+static SpaprDrc *spapr_phb_get_pci_drc(SpaprPhbState *phb,
PCIDevice *pdev)
{
uint32_t busnr = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))));
return spapr_phb_get_pci_func_drc(phb, busnr, pdev->devfn);
}
-static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
+static uint32_t spapr_phb_get_pci_drc_index(SpaprPhbState *phb,
PCIDevice *pdev)
{
- sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
+ SpaprDrc *drc = spapr_phb_get_pci_drc(phb, pdev);
if (!drc) {
return 0;
@@ -1409,11 +1409,11 @@ static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
return spapr_drc_index(drc);
}
-int spapr_pci_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_pci_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp)
{
HotplugHandler *plug_handler = qdev_get_hotplug_handler(drc->dev);
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(plug_handler);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(plug_handler);
PCIDevice *pdev = PCI_DEVICE(drc->dev);
*fdt_start_offset = spapr_create_pci_child_dt(sphb, pdev, fdt, 0);
@@ -1423,9 +1423,9 @@ int spapr_pci_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
static void spapr_pci_plug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp)
{
- sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
+ SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
- sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
+ SpaprDrc *drc = spapr_phb_get_pci_drc(phb, pdev);
Error *local_err = NULL;
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
@@ -1472,9 +1472,9 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
int i;
for (i = 0; i < 8; i++) {
- sPAPRDRConnector *func_drc;
- sPAPRDRConnectorClass *func_drck;
- sPAPRDREntitySense state;
+ SpaprDrc *func_drc;
+ SpaprDrcClass *func_drck;
+ SpaprDREntitySense state;
func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus),
PCI_DEVFN(slotnr, i));
@@ -1513,9 +1513,9 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler,
static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp)
{
- sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
+ SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
- sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
+ SpaprDrc *drc = spapr_phb_get_pci_drc(phb, pdev);
if (!phb->dr_enabled) {
error_setg(errp, QERR_BUS_NO_HOTPLUG,
@@ -1529,9 +1529,9 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
if (!spapr_drc_unplug_requested(drc)) {
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
- sPAPRDRConnector *func_drc;
- sPAPRDRConnectorClass *func_drck;
- sPAPRDREntitySense state;
+ SpaprDrc *func_drc;
+ SpaprDrcClass *func_drck;
+ SpaprDREntitySense state;
int i;
/* ensure any other present functions are pending unplug */
@@ -1573,7 +1573,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
static void spapr_phb_finalizefn(Object *obj)
{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(obj);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(obj);
g_free(sphb->dtbusname);
sphb->dtbusname = NULL;
@@ -1581,11 +1581,11 @@ static void spapr_phb_finalizefn(Object *obj)
static void spapr_phb_unrealize(DeviceState *dev, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
SysBusDevice *s = SYS_BUS_DEVICE(dev);
PCIHostState *phb = PCI_HOST_BRIDGE(s);
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(phb);
- sPAPRTCETable *tcet;
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(phb);
+ SpaprTceTable *tcet;
int i;
const unsigned windows_supported = spapr_phb_windows_supported(sphb);
@@ -1608,7 +1608,7 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp)
if (sphb->dr_enabled) {
for (i = PCI_SLOT_MAX * 8 - 1; i >= 0; i--) {
- sPAPRDRConnector *drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PCI,
+ SpaprDrc *drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PCI,
(sphb->index << 16) | i);
if (drc) {
@@ -1645,18 +1645,18 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
/* We don't use SPAPR_MACHINE() in order to exit gracefully if the user
* tries to add a sPAPR PHB to a non-pseries machine.
*/
- sPAPRMachineState *spapr =
- (sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(),
+ SpaprMachineState *spapr =
+ (SpaprMachineState *) object_dynamic_cast(qdev_get_machine(),
TYPE_SPAPR_MACHINE);
- sPAPRMachineClass *smc = spapr ? SPAPR_MACHINE_GET_CLASS(spapr) : NULL;
+ SpaprMachineClass *smc = spapr ? SPAPR_MACHINE_GET_CLASS(spapr) : NULL;
SysBusDevice *s = SYS_BUS_DEVICE(dev);
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
PCIHostState *phb = PCI_HOST_BRIDGE(s);
char *namebuf;
int i;
PCIBus *bus;
uint64_t msi_window_size = 4096;
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
const unsigned windows_supported = spapr_phb_windows_supported(sphb);
if (!spapr) {
@@ -1855,10 +1855,10 @@ static int spapr_phb_children_reset(Object *child, void *opaque)
return 0;
}
-void spapr_phb_dma_reset(sPAPRPHBState *sphb)
+void spapr_phb_dma_reset(SpaprPhbState *sphb)
{
int i;
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
for (i = 0; i < SPAPR_PCI_DMA_MAX_WINDOWS; ++i) {
tcet = spapr_tce_find_by_liobn(sphb->dma_liobn[i]);
@@ -1876,7 +1876,7 @@ void spapr_phb_dma_reset(sPAPRPHBState *sphb)
static void spapr_phb_reset(DeviceState *qdev)
{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(qdev);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(qdev);
spapr_phb_dma_reset(sphb);
@@ -1889,27 +1889,27 @@ static void spapr_phb_reset(DeviceState *qdev)
}
static Property spapr_phb_properties[] = {
- DEFINE_PROP_UINT32("index", sPAPRPHBState, index, -1),
- DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size,
+ DEFINE_PROP_UINT32("index", SpaprPhbState, index, -1),
+ DEFINE_PROP_UINT64("mem_win_size", SpaprPhbState, mem_win_size,
SPAPR_PCI_MEM32_WIN_SIZE),
- DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size,
+ DEFINE_PROP_UINT64("mem64_win_size", SpaprPhbState, mem64_win_size,
SPAPR_PCI_MEM64_WIN_SIZE),
- DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_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,
+ 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),
- DEFINE_PROP_UINT64("dma64_win_addr", sPAPRPHBState, dma64_win_addr,
+ DEFINE_PROP_UINT64("dma_win_addr", SpaprPhbState, dma_win_addr, 0),
+ DEFINE_PROP_UINT64("dma_win_size", SpaprPhbState, dma_win_size, 0x40000000),
+ DEFINE_PROP_UINT64("dma64_win_addr", SpaprPhbState, dma64_win_addr,
0x800000000000000ULL),
- DEFINE_PROP_BOOL("ddw", sPAPRPHBState, ddw_enabled, true),
- DEFINE_PROP_UINT64("pgsz", sPAPRPHBState, page_size_mask,
+ DEFINE_PROP_BOOL("ddw", SpaprPhbState, ddw_enabled, true),
+ DEFINE_PROP_UINT64("pgsz", SpaprPhbState, page_size_mask,
(1ULL << 12) | (1ULL << 16)),
- DEFINE_PROP_UINT32("numa_node", sPAPRPHBState, numa_node, -1),
- DEFINE_PROP_BOOL("pre-2.8-migration", sPAPRPHBState,
+ 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,
+ DEFINE_PROP_BOOL("pcie-extended-configuration-space", SpaprPhbState,
pcie_ecs, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1939,7 +1939,7 @@ static const VMStateDescription vmstate_spapr_pci_msi = {
static int spapr_pci_pre_save(void *opaque)
{
- sPAPRPHBState *sphb = opaque;
+ SpaprPhbState *sphb = opaque;
GHashTableIter iter;
gpointer key, value;
int i;
@@ -1977,7 +1977,7 @@ static int spapr_pci_pre_save(void *opaque)
static int spapr_pci_post_load(void *opaque, int version_id)
{
- sPAPRPHBState *sphb = opaque;
+ SpaprPhbState *sphb = opaque;
gpointer key, value;
int i;
@@ -1997,7 +1997,7 @@ static int spapr_pci_post_load(void *opaque, int version_id)
static bool pre_2_8_migration(void *opaque, int version_id)
{
- sPAPRPHBState *sphb = opaque;
+ SpaprPhbState *sphb = opaque;
return sphb->pre_2_8_migration;
}
@@ -2009,16 +2009,16 @@ static const VMStateDescription vmstate_spapr_pci = {
.pre_save = spapr_pci_pre_save,
.post_load = spapr_pci_post_load,
.fields = (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_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, struct spapr_pci_lsi),
- VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
- VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, sPAPRPHBState, msi_devs_num, 0,
+ VMSTATE_INT32(msi_devs_num, SpaprPhbState),
+ VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, SpaprPhbState, msi_devs_num, 0,
vmstate_spapr_pci_msi, spapr_pci_msi_mig),
VMSTATE_END_OF_LIST()
},
@@ -2027,7 +2027,7 @@ static const VMStateDescription vmstate_spapr_pci = {
static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
- sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(host_bridge);
+ SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(host_bridge);
return sphb->dtbusname;
}
@@ -2055,7 +2055,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
static const TypeInfo spapr_phb_info = {
.name = TYPE_SPAPR_PCI_HOST_BRIDGE,
.parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(sPAPRPHBState),
+ .instance_size = sizeof(SpaprPhbState),
.instance_finalize = spapr_phb_finalizefn,
.class_init = spapr_phb_class_init,
.interfaces = (InterfaceInfo[]) {
@@ -2064,19 +2064,19 @@ static const TypeInfo spapr_phb_info = {
}
};
-typedef struct sPAPRFDT {
+typedef struct SpaprFdt {
void *fdt;
int node_off;
- sPAPRPHBState *sphb;
-} sPAPRFDT;
+ SpaprPhbState *sphb;
+} SpaprFdt;
static void spapr_populate_pci_devices_dt(PCIBus *bus, PCIDevice *pdev,
void *opaque)
{
PCIBus *sec_bus;
- sPAPRFDT *p = opaque;
+ SpaprFdt *p = opaque;
int offset;
- sPAPRFDT s_fdt;
+ SpaprFdt s_fdt;
offset = spapr_create_pci_child_dt(p->sphb, pdev, p->fdt, p->node_off);
if (!offset) {
@@ -2128,7 +2128,7 @@ static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, *bus_no, 1);
}
-static void spapr_phb_pci_enumerate(sPAPRPHBState *phb)
+static void spapr_phb_pci_enumerate(SpaprPhbState *phb)
{
PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus;
unsigned int bus_no = 0;
@@ -2139,7 +2139,7 @@ static void spapr_phb_pci_enumerate(sPAPRPHBState *phb)
}
-int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t intc_phandle, void *fdt,
+int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
uint32_t nr_msis, int *node_offset)
{
int bus_off, i, j, ret;
@@ -2187,10 +2187,10 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t intc_phandle, void *fdt,
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(phb->numa_node)};
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus;
- sPAPRFDT s_fdt;
- sPAPRDRConnector *drc;
+ SpaprFdt s_fdt;
+ SpaprDrc *drc;
/* Start populating the FDT */
nodename = g_strdup_printf("pci@%" PRIx64, phb->buid);
@@ -2345,8 +2345,8 @@ static int spapr_switch_one_vga(DeviceState *dev, void *opaque)
void spapr_pci_switch_vga(bool big_endian)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- sPAPRPHBState *sphb;
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprPhbState *sphb;
/*
* For backward compatibility with existing guests, we switch
diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c
index 71491dbd28..5f5dde567d 100644
--- a/hw/ppc/spapr_pci_vfio.c
+++ b/hw/ppc/spapr_pci_vfio.c
@@ -28,12 +28,12 @@
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
-bool spapr_phb_eeh_available(sPAPRPHBState *sphb)
+bool spapr_phb_eeh_available(SpaprPhbState *sphb)
{
return vfio_eeh_as_ok(&sphb->iommu_as);
}
-static void spapr_phb_vfio_eeh_reenable(sPAPRPHBState *sphb)
+static void spapr_phb_vfio_eeh_reenable(SpaprPhbState *sphb)
{
vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_ENABLE);
}
@@ -49,7 +49,7 @@ void spapr_phb_vfio_reset(DeviceState *qdev)
spapr_phb_vfio_eeh_reenable(SPAPR_PCI_HOST_BRIDGE(qdev));
}
-int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
+int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
unsigned int addr, int option)
{
uint32_t op;
@@ -96,7 +96,7 @@ int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
return RTAS_OUT_SUCCESS;
}
-int spapr_phb_vfio_eeh_get_state(sPAPRPHBState *sphb, int *state)
+int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state)
{
int ret;
@@ -145,14 +145,14 @@ static void spapr_phb_vfio_eeh_clear_bus_msix(PCIBus *bus, void *opaque)
spapr_phb_vfio_eeh_clear_dev_msix, NULL);
}
-static void spapr_phb_vfio_eeh_pre_reset(sPAPRPHBState *sphb)
+static void spapr_phb_vfio_eeh_pre_reset(SpaprPhbState *sphb)
{
PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
pci_for_each_bus(phb->bus, spapr_phb_vfio_eeh_clear_bus_msix, NULL);
}
-int spapr_phb_vfio_eeh_reset(sPAPRPHBState *sphb, int option)
+int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
{
uint32_t op;
int ret;
@@ -181,7 +181,7 @@ int spapr_phb_vfio_eeh_reset(sPAPRPHBState *sphb, int option)
return RTAS_OUT_SUCCESS;
}
-int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb)
+int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
{
int ret;
diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c
index 644bac96f8..4060987590 100644
--- a/hw/ppc/spapr_rng.c
+++ b/hw/ppc/spapr_rng.c
@@ -29,15 +29,15 @@
#include "kvm_ppc.h"
#define SPAPR_RNG(obj) \
- OBJECT_CHECK(sPAPRRngState, (obj), TYPE_SPAPR_RNG)
+ OBJECT_CHECK(SpaprRngState, (obj), TYPE_SPAPR_RNG)
-struct sPAPRRngState {
+struct SpaprRngState {
/*< private >*/
DeviceState ds;
RngBackend *backend;
bool use_kvm;
};
-typedef struct sPAPRRngState sPAPRRngState;
+typedef struct SpaprRngState SpaprRngState;
struct HRandomData {
QemuSemaphore sem;
@@ -64,10 +64,10 @@ static void random_recv(void *dest, const void *src, size_t size)
}
/* Handler for the H_RANDOM hypercall */
-static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_random(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- sPAPRRngState *rngstate;
+ SpaprRngState *rngstate;
HRandomData hrdata;
rngstate = SPAPR_RNG(object_resolve_path_type("", TYPE_SPAPR_RNG, NULL));
@@ -109,7 +109,7 @@ static void spapr_rng_instance_init(Object *obj)
static void spapr_rng_realize(DeviceState *dev, Error **errp)
{
- sPAPRRngState *rngstate = SPAPR_RNG(dev);
+ SpaprRngState *rngstate = SPAPR_RNG(dev);
if (rngstate->use_kvm) {
if (kvmppc_enable_hwrng() == 0) {
@@ -133,8 +133,8 @@ static void spapr_rng_realize(DeviceState *dev, Error **errp)
}
static Property spapr_rng_properties[] = {
- DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false),
- DEFINE_PROP_LINK("rng", sPAPRRngState, backend, TYPE_RNG_BACKEND,
+ DEFINE_PROP_BOOL("use-kvm", SpaprRngState, use_kvm, false),
+ DEFINE_PROP_LINK("rng", SpaprRngState, backend, TYPE_RNG_BACKEND,
RngBackend *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -152,7 +152,7 @@ static void spapr_rng_class_init(ObjectClass *oc, void *data)
static const TypeInfo spapr_rng_info = {
.name = TYPE_SPAPR_RNG,
.parent = TYPE_DEVICE,
- .instance_size = sizeof(sPAPRRngState),
+ .instance_size = sizeof(SpaprRngState),
.instance_init = spapr_rng_instance_init,
.class_init = spapr_rng_class_init,
};
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 7a2cb786a3..24c45b12d4 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -50,13 +50,13 @@
#include "target/ppc/mmu-hash64.h"
#include "target/ppc/mmu-book3s-v3.h"
-static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_display_character(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
uint8_t c = rtas_ld(args, 0);
- VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
+ SpaprVioDevice *sdev = vty_lookup(spapr, 0);
if (!sdev) {
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
@@ -66,7 +66,7 @@ static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
}
-static void rtas_power_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_power_off(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
@@ -79,7 +79,7 @@ static void rtas_power_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void rtas_system_reboot(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_system_reboot(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -93,7 +93,7 @@ static void rtas_system_reboot(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -123,7 +123,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
-static void rtas_start_cpu(PowerPCCPU *callcpu, sPAPRMachineState *spapr,
+static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -194,7 +194,7 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -226,7 +226,7 @@ static inline int sysparm_st(target_ulong addr, target_ulong len,
}
static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -268,7 +268,7 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
}
static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -288,7 +288,7 @@ static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
}
static void rtas_ibm_os_term(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -298,7 +298,7 @@ static void rtas_ibm_os_term(PowerPCCPU *cpu,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void rtas_set_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_set_power_level(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
@@ -323,7 +323,7 @@ static void rtas_set_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 1, 100);
}
-static void rtas_get_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_get_power_level(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
@@ -353,7 +353,7 @@ static struct rtas_call {
spapr_rtas_fn fn;
} rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE];
-target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+target_ulong spapr_rtas_call(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
@@ -387,7 +387,7 @@ uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) {
if (strcmp(cmd, rtas_table[token].name) == 0) {
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE,
@@ -425,7 +425,7 @@ void spapr_dt_rtas_tokens(void *fdt, int rtas)
}
}
-void spapr_load_rtas(sPAPRMachineState *spapr, void *fdt, hwaddr addr)
+void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr)
{
int rtas_node;
int ret;
diff --git a/hw/ppc/spapr_rtas_ddw.c b/hw/ppc/spapr_rtas_ddw.c
index cb8a410359..f6538189f4 100644
--- a/hw/ppc/spapr_rtas_ddw.c
+++ b/hw/ppc/spapr_rtas_ddw.c
@@ -26,16 +26,16 @@
static int spapr_phb_get_active_win_num_cb(Object *child, void *opaque)
{
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
- tcet = (sPAPRTCETable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE);
+ tcet = (SpaprTceTable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE);
if (tcet && tcet->nb_table) {
++*(unsigned *)opaque;
}
return 0;
}
-static unsigned spapr_phb_get_active_win_num(sPAPRPHBState *sphb)
+static unsigned spapr_phb_get_active_win_num(SpaprPhbState *sphb)
{
unsigned ret = 0;
@@ -46,9 +46,9 @@ static unsigned spapr_phb_get_active_win_num(sPAPRPHBState *sphb)
static int spapr_phb_get_free_liobn_cb(Object *child, void *opaque)
{
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
- tcet = (sPAPRTCETable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE);
+ tcet = (SpaprTceTable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE);
if (tcet && !tcet->nb_table) {
*(uint32_t *)opaque = tcet->liobn;
return 1;
@@ -56,7 +56,7 @@ static int spapr_phb_get_free_liobn_cb(Object *child, void *opaque)
return 0;
}
-static unsigned spapr_phb_get_free_liobn(sPAPRPHBState *sphb)
+static unsigned spapr_phb_get_free_liobn(SpaprPhbState *sphb)
{
uint32_t liobn = 0;
@@ -90,12 +90,12 @@ static uint32_t spapr_page_mask_to_query_mask(uint64_t page_mask)
}
static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
uint64_t buid;
uint32_t avail, addr, pgmask = 0;
@@ -129,13 +129,13 @@ param_error_exit:
}
static void rtas_ibm_create_pe_dma_window(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- sPAPRPHBState *sphb;
- sPAPRTCETable *tcet = NULL;
+ SpaprPhbState *sphb;
+ SpaprTceTable *tcet = NULL;
uint32_t addr, page_shift, window_shift, liobn;
uint64_t buid, win_addr;
int windows;
@@ -171,8 +171,18 @@ static void rtas_ibm_create_pe_dma_window(PowerPCCPU *cpu,
}
win_addr = (windows == 0) ? sphb->dma_win_addr : sphb->dma64_win_addr;
+ /*
+ * We have just created a window, we know for the fact that it is empty,
+ * use a hack to avoid iterating over the table as it is quite possible
+ * to have billions of TCEs, all empty.
+ * Note that we cannot delay this to the first H_PUT_TCE as this hcall is
+ * mostly likely to be handled in KVM so QEMU just does not know if it
+ * happened.
+ */
+ tcet->skipping_replay = true;
spapr_tce_table_enable(tcet, page_shift, win_addr,
1ULL << (window_shift - page_shift));
+ tcet->skipping_replay = false;
if (!tcet->nb_table) {
goto hw_error_exit;
}
@@ -196,13 +206,13 @@ param_error_exit:
}
static void rtas_ibm_remove_pe_dma_window(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- sPAPRPHBState *sphb;
- sPAPRTCETable *tcet;
+ SpaprPhbState *sphb;
+ SpaprTceTable *tcet;
uint32_t liobn;
if ((nargs != 1) || (nret != 1)) {
@@ -231,12 +241,12 @@ param_error_exit:
}
static void rtas_ibm_reset_pe_dma_window(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- sPAPRPHBState *sphb;
+ SpaprPhbState *sphb;
uint64_t buid;
uint32_t addr;
diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c
index eb95a7077d..d732a3ea95 100644
--- a/hw/ppc/spapr_rtc.c
+++ b/hw/ppc/spapr_rtc.c
@@ -34,7 +34,7 @@
#include "qapi/qapi-events-target.h"
#include "qemu/cutils.h"
-void spapr_rtc_read(sPAPRRTCState *rtc, struct tm *tm, uint32_t *ns)
+void spapr_rtc_read(SpaprRtcState *rtc, struct tm *tm, uint32_t *ns)
{
int64_t host_ns = qemu_clock_get_ns(rtc_clock);
int64_t guest_ns;
@@ -53,7 +53,7 @@ void spapr_rtc_read(sPAPRRTCState *rtc, struct tm *tm, uint32_t *ns)
}
}
-int spapr_rtc_import_offset(sPAPRRTCState *rtc, int64_t legacy_offset)
+int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset)
{
if (!rtc) {
return -ENODEV;
@@ -64,7 +64,7 @@ int spapr_rtc_import_offset(sPAPRRTCState *rtc, int64_t legacy_offset)
return 0;
}
-static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_get_time_of_day(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
@@ -89,12 +89,12 @@ static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 7, ns);
}
-static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_set_time_of_day(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- sPAPRRTCState *rtc = &spapr->rtc;
+ SpaprRtcState *rtc = &spapr->rtc;
struct tm tm;
time_t new_s;
int64_t host_ns;
@@ -134,7 +134,7 @@ static void spapr_rtc_qom_date(Object *obj, struct tm *current_tm, Error **errp)
static void spapr_rtc_realize(DeviceState *dev, Error **errp)
{
- sPAPRRTCState *rtc = SPAPR_RTC(dev);
+ SpaprRtcState *rtc = SPAPR_RTC(dev);
struct tm tm;
time_t host_s;
int64_t rtc_ns;
@@ -154,7 +154,7 @@ static const VMStateDescription vmstate_spapr_rtc = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_INT64(ns_offset, sPAPRRTCState),
+ VMSTATE_INT64(ns_offset, SpaprRtcState),
VMSTATE_END_OF_LIST()
},
};
@@ -177,7 +177,7 @@ static void spapr_rtc_class_init(ObjectClass *oc, void *data)
static const TypeInfo spapr_rtc_info = {
.name = TYPE_SPAPR_RTC,
.parent = TYPE_DEVICE,
- .instance_size = sizeof(sPAPRRTCState),
+ .instance_size = sizeof(SpaprRtcState),
.class_init = spapr_rtc_class_init,
};
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 2b7e7ecac5..583c13deda 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -46,8 +46,8 @@
static char *spapr_vio_get_dev_name(DeviceState *qdev)
{
- VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+ SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev);
+ SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
/* Device tree style name device@reg */
return g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
@@ -65,16 +65,16 @@ static const TypeInfo spapr_vio_bus_info = {
.name = TYPE_SPAPR_VIO_BUS,
.parent = TYPE_BUS,
.class_init = spapr_vio_bus_class_init,
- .instance_size = sizeof(VIOsPAPRBus),
+ .instance_size = sizeof(SpaprVioBus),
};
-VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
+SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg)
{
BusChild *kid;
- VIOsPAPRDevice *dev = NULL;
+ SpaprVioDevice *dev = NULL;
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- dev = (VIOsPAPRDevice *)kid->child;
+ dev = (SpaprVioDevice *)kid->child;
if (dev->reg == reg) {
return dev;
}
@@ -83,10 +83,10 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
return NULL;
}
-static int vio_make_devnode(VIOsPAPRDevice *dev,
+static int vio_make_devnode(SpaprVioDevice *dev,
void *fdt)
{
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+ SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
int vdevice_off, node_off, ret;
char *dt_name;
@@ -152,13 +152,13 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
/*
* CRQ handling
*/
-static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_reg_crq(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
target_ulong queue_addr = args[1];
target_ulong queue_len = args[2];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
@@ -197,7 +197,7 @@ static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-static target_ulong free_crq(VIOsPAPRDevice *dev)
+static target_ulong free_crq(SpaprVioDevice *dev)
{
dev->crq.qladdr = 0;
dev->crq.qsize = 0;
@@ -208,11 +208,11 @@ static target_ulong free_crq(VIOsPAPRDevice *dev)
return H_SUCCESS;
}
-static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_free_crq(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
@@ -222,13 +222,13 @@ static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return free_crq(dev);
}
-static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_send_crq(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
target_ulong msg_hi = args[1];
target_ulong msg_lo = args[2];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
uint64_t crq_mangle[2];
if (!dev) {
@@ -245,11 +245,11 @@ static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_HARDWARE;
}
-static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_enable_crq(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong reg = args[0];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
@@ -260,7 +260,7 @@ static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
/* Returns negative error, 0 success, or positive: queue full */
-int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
+int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq)
{
int rc;
uint8_t byte;
@@ -303,7 +303,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
/* "quiesce" handling */
-static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
+static void spapr_vio_quiesce_one(SpaprVioDevice *dev)
{
if (dev->tcet) {
device_reset(DEVICE(dev->tcet));
@@ -311,7 +311,7 @@ static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
free_crq(dev);
}
-void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass)
+void spapr_vio_set_bypass(SpaprVioDevice *dev, bool bypass)
{
if (!dev->tcet) {
return;
@@ -323,13 +323,13 @@ void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass)
dev->tcet->bypass = bypass;
}
-static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_set_tce_bypass(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
- VIOsPAPRBus *bus = spapr->vio_bus;
- VIOsPAPRDevice *dev;
+ SpaprVioBus *bus = spapr->vio_bus;
+ SpaprVioDevice *dev;
uint32_t unit, enable;
if (nargs != 2) {
@@ -354,14 +354,14 @@ static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void rtas_quiesce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static void rtas_quiesce(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
- VIOsPAPRBus *bus = spapr->vio_bus;
+ SpaprVioBus *bus = spapr->vio_bus;
BusChild *kid;
- VIOsPAPRDevice *dev = NULL;
+ SpaprVioDevice *dev = NULL;
if (nargs != 0) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -369,18 +369,18 @@ static void rtas_quiesce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- dev = (VIOsPAPRDevice *)kid->child;
+ dev = (SpaprVioDevice *)kid->child;
spapr_vio_quiesce_one(dev);
}
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
+static SpaprVioDevice *reg_conflict(SpaprVioDevice *dev)
{
- VIOsPAPRBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
+ SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
BusChild *kid;
- VIOsPAPRDevice *other;
+ SpaprVioDevice *other;
/*
* Check for a device other than the given one which is already
@@ -400,8 +400,8 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
static void spapr_vio_busdev_reset(DeviceState *qdev)
{
- VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+ SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev);
+ SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
/* Shut down the request queue and TCEs if necessary */
spapr_vio_quiesce_one(dev);
@@ -465,9 +465,9 @@ static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg)
static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
- VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprVioDevice *dev = (SpaprVioDevice *)qdev;
+ SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
char *id;
Error *local_err = NULL;
@@ -478,7 +478,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
* rather than using spapr_vio_find_by_reg() because sdev
* itself is already in the list.
*/
- VIOsPAPRDevice *other = reg_conflict(dev);
+ SpaprVioDevice *other = reg_conflict(dev);
if (other) {
error_setg(errp, "%s and %s devices conflict at address %#x",
@@ -489,7 +489,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
}
} else {
/* Need to assign an address */
- VIOsPAPRBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
+ SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
do {
dev->reg = bus->next_reg++;
@@ -540,14 +540,14 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
pc->realize(dev, errp);
}
-static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_vio_signal(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong reg = args[0];
target_ulong mode = args[1];
- VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRDeviceClass *pc;
+ SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ SpaprVioDeviceClass *pc;
if (!dev) {
return H_PARAMETER;
@@ -564,9 +564,9 @@ static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
-VIOsPAPRBus *spapr_vio_bus_init(void)
+SpaprVioBus *spapr_vio_bus_init(void)
{
- VIOsPAPRBus *bus;
+ SpaprVioBus *bus;
BusState *qbus;
DeviceState *dev;
@@ -615,14 +615,14 @@ const VMStateDescription vmstate_spapr_vio = {
.minimum_version_id = 1,
.fields = (VMStateField[]) {
/* Sanity check */
- VMSTATE_UINT32_EQUAL(reg, VIOsPAPRDevice, NULL),
- VMSTATE_UINT32_EQUAL(irq, VIOsPAPRDevice, NULL),
+ VMSTATE_UINT32_EQUAL(reg, SpaprVioDevice, NULL),
+ VMSTATE_UINT32_EQUAL(irq, SpaprVioDevice, NULL),
/* General VIO device state */
- VMSTATE_UINT64(signal_state, VIOsPAPRDevice),
- VMSTATE_UINT64(crq.qladdr, VIOsPAPRDevice),
- VMSTATE_UINT32(crq.qsize, VIOsPAPRDevice),
- VMSTATE_UINT32(crq.qnext, VIOsPAPRDevice),
+ VMSTATE_UINT64(signal_state, SpaprVioDevice),
+ VMSTATE_UINT64(crq.qladdr, SpaprVioDevice),
+ VMSTATE_UINT32(crq.qsize, SpaprVioDevice),
+ VMSTATE_UINT32(crq.qnext, SpaprVioDevice),
VMSTATE_END_OF_LIST()
},
@@ -639,9 +639,9 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
static const TypeInfo spapr_vio_type_info = {
.name = TYPE_VIO_SPAPR_DEVICE,
.parent = TYPE_DEVICE,
- .instance_size = sizeof(VIOsPAPRDevice),
+ .instance_size = sizeof(SpaprVioDevice),
.abstract = true,
- .class_size = sizeof(VIOsPAPRDeviceClass),
+ .class_size = sizeof(SpaprVioDeviceClass),
.class_init = vio_spapr_device_class_init,
};
@@ -656,10 +656,10 @@ type_init(spapr_vio_register_types)
static int compare_reg(const void *p1, const void *p2)
{
- VIOsPAPRDevice const *dev1, *dev2;
+ SpaprVioDevice const *dev1, *dev2;
- dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
- dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
+ dev1 = (SpaprVioDevice *)*(DeviceState **)p1;
+ dev2 = (SpaprVioDevice *)*(DeviceState **)p2;
if (dev1->reg < dev2->reg) {
return -1;
@@ -672,7 +672,7 @@ static int compare_reg(const void *p1, const void *p2)
return 1;
}
-void spapr_dt_vdevice(VIOsPAPRBus *bus, void *fdt)
+void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt)
{
DeviceState *qdev, **qdevs;
BusChild *kid;
@@ -707,8 +707,8 @@ void spapr_dt_vdevice(VIOsPAPRBus *bus, void *fdt)
/* Hack alert. Give the devices to libfdt in reverse order, we happen
* to know that will mean they are in forward order in the tree. */
for (i = num - 1; i >= 0; i--) {
- VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
- VIOsPAPRDeviceClass *vdc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+ SpaprVioDevice *dev = (SpaprVioDevice *)(qdevs[i]);
+ SpaprVioDeviceClass *vdc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
ret = vio_make_devnode(dev, fdt);
if (ret < 0) {
@@ -721,9 +721,9 @@ void spapr_dt_vdevice(VIOsPAPRBus *bus, void *fdt)
g_free(qdevs);
}
-gchar *spapr_vio_stdout_path(VIOsPAPRBus *bus)
+gchar *spapr_vio_stdout_path(SpaprVioBus *bus)
{
- VIOsPAPRDevice *dev;
+ SpaprVioDevice *dev;
char *name, *path;
dev = spapr_vty_get_default(bus);
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 26e2312006..0e4c7409e0 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -226,10 +226,9 @@ static void virtex_init(MachineState *machine)
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(PFLASH_BASEADDR, NULL, "virtex.flash", FLASH_SIZE,
+ pflash_cfi01_register(PFLASH_BASEADDR, "virtex.flash", FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- 64 * KiB, FLASH_SIZE >> 16,
- 1, 0x89, 0x18, 0x0000, 0x0, 1);
+ 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1);
cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
dev = qdev_create(NULL, "xlnx.xps-intc");
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index a9e49c7cb5..26dfc0340f 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -91,7 +91,7 @@ typedef struct vscsi_req {
OBJECT_CHECK(VSCSIState, (obj), TYPE_VIO_SPAPR_VSCSI_DEVICE)
typedef struct {
- VIOsPAPRDevice vdev;
+ SpaprVioDevice vdev;
SCSIBus bus;
vscsi_req reqs[VSCSI_REQ_LIMIT];
} VSCSIState;
@@ -1115,7 +1115,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
}
-static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
+static int vscsi_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
{
VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
vscsi_crq crq;
@@ -1187,7 +1187,7 @@ static const struct SCSIBusInfo vscsi_scsi_info = {
.load_request = vscsi_load_request,
};
-static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
+static void spapr_vscsi_reset(SpaprVioDevice *dev)
{
VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
int i;
@@ -1198,7 +1198,7 @@ static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
}
}
-static void spapr_vscsi_realize(VIOsPAPRDevice *dev, Error **errp)
+static void spapr_vscsi_realize(SpaprVioDevice *dev, Error **errp)
{
VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
@@ -1208,7 +1208,7 @@ static void spapr_vscsi_realize(VIOsPAPRDevice *dev, Error **errp)
&vscsi_scsi_info, NULL);
}
-void spapr_vscsi_create(VIOsPAPRBus *bus)
+void spapr_vscsi_create(SpaprVioBus *bus)
{
DeviceState *dev;
@@ -1218,7 +1218,7 @@ void spapr_vscsi_create(VIOsPAPRBus *bus)
scsi_bus_legacy_handle_cmdline(&VIO_SPAPR_VSCSI_DEVICE(dev)->bus);
}
-static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+static int spapr_vscsi_devnode(SpaprVioDevice *dev, void *fdt, int node_off)
{
int ret;
@@ -1256,7 +1256,7 @@ static const VMStateDescription vmstate_spapr_vscsi = {
static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->realize = spapr_vscsi_realize;
k->reset = spapr_vscsi_reset;
diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c
index 6728878a52..8b1e6876db 100644
--- a/hw/scsi/vhost-user-scsi.c
+++ b/hw/scsi/vhost-user-scsi.c
@@ -69,7 +69,6 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp)
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
VHostUserSCSI *s = VHOST_USER_SCSI(dev);
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
- VhostUserState *user;
Error *err = NULL;
int ret;
@@ -86,30 +85,24 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp)
return;
}
- user = vhost_user_init();
- if (!user) {
- error_setg(errp, "vhost-user-scsi: failed to init vhost_user");
+ if (!vhost_user_init(&s->vhost_user, &vs->conf.chardev, errp)) {
return;
}
- user->chr = &vs->conf.chardev;
vsc->dev.nvqs = 2 + vs->conf.num_queues;
vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs);
vsc->dev.vq_index = 0;
vsc->dev.backend_features = 0;
- ret = vhost_dev_init(&vsc->dev, user,
+ ret = vhost_dev_init(&vsc->dev, &s->vhost_user,
VHOST_BACKEND_TYPE_USER, 0);
if (ret < 0) {
error_setg(errp, "vhost-user-scsi: vhost initialization failed: %s",
strerror(-ret));
- vhost_user_cleanup(user);
- g_free(user);
+ vhost_user_cleanup(&s->vhost_user);
return;
}
- s->vhost_user = user;
-
/* Channel and lun both are 0 for bootable vhost-user-scsi disk */
vsc->channel = 0;
vsc->lun = 0;
@@ -130,12 +123,7 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp)
g_free(vqs);
virtio_scsi_common_unrealize(dev, errp);
-
- if (s->vhost_user) {
- vhost_user_cleanup(s->vhost_user);
- g_free(s->vhost_user);
- s->vhost_user = NULL;
- }
+ vhost_user_cleanup(&s->vhost_user);
}
static Property vhost_user_scsi_properties[] = {
diff --git a/hw/sd/Kconfig b/hw/sd/Kconfig
index 864f535011..c5e1e5581c 100644
--- a/hw/sd/Kconfig
+++ b/hw/sd/Kconfig
@@ -12,6 +12,10 @@ config SD
config SDHCI
bool
+ select SD
+
+config SDHCI_PCI
+ bool
default y if PCI_DEVICES
depends on PCI
- select SD
+ select SDHCI
diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs
index a99d9fbb04..06657279d1 100644
--- a/hw/sd/Makefile.objs
+++ b/hw/sd/Makefile.objs
@@ -2,6 +2,7 @@ common-obj-$(CONFIG_PL181) += pl181.o
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
common-obj-$(CONFIG_SD) += sd.o core.o sdmmc-internal.o
common-obj-$(CONFIG_SDHCI) += sdhci.o
+common-obj-$(CONFIG_SDHCI_PCI) += sdhci-pci.o
obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
obj-$(CONFIG_OMAP) += omap_mmc.o
diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h
index 19665fd401..34141400f8 100644
--- a/hw/sd/sdhci-internal.h
+++ b/hw/sd/sdhci-internal.h
@@ -304,4 +304,38 @@ extern const VMStateDescription sdhci_vmstate;
#define ESDHC_PRNSTS_SDSTB (1 << 3)
+/*
+ * Default SD/MMC host controller features information, which will be
+ * presented in CAPABILITIES register of generic SD host controller at reset.
+ *
+ * support:
+ * - 3.3v and 1.8v voltages
+ * - SDMA/ADMA1/ADMA2
+ * - high-speed
+ * max host controller R/W buffers size: 512B
+ * max clock frequency for SDclock: 52 MHz
+ * timeout clock frequency: 52 MHz
+ *
+ * does not support:
+ * - 3.0v voltage
+ * - 64-bit system bus
+ * - suspend/resume
+ */
+#define SDHC_CAPAB_REG_DEFAULT 0x057834b4
+
+#define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \
+ DEFINE_PROP_UINT8("sd-spec-version", _state, sd_spec_version, 2), \
+ DEFINE_PROP_UINT8("uhs", _state, uhs_mode, UHS_NOT_SUPPORTED), \
+ \
+ /* Capabilities registers provide information on supported
+ * features of this specific host controller implementation */ \
+ DEFINE_PROP_UINT64("capareg", _state, capareg, SDHC_CAPAB_REG_DEFAULT), \
+ DEFINE_PROP_UINT64("maxcurr", _state, maxcurr, 0)
+
+void sdhci_initfn(SDHCIState *s);
+void sdhci_uninitfn(SDHCIState *s);
+void sdhci_common_realize(SDHCIState *s, Error **errp);
+void sdhci_common_unrealize(SDHCIState *s, Error **errp);
+void sdhci_common_class_init(ObjectClass *klass, void *data);
+
#endif
diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c
new file mode 100644
index 0000000000..f884661862
--- /dev/null
+++ b/hw/sd/sdhci-pci.c
@@ -0,0 +1,87 @@
+/*
+ * SDHCI device on PCI
+ *
+ * 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/sd/sdhci.h"
+#include "sdhci-internal.h"
+
+static Property sdhci_pci_properties[] = {
+ DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
+{
+ SDHCIState *s = PCI_SDHCI(dev);
+ Error *local_err = NULL;
+
+ sdhci_initfn(s);
+ sdhci_common_realize(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */
+ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+ s->irq = pci_allocate_irq(dev);
+ s->dma_as = pci_get_address_space(dev);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem);
+}
+
+static void sdhci_pci_exit(PCIDevice *dev)
+{
+ SDHCIState *s = PCI_SDHCI(dev);
+
+ sdhci_common_unrealize(s, &error_abort);
+ sdhci_uninitfn(s);
+}
+
+static void sdhci_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = sdhci_pci_realize;
+ k->exit = sdhci_pci_exit;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT;
+ k->device_id = PCI_DEVICE_ID_REDHAT_SDHCI;
+ k->class_id = PCI_CLASS_SYSTEM_SDHCI;
+ dc->props = sdhci_pci_properties;
+
+ sdhci_common_class_init(klass, data);
+}
+
+static const TypeInfo sdhci_pci_info = {
+ .name = TYPE_PCI_SDHCI,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(SDHCIState),
+ .class_init = sdhci_pci_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+static void sdhci_pci_register_type(void)
+{
+ type_register_static(&sdhci_pci_info);
+}
+
+type_init(sdhci_pci_register_type)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 83f1574ffd..17ad5465a7 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -40,24 +40,6 @@
#define MASKED_WRITE(reg, mask, val) (reg = (reg & (mask)) | (val))
-/* Default SD/MMC host controller features information, which will be
- * presented in CAPABILITIES register of generic SD host controller at reset.
- *
- * support:
- * - 3.3v and 1.8v voltages
- * - SDMA/ADMA1/ADMA2
- * - high-speed
- * max host controller R/W buffers size: 512B
- * max clock frequency for SDclock: 52 MHz
- * timeout clock frequency: 52 MHz
- *
- * does not support:
- * - 3.0v voltage
- * - 64-bit system bus
- * - suspend/resume
- */
-#define SDHC_CAPAB_REG_DEFAULT 0x057834b4
-
static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
{
return 1 << (9 + FIELD_EX32(s->capareg, SDHC_CAPAB, MAXBLOCKLENGTH));
@@ -1328,16 +1310,7 @@ static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp)
/* --- qdev common --- */
-#define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \
- DEFINE_PROP_UINT8("sd-spec-version", _state, sd_spec_version, 2), \
- DEFINE_PROP_UINT8("uhs", _state, uhs_mode, UHS_NOT_SUPPORTED), \
- \
- /* Capabilities registers provide information on supported
- * features of this specific host controller implementation */ \
- DEFINE_PROP_UINT64("capareg", _state, capareg, SDHC_CAPAB_REG_DEFAULT), \
- DEFINE_PROP_UINT64("maxcurr", _state, maxcurr, 0)
-
-static void sdhci_initfn(SDHCIState *s)
+void sdhci_initfn(SDHCIState *s)
{
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
TYPE_SDHCI_BUS, DEVICE(s), "sd-bus");
@@ -1348,7 +1321,7 @@ static void sdhci_initfn(SDHCIState *s)
s->io_ops = &sdhci_mmio_ops;
}
-static void sdhci_uninitfn(SDHCIState *s)
+void sdhci_uninitfn(SDHCIState *s)
{
timer_del(s->insert_timer);
timer_free(s->insert_timer);
@@ -1359,7 +1332,7 @@ static void sdhci_uninitfn(SDHCIState *s)
s->fifo_buffer = NULL;
}
-static void sdhci_common_realize(SDHCIState *s, Error **errp)
+void sdhci_common_realize(SDHCIState *s, Error **errp)
{
Error *local_err = NULL;
@@ -1375,7 +1348,7 @@ static void sdhci_common_realize(SDHCIState *s, Error **errp)
SDHC_REGISTERS_MAP_SIZE);
}
-static void sdhci_common_unrealize(SDHCIState *s, Error **errp)
+void sdhci_common_unrealize(SDHCIState *s, Error **errp)
{
/* This function is expected to be called only once for each class:
* - SysBus: via DeviceClass->unrealize(),
@@ -1445,7 +1418,7 @@ const VMStateDescription sdhci_vmstate = {
},
};
-static void sdhci_common_class_init(ObjectClass *klass, void *data)
+void sdhci_common_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1454,66 +1427,6 @@ static void sdhci_common_class_init(ObjectClass *klass, void *data)
dc->reset = sdhci_poweron_reset;
}
-/* --- qdev PCI --- */
-
-static Property sdhci_pci_properties[] = {
- DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
-{
- SDHCIState *s = PCI_SDHCI(dev);
- Error *local_err = NULL;
-
- sdhci_initfn(s);
- sdhci_common_realize(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */
- dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
- s->irq = pci_allocate_irq(dev);
- s->dma_as = pci_get_address_space(dev);
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem);
-}
-
-static void sdhci_pci_exit(PCIDevice *dev)
-{
- SDHCIState *s = PCI_SDHCI(dev);
-
- sdhci_common_unrealize(s, &error_abort);
- sdhci_uninitfn(s);
-}
-
-static void sdhci_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = sdhci_pci_realize;
- k->exit = sdhci_pci_exit;
- k->vendor_id = PCI_VENDOR_ID_REDHAT;
- k->device_id = PCI_DEVICE_ID_REDHAT_SDHCI;
- k->class_id = PCI_CLASS_SYSTEM_SDHCI;
- dc->props = sdhci_pci_properties;
-
- sdhci_common_class_init(klass, data);
-}
-
-static const TypeInfo sdhci_pci_info = {
- .name = TYPE_PCI_SDHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(SDHCIState),
- .class_init = sdhci_pci_class_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- { },
- },
-};
-
/* --- qdev SysBus --- */
static Property sdhci_sysbus_properties[] = {
@@ -1846,7 +1759,6 @@ static const TypeInfo imx_usdhc_info = {
static void sdhci_register_types(void)
{
- type_register_static(&sdhci_pci_info);
type_register_static(&sdhci_sysbus_info);
type_register_static(&sdhci_bus_info);
type_register_static(&imx_usdhc_info);
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index 28ed6be05b..0bcb769c85 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -43,7 +43,7 @@
#include "exec/address-spaces.h"
#define FLASH_BASE 0x00000000
-#define FLASH_SIZE 0x02000000
+#define FLASH_SIZE (16 * MiB)
#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
#define SDRAM_SIZE 0x04000000
@@ -287,12 +287,19 @@ static void r2d_init(MachineState *machine)
sysbus_mmio_map(busdev, 1, 0x1400080c);
mmio_ide_init_drives(dev, dinfo, NULL);
- /* onboard flash memory */
+ /*
+ * Onboard flash memory
+ * According to the old board user document in Japanese (under
+ * NDA) what is referred to as FROM (Area0) is connected via a
+ * 32-bit bus and CS0 to CN8. The docs mention a Cypress
+ * S29PL127J60TFI130 chipsset. Per the 'S29PL-J 002-00615
+ * Rev. *E' datasheet, it is a 128Mbit NOR parallel flash
+ * addressable in words of 16bit.
+ */
dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE,
+ pflash_cfi02_register(0x0, "r2d.flash", FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- 16 * KiB, FLASH_SIZE >> 16,
- 1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
+ 64 * KiB, 1, 2, 0x0001, 0x227e, 0x2220, 0x2200,
0x555, 0x2aa, 0);
/* NIC: rtl8139 on-board, and 2 slots. */
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index 28ac7c5165..c46d5eeb79 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -650,7 +650,7 @@ static void usb_audio_realize(USBDevice *dev, Error **errp)
s->out.vol[1] = 240; /* 0 dB */
s->out.as.freq = USBAUDIO_SAMPLE_RATE;
s->out.as.nchannels = 2;
- s->out.as.fmt = AUD_FMT_S16;
+ s->out.as.fmt = AUDIO_FORMAT_S16;
s->out.as.endianness = 0;
streambuf_init(&s->out.buf, s->buffer);
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index df2b4721bf..4374cc6176 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -729,7 +729,7 @@ static void vfio_listener_release(VFIOContainer *container)
}
}
-static struct vfio_info_cap_header *
+struct vfio_info_cap_header *
vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id)
{
struct vfio_info_cap_header *hdr;
diff --git a/hw/vfio/display.c b/hw/vfio/display.c
index dead30e626..a3d9c8f5be 100644
--- a/hw/vfio/display.c
+++ b/hw/vfio/display.c
@@ -15,15 +15,181 @@
#include <sys/ioctl.h>
#include "sysemu/sysemu.h"
+#include "hw/display/edid.h"
#include "ui/console.h"
#include "qapi/error.h"
#include "pci.h"
+#include "trace.h"
#ifndef DRM_PLANE_TYPE_PRIMARY
# define DRM_PLANE_TYPE_PRIMARY 1
# define DRM_PLANE_TYPE_CURSOR 2
#endif
+#define pread_field(_fd, _reg, _ptr, _fld) \
+ (sizeof(_ptr->_fld) != \
+ pread(_fd, &(_ptr->_fld), sizeof(_ptr->_fld), \
+ _reg->offset + offsetof(typeof(*_ptr), _fld)))
+
+#define pwrite_field(_fd, _reg, _ptr, _fld) \
+ (sizeof(_ptr->_fld) != \
+ pwrite(_fd, &(_ptr->_fld), sizeof(_ptr->_fld), \
+ _reg->offset + offsetof(typeof(*_ptr), _fld)))
+
+
+static void vfio_display_edid_link_up(void *opaque)
+{
+ VFIOPCIDevice *vdev = opaque;
+ VFIODisplay *dpy = vdev->dpy;
+ int fd = vdev->vbasedev.fd;
+
+ dpy->edid_regs->link_state = VFIO_DEVICE_GFX_LINK_STATE_UP;
+ if (pwrite_field(fd, dpy->edid_info, dpy->edid_regs, link_state)) {
+ goto err;
+ }
+ trace_vfio_display_edid_link_up();
+ return;
+
+err:
+ trace_vfio_display_edid_write_error();
+}
+
+static void vfio_display_edid_update(VFIOPCIDevice *vdev, bool enabled,
+ int prefx, int prefy)
+{
+ VFIODisplay *dpy = vdev->dpy;
+ int fd = vdev->vbasedev.fd;
+ qemu_edid_info edid = {
+ .maxx = dpy->edid_regs->max_xres,
+ .maxy = dpy->edid_regs->max_yres,
+ .prefx = prefx ?: vdev->display_xres,
+ .prefy = prefy ?: vdev->display_yres,
+ };
+
+ timer_del(dpy->edid_link_timer);
+ dpy->edid_regs->link_state = VFIO_DEVICE_GFX_LINK_STATE_DOWN;
+ if (pwrite_field(fd, dpy->edid_info, dpy->edid_regs, link_state)) {
+ goto err;
+ }
+ trace_vfio_display_edid_link_down();
+
+ if (!enabled) {
+ return;
+ }
+
+ if (edid.maxx && edid.prefx > edid.maxx) {
+ edid.prefx = edid.maxx;
+ }
+ if (edid.maxy && edid.prefy > edid.maxy) {
+ edid.prefy = edid.maxy;
+ }
+ qemu_edid_generate(dpy->edid_blob,
+ dpy->edid_regs->edid_max_size,
+ &edid);
+ trace_vfio_display_edid_update(edid.prefx, edid.prefy);
+
+ dpy->edid_regs->edid_size = qemu_edid_size(dpy->edid_blob);
+ if (pwrite_field(fd, dpy->edid_info, dpy->edid_regs, edid_size)) {
+ goto err;
+ }
+ if (pwrite(fd, dpy->edid_blob, dpy->edid_regs->edid_size,
+ dpy->edid_info->offset + dpy->edid_regs->edid_offset)
+ != dpy->edid_regs->edid_size) {
+ goto err;
+ }
+
+ timer_mod(dpy->edid_link_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 100);
+ return;
+
+err:
+ trace_vfio_display_edid_write_error();
+ return;
+}
+
+static int vfio_display_edid_ui_info(void *opaque, uint32_t idx,
+ QemuUIInfo *info)
+{
+ VFIOPCIDevice *vdev = opaque;
+ VFIODisplay *dpy = vdev->dpy;
+
+ if (!dpy->edid_regs) {
+ return 0;
+ }
+
+ if (info->width && info->height) {
+ vfio_display_edid_update(vdev, true, info->width, info->height);
+ } else {
+ vfio_display_edid_update(vdev, false, 0, 0);
+ }
+
+ return 0;
+}
+
+static void vfio_display_edid_init(VFIOPCIDevice *vdev)
+{
+ VFIODisplay *dpy = vdev->dpy;
+ 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);
+ if (ret) {
+ return;
+ }
+
+ trace_vfio_display_edid_available();
+ dpy->edid_regs = g_new0(struct vfio_region_gfx_edid, 1);
+ if (pread_field(fd, dpy->edid_info, dpy->edid_regs, edid_offset)) {
+ goto err;
+ }
+ if (pread_field(fd, dpy->edid_info, dpy->edid_regs, edid_max_size)) {
+ goto err;
+ }
+ if (pread_field(fd, dpy->edid_info, dpy->edid_regs, max_xres)) {
+ goto err;
+ }
+ if (pread_field(fd, dpy->edid_info, dpy->edid_regs, max_yres)) {
+ goto err;
+ }
+
+ dpy->edid_blob = g_malloc0(dpy->edid_regs->edid_max_size);
+
+ /* if xres + yres properties are unset use the maximum resolution */
+ if (!vdev->display_xres) {
+ vdev->display_xres = dpy->edid_regs->max_xres;
+ }
+ if (!vdev->display_yres) {
+ vdev->display_yres = dpy->edid_regs->max_yres;
+ }
+
+ dpy->edid_link_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+ vfio_display_edid_link_up, vdev);
+
+ vfio_display_edid_update(vdev, true, 0, 0);
+ return;
+
+err:
+ trace_vfio_display_edid_write_error();
+ g_free(dpy->edid_regs);
+ dpy->edid_regs = NULL;
+ return;
+}
+
+static void vfio_display_edid_exit(VFIODisplay *dpy)
+{
+ if (!dpy->edid_regs) {
+ return;
+ }
+
+ g_free(dpy->edid_regs);
+ g_free(dpy->edid_blob);
+ timer_del(dpy->edid_link_timer);
+ timer_free(dpy->edid_link_timer);
+}
+
static void vfio_display_update_cursor(VFIODMABuf *dmabuf,
struct vfio_device_gfx_plane_info *plane)
{
@@ -171,6 +337,7 @@ static void vfio_display_dmabuf_update(void *opaque)
static const GraphicHwOps vfio_display_dmabuf_ops = {
.gfx_update = vfio_display_dmabuf_update,
+ .ui_info = vfio_display_edid_ui_info,
};
static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
@@ -187,6 +354,7 @@ static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
if (vdev->enable_ramfb) {
vdev->dpy->ramfb = ramfb_setup(errp);
}
+ vfio_display_edid_init(vdev);
return 0;
}
@@ -366,5 +534,6 @@ void vfio_display_finalize(VFIOPCIDevice *vdev)
graphic_console_close(vdev->dpy->con);
vfio_display_dmabuf_exit(vdev->dpy);
vfio_display_region_exit(vdev->dpy);
+ vfio_display_edid_exit(vdev->dpy);
g_free(vdev->dpy);
}
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index dd12f36391..504019c458 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3068,6 +3068,16 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
error_setg(errp, "ramfb=on requires display=on");
goto out_teardown;
}
+ if (vdev->display_xres || vdev->display_yres) {
+ if (vdev->dpy == NULL) {
+ error_setg(errp, "xres and yres properties require display=on");
+ goto out_teardown;
+ }
+ if (vdev->dpy->edid_regs == NULL) {
+ error_setg(errp, "xres and yres properties need edid support");
+ goto out_teardown;
+ }
+ }
vfio_register_err_notifier(vdev);
vfio_register_req_notifier(vdev);
@@ -3182,6 +3192,8 @@ static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev),
DEFINE_PROP_ON_OFF_AUTO("display", VFIOPCIDevice,
display, ON_OFF_AUTO_OFF),
+ DEFINE_PROP_UINT32("xres", VFIOPCIDevice, display_xres, 0),
+ DEFINE_PROP_UINT32("yres", VFIOPCIDevice, display_yres, 0),
DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice,
intx.mmap_timeout, 1100),
DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features,
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index b1ae4c0754..c11c3f1670 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -149,6 +149,8 @@ typedef struct VFIOPCIDevice {
#define VFIO_FEATURE_ENABLE_IGD_OPREGION \
(1 << VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT)
OnOffAuto display;
+ uint32_t display_xres;
+ uint32_t display_yres;
int32_t bootindex;
uint32_t igd_gms;
OffAutoPCIBAR msix_relo;
diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index becf71a3fc..57fe758e54 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -143,19 +143,19 @@ int vfio_spapr_create_window(VFIOContainer *container,
MemoryRegionSection *section,
hwaddr *pgsize)
{
- int ret;
+ int ret = 0;
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
- unsigned entries, pages;
+ unsigned entries, bits_total, bits_per_level, max_levels;
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
- long systempagesize = qemu_getrampagesize();
+ long rampagesize = qemu_getrampagesize();
/*
* The host might not support the guest supported IOMMU page size,
* so we will use smaller physical IOMMU pages to back them.
*/
- if (pagesize > systempagesize) {
- pagesize = systempagesize;
+ if (pagesize > rampagesize) {
+ pagesize = rampagesize;
}
pagesize = 1ULL << (63 - clz64(container->pgsizes &
(pagesize | (pagesize - 1))));
@@ -176,16 +176,38 @@ int vfio_spapr_create_window(VFIOContainer *container,
create.window_size = int128_get64(section->size);
create.page_shift = ctz64(pagesize);
/*
- * SPAPR host supports multilevel TCE tables, there is some
- * heuristic to decide how many levels we want for our table:
- * 0..64 = 1; 65..4096 = 2; 4097..262144 = 3; 262145.. = 4
+ * SPAPR host supports multilevel TCE tables. We try to guess optimal
+ * levels number and if this fails (for example due to the host memory
+ * fragmentation), we increase levels. The DMA address structure is:
+ * rrrrrrrr rxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx iiiiiiii
+ * where:
+ * r = reserved (bits >= 55 are reserved in the existing hardware)
+ * i = IOMMU page offset (64K in this example)
+ * x = bits to index a TCE which can be split to equal chunks to index
+ * within the level.
+ * The aim is to split "x" to smaller possible number of levels.
*/
entries = create.window_size >> create.page_shift;
- pages = MAX((entries * sizeof(uint64_t)) / getpagesize(), 1);
- pages = MAX(pow2ceil(pages), 1); /* Round up */
- create.levels = ctz64(pages) / 6 + 1;
-
- ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
+ /* bits_total is number of "x" needed */
+ bits_total = ctz64(entries * sizeof(uint64_t));
+ /*
+ * bits_per_level is a safe guess of how much we can allocate per level:
+ * 8 is the current minimum for CONFIG_FORCE_MAX_ZONEORDER and MAX_ORDER
+ * is usually bigger than that.
+ * Below we look at getpagesize() as TCEs are allocated from system pages.
+ */
+ bits_per_level = ctz64(getpagesize()) + 8;
+ create.levels = bits_total / bits_per_level;
+ if (bits_total % bits_per_level) {
+ ++create.levels;
+ }
+ max_levels = (64 - create.page_shift) / ctz64(getpagesize());
+ for ( ; create.levels <= max_levels; ++create.levels) {
+ ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
+ if (!ret) {
+ break;
+ }
+ }
if (ret) {
error_report("Failed to create a window, ret = %d (%m)", ret);
return -errno;
@@ -200,6 +222,7 @@ int vfio_spapr_create_window(VFIOContainer *container,
return -EINVAL;
}
trace_vfio_spapr_create_window(create.page_shift,
+ create.levels,
create.window_size,
create.start_addr);
*pgsize = pagesize;
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index ed2f333ad7..22019728e0 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -129,6 +129,13 @@ vfio_prereg_listener_region_add_skip(uint64_t start, uint64_t end) "0x%"PRIx64"
vfio_prereg_listener_region_del_skip(uint64_t start, uint64_t end) "0x%"PRIx64" - 0x%"PRIx64
vfio_prereg_register(uint64_t va, uint64_t size, int ret) "va=0x%"PRIx64" size=0x%"PRIx64" ret=%d"
vfio_prereg_unregister(uint64_t va, uint64_t size, int ret) "va=0x%"PRIx64" size=0x%"PRIx64" ret=%d"
-vfio_spapr_create_window(int ps, uint64_t ws, uint64_t off) "pageshift=0x%x winsize=0x%"PRIx64" offset=0x%"PRIx64
+vfio_spapr_create_window(int ps, unsigned int levels, uint64_t ws, uint64_t off) "pageshift=0x%x levels=%u winsize=0x%"PRIx64" offset=0x%"PRIx64
vfio_spapr_remove_window(uint64_t off) "offset=0x%"PRIx64
vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d"
+
+# hw/vfio/display.c
+vfio_display_edid_available(void) ""
+vfio_display_edid_link_up(void) ""
+vfio_display_edid_link_down(void) ""
+vfio_display_edid_update(uint32_t prefx, uint32_t prefy) "%ux%u"
+vfio_display_edid_write_error(void) ""
diff --git a/hw/virtio/vhost-stub.c b/hw/virtio/vhost-stub.c
index 049089b5e2..c175148fce 100644
--- a/hw/virtio/vhost-stub.c
+++ b/hw/virtio/vhost-stub.c
@@ -7,9 +7,9 @@ bool vhost_has_free_slot(void)
return true;
}
-VhostUserState *vhost_user_init(void)
+bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)
{
- return NULL;
+ return false;
}
void vhost_user_cleanup(VhostUserState *user)
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 0d6c64e5ca..553319c7ac 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -56,6 +56,7 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_CONFIG = 9,
VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10,
VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12,
VHOST_USER_PROTOCOL_F_MAX
};
@@ -93,6 +94,8 @@ typedef enum VhostUserRequest {
VHOST_USER_POSTCOPY_ADVISE = 28,
VHOST_USER_POSTCOPY_LISTEN = 29,
VHOST_USER_POSTCOPY_END = 30,
+ VHOST_USER_GET_INFLIGHT_FD = 31,
+ VHOST_USER_SET_INFLIGHT_FD = 32,
VHOST_USER_MAX
} VhostUserRequest;
@@ -151,6 +154,13 @@ typedef struct VhostUserVringArea {
uint64_t offset;
} VhostUserVringArea;
+typedef struct VhostUserInflight {
+ uint64_t mmap_size;
+ uint64_t mmap_offset;
+ uint16_t num_queues;
+ uint16_t queue_size;
+} VhostUserInflight;
+
typedef struct {
VhostUserRequest request;
@@ -173,6 +183,7 @@ typedef union {
VhostUserConfig config;
VhostUserCryptoSession session;
VhostUserVringArea area;
+ VhostUserInflight inflight;
} VhostUserPayload;
typedef struct VhostUserMsg {
@@ -214,7 +225,7 @@ static bool ioeventfd_enabled(void)
return !kvm_enabled() || kvm_eventfds_enabled();
}
-static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
+static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg)
{
struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr;
@@ -225,7 +236,7 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
if (r != size) {
error_report("Failed to read msg header. Read %d instead of %d."
" Original request %d.", r, size, msg->hdr.request);
- goto fail;
+ return -1;
}
/* validate received flags */
@@ -233,7 +244,21 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
error_report("Failed to read msg header."
" Flags 0x%x instead of 0x%x.", msg->hdr.flags,
VHOST_USER_REPLY_MASK | VHOST_USER_VERSION);
- goto fail;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
+{
+ struct vhost_user *u = dev->opaque;
+ CharBackend *chr = u->user->chr;
+ uint8_t *p = (uint8_t *) msg;
+ int r, size;
+
+ if (vhost_user_read_header(dev, msg) < 0) {
+ return -1;
}
/* validate message size is sane */
@@ -241,7 +266,7 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
error_report("Failed to read msg header."
" Size %d exceeds the maximum %zu.", msg->hdr.size,
VHOST_USER_PAYLOAD_SIZE);
- goto fail;
+ return -1;
}
if (msg->hdr.size) {
@@ -251,14 +276,11 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
if (r != size) {
error_report("Failed to read msg payload."
" Read %d instead of %d.", r, msg->hdr.size);
- goto fail;
+ return -1;
}
}
return 0;
-
-fail:
- return -1;
}
static int process_message_reply(struct vhost_dev *dev,
@@ -968,7 +990,10 @@ static void slave_read(void *opaque)
iov.iov_base = &hdr;
iov.iov_len = VHOST_USER_HDR_SIZE;
- size = recvmsg(u->slave_fd, &msgh, 0);
+ do {
+ size = recvmsg(u->slave_fd, &msgh, 0);
+ } while (size < 0 && (errno == EINTR || errno == EAGAIN));
+
if (size != VHOST_USER_HDR_SIZE) {
error_report("Failed to read from slave.");
goto err;
@@ -997,7 +1022,10 @@ static void slave_read(void *opaque)
}
/* Read payload */
- size = read(u->slave_fd, &payload, hdr.size);
+ do {
+ size = read(u->slave_fd, &payload, hdr.size);
+ } while (size < 0 && (errno == EINTR || errno == EAGAIN));
+
if (size != hdr.size) {
error_report("Failed to read payload from slave.");
goto err;
@@ -1045,7 +1073,10 @@ static void slave_read(void *opaque)
iovec[1].iov_base = &payload;
iovec[1].iov_len = hdr.size;
- size = writev(u->slave_fd, iovec, ARRAY_SIZE(iovec));
+ do {
+ size = writev(u->slave_fd, iovec, ARRAY_SIZE(iovec));
+ } while (size < 0 && (errno == EINTR || errno == EAGAIN));
+
if (size != VHOST_USER_HDR_SIZE + hdr.size) {
error_report("Failed to send msg reply to slave.");
goto err;
@@ -1750,17 +1781,118 @@ static bool vhost_user_mem_section_filter(struct vhost_dev *dev,
return result;
}
-VhostUserState *vhost_user_init(void)
+static int vhost_user_get_inflight_fd(struct vhost_dev *dev,
+ uint16_t queue_size,
+ struct vhost_inflight *inflight)
+{
+ void *addr;
+ int fd;
+ struct vhost_user *u = dev->opaque;
+ CharBackend *chr = u->user->chr;
+ VhostUserMsg msg = {
+ .hdr.request = VHOST_USER_GET_INFLIGHT_FD,
+ .hdr.flags = VHOST_USER_VERSION,
+ .payload.inflight.num_queues = dev->nvqs,
+ .payload.inflight.queue_size = queue_size,
+ .hdr.size = sizeof(msg.payload.inflight),
+ };
+
+ if (!virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ return 0;
+ }
+
+ if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
+ return -1;
+ }
+
+ if (vhost_user_read(dev, &msg) < 0) {
+ return -1;
+ }
+
+ if (msg.hdr.request != VHOST_USER_GET_INFLIGHT_FD) {
+ error_report("Received unexpected msg type. "
+ "Expected %d received %d",
+ VHOST_USER_GET_INFLIGHT_FD, msg.hdr.request);
+ return -1;
+ }
+
+ if (msg.hdr.size != sizeof(msg.payload.inflight)) {
+ error_report("Received bad msg size.");
+ return -1;
+ }
+
+ if (!msg.payload.inflight.mmap_size) {
+ return 0;
+ }
+
+ fd = qemu_chr_fe_get_msgfd(chr);
+ if (fd < 0) {
+ error_report("Failed to get mem fd");
+ return -1;
+ }
+
+ addr = mmap(0, msg.payload.inflight.mmap_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, msg.payload.inflight.mmap_offset);
+
+ if (addr == MAP_FAILED) {
+ error_report("Failed to mmap mem fd");
+ close(fd);
+ return -1;
+ }
+
+ inflight->addr = addr;
+ inflight->fd = fd;
+ inflight->size = msg.payload.inflight.mmap_size;
+ inflight->offset = msg.payload.inflight.mmap_offset;
+ inflight->queue_size = queue_size;
+
+ return 0;
+}
+
+static int vhost_user_set_inflight_fd(struct vhost_dev *dev,
+ struct vhost_inflight *inflight)
{
- VhostUserState *user = g_new0(struct VhostUserState, 1);
+ VhostUserMsg msg = {
+ .hdr.request = VHOST_USER_SET_INFLIGHT_FD,
+ .hdr.flags = VHOST_USER_VERSION,
+ .payload.inflight.mmap_size = inflight->size,
+ .payload.inflight.mmap_offset = inflight->offset,
+ .payload.inflight.num_queues = dev->nvqs,
+ .payload.inflight.queue_size = inflight->queue_size,
+ .hdr.size = sizeof(msg.payload.inflight),
+ };
- return user;
+ if (!virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ return 0;
+ }
+
+ if (vhost_user_write(dev, &msg, &inflight->fd, 1) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)
+{
+ if (user->chr) {
+ error_setg(errp, "Cannot initialize vhost-user state");
+ return false;
+ }
+ user->chr = chr;
+ return true;
}
void vhost_user_cleanup(VhostUserState *user)
{
int i;
+ if (!user->chr) {
+ return;
+ }
+
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
if (user->notifier[i].addr) {
object_unparent(OBJECT(&user->notifier[i].mr));
@@ -1768,6 +1900,7 @@ void vhost_user_cleanup(VhostUserState *user)
user->notifier[i].addr = NULL;
}
}
+ user->chr = NULL;
}
const VhostOps user_ops = {
@@ -1801,4 +1934,6 @@ const VhostOps user_ops = {
.vhost_crypto_create_session = vhost_user_crypto_create_session,
.vhost_crypto_close_session = vhost_user_crypto_close_session,
.vhost_backend_mem_section_filter = vhost_user_mem_section_filter,
+ .vhost_get_inflight_fd = vhost_user_get_inflight_fd,
+ .vhost_set_inflight_fd = vhost_user_set_inflight_fd,
};
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 311432f190..7f61018f2a 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1481,6 +1481,102 @@ void vhost_dev_set_config_notifier(struct vhost_dev *hdev,
hdev->config_ops = ops;
}
+void vhost_dev_free_inflight(struct vhost_inflight *inflight)
+{
+ if (inflight->addr) {
+ qemu_memfd_free(inflight->addr, inflight->size, inflight->fd);
+ inflight->addr = NULL;
+ inflight->fd = -1;
+ }
+}
+
+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 -1;
+ }
+
+ 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) {
+ if (vhost_dev_resize_inflight(inflight, size)) {
+ return -1;
+ }
+ }
+ inflight->queue_size = qemu_get_be16(f);
+
+ qemu_get_buffer(f, inflight->addr, size);
+
+ return 0;
+}
+
+int vhost_dev_set_inflight(struct vhost_dev *dev,
+ struct vhost_inflight *inflight)
+{
+ int r;
+
+ if (dev->vhost_ops->vhost_set_inflight_fd && inflight->addr) {
+ r = dev->vhost_ops->vhost_set_inflight_fd(dev, inflight);
+ if (r) {
+ VHOST_OPS_DEBUG("vhost_set_inflight_fd failed");
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
+int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size,
+ struct vhost_inflight *inflight)
+{
+ int r;
+
+ if (dev->vhost_ops->vhost_get_inflight_fd) {
+ r = dev->vhost_ops->vhost_get_inflight_fd(dev, queue_size, inflight);
+ if (r) {
+ VHOST_OPS_DEBUG("vhost_get_inflight_fd failed");
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
/* Host notifiers must be enabled at this point. */
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
{
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index e3a65940ef..2112874055 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -82,7 +82,7 @@ static void balloon_inflate_page(VirtIOBalloon *balloon,
/* We've partially ballooned part of a host page, but now
* we're trying to balloon part of a different one. Too hard,
* give up on the old partial page */
- free(balloon->pbp);
+ g_free(balloon->pbp);
balloon->pbp = NULL;
}
@@ -107,11 +107,61 @@ static void balloon_inflate_page(VirtIOBalloon *balloon,
* has already reported them, and failing to discard a balloon
* page is not fatal */
- free(balloon->pbp);
+ g_free(balloon->pbp);
balloon->pbp = NULL;
}
}
+static void balloon_deflate_page(VirtIOBalloon *balloon,
+ MemoryRegion *mr, hwaddr offset)
+{
+ void *addr = memory_region_get_ram_ptr(mr) + offset;
+ RAMBlock *rb;
+ size_t rb_page_size;
+ ram_addr_t ram_offset, host_page_base;
+ void *host_addr;
+ int ret;
+
+ /* XXX is there a better way to get to the RAMBlock than via a
+ * host address? */
+ rb = qemu_ram_block_from_host(addr, false, &ram_offset);
+ rb_page_size = qemu_ram_pagesize(rb);
+ host_page_base = ram_offset & ~(rb_page_size - 1);
+
+ if (balloon->pbp
+ && rb == balloon->pbp->rb
+ && host_page_base == balloon->pbp->base) {
+ int subpages = rb_page_size / BALLOON_PAGE_SIZE;
+
+ /*
+ * This means the guest has asked to discard some of the 4kiB
+ * subpages of a host page, but then changed its mind and
+ * asked to keep them after all. It's exceedingly unlikely
+ * for a guest to do this in practice, but handle it anyway,
+ * since getting it wrong could mean discarding memory the
+ * guest is still using. */
+ bitmap_clear(balloon->pbp->bitmap,
+ (ram_offset - balloon->pbp->base) / BALLOON_PAGE_SIZE,
+ subpages);
+
+ if (bitmap_empty(balloon->pbp->bitmap, subpages)) {
+ g_free(balloon->pbp);
+ balloon->pbp = NULL;
+ }
+ }
+
+ host_addr = (void *)((uintptr_t)addr & ~(rb_page_size - 1));
+
+ /* When a page is deflated, we hint the whole host page it lives
+ * on, since we can't do anything smaller */
+ ret = qemu_madvise(host_addr, rb_page_size, QEMU_MADV_WILLNEED);
+ if (ret != 0) {
+ warn_report("Couldn't MADV_WILLNEED on balloon deflate: %s",
+ strerror(errno));
+ /* Otherwise ignore, failing to page hint shouldn't be fatal */
+ }
+}
+
static const char *balloon_stat_names[] = {
[VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in",
[VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out",
@@ -315,8 +365,15 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
trace_virtio_balloon_handle_output(memory_region_name(section.mr),
pa);
- if (!qemu_balloon_is_inhibited() && vq != s->dvq) {
- balloon_inflate_page(s, section.mr, section.offset_within_region);
+ if (!qemu_balloon_is_inhibited()) {
+ if (vq == s->ivq) {
+ balloon_inflate_page(s, section.mr,
+ section.offset_within_region);
+ } else if (vq == s->dvq) {
+ balloon_deflate_page(s, section.mr, section.offset_within_region);
+ } else {
+ g_assert_not_reached();
+ }
}
memory_region_unref(section.mr);
}
@@ -391,6 +448,7 @@ static bool get_free_page_hints(VirtIOBalloon *dev)
VirtQueueElement *elem;
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtQueue *vq = dev->free_page_vq;
+ bool ret = true;
while (dev->block_iothread) {
qemu_cond_wait(&dev->free_page_cond, &dev->free_page_lock);
@@ -405,13 +463,12 @@ static bool get_free_page_hints(VirtIOBalloon *dev)
uint32_t id;
size_t size = iov_to_buf(elem->out_sg, elem->out_num, 0,
&id, sizeof(id));
- virtqueue_push(vq, elem, size);
- g_free(elem);
virtio_tswap32s(vdev, &id);
if (unlikely(size != sizeof(id))) {
virtio_error(vdev, "received an incorrect cmd id");
- return false;
+ ret = false;
+ goto out;
}
if (id == dev->free_page_report_cmd_id) {
dev->free_page_report_status = FREE_PAGE_REPORT_S_START;
@@ -431,11 +488,12 @@ static bool get_free_page_hints(VirtIOBalloon *dev)
qemu_guest_free_page_hint(elem->in_sg[0].iov_base,
elem->in_sg[0].iov_len);
}
- virtqueue_push(vq, elem, 1);
- g_free(elem);
}
- return true;
+out:
+ virtqueue_push(vq, elem, 1);
+ g_free(elem);
+ return ret;
}
static void virtio_ballloon_get_free_page_hints(void *opaque)
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index ab3e52b415..e05ef75a75 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -162,12 +162,12 @@ static void xtfpga_net_init(MemoryRegion *address_space,
memory_region_add_subregion(address_space, buffers, ram);
}
-static pflash_t *xtfpga_flash_init(MemoryRegion *address_space,
- const XtfpgaBoardDesc *board,
- DriveInfo *dinfo, int be)
+static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space,
+ const XtfpgaBoardDesc *board,
+ DriveInfo *dinfo, int be)
{
SysBusDevice *s;
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
&error_abort);
@@ -181,7 +181,7 @@ static pflash_t *xtfpga_flash_init(MemoryRegion *address_space,
s = SYS_BUS_DEVICE(dev);
memory_region_add_subregion(address_space, board->flash->base,
sysbus_mmio_get_region(s, 0));
- return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
+ return PFLASH_CFI01(dev);
}
static uint64_t translate_phys_addr(void *opaque, uint64_t addr)
@@ -229,7 +229,7 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
XtensaMxPic *mx_pic = NULL;
qemu_irq *extints;
DriveInfo *dinfo;
- pflash_t *flash = NULL;
+ PFlashCFI01 *flash = NULL;
QemuOpts *machine_opts = qemu_get_machine_opts();
const char *kernel_filename = qemu_opt_get(machine_opts, "kernel");
const char *kernel_cmdline = qemu_opt_get(machine_opts, "append");
diff --git a/include/block/block.h b/include/block/block.h
index 6a758a76f8..e452988b66 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -187,6 +187,9 @@ typedef struct BDRVReopenState {
BlockDriverState *bs;
int flags;
BlockdevDetectZeroesOptions detect_zeroes;
+ bool backing_missing;
+ bool replace_backing_bs; /* new_backing_bs is ignored if this is false */
+ BlockDriverState *new_backing_bs; /* If NULL then detach the current bs */
uint64_t perm, shared_perm;
QDict *options;
QDict *explicit_options;
@@ -299,8 +302,9 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
int flags, Error **errp);
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
- BlockDriverState *bs, QDict *options);
-int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp);
+ BlockDriverState *bs, QDict *options,
+ bool keep_old_opts);
+int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
Error **errp);
int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
@@ -353,6 +357,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
BlockDriverState *bs);
BlockDriverState *bdrv_find_base(BlockDriverState *bs);
+bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
+ Error **errp);
+int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
+ Error **errp);
+void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
typedef struct BdrvCheckResult {
diff --git a/include/block/block_int.h b/include/block/block_int.h
index a23cabaddd..01e855a066 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -383,6 +383,14 @@ struct BlockDriver {
/* List of options for creating images, terminated by name == NULL */
QemuOptsList *create_opts;
+ /*
+ * If this driver supports reopening images this contains a
+ * NULL-terminated list of the runtime options that can be
+ * modified. If an option in this list is unspecified during
+ * reopen then it _must_ be reset to its default value or return
+ * an error.
+ */
+ const char *const *mutable_opts;
/*
* Returns 0 for completed check, -errno for internal errors.
@@ -711,6 +719,12 @@ struct BdrvChild {
uint64_t backup_perm;
uint64_t backup_shared_perm;
+ /*
+ * This link is frozen: the child can neither be replaced nor
+ * detached from the parent.
+ */
+ bool frozen;
+
QLIST_ENTRY(BdrvChild) next;
QLIST_ENTRY(BdrvChild) next_parent;
};
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 04a117fc81..8044ace63e 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -5,6 +5,16 @@
#include "qapi/qapi-types-block-core.h"
#include "qemu/hbitmap.h"
+typedef enum BitmapCheckFlags {
+ BDRV_BITMAP_BUSY = 1,
+ BDRV_BITMAP_RO = 2,
+ BDRV_BITMAP_INCONSISTENT = 4,
+} BitmapCheckFlags;
+
+#define BDRV_BITMAP_DEFAULT (BDRV_BITMAP_BUSY | BDRV_BITMAP_RO | \
+ BDRV_BITMAP_INCONSISTENT)
+#define BDRV_BITMAP_ALLOW_RO (BDRV_BITMAP_BUSY | BDRV_BITMAP_INCONSISTENT)
+
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
uint32_t granularity,
const char *name,
@@ -24,6 +34,8 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap);
BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
const char *name);
+int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
+ Error **errp);
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
@@ -36,7 +48,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
-bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap);
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap);
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
@@ -66,9 +78,10 @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value);
-void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
+void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap,
bool persistent);
-void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked);
+void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap);
+void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy);
void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
HBitmap **backup, Error **errp);
void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration);
@@ -90,9 +103,8 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
-bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
-bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap);
-bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap);
bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs);
BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap);
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
index 59aeb06393..41568d1837 100644
--- a/include/hw/acpi/ich9.h
+++ b/include/hw/acpi/ich9.h
@@ -74,6 +74,8 @@ extern const VMStateDescription vmstate_ich9_pm;
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp);
+void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h
index 67c3aa329e..a0f488732a 100644
--- a/include/hw/block/flash.h
+++ b/include/hw/block/flash.h
@@ -5,32 +5,46 @@
#include "exec/memory.h"
-#define TYPE_CFI_PFLASH01 "cfi.pflash01"
-#define TYPE_CFI_PFLASH02 "cfi.pflash02"
+/* pflash_cfi01.c */
-typedef struct pflash_t pflash_t;
+#define TYPE_PFLASH_CFI01 "cfi.pflash01"
+#define PFLASH_CFI01(obj) \
+ OBJECT_CHECK(PFlashCFI01, (obj), TYPE_PFLASH_CFI01)
-/* pflash_cfi01.c */
-pflash_t *pflash_cfi01_register(hwaddr base,
- DeviceState *qdev, const char *name,
- hwaddr size,
- BlockBackend *blk,
- uint32_t sector_len, int nb_blocs, int width,
- uint16_t id0, uint16_t id1,
- uint16_t id2, uint16_t id3, int be);
+typedef struct PFlashCFI01 PFlashCFI01;
+
+PFlashCFI01 *pflash_cfi01_register(hwaddr base,
+ const char *name,
+ hwaddr size,
+ BlockBackend *blk,
+ uint32_t sector_len,
+ int width,
+ uint16_t id0, uint16_t id1,
+ uint16_t id2, uint16_t id3,
+ int be);
+BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl);
+MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl);
/* pflash_cfi02.c */
-pflash_t *pflash_cfi02_register(hwaddr base,
- DeviceState *qdev, const char *name,
- hwaddr size,
- BlockBackend *blk, uint32_t sector_len,
- int nb_blocs, int nb_mappings, int width,
- uint16_t id0, uint16_t id1,
- uint16_t id2, uint16_t id3,
- uint16_t unlock_addr0, uint16_t unlock_addr1,
- int be);
-
-MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl);
+
+#define TYPE_PFLASH_CFI02 "cfi.pflash02"
+#define PFLASH_CFI02(obj) \
+ OBJECT_CHECK(PFlashCFI02, (obj), TYPE_PFLASH_CFI02)
+
+typedef struct PFlashCFI02 PFlashCFI02;
+
+PFlashCFI02 *pflash_cfi02_register(hwaddr base,
+ const char *name,
+ hwaddr size,
+ BlockBackend *blk,
+ uint32_t sector_len,
+ int nb_mappings,
+ int width,
+ uint16_t id0, uint16_t id1,
+ uint16_t id2, uint16_t id3,
+ uint16_t unlock_addr0,
+ uint16_t unlock_addr1,
+ int be);
/* nand.c */
DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 9690c71a6d..e231860666 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -210,6 +210,7 @@ struct MachineClass {
int nb_nodes, ram_addr_t size);
bool ignore_boot_device_suffixes;
bool smbus_no_migration_support;
+ bool nvdimm_supported;
HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
DeviceState *dev);
@@ -272,6 +273,7 @@ struct MachineState {
const char *cpu_type;
AccelState *accelerator;
CPUArchIdList *possible_cpus;
+ struct NVDIMMState *nvdimms_state;
};
#define DEFINE_MACHINE(namestr, machine_initfn) \
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index a321cc9691..c11e3d5b34 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -66,11 +66,20 @@ typedef struct VTDIOTLBEntry VTDIOTLBEntry;
typedef struct VTDBus VTDBus;
typedef union VTD_IR_TableEntry VTD_IR_TableEntry;
typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress;
+typedef struct VTDPASIDDirEntry VTDPASIDDirEntry;
+typedef struct VTDPASIDEntry VTDPASIDEntry;
/* Context-Entry */
struct VTDContextEntry {
- uint64_t lo;
- uint64_t hi;
+ union {
+ struct {
+ uint64_t lo;
+ uint64_t hi;
+ };
+ struct {
+ uint64_t val[4];
+ };
+ };
};
struct VTDContextCacheEntry {
@@ -81,6 +90,16 @@ struct VTDContextCacheEntry {
struct VTDContextEntry context_entry;
};
+/* PASID Directory Entry */
+struct VTDPASIDDirEntry {
+ uint64_t val;
+};
+
+/* PASID Table Entry */
+struct VTDPASIDEntry {
+ uint64_t val[8];
+};
+
struct VTDAddressSpace {
PCIBus *bus;
uint8_t devfn;
@@ -208,16 +227,19 @@ struct IntelIOMMUState {
uint8_t womask[DMAR_REG_SIZE]; /* WO (write only - read returns 0) */
uint32_t version;
- bool caching_mode; /* RO - is cap CM enabled? */
+ bool caching_mode; /* RO - is cap CM enabled? */
+ bool scalable_mode; /* RO - is Scalable Mode supported? */
dma_addr_t root; /* Current root table pointer */
bool root_extended; /* Type of root table (extended or not) */
+ bool root_scalable; /* Type of root table (scalable or not) */
bool dmar_enabled; /* Set if DMA remapping is enabled */
uint16_t iq_head; /* Current invalidation queue head */
uint16_t iq_tail; /* Current invalidation queue tail */
dma_addr_t iq; /* Current invalidation queue pointer */
uint16_t iq_size; /* IQ Size in number of entries */
+ bool iq_dw; /* IQ descriptor width 256bit or not */
bool qi_enabled; /* Set if the QI is enabled */
uint8_t iq_last_desc_type; /* The type of last completed descriptor */
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 54222a202d..ca65ef18af 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -6,6 +6,7 @@
#include "hw/boards.h"
#include "hw/isa/isa.h"
#include "hw/block/fdc.h"
+#include "hw/block/flash.h"
#include "net/net.h"
#include "hw/i386/ioapic.h"
@@ -39,14 +40,13 @@ struct PCMachineState {
PCIBus *bus;
FWCfgState *fw_cfg;
qemu_irq *gsi;
+ PFlashCFI01 *flash[2];
/* Configuration options: */
uint64_t max_ram_below_4g;
OnOffAuto vmport;
OnOffAuto smm;
- AcpiNVDIMMState acpi_nvdimm_state;
-
bool acpi_build_enabled;
bool smbus_enabled;
bool sata_enabled;
@@ -74,8 +74,6 @@ struct PCMachineState {
#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g"
#define PC_MACHINE_VMPORT "vmport"
#define PC_MACHINE_SMM "smm"
-#define PC_MACHINE_NVDIMM "nvdimm"
-#define PC_MACHINE_NVDIMM_PERSIST "nvdimm-persistence"
#define PC_MACHINE_SMBUS "smbus"
#define PC_MACHINE_SATA "sata"
#define PC_MACHINE_PIT "pit"
@@ -277,8 +275,8 @@ extern PCIDevice *piix4_dev;
int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn);
/* pc_sysfw.c */
-void pc_system_firmware_init(MemoryRegion *rom_memory,
- bool isapc_ram_fw);
+void pc_system_flash_create(PCMachineState *pcms);
+void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory);
/* acpi-build.c */
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h
index c5c9b3c7f8..523a9b3d4a 100644
--- a/include/hw/mem/nvdimm.h
+++ b/include/hw/mem/nvdimm.h
@@ -123,7 +123,7 @@ struct NvdimmFitBuffer {
};
typedef struct NvdimmFitBuffer NvdimmFitBuffer;
-struct AcpiNVDIMMState {
+struct NVDIMMState {
/* detect if NVDIMM support is enabled. */
bool is_enabled;
@@ -141,13 +141,13 @@ struct AcpiNVDIMMState {
int32_t persistence;
char *persistence_string;
};
-typedef struct AcpiNVDIMMState AcpiNVDIMMState;
+typedef struct NVDIMMState NVDIMMState;
-void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io,
+void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io,
FWCfgState *fw_cfg, Object *owner);
void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
- BIOSLinker *linker, AcpiNVDIMMState *state,
+ BIOSLinker *linker, NVDIMMState *state,
uint32_t ram_slots);
-void nvdimm_plug(AcpiNVDIMMState *state);
+void nvdimm_plug(NVDIMMState *state);
void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev);
#endif
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index ab0e3a0a6f..b4aad26798 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -28,11 +28,11 @@
#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
#define SPAPR_PCI_HOST_BRIDGE(obj) \
- OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
+ OBJECT_CHECK(SpaprPhbState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
#define SPAPR_PCI_DMA_MAX_WINDOWS 2
-typedef struct sPAPRPHBState sPAPRPHBState;
+typedef struct SpaprPhbState SpaprPhbState;
typedef struct spapr_pci_msi {
uint32_t first_irq;
@@ -44,7 +44,7 @@ typedef struct spapr_pci_msi_mig {
spapr_pci_msi value;
} spapr_pci_msi_mig;
-struct sPAPRPHBState {
+struct SpaprPhbState {
PCIHostState parent_obj;
uint32_t index;
@@ -72,7 +72,7 @@ struct sPAPRPHBState {
int32_t msi_devs_num;
spapr_pci_msi_mig *msi_devs;
- QLIST_ENTRY(sPAPRPHBState) list;
+ QLIST_ENTRY(SpaprPhbState) list;
bool ddw_enabled;
uint64_t page_size_mask;
@@ -105,56 +105,56 @@ struct sPAPRPHBState {
#define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL
-static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
+static inline qemu_irq spapr_phb_lsi_qirq(struct SpaprPhbState *phb, int pin)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
return spapr_qirq(spapr, phb->lsi_table[pin].irq);
}
-int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t intc_phandle, void *fdt,
+int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
uint32_t nr_msis, int *node_offset);
void spapr_pci_rtas_init(void);
-sPAPRPHBState *spapr_pci_find_phb(sPAPRMachineState *spapr, uint64_t buid);
-PCIDevice *spapr_pci_find_dev(sPAPRMachineState *spapr, uint64_t buid,
+SpaprPhbState *spapr_pci_find_phb(SpaprMachineState *spapr, uint64_t buid);
+PCIDevice *spapr_pci_find_dev(SpaprMachineState *spapr, uint64_t buid,
uint32_t config_addr);
/* DRC callbacks */
void spapr_phb_remove_pci_device_cb(DeviceState *dev);
-int spapr_pci_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_pci_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
/* VFIO EEH hooks */
#ifdef CONFIG_LINUX
-bool spapr_phb_eeh_available(sPAPRPHBState *sphb);
-int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
+bool spapr_phb_eeh_available(SpaprPhbState *sphb);
+int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
unsigned int addr, int option);
-int spapr_phb_vfio_eeh_get_state(sPAPRPHBState *sphb, int *state);
-int spapr_phb_vfio_eeh_reset(sPAPRPHBState *sphb, int option);
-int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb);
+int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state);
+int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option);
+int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb);
void spapr_phb_vfio_reset(DeviceState *qdev);
#else
-static inline bool spapr_phb_eeh_available(sPAPRPHBState *sphb)
+static inline bool spapr_phb_eeh_available(SpaprPhbState *sphb)
{
return false;
}
-static inline int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
+static inline int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
unsigned int addr, int option)
{
return RTAS_OUT_HW_ERROR;
}
-static inline int spapr_phb_vfio_eeh_get_state(sPAPRPHBState *sphb,
+static inline int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb,
int *state)
{
return RTAS_OUT_HW_ERROR;
}
-static inline int spapr_phb_vfio_eeh_reset(sPAPRPHBState *sphb, int option)
+static inline int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
{
return RTAS_OUT_HW_ERROR;
}
-static inline int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb)
+static inline int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
{
return RTAS_OUT_HW_ERROR;
}
@@ -163,9 +163,9 @@ static inline void spapr_phb_vfio_reset(DeviceState *qdev)
}
#endif
-void spapr_phb_dma_reset(sPAPRPHBState *sphb);
+void spapr_phb_dma_reset(SpaprPhbState *sphb);
-static inline unsigned spapr_phb_windows_supported(sPAPRPHBState *sphb)
+static inline unsigned spapr_phb_windows_supported(SpaprPhbState *sphb)
{
return sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1;
}
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
index 5b82a0d244..e30334d74d 100644
--- a/include/hw/pci/pcie.h
+++ b/include/hw/pci/pcie.h
@@ -79,6 +79,9 @@ struct PCIExpressDevice {
/* Offset of ATS capability in config space */
uint16_t ats_cap;
+
+ /* ACS */
+ uint16_t acs_cap;
};
#define COMPAT_PROP_PCP "power_controller_present"
@@ -128,6 +131,9 @@ void pcie_add_capability(PCIDevice *dev,
uint16_t offset, uint16_t size);
void pcie_sync_bridge_lnk(PCIDevice *dev);
+void pcie_acs_init(PCIDevice *dev, uint16_t offset);
+void pcie_acs_reset(PCIDevice *dev);
+
void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
void pcie_ats_init(PCIDevice *dev, uint16_t offset);
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index df242a0caf..09586f4641 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -78,6 +78,7 @@ typedef struct PCIERootPortClass {
int exp_offset;
int aer_offset;
int ssvid_offset;
+ int acs_offset; /* If nonzero, optional ACS capability offset */
int ssid;
} PCIERootPortClass;
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
index ad4e7808b8..1db86b0ec4 100644
--- a/include/hw/pci/pcie_regs.h
+++ b/include/hw/pci/pcie_regs.h
@@ -175,4 +175,8 @@ typedef enum PCIExpLinkWidth {
PCI_ERR_COR_INTERNAL | \
PCI_ERR_COR_HL_OVERFLOW)
+/* ACS */
+#define PCI_ACS_VER 0x1
+#define PCI_ACS_SIZEOF 8
+
#endif /* QEMU_PCIE_REGS_H */
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 6b65397b7e..e5b00d373e 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -25,6 +25,8 @@
#include "hw/ppc/pnv_lpc.h"
#include "hw/ppc/pnv_psi.h"
#include "hw/ppc/pnv_occ.h"
+#include "hw/ppc/pnv_xive.h"
+#include "hw/ppc/pnv_core.h"
#define TYPE_PNV_CHIP "pnv-chip"
#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
@@ -57,6 +59,8 @@ typedef struct PnvChip {
MemoryRegion xscom_mmio;
MemoryRegion xscom;
AddressSpace xscom_as;
+
+ gchar *dt_isa_nodename;
} PnvChip;
#define TYPE_PNV8_CHIP "pnv8-chip"
@@ -70,7 +74,7 @@ typedef struct Pnv8Chip {
MemoryRegion icp_mmio;
PnvLpcController lpc;
- PnvPsi psi;
+ Pnv8Psi psi;
PnvOCC occ;
} Pnv8Chip;
@@ -82,6 +86,13 @@ typedef struct Pnv9Chip {
PnvChip parent_obj;
/*< public >*/
+ PnvXive xive;
+ Pnv9Psi psi;
+ PnvLpcController lpc;
+ PnvOCC occ;
+
+ uint32_t nr_quads;
+ PnvQuad *quads;
} Pnv9Chip;
typedef struct PnvChipClass {
@@ -100,6 +111,8 @@ typedef struct PnvChipClass {
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
ISABus *(*isa_create)(PnvChip *chip, Error **errp);
+ void (*dt_populate)(PnvChip *chip, void *fdt);
+ void (*pic_print_info)(PnvChip *chip, Monitor *mon);
} PnvChipClass;
#define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
@@ -215,4 +228,31 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
(0x0003ffe000000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * \
PNV_PSIHB_FSP_SIZE)
+/*
+ * POWER9 MMIO base addresses
+ */
+#define PNV9_CHIP_BASE(chip, base) \
+ ((base) + ((uint64_t) (chip)->chip_id << 42))
+
+#define PNV9_XIVE_VC_SIZE 0x0000008000000000ull
+#define PNV9_XIVE_VC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006010000000000ull)
+
+#define PNV9_XIVE_PC_SIZE 0x0000001000000000ull
+#define PNV9_XIVE_PC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
+
+#define PNV9_LPCM_SIZE 0x0000000100000000ull
+#define PNV9_LPCM_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030000000000ull)
+
+#define PNV9_PSIHB_SIZE 0x0000000000100000ull
+#define PNV9_PSIHB_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
+
+#define PNV9_XIVE_IC_SIZE 0x0000000000080000ull
+#define PNV9_XIVE_IC_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
+
+#define PNV9_XIVE_TM_SIZE 0x0000000000040000ull
+#define PNV9_XIVE_TM_BASE(chip) PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
+
+#define PNV9_PSIHB_ESB_SIZE 0x0000000000010000ull
+#define PNV9_PSIHB_ESB_BASE(chip) PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
+
#endif /* _PPC_PNV_H */
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 9961ea3a92..50cdb2b358 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -42,13 +42,15 @@ typedef struct PnvCore {
typedef struct PnvCoreClass {
DeviceClass parent_class;
+
+ const MemoryRegionOps *xscom_ops;
} PnvCoreClass;
#define PNV_CORE_TYPE_SUFFIX "-" TYPE_PNV_CORE
#define PNV_CORE_TYPE_NAME(cpu_model) cpu_model PNV_CORE_TYPE_SUFFIX
typedef struct PnvCPUState {
- struct ICPState *icp;
+ Object *intc;
} PnvCPUState;
static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
@@ -56,4 +58,14 @@ static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
return (PnvCPUState *)cpu->machine_data;
}
+#define TYPE_PNV_QUAD "powernv-cpu-quad"
+#define PNV_QUAD(obj) \
+ OBJECT_CHECK(PnvQuad, (obj), TYPE_PNV_QUAD)
+
+typedef struct PnvQuad {
+ DeviceState parent_obj;
+
+ uint32_t id;
+ MemoryRegion xscom_regs;
+} PnvQuad;
#endif /* _PPC_PNV_CORE_H */
diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
index d657489b07..413579792e 100644
--- a/include/hw/ppc/pnv_lpc.h
+++ b/include/hw/ppc/pnv_lpc.h
@@ -24,6 +24,11 @@
#define TYPE_PNV_LPC "pnv-lpc"
#define PNV_LPC(obj) \
OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC)
+#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8"
+#define PNV8_LPC(obj) OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV8_LPC)
+
+#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9"
+#define PNV9_LPC(obj) OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV9_LPC)
typedef struct PnvLpcController {
DeviceState parent;
@@ -50,6 +55,8 @@ typedef struct PnvLpcController {
MemoryRegion opb_master_regs;
/* OPB Master LS registers */
+ uint32_t opb_irq_route0;
+ uint32_t opb_irq_route1;
uint32_t opb_irq_stat;
uint32_t opb_irq_mask;
uint32_t opb_irq_pol;
@@ -70,6 +77,25 @@ typedef struct PnvLpcController {
PnvPsi *psi;
} PnvLpcController;
+#define PNV_LPC_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PnvLpcClass, (klass), TYPE_PNV_LPC)
+#define PNV_LPC_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PnvLpcClass, (obj), TYPE_PNV_LPC)
+
+typedef struct PnvLpcClass {
+ DeviceClass parent_class;
+
+ int psi_irq;
+
+ DeviceRealize parent_realize;
+} PnvLpcClass;
+
+/*
+ * Old compilers error on typdef forward declarations. Keep them happy.
+ */
+struct PnvChip;
+
ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
+int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset);
#endif /* _PPC_PNV_LPC_H */
diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
index 82f299dc76..d22b65a71a 100644
--- a/include/hw/ppc/pnv_occ.h
+++ b/include/hw/ppc/pnv_occ.h
@@ -23,6 +23,10 @@
#define TYPE_PNV_OCC "pnv-occ"
#define PNV_OCC(obj) OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV_OCC)
+#define TYPE_PNV8_OCC TYPE_PNV_OCC "-POWER8"
+#define PNV8_OCC(obj) OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV8_OCC)
+#define TYPE_PNV9_OCC TYPE_PNV_OCC "-POWER9"
+#define PNV9_OCC(obj) OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV9_OCC)
typedef struct PnvOCC {
DeviceState xd;
@@ -35,4 +39,17 @@ typedef struct PnvOCC {
MemoryRegion xscom_regs;
} PnvOCC;
+#define PNV_OCC_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PnvOCCClass, (klass), TYPE_PNV_OCC)
+#define PNV_OCC_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PnvOCCClass, (obj), TYPE_PNV_OCC)
+
+typedef struct PnvOCCClass {
+ DeviceClass parent_class;
+
+ int xscom_size;
+ const MemoryRegionOps *xscom_ops;
+ int psi_irq;
+} PnvOCCClass;
+
#endif /* _PPC_PNV_OCC_H */
diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
index 64ac73512e..2c1b27e865 100644
--- a/include/hw/ppc/pnv_psi.h
+++ b/include/hw/ppc/pnv_psi.h
@@ -21,6 +21,7 @@
#include "hw/sysbus.h"
#include "hw/ppc/xics.h"
+#include "hw/ppc/xive.h"
#define TYPE_PNV_PSI "pnv-psi"
#define PNV_PSI(obj) \
@@ -39,7 +40,6 @@ typedef struct PnvPsi {
uint64_t fsp_bar;
/* Interrupt generation */
- ICSState ics;
qemu_irq *qirqs;
/* Registers */
@@ -48,6 +48,42 @@ typedef struct PnvPsi {
MemoryRegion xscom_regs;
} PnvPsi;
+#define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
+#define PNV8_PSI(obj) \
+ OBJECT_CHECK(Pnv8Psi, (obj), TYPE_PNV8_PSI)
+
+typedef struct Pnv8Psi {
+ PnvPsi parent;
+
+ ICSState ics;
+} Pnv8Psi;
+
+#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
+#define PNV9_PSI(obj) \
+ OBJECT_CHECK(Pnv9Psi, (obj), TYPE_PNV9_PSI)
+
+typedef struct Pnv9Psi {
+ PnvPsi parent;
+
+ XiveSource source;
+} Pnv9Psi;
+
+#define PNV_PSI_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PnvPsiClass, (klass), TYPE_PNV_PSI)
+#define PNV_PSI_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PnvPsiClass, (obj), TYPE_PNV_PSI)
+
+typedef struct PnvPsiClass {
+ SysBusDeviceClass parent_class;
+
+ int chip_type;
+ uint32_t xscom_pcba;
+ uint32_t xscom_size;
+ uint64_t bar_mask;
+
+ void (*irq_set)(PnvPsi *psi, int, bool state);
+} PnvPsiClass;
+
/* The PSI and FSP interrupts are muxed on the same IRQ number */
typedef enum PnvPsiIrq {
PSIHB_IRQ_PSI, /* internal use only */
@@ -61,6 +97,25 @@ typedef enum PnvPsiIrq {
#define PSI_NUM_INTERRUPTS 6
-extern void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state);
+void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
+
+/* P9 PSI Interrupts */
+#define PSIHB9_IRQ_PSI 0
+#define PSIHB9_IRQ_OCC 1
+#define PSIHB9_IRQ_FSI 2
+#define PSIHB9_IRQ_LPCHC 3
+#define PSIHB9_IRQ_LOCAL_ERR 4
+#define PSIHB9_IRQ_GLOBAL_ERR 5
+#define PSIHB9_IRQ_TPM 6
+#define PSIHB9_IRQ_LPC_SIRQ0 7
+#define PSIHB9_IRQ_LPC_SIRQ1 8
+#define PSIHB9_IRQ_LPC_SIRQ2 9
+#define PSIHB9_IRQ_LPC_SIRQ3 10
+#define PSIHB9_IRQ_SBE_I2C 11
+#define PSIHB9_IRQ_DIO 12
+#define PSIHB9_IRQ_PSU 13
+#define PSIHB9_NUM_IRQS 14
+
+void pnv_psi_pic_print_info(Pnv9Psi *psi, Monitor *mon);
#endif /* _PPC_PNV_PSI_H */
diff --git a/include/hw/ppc/pnv_xive.h b/include/hw/ppc/pnv_xive.h
new file mode 100644
index 0000000000..4fdaa9247d
--- /dev/null
+++ b/include/hw/ppc/pnv_xive.h
@@ -0,0 +1,93 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2019, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_PNV_XIVE_H
+#define PPC_PNV_XIVE_H
+
+#include "hw/ppc/xive.h"
+
+struct PnvChip;
+
+#define TYPE_PNV_XIVE "pnv-xive"
+#define PNV_XIVE(obj) OBJECT_CHECK(PnvXive, (obj), TYPE_PNV_XIVE)
+
+#define XIVE_BLOCK_MAX 16
+
+#define XIVE_TABLE_BLK_MAX 16 /* Block Scope Table (0-15) */
+#define XIVE_TABLE_MIG_MAX 16 /* Migration Register Table (1-15) */
+#define XIVE_TABLE_VDT_MAX 16 /* VDT Domain Table (0-15) */
+#define XIVE_TABLE_EDT_MAX 64 /* EDT Domain Table (0-63) */
+
+typedef struct PnvXive {
+ XiveRouter parent_obj;
+
+ /* Owning chip */
+ struct PnvChip *chip;
+
+ /* XSCOM addresses giving access to the controller registers */
+ MemoryRegion xscom_regs;
+
+ /* Main MMIO regions that can be configured by FW */
+ MemoryRegion ic_mmio;
+ MemoryRegion ic_reg_mmio;
+ MemoryRegion ic_notify_mmio;
+ MemoryRegion ic_lsi_mmio;
+ MemoryRegion tm_indirect_mmio;
+ MemoryRegion vc_mmio;
+ MemoryRegion pc_mmio;
+ MemoryRegion tm_mmio;
+
+ /*
+ * IPI and END address spaces modeling the EDT segmentation in the
+ * VC region
+ */
+ AddressSpace ipi_as;
+ MemoryRegion ipi_mmio;
+ MemoryRegion ipi_edt_mmio;
+
+ AddressSpace end_as;
+ MemoryRegion end_mmio;
+ MemoryRegion end_edt_mmio;
+
+ /* Shortcut values for the Main MMIO regions */
+ hwaddr ic_base;
+ uint32_t ic_shift;
+ hwaddr vc_base;
+ uint32_t vc_shift;
+ hwaddr pc_base;
+ uint32_t pc_shift;
+ hwaddr tm_base;
+ uint32_t tm_shift;
+
+ /* Our XIVE source objects for IPIs and ENDs */
+ XiveSource ipi_source;
+ XiveENDSource end_source;
+
+ /* Interrupt controller registers */
+ uint64_t regs[0x300];
+
+ /* Can be configured by FW */
+ uint32_t tctx_chipid;
+
+ /*
+ * Virtual Structure Descriptor tables : EAT, SBE, ENDT, NVTT, IRQ
+ * These are in a SRAM protected by ECC.
+ */
+ uint64_t vsds[5][XIVE_BLOCK_MAX];
+
+ /* Translation tables */
+ uint64_t blk[XIVE_TABLE_BLK_MAX];
+ uint64_t mig[XIVE_TABLE_MIG_MAX];
+ uint64_t vdt[XIVE_TABLE_VDT_MAX];
+ uint64_t edt[XIVE_TABLE_EDT_MAX];
+} PnvXive;
+
+void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon);
+
+#endif /* PPC_PNV_XIVE_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 255b26a5aa..68dfae0dfe 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -60,10 +60,6 @@ typedef struct PnvXScomInterfaceClass {
(PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24))
#define PNV_XSCOM_EX_SIZE 0x100000
-#define PNV_XSCOM_P9_EC_BASE(core) \
- ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
-#define PNV_XSCOM_P9_EC_SIZE 0x100000
-
#define PNV_XSCOM_LPC_BASE 0xb0020
#define PNV_XSCOM_LPC_SIZE 0x4
@@ -73,6 +69,23 @@ typedef struct PnvXScomInterfaceClass {
#define PNV_XSCOM_OCC_BASE 0x0066000
#define PNV_XSCOM_OCC_SIZE 0x6000
+#define PNV9_XSCOM_EC_BASE(core) \
+ ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
+#define PNV9_XSCOM_EC_SIZE 0x100000
+
+#define PNV9_XSCOM_EQ_BASE(core) \
+ ((uint64_t)(((core) & 0x1C) + 0x40) << 22)
+#define PNV9_XSCOM_EQ_SIZE 0x100000
+
+#define PNV9_XSCOM_OCC_BASE PNV_XSCOM_OCC_BASE
+#define PNV9_XSCOM_OCC_SIZE 0x8000
+
+#define PNV9_XSCOM_PSIHB_BASE 0x5012900
+#define PNV9_XSCOM_PSIHB_SIZE 0x100
+
+#define PNV9_XSCOM_XIVE_BASE 0x5013000
+#define PNV9_XSCOM_XIVE_SIZE 0x300
+
extern void pnv_xscom_realize(PnvChip *chip, Error **errp);
extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset);
diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
index 746170f635..4bdcb8bacd 100644
--- a/include/hw/ppc/ppc.h
+++ b/include/hw/ppc/ppc.h
@@ -4,6 +4,7 @@
#include "target/ppc/cpu-qom.h"
void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level);
+PowerPCCPU *ppc_get_vcpu_by_pir(int pir);
/* PowerPC hardware exceptions management helpers */
typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 59073a7579..2b4c05a2ec 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -8,16 +8,16 @@
#include "hw/mem/pc-dimm.h"
#include "hw/ppc/spapr_ovec.h"
#include "hw/ppc/spapr_irq.h"
-#include "hw/ppc/spapr_xive.h" /* For sPAPRXive */
+#include "hw/ppc/spapr_xive.h" /* For SpaprXive */
#include "hw/ppc/xics.h" /* For ICSState */
-struct VIOsPAPRBus;
-struct sPAPRPHBState;
-struct sPAPRNVRAM;
+struct SpaprVioBus;
+struct SpaprPhbState;
+struct SpaprNvram;
-typedef struct sPAPREventLogEntry sPAPREventLogEntry;
-typedef struct sPAPREventSource sPAPREventSource;
-typedef struct sPAPRPendingHPT sPAPRPendingHPT;
+typedef struct SpaprEventLogEntry SpaprEventLogEntry;
+typedef struct SpaprEventSource SpaprEventSource;
+typedef struct SpaprPendingHpt SpaprPendingHpt;
#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
#define SPAPR_ENTRY_POINT 0x100
@@ -27,32 +27,32 @@ typedef struct sPAPRPendingHPT sPAPRPendingHPT;
#define TYPE_SPAPR_RTC "spapr-rtc"
#define SPAPR_RTC(obj) \
- OBJECT_CHECK(sPAPRRTCState, (obj), TYPE_SPAPR_RTC)
+ OBJECT_CHECK(SpaprRtcState, (obj), TYPE_SPAPR_RTC)
-typedef struct sPAPRRTCState sPAPRRTCState;
-struct sPAPRRTCState {
+typedef struct SpaprRtcState SpaprRtcState;
+struct SpaprRtcState {
/*< private >*/
DeviceState parent_obj;
int64_t ns_offset;
};
-typedef struct sPAPRDIMMState sPAPRDIMMState;
-typedef struct sPAPRMachineClass sPAPRMachineClass;
+typedef struct SpaprDimmState SpaprDimmState;
+typedef struct SpaprMachineClass SpaprMachineClass;
#define TYPE_SPAPR_MACHINE "spapr-machine"
#define SPAPR_MACHINE(obj) \
- OBJECT_CHECK(sPAPRMachineState, (obj), TYPE_SPAPR_MACHINE)
+ OBJECT_CHECK(SpaprMachineState, (obj), TYPE_SPAPR_MACHINE)
#define SPAPR_MACHINE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRMachineClass, obj, TYPE_SPAPR_MACHINE)
+ OBJECT_GET_CLASS(SpaprMachineClass, obj, TYPE_SPAPR_MACHINE)
#define SPAPR_MACHINE_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRMachineClass, klass, TYPE_SPAPR_MACHINE)
+ OBJECT_CLASS_CHECK(SpaprMachineClass, klass, TYPE_SPAPR_MACHINE)
typedef enum {
SPAPR_RESIZE_HPT_DEFAULT = 0,
SPAPR_RESIZE_HPT_DISABLED,
SPAPR_RESIZE_HPT_ENABLED,
SPAPR_RESIZE_HPT_REQUIRED,
-} sPAPRResizeHPT;
+} SpaprResizeHpt;
/**
* Capabilities
@@ -74,8 +74,12 @@ typedef enum {
#define SPAPR_CAP_HPT_MAXPAGESIZE 0x06
/* Nested KVM-HV */
#define SPAPR_CAP_NESTED_KVM_HV 0x07
+/* Large Decrementer */
+#define SPAPR_CAP_LARGE_DECREMENTER 0x08
+/* Count Cache Flush Assist HW Instruction */
+#define SPAPR_CAP_CCF_ASSIST 0x09
/* Num Caps */
-#define SPAPR_CAP_NUM (SPAPR_CAP_NESTED_KVM_HV + 1)
+#define SPAPR_CAP_NUM (SPAPR_CAP_CCF_ASSIST + 1)
/*
* Capability Values
@@ -83,22 +87,27 @@ typedef enum {
/* Bool Caps */
#define SPAPR_CAP_OFF 0x00
#define SPAPR_CAP_ON 0x01
+
/* Custom Caps */
+
+/* Generic */
#define SPAPR_CAP_BROKEN 0x00
#define SPAPR_CAP_WORKAROUND 0x01
#define SPAPR_CAP_FIXED 0x02
+/* SPAPR_CAP_IBS (cap-ibs) */
#define SPAPR_CAP_FIXED_IBS 0x02
#define SPAPR_CAP_FIXED_CCD 0x03
+#define SPAPR_CAP_FIXED_NA 0x10 /* Lets leave a bit of a gap... */
-typedef struct sPAPRCapabilities sPAPRCapabilities;
-struct sPAPRCapabilities {
+typedef struct SpaprCapabilities SpaprCapabilities;
+struct SpaprCapabilities {
uint8_t caps[SPAPR_CAP_NUM];
};
/**
- * sPAPRMachineClass:
+ * SpaprMachineClass:
*/
-struct sPAPRMachineClass {
+struct SpaprMachineClass {
/*< private >*/
MachineClass parent_class;
@@ -110,33 +119,33 @@ struct sPAPRMachineClass {
bool pre_2_10_has_unused_icps;
bool legacy_irq_allocation;
- void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index,
+ void (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns, Error **errp);
- sPAPRResizeHPT resize_hpt_default;
- sPAPRCapabilities default_caps;
- sPAPRIrq *irq;
+ SpaprResizeHpt resize_hpt_default;
+ SpaprCapabilities default_caps;
+ SpaprIrq *irq;
};
/**
- * sPAPRMachineState:
+ * SpaprMachineState:
*/
-struct sPAPRMachineState {
+struct SpaprMachineState {
/*< private >*/
MachineState parent_obj;
- struct VIOsPAPRBus *vio_bus;
- QLIST_HEAD(, sPAPRPHBState) phbs;
- struct sPAPRNVRAM *nvram;
+ struct SpaprVioBus *vio_bus;
+ QLIST_HEAD(, SpaprPhbState) phbs;
+ struct SpaprNvram *nvram;
ICSState *ics;
- sPAPRRTCState rtc;
+ SpaprRtcState rtc;
- sPAPRResizeHPT resize_hpt;
+ SpaprResizeHpt resize_hpt;
void *htab;
uint32_t htab_shift;
uint64_t patb_entry; /* Process tbl registed in H_REGISTER_PROCESS_TABLE */
- sPAPRPendingHPT *pending_hpt; /* in-progress resize */
+ SpaprPendingHpt *pending_hpt; /* in-progress resize */
hwaddr rma_size;
int vrma_adjust;
@@ -155,15 +164,15 @@ struct sPAPRMachineState {
uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */
Notifier epow_notifier;
- QTAILQ_HEAD(, sPAPREventLogEntry) pending_events;
+ QTAILQ_HEAD(, SpaprEventLogEntry) pending_events;
bool use_hotplug_event_source;
- sPAPREventSource *event_sources;
+ SpaprEventSource *event_sources;
/* ibm,client-architecture-support option negotiation */
bool cas_reboot;
bool cas_legacy_guest_workaround;
- sPAPROptionVector *ov5; /* QEMU-supported option vectors */
- sPAPROptionVector *ov5_cas; /* negotiated (via CAS) option vectors */
+ SpaprOptionVector *ov5; /* QEMU-supported option vectors */
+ SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */
uint32_t max_compat_pvr;
/* Migration state */
@@ -174,7 +183,7 @@ struct sPAPRMachineState {
/* Pending DIMM unplug cache. It is populated when a LMB
* unplug starts. It can be regenerated if a migration
* occurs during the unplug process. */
- QTAILQ_HEAD(, sPAPRDIMMState) pending_dimm_unplugs;
+ QTAILQ_HEAD(, SpaprDimmState) pending_dimm_unplugs;
/*< public >*/
char *kvm_type;
@@ -183,12 +192,12 @@ struct sPAPRMachineState {
int32_t irq_map_nr;
unsigned long *irq_map;
- sPAPRXive *xive;
- sPAPRIrq *irq;
+ SpaprXive *xive;
+ SpaprIrq *irq;
qemu_irq *qirqs;
bool cmd_line_caps[SPAPR_CAP_NUM];
- sPAPRCapabilities def, eff, mig;
+ SpaprCapabilities def, eff, mig;
};
#define H_SUCCESS 0
@@ -337,9 +346,11 @@ struct sPAPRMachineState {
#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5)
#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6)
#define H_CPU_CHAR_CACHE_COUNT_DIS PPC_BIT(7)
+#define H_CPU_CHAR_BCCTR_FLUSH_ASSIST PPC_BIT(9)
#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0)
#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1)
#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2)
+#define H_CPU_BEHAV_FLUSH_COUNT_CACHE PPC_BIT(5)
/* Each control block has to be on a 4K boundary */
#define H_CB_ALIGNMENT 4096
@@ -492,16 +503,16 @@ struct sPAPRMachineState {
#define KVMPPC_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3)
#define KVMPPC_HCALL_MAX KVMPPC_H_UPDATE_DT
-typedef struct sPAPRDeviceTreeUpdateHeader {
+typedef struct SpaprDeviceTreeUpdateHeader {
uint32_t version_id;
-} sPAPRDeviceTreeUpdateHeader;
+} SpaprDeviceTreeUpdateHeader;
#define hcall_dprintf(fmt, ...) \
do { \
qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt, __func__, ## __VA_ARGS__); \
} while (0)
-typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPRMachineState *sm,
+typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, SpaprMachineState *sm,
target_ulong opcode,
target_ulong *args);
@@ -655,16 +666,16 @@ static inline void rtas_st(target_ulong phys, int n, uint32_t val)
stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val);
}
-typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, sPAPRMachineState *sm,
+typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, SpaprMachineState *sm,
uint32_t token,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets);
void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn);
-target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *sm,
+target_ulong spapr_rtas_call(PowerPCCPU *cpu, SpaprMachineState *sm,
uint32_t token, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets);
void spapr_dt_rtas_tokens(void *fdt, int rtas);
-void spapr_load_rtas(sPAPRMachineState *spapr, void *fdt, hwaddr addr);
+void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr);
#define SPAPR_TCE_PAGE_SHIFT 12
#define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT)
@@ -691,17 +702,17 @@ static inline void spapr_dt_irq(uint32_t *intspec, int irq, bool is_lsi)
intspec[1] = is_lsi ? cpu_to_be32(1) : 0;
}
-typedef struct sPAPRTCETable sPAPRTCETable;
+typedef struct SpaprTceTable SpaprTceTable;
#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table"
#define SPAPR_TCE_TABLE(obj) \
- OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE)
+ OBJECT_CHECK(SpaprTceTable, (obj), TYPE_SPAPR_TCE_TABLE)
#define TYPE_SPAPR_IOMMU_MEMORY_REGION "spapr-iommu-memory-region"
#define SPAPR_IOMMU_MEMORY_REGION(obj) \
OBJECT_CHECK(IOMMUMemoryRegion, (obj), TYPE_SPAPR_IOMMU_MEMORY_REGION)
-struct sPAPRTCETable {
+struct SpaprTceTable {
DeviceState parent;
uint32_t liobn;
uint32_t nb_table;
@@ -712,76 +723,77 @@ struct sPAPRTCETable {
uint64_t *mig_table;
bool bypass;
bool need_vfio;
+ bool skipping_replay;
int fd;
MemoryRegion root;
IOMMUMemoryRegion iommu;
- struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */
- QLIST_ENTRY(sPAPRTCETable) list;
+ struct SpaprVioDevice *vdev; /* for @bypass migration compatibility only */
+ QLIST_ENTRY(SpaprTceTable) list;
};
-sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn);
+SpaprTceTable *spapr_tce_find_by_liobn(target_ulong liobn);
-struct sPAPREventLogEntry {
+struct SpaprEventLogEntry {
uint32_t summary;
uint32_t extended_length;
void *extended_log;
- QTAILQ_ENTRY(sPAPREventLogEntry) next;
+ QTAILQ_ENTRY(SpaprEventLogEntry) next;
};
-void spapr_events_init(sPAPRMachineState *sm);
-void spapr_dt_events(sPAPRMachineState *sm, void *fdt);
-int spapr_h_cas_compose_response(sPAPRMachineState *sm,
+void spapr_events_init(SpaprMachineState *sm);
+void spapr_dt_events(SpaprMachineState *sm, void *fdt);
+int spapr_h_cas_compose_response(SpaprMachineState *sm,
target_ulong addr, target_ulong size,
- sPAPROptionVector *ov5_updates);
-void close_htab_fd(sPAPRMachineState *spapr);
-void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr);
-void spapr_free_hpt(sPAPRMachineState *spapr);
-sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
-void spapr_tce_table_enable(sPAPRTCETable *tcet,
+ SpaprOptionVector *ov5_updates);
+void close_htab_fd(SpaprMachineState *spapr);
+void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr);
+void spapr_free_hpt(SpaprMachineState *spapr);
+SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
+void spapr_tce_table_enable(SpaprTceTable *tcet,
uint32_t page_shift, uint64_t bus_offset,
uint32_t nb_table);
-void spapr_tce_table_disable(sPAPRTCETable *tcet);
-void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio);
+void spapr_tce_table_disable(SpaprTceTable *tcet);
+void spapr_tce_set_need_vfio(SpaprTceTable *tcet, bool need_vfio);
-MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet);
+MemoryRegion *spapr_tce_get_iommu(SpaprTceTable *tcet);
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
uint32_t liobn, uint64_t window, uint32_t size);
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
- sPAPRTCETable *tcet);
+ SpaprTceTable *tcet);
void spapr_pci_switch_vga(bool big_endian);
-void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc);
-void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc);
-void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_add_by_index(SpaprDrc *drc);
+void spapr_hotplug_req_remove_by_index(SpaprDrc *drc);
+void spapr_hotplug_req_add_by_count(SpaprDrcType drc_type,
uint32_t count);
-void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_remove_by_count(SpaprDrcType drc_type,
uint32_t count);
-void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_add_by_count_indexed(SpaprDrcType drc_type,
uint32_t count, uint32_t index);
-void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
+void spapr_hotplug_req_remove_by_count_indexed(SpaprDrcType drc_type,
uint32_t count, uint32_t index);
int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
-void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
+void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
Error **errp);
-void spapr_clear_pending_events(sPAPRMachineState *spapr);
-int spapr_max_server_number(sPAPRMachineState *spapr);
+void spapr_clear_pending_events(SpaprMachineState *spapr);
+int spapr_max_server_number(SpaprMachineState *spapr);
/* DRC callbacks. */
void spapr_core_release(DeviceState *dev);
-int spapr_core_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
void spapr_lmb_release(DeviceState *dev);
-int spapr_lmb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
void spapr_phb_release(DeviceState *dev);
-int spapr_phb_dt_populate(sPAPRDRConnector *drc, sPAPRMachineState *spapr,
+int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
-void spapr_rtc_read(sPAPRRTCState *rtc, struct tm *tm, uint32_t *ns);
-int spapr_rtc_import_offset(sPAPRRTCState *rtc, int64_t legacy_offset);
+void spapr_rtc_read(SpaprRtcState *rtc, struct tm *tm, uint32_t *ns);
+int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset);
#define TYPE_SPAPR_RNG "spapr-rng"
-#define SPAPR_MEMORY_BLOCK_SIZE (1 << 28) /* 256MB */
+#define SPAPR_MEMORY_BLOCK_SIZE ((hwaddr)1 << 28) /* 256MB */
/*
* This defines the maximum number of DIMM slots we can have for sPAPR
@@ -828,19 +840,21 @@ extern const VMStateDescription vmstate_spapr_cap_cfpc;
extern const VMStateDescription vmstate_spapr_cap_sbbc;
extern const VMStateDescription vmstate_spapr_cap_ibs;
extern const VMStateDescription vmstate_spapr_cap_nested_kvm_hv;
+extern const VMStateDescription vmstate_spapr_cap_large_decr;
+extern const VMStateDescription vmstate_spapr_cap_ccf_assist;
-static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap)
+static inline uint8_t spapr_get_cap(SpaprMachineState *spapr, int cap)
{
return spapr->eff.caps[cap];
}
-void spapr_caps_init(sPAPRMachineState *spapr);
-void spapr_caps_apply(sPAPRMachineState *spapr);
-void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu);
-void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp);
-int spapr_caps_post_migration(sPAPRMachineState *spapr);
+void spapr_caps_init(SpaprMachineState *spapr);
+void spapr_caps_apply(SpaprMachineState *spapr);
+void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu);
+void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp);
+int spapr_caps_post_migration(SpaprMachineState *spapr);
-void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize,
+void spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize,
Error **errp);
/*
* XIVE definitions
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index d64f86bc28..f9645a7290 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -16,43 +16,43 @@
#define TYPE_SPAPR_CPU_CORE "spapr-cpu-core"
#define SPAPR_CPU_CORE(obj) \
- OBJECT_CHECK(sPAPRCPUCore, (obj), TYPE_SPAPR_CPU_CORE)
+ OBJECT_CHECK(SpaprCpuCore, (obj), TYPE_SPAPR_CPU_CORE)
#define SPAPR_CPU_CORE_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRCPUCoreClass, (klass), TYPE_SPAPR_CPU_CORE)
+ OBJECT_CLASS_CHECK(SpaprCpuCoreClass, (klass), TYPE_SPAPR_CPU_CORE)
#define SPAPR_CPU_CORE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRCPUCoreClass, (obj), TYPE_SPAPR_CPU_CORE)
+ OBJECT_GET_CLASS(SpaprCpuCoreClass, (obj), TYPE_SPAPR_CPU_CORE)
#define SPAPR_CPU_CORE_TYPE_NAME(model) model "-" TYPE_SPAPR_CPU_CORE
-typedef struct sPAPRCPUCore {
+typedef struct SpaprCpuCore {
/*< private >*/
CPUCore parent_obj;
/*< public >*/
PowerPCCPU **threads;
int node_id;
- bool pre_3_0_migration; /* older machine don't know about sPAPRCPUState */
-} sPAPRCPUCore;
+ bool pre_3_0_migration; /* older machine don't know about SpaprCpuState */
+} SpaprCpuCore;
-typedef struct sPAPRCPUCoreClass {
+typedef struct SpaprCpuCoreClass {
DeviceClass parent_class;
const char *cpu_type;
-} sPAPRCPUCoreClass;
+} SpaprCpuCoreClass;
const char *spapr_get_cpu_core_type(const char *cpu_type);
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3);
-typedef struct sPAPRCPUState {
+typedef struct SpaprCpuState {
uint64_t vpa_addr;
uint64_t slb_shadow_addr, slb_shadow_size;
uint64_t dtl_addr, dtl_size;
struct ICPState *icp;
struct XiveTCTX *tctx;
-} sPAPRCPUState;
+} SpaprCpuState;
-static inline sPAPRCPUState *spapr_cpu_state(PowerPCCPU *cpu)
+static inline SpaprCpuState *spapr_cpu_state(PowerPCCPU *cpu)
{
- return (sPAPRCPUState *)cpu->machine_data;
+ return (SpaprCpuState *)cpu->machine_data;
}
#endif
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
index 46b0f6216d..fad0a887f9 100644
--- a/include/hw/ppc/spapr_drc.h
+++ b/include/hw/ppc/spapr_drc.h
@@ -22,65 +22,65 @@
#define TYPE_SPAPR_DR_CONNECTOR "spapr-dr-connector"
#define SPAPR_DR_CONNECTOR_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DR_CONNECTOR)
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DR_CONNECTOR)
#define SPAPR_DR_CONNECTOR_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, \
TYPE_SPAPR_DR_CONNECTOR)
-#define SPAPR_DR_CONNECTOR(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
+#define SPAPR_DR_CONNECTOR(obj) OBJECT_CHECK(SpaprDrc, (obj), \
TYPE_SPAPR_DR_CONNECTOR)
#define TYPE_SPAPR_DRC_PHYSICAL "spapr-drc-physical"
#define SPAPR_DRC_PHYSICAL_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DRC_PHYSICAL)
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DRC_PHYSICAL)
#define SPAPR_DRC_PHYSICAL_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, \
TYPE_SPAPR_DRC_PHYSICAL)
-#define SPAPR_DRC_PHYSICAL(obj) OBJECT_CHECK(sPAPRDRCPhysical, (obj), \
+#define SPAPR_DRC_PHYSICAL(obj) OBJECT_CHECK(SpaprDrcPhysical, (obj), \
TYPE_SPAPR_DRC_PHYSICAL)
#define TYPE_SPAPR_DRC_LOGICAL "spapr-drc-logical"
#define SPAPR_DRC_LOGICAL_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DRC_LOGICAL)
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DRC_LOGICAL)
#define SPAPR_DRC_LOGICAL_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, \
TYPE_SPAPR_DRC_LOGICAL)
-#define SPAPR_DRC_LOGICAL(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
+#define SPAPR_DRC_LOGICAL(obj) OBJECT_CHECK(SpaprDrc, (obj), \
TYPE_SPAPR_DRC_LOGICAL)
#define TYPE_SPAPR_DRC_CPU "spapr-drc-cpu"
#define SPAPR_DRC_CPU_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DRC_CPU)
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DRC_CPU)
#define SPAPR_DRC_CPU_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, TYPE_SPAPR_DRC_CPU)
-#define SPAPR_DRC_CPU(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, TYPE_SPAPR_DRC_CPU)
+#define SPAPR_DRC_CPU(obj) OBJECT_CHECK(SpaprDrc, (obj), \
TYPE_SPAPR_DRC_CPU)
#define TYPE_SPAPR_DRC_PCI "spapr-drc-pci"
#define SPAPR_DRC_PCI_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DRC_PCI)
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DRC_PCI)
#define SPAPR_DRC_PCI_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, TYPE_SPAPR_DRC_PCI)
-#define SPAPR_DRC_PCI(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, TYPE_SPAPR_DRC_PCI)
+#define SPAPR_DRC_PCI(obj) OBJECT_CHECK(SpaprDrc, (obj), \
TYPE_SPAPR_DRC_PCI)
#define TYPE_SPAPR_DRC_LMB "spapr-drc-lmb"
#define SPAPR_DRC_LMB_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DRC_LMB)
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DRC_LMB)
#define SPAPR_DRC_LMB_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, TYPE_SPAPR_DRC_LMB)
-#define SPAPR_DRC_LMB(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, TYPE_SPAPR_DRC_LMB)
+#define SPAPR_DRC_LMB(obj) OBJECT_CHECK(SpaprDrc, (obj), \
TYPE_SPAPR_DRC_LMB)
#define TYPE_SPAPR_DRC_PHB "spapr-drc-phb"
#define SPAPR_DRC_PHB_GET_CLASS(obj) \
- OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DRC_PHB)
+ OBJECT_GET_CLASS(SpaprDrcClass, obj, TYPE_SPAPR_DRC_PHB)
#define SPAPR_DRC_PHB_CLASS(klass) \
- OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, TYPE_SPAPR_DRC_PHB)
-#define SPAPR_DRC_PHB(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
+ OBJECT_CLASS_CHECK(SpaprDrcClass, klass, TYPE_SPAPR_DRC_PHB)
+#define SPAPR_DRC_PHB(obj) OBJECT_CHECK(SpaprDrc, (obj), \
TYPE_SPAPR_DRC_PHB)
/*
- * Various hotplug types managed by sPAPRDRConnector
+ * Various hotplug types managed by SpaprDrc
*
* these are somewhat arbitrary, but to make things easier
* when generating DRC indexes later we've aligned the bit
@@ -96,7 +96,7 @@ typedef enum {
SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO = 3,
SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI = 4,
SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB = 8,
-} sPAPRDRConnectorTypeShift;
+} SpaprDrcTypeShift;
typedef enum {
SPAPR_DR_CONNECTOR_TYPE_ANY = ~0,
@@ -105,7 +105,7 @@ typedef enum {
SPAPR_DR_CONNECTOR_TYPE_VIO = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO,
SPAPR_DR_CONNECTOR_TYPE_PCI = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI,
SPAPR_DR_CONNECTOR_TYPE_LMB = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB,
-} sPAPRDRConnectorType;
+} SpaprDrcType;
/*
* set via set-indicator RTAS calls
@@ -117,7 +117,7 @@ typedef enum {
typedef enum {
SPAPR_DR_ISOLATION_STATE_ISOLATED = 0,
SPAPR_DR_ISOLATION_STATE_UNISOLATED = 1
-} sPAPRDRIsolationState;
+} SpaprDRIsolationState;
/*
* set via set-indicator RTAS calls
@@ -133,7 +133,7 @@ typedef enum {
SPAPR_DR_ALLOCATION_STATE_USABLE = 1,
SPAPR_DR_ALLOCATION_STATE_EXCHANGE = 2,
SPAPR_DR_ALLOCATION_STATE_RECOVER = 3
-} sPAPRDRAllocationState;
+} SpaprDRAllocationState;
/*
* DR-indicator (LED/visual indicator)
@@ -152,7 +152,7 @@ typedef enum {
SPAPR_DR_INDICATOR_ACTIVE = 1,
SPAPR_DR_INDICATOR_IDENTIFY = 2,
SPAPR_DR_INDICATOR_ACTION = 3,
-} sPAPRDRIndicatorState;
+} SpaprDRIndicatorState;
/*
* returned via get-sensor-state RTAS calls
@@ -170,7 +170,7 @@ typedef enum {
SPAPR_DR_ENTITY_SENSE_UNUSABLE = 2,
SPAPR_DR_ENTITY_SENSE_EXCHANGE = 3,
SPAPR_DR_ENTITY_SENSE_RECOVER = 4,
-} sPAPRDREntitySense;
+} SpaprDREntitySense;
typedef enum {
SPAPR_DR_CC_RESPONSE_NEXT_SIB = 1, /* currently unused */
@@ -181,7 +181,7 @@ typedef enum {
SPAPR_DR_CC_RESPONSE_ERROR = -1,
SPAPR_DR_CC_RESPONSE_CONTINUE = -2,
SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE = -9003,
-} sPAPRDRCCResponse;
+} SpaprDRCCResponse;
typedef enum {
/*
@@ -199,9 +199,9 @@ typedef enum {
SPAPR_DRC_STATE_PHYSICAL_POWERON = 6,
SPAPR_DRC_STATE_PHYSICAL_UNISOLATE = 7,
SPAPR_DRC_STATE_PHYSICAL_CONFIGURED = 8,
-} sPAPRDRCState;
+} SpaprDrcState;
-typedef struct sPAPRDRConnector {
+typedef struct SpaprDrc {
/*< private >*/
DeviceState parent;
@@ -220,60 +220,60 @@ typedef struct sPAPRDRConnector {
bool unplug_requested;
void *fdt;
int fdt_start_offset;
-} sPAPRDRConnector;
+} SpaprDrc;
-struct sPAPRMachineState;
+struct SpaprMachineState;
-typedef struct sPAPRDRConnectorClass {
+typedef struct SpaprDrcClass {
/*< private >*/
DeviceClass parent;
- sPAPRDRCState empty_state;
- sPAPRDRCState ready_state;
+ SpaprDrcState empty_state;
+ SpaprDrcState ready_state;
/*< public >*/
- sPAPRDRConnectorTypeShift typeshift;
+ SpaprDrcTypeShift typeshift;
const char *typename; /* used in device tree, PAPR 13.5.2.6 & C.6.1 */
const char *drc_name_prefix; /* used other places in device tree */
- sPAPRDREntitySense (*dr_entity_sense)(sPAPRDRConnector *drc);
- uint32_t (*isolate)(sPAPRDRConnector *drc);
- uint32_t (*unisolate)(sPAPRDRConnector *drc);
+ SpaprDREntitySense (*dr_entity_sense)(SpaprDrc *drc);
+ uint32_t (*isolate)(SpaprDrc *drc);
+ uint32_t (*unisolate)(SpaprDrc *drc);
void (*release)(DeviceState *dev);
- int (*dt_populate)(sPAPRDRConnector *drc, struct sPAPRMachineState *spapr,
+ int (*dt_populate)(SpaprDrc *drc, struct SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
-} sPAPRDRConnectorClass;
+} SpaprDrcClass;
-typedef struct sPAPRDRCPhysical {
+typedef struct SpaprDrcPhysical {
/*< private >*/
- sPAPRDRConnector parent;
+ SpaprDrc parent;
/* DR-indicator */
uint32_t dr_indicator;
-} sPAPRDRCPhysical;
+} SpaprDrcPhysical;
static inline bool spapr_drc_hotplugged(DeviceState *dev)
{
return dev->hotplugged && !runstate_check(RUN_STATE_INMIGRATE);
}
-void spapr_drc_reset(sPAPRDRConnector *drc);
+void spapr_drc_reset(SpaprDrc *drc);
-uint32_t spapr_drc_index(sPAPRDRConnector *drc);
-sPAPRDRConnectorType spapr_drc_type(sPAPRDRConnector *drc);
+uint32_t spapr_drc_index(SpaprDrc *drc);
+SpaprDrcType spapr_drc_type(SpaprDrc *drc);
-sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
+SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
uint32_t id);
-sPAPRDRConnector *spapr_drc_by_index(uint32_t index);
-sPAPRDRConnector *spapr_drc_by_id(const char *type, uint32_t id);
+SpaprDrc *spapr_drc_by_index(uint32_t index);
+SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id);
int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
uint32_t drc_type_mask);
-void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, Error **errp);
-void spapr_drc_detach(sPAPRDRConnector *drc);
+void spapr_drc_attach(SpaprDrc *drc, DeviceState *d, Error **errp);
+void spapr_drc_detach(SpaprDrc *drc);
bool spapr_drc_needed(void *opaque);
-static inline bool spapr_drc_unplug_requested(sPAPRDRConnector *drc)
+static inline bool spapr_drc_unplug_requested(SpaprDrc *drc)
{
return drc->unplug_requested;
}
diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h
index ec1ee64fa6..b855f74e44 100644
--- a/include/hw/ppc/spapr_irq.h
+++ b/include/hw/ppc/spapr_irq.h
@@ -22,51 +22,51 @@
#define SPAPR_IRQ_MSI 0x1300 /* Offset of the dynamic range covered
* by the bitmap allocator */
-typedef struct sPAPRMachineState sPAPRMachineState;
+typedef struct SpaprMachineState SpaprMachineState;
-void spapr_irq_msi_init(sPAPRMachineState *spapr, uint32_t nr_msis);
-int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
+void spapr_irq_msi_init(SpaprMachineState *spapr, uint32_t nr_msis);
+int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align,
Error **errp);
-void spapr_irq_msi_free(sPAPRMachineState *spapr, int irq, uint32_t num);
-void spapr_irq_msi_reset(sPAPRMachineState *spapr);
+void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num);
+void spapr_irq_msi_reset(SpaprMachineState *spapr);
-typedef struct sPAPRIrq {
+typedef struct SpaprIrq {
uint32_t nr_irqs;
uint32_t nr_msis;
uint8_t ov5;
- void (*init)(sPAPRMachineState *spapr, int nr_irqs, Error **errp);
- int (*claim)(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
- void (*free)(sPAPRMachineState *spapr, int irq, int num);
- qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq);
- void (*print_info)(sPAPRMachineState *spapr, Monitor *mon);
- void (*dt_populate)(sPAPRMachineState *spapr, uint32_t nr_servers,
+ void (*init)(SpaprMachineState *spapr, int nr_irqs, Error **errp);
+ int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp);
+ void (*free)(SpaprMachineState *spapr, int irq, int num);
+ qemu_irq (*qirq)(SpaprMachineState *spapr, int irq);
+ void (*print_info)(SpaprMachineState *spapr, Monitor *mon);
+ void (*dt_populate)(SpaprMachineState *spapr, uint32_t nr_servers,
void *fdt, uint32_t phandle);
- void (*cpu_intc_create)(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+ void (*cpu_intc_create)(SpaprMachineState *spapr, PowerPCCPU *cpu,
Error **errp);
- int (*post_load)(sPAPRMachineState *spapr, int version_id);
- void (*reset)(sPAPRMachineState *spapr, Error **errp);
+ int (*post_load)(SpaprMachineState *spapr, int version_id);
+ void (*reset)(SpaprMachineState *spapr, Error **errp);
void (*set_irq)(void *opaque, int srcno, int val);
- const char *(*get_nodename)(sPAPRMachineState *spapr);
-} sPAPRIrq;
+ const char *(*get_nodename)(SpaprMachineState *spapr);
+} SpaprIrq;
-extern sPAPRIrq spapr_irq_xics;
-extern sPAPRIrq spapr_irq_xics_legacy;
-extern sPAPRIrq spapr_irq_xive;
-extern sPAPRIrq spapr_irq_dual;
+extern SpaprIrq spapr_irq_xics;
+extern SpaprIrq spapr_irq_xics_legacy;
+extern SpaprIrq spapr_irq_xive;
+extern SpaprIrq spapr_irq_dual;
-void spapr_irq_init(sPAPRMachineState *spapr, Error **errp);
-int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
-void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
-qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
-int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id);
-void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp);
-int spapr_irq_get_phandle(sPAPRMachineState *spapr, void *fdt, Error **errp);
+void spapr_irq_init(SpaprMachineState *spapr, Error **errp);
+int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp);
+void spapr_irq_free(SpaprMachineState *spapr, int irq, int num);
+qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq);
+int spapr_irq_post_load(SpaprMachineState *spapr, int version_id);
+void spapr_irq_reset(SpaprMachineState *spapr, Error **errp);
+int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp);
/*
* XICS legacy routines
*/
-int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp);
+int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp);
#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp)
#endif
diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h
index 0f2d8d715d..188a9367e2 100644
--- a/include/hw/ppc/spapr_ovec.h
+++ b/include/hw/ppc/spapr_ovec.h
@@ -39,7 +39,7 @@
#include "cpu.h"
#include "migration/vmstate.h"
-typedef struct sPAPROptionVector sPAPROptionVector;
+typedef struct SpaprOptionVector SpaprOptionVector;
#define OV_BIT(byte, bit) ((byte - 1) * BITS_PER_BYTE + bit)
@@ -61,21 +61,21 @@ typedef struct sPAPROptionVector sPAPROptionVector;
#define OV5_MMU_RADIX_GTSE OV_BIT(26, 1) /* Radix GTSE */
/* interfaces */
-sPAPROptionVector *spapr_ovec_new(void);
-sPAPROptionVector *spapr_ovec_clone(sPAPROptionVector *ov_orig);
-void spapr_ovec_intersect(sPAPROptionVector *ov,
- sPAPROptionVector *ov1,
- sPAPROptionVector *ov2);
-bool spapr_ovec_diff(sPAPROptionVector *ov,
- sPAPROptionVector *ov_old,
- sPAPROptionVector *ov_new);
-void spapr_ovec_cleanup(sPAPROptionVector *ov);
-void spapr_ovec_set(sPAPROptionVector *ov, long bitnr);
-void spapr_ovec_clear(sPAPROptionVector *ov, long bitnr);
-bool spapr_ovec_test(sPAPROptionVector *ov, long bitnr);
-sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector);
+SpaprOptionVector *spapr_ovec_new(void);
+SpaprOptionVector *spapr_ovec_clone(SpaprOptionVector *ov_orig);
+void spapr_ovec_intersect(SpaprOptionVector *ov,
+ SpaprOptionVector *ov1,
+ SpaprOptionVector *ov2);
+bool spapr_ovec_diff(SpaprOptionVector *ov,
+ SpaprOptionVector *ov_old,
+ SpaprOptionVector *ov_new);
+void spapr_ovec_cleanup(SpaprOptionVector *ov);
+void spapr_ovec_set(SpaprOptionVector *ov, long bitnr);
+void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr);
+bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr);
+SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector);
int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
- sPAPROptionVector *ov, const char *name);
+ SpaprOptionVector *ov, const char *name);
/* migration */
extern const VMStateDescription vmstate_spapr_ovec;
diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h
index e8b006d18f..04609f214e 100644
--- a/include/hw/ppc/spapr_vio.h
+++ b/include/hw/ppc/spapr_vio.h
@@ -26,91 +26,91 @@
#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device"
#define VIO_SPAPR_DEVICE(obj) \
- OBJECT_CHECK(VIOsPAPRDevice, (obj), TYPE_VIO_SPAPR_DEVICE)
+ OBJECT_CHECK(SpaprVioDevice, (obj), TYPE_VIO_SPAPR_DEVICE)
#define VIO_SPAPR_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(VIOsPAPRDeviceClass, (klass), TYPE_VIO_SPAPR_DEVICE)
+ OBJECT_CLASS_CHECK(SpaprVioDeviceClass, (klass), TYPE_VIO_SPAPR_DEVICE)
#define VIO_SPAPR_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VIOsPAPRDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE)
+ OBJECT_GET_CLASS(SpaprVioDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE)
#define TYPE_SPAPR_VIO_BUS "spapr-vio-bus"
-#define SPAPR_VIO_BUS(obj) OBJECT_CHECK(VIOsPAPRBus, (obj), TYPE_SPAPR_VIO_BUS)
+#define SPAPR_VIO_BUS(obj) OBJECT_CHECK(SpaprVioBus, (obj), TYPE_SPAPR_VIO_BUS)
#define TYPE_SPAPR_VIO_BRIDGE "spapr-vio-bridge"
-typedef struct VIOsPAPR_CRQ {
+typedef struct SpaprVioCrq {
uint64_t qladdr;
uint32_t qsize;
uint32_t qnext;
- int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
-} VIOsPAPR_CRQ;
+ int(*SendFunc)(struct SpaprVioDevice *vdev, uint8_t *crq);
+} SpaprVioCrq;
-typedef struct VIOsPAPRDevice VIOsPAPRDevice;
-typedef struct VIOsPAPRBus VIOsPAPRBus;
+typedef struct SpaprVioDevice SpaprVioDevice;
+typedef struct SpaprVioBus SpaprVioBus;
-typedef struct VIOsPAPRDeviceClass {
+typedef struct SpaprVioDeviceClass {
DeviceClass parent_class;
const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask;
uint32_t rtce_window_size;
- void (*realize)(VIOsPAPRDevice *dev, Error **errp);
- void (*reset)(VIOsPAPRDevice *dev);
- int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
-} VIOsPAPRDeviceClass;
+ void (*realize)(SpaprVioDevice *dev, Error **errp);
+ void (*reset)(SpaprVioDevice *dev);
+ int (*devnode)(SpaprVioDevice *dev, void *fdt, int node_off);
+} SpaprVioDeviceClass;
-struct VIOsPAPRDevice {
+struct SpaprVioDevice {
DeviceState qdev;
uint32_t reg;
uint32_t irq;
uint64_t signal_state;
- VIOsPAPR_CRQ crq;
+ SpaprVioCrq crq;
AddressSpace as;
MemoryRegion mrroot;
MemoryRegion mrbypass;
- sPAPRTCETable *tcet;
+ SpaprTceTable *tcet;
};
#define DEFINE_SPAPR_PROPERTIES(type, field) \
DEFINE_PROP_UINT32("reg", type, field.reg, -1)
-struct VIOsPAPRBus {
+struct SpaprVioBus {
BusState bus;
uint32_t next_reg;
};
-extern VIOsPAPRBus *spapr_vio_bus_init(void);
-extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
-void spapr_dt_vdevice(VIOsPAPRBus *bus, void *fdt);
-extern gchar *spapr_vio_stdout_path(VIOsPAPRBus *bus);
+extern SpaprVioBus *spapr_vio_bus_init(void);
+extern SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg);
+void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt);
+extern gchar *spapr_vio_stdout_path(SpaprVioBus *bus);
-static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
+static inline qemu_irq spapr_vio_qirq(SpaprVioDevice *dev)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
return spapr_qirq(spapr, dev->irq);
}
-static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
+static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr,
uint32_t size, DMADirection dir)
{
return dma_memory_valid(&dev->as, taddr, size, dir);
}
-static inline int spapr_vio_dma_read(VIOsPAPRDevice *dev, uint64_t taddr,
+static inline int spapr_vio_dma_read(SpaprVioDevice *dev, uint64_t taddr,
void *buf, uint32_t size)
{
return (dma_memory_read(&dev->as, taddr, buf, size) != 0) ?
H_DEST_PARM : H_SUCCESS;
}
-static inline int spapr_vio_dma_write(VIOsPAPRDevice *dev, uint64_t taddr,
+static inline int spapr_vio_dma_write(SpaprVioDevice *dev, uint64_t taddr,
const void *buf, uint32_t size)
{
return (dma_memory_write(&dev->as, taddr, buf, size) != 0) ?
H_DEST_PARM : H_SUCCESS;
}
-static inline int spapr_vio_dma_set(VIOsPAPRDevice *dev, uint64_t taddr,
+static inline int spapr_vio_dma_set(SpaprVioDevice *dev, uint64_t taddr,
uint8_t c, uint32_t size)
{
return (dma_memory_set(&dev->as, taddr, c, size) != 0) ?
@@ -123,21 +123,21 @@ static inline int spapr_vio_dma_set(VIOsPAPRDevice *dev, uint64_t taddr,
#define vio_stq(_dev, _addr, _val) (stq_be_dma(&(_dev)->as, (_addr), (_val)))
#define vio_ldq(_dev, _addr) (ldq_be_dma(&(_dev)->as, (_addr)))
-int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
+int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq);
-VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg);
-void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
-void spapr_vty_create(VIOsPAPRBus *bus, Chardev *chardev);
-void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd);
-void spapr_vscsi_create(VIOsPAPRBus *bus);
+SpaprVioDevice *vty_lookup(SpaprMachineState *spapr, target_ulong reg);
+void vty_putchars(SpaprVioDevice *sdev, uint8_t *buf, int len);
+void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev);
+void spapr_vlan_create(SpaprVioBus *bus, NICInfo *nd);
+void spapr_vscsi_create(SpaprVioBus *bus);
-VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
+SpaprVioDevice *spapr_vty_get_default(SpaprVioBus *bus);
extern const VMStateDescription vmstate_spapr_vio;
#define VMSTATE_SPAPR_VIO(_f, _s) \
- VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, VIOsPAPRDevice)
+ VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, SpaprVioDevice)
-void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass);
+void spapr_vio_set_bypass(SpaprVioDevice *dev, bool bypass);
#endif /* HW_SPAPR_VIO_H */
diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h
index 2d31f24e3b..fc3e9652f9 100644
--- a/include/hw/ppc/spapr_xive.h
+++ b/include/hw/ppc/spapr_xive.h
@@ -13,9 +13,9 @@
#include "hw/ppc/xive.h"
#define TYPE_SPAPR_XIVE "spapr-xive"
-#define SPAPR_XIVE(obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE)
+#define SPAPR_XIVE(obj) OBJECT_CHECK(SpaprXive, (obj), TYPE_SPAPR_XIVE)
-typedef struct sPAPRXive {
+typedef struct SpaprXive {
XiveRouter parent;
/* Internal interrupt source for IPIs and virtual devices */
@@ -38,16 +38,16 @@ typedef struct sPAPRXive {
/* TIMA mapping address */
hwaddr tm_base;
MemoryRegion tm_mmio;
-} sPAPRXive;
+} SpaprXive;
-bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi);
-bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn);
-void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon);
+bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi);
+bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn);
+void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon);
-void spapr_xive_hcall_init(sPAPRMachineState *spapr);
-void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+void spapr_xive_hcall_init(SpaprMachineState *spapr);
+void spapr_dt_xive(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
uint32_t phandle);
void spapr_xive_set_tctx_os_cam(XiveTCTX *tctx);
-void spapr_xive_mmio_set_enabled(sPAPRXive *xive, bool enable);
+void spapr_xive_mmio_set_enabled(SpaprXive *xive, bool enable);
#endif /* PPC_SPAPR_XIVE_H */
diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h
index b8d924baf4..15a8dcff66 100644
--- a/include/hw/ppc/xics_spapr.h
+++ b/include/hw/ppc/xics_spapr.h
@@ -31,9 +31,9 @@
#define XICS_NODENAME "interrupt-controller"
-void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
uint32_t phandle);
-int xics_kvm_init(sPAPRMachineState *spapr, Error **errp);
-void xics_spapr_init(sPAPRMachineState *spapr);
+int xics_kvm_init(SpaprMachineState *spapr, Error **errp);
+void xics_spapr_init(SpaprMachineState *spapr);
#endif /* XICS_SPAPR_H */
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 13a487527b..c4f27742ca 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -364,6 +364,7 @@ int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
XiveNVT *nvt, uint8_t word_number);
XiveTCTX *xive_router_get_tctx(XiveRouter *xrtr, CPUState *cs);
+void xive_router_notify(XiveNotifier *xn, uint32_t lisn);
/*
* XIVE END ESBs
@@ -410,6 +411,9 @@ void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
#define XIVE_TM_USER_PAGE 0x3
extern const MemoryRegionOps xive_tm_ops;
+void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
+ unsigned size);
+uint64_t xive_tctx_tm_read(XiveTCTX *tctx, hwaddr offset, unsigned size);
void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon);
Object *xive_tctx_create(Object *cpu, XiveRouter *xrtr, Error **errp);
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 17f09aac72..33ed3b8dde 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -431,8 +431,6 @@ const char *qdev_fw_name(DeviceState *dev);
Object *qdev_get_machine(void);
-void object_apply_compat_props(Object *obj);
-
/* FIXME: make this a link<> */
void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 7624c9f511..1155b79678 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -148,6 +148,10 @@ typedef struct 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;
@@ -189,6 +193,8 @@ int vfio_get_region_info(VFIODevice *vbasedev, int index,
int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
uint32_t subtype, struct vfio_region_info **info);
bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type);
+struct vfio_info_cap_header *
+vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id);
#endif
extern const MemoryListener vfio_prereg_listener;
diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h
index 81283ec50f..d6632a18e6 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -25,6 +25,7 @@ typedef enum VhostSetConfigType {
VHOST_SET_CONFIG_TYPE_MIGRATION = 1,
} VhostSetConfigType;
+struct vhost_inflight;
struct vhost_dev;
struct vhost_log;
struct vhost_memory;
@@ -104,6 +105,13 @@ typedef int (*vhost_crypto_close_session_op)(struct vhost_dev *dev,
typedef bool (*vhost_backend_mem_section_filter_op)(struct vhost_dev *dev,
MemoryRegionSection *section);
+typedef int (*vhost_get_inflight_fd_op)(struct vhost_dev *dev,
+ uint16_t queue_size,
+ struct vhost_inflight *inflight);
+
+typedef int (*vhost_set_inflight_fd_op)(struct vhost_dev *dev,
+ struct vhost_inflight *inflight);
+
typedef struct VhostOps {
VhostBackendType backend_type;
vhost_backend_init vhost_backend_init;
@@ -142,6 +150,8 @@ typedef struct VhostOps {
vhost_crypto_create_session_op vhost_crypto_create_session;
vhost_crypto_close_session_op vhost_crypto_close_session;
vhost_backend_mem_section_filter_op vhost_backend_mem_section_filter;
+ vhost_get_inflight_fd_op vhost_get_inflight_fd;
+ vhost_set_inflight_fd_op vhost_set_inflight_fd;
} VhostOps;
extern const VhostOps user_ops;
diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h
index d52944aeeb..68634bee61 100644
--- a/include/hw/virtio/vhost-user-blk.h
+++ b/include/hw/virtio/vhost-user-blk.h
@@ -36,7 +36,8 @@ typedef struct VHostUserBlk {
uint32_t queue_size;
uint32_t config_wce;
struct vhost_dev dev;
- VhostUserState *vhost_user;
+ struct vhost_inflight *inflight;
+ VhostUserState vhost_user;
} VHostUserBlk;
#endif
diff --git a/include/hw/virtio/vhost-user-scsi.h b/include/hw/virtio/vhost-user-scsi.h
index e429cacd8e..738f9288bd 100644
--- a/include/hw/virtio/vhost-user-scsi.h
+++ b/include/hw/virtio/vhost-user-scsi.h
@@ -30,7 +30,7 @@
typedef struct VHostUserSCSI {
VHostSCSICommon parent_obj;
- VhostUserState *vhost_user;
+ VhostUserState vhost_user;
} VHostUserSCSI;
#endif /* VHOST_USER_SCSI_H */
diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
index fd660393a0..811e325f42 100644
--- a/include/hw/virtio/vhost-user.h
+++ b/include/hw/virtio/vhost-user.h
@@ -22,7 +22,7 @@ typedef struct VhostUserState {
VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX];
} VhostUserState;
-VhostUserState *vhost_user_init(void);
+bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp);
void vhost_user_cleanup(VhostUserState *user);
#endif
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index a7f449fa87..619498c8f4 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -7,6 +7,15 @@
#include "exec/memory.h"
/* Generic structures common for any vhost based device. */
+
+struct vhost_inflight {
+ int fd;
+ void *addr;
+ uint64_t size;
+ uint64_t offset;
+ uint16_t queue_size;
+};
+
struct vhost_virtqueue {
int kick;
int call;
@@ -120,4 +129,13 @@ int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data,
*/
void vhost_dev_set_config_notifier(struct vhost_dev *dev,
const VhostDevConfigOps *ops);
+
+void vhost_dev_reset_inflight(struct vhost_inflight *inflight);
+void vhost_dev_free_inflight(struct vhost_inflight *inflight);
+void vhost_dev_save_inflight(struct vhost_inflight *inflight, QEMUFile *f);
+int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f);
+int vhost_dev_set_inflight(struct vhost_dev *dev,
+ struct vhost_inflight *inflight);
+int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size,
+ struct vhost_inflight *inflight);
#endif
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 840af09cb0..303d315c5d 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -571,6 +571,19 @@ void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus,
Error **errp);
/**
+ * qemu_get_pmem_size:
+ * @filename: path to a pmem file
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Determine the size of a persistent memory file. Besides supporting files on
+ * DAX file systems, this function also supports Linux devdax character
+ * devices.
+ *
+ * Returns: the size or 0 on failure
+ */
+uint64_t qemu_get_pmem_size(const char *filename, Error **errp);
+
+/**
* qemu_get_pid_name:
* @pid: pid of a process
*
diff --git a/include/qom/object.h b/include/qom/object.h
index e0262962b5..288cdddf44 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -677,6 +677,9 @@ Object *object_new_with_propv(const char *typename,
void object_apply_global_props(Object *obj, const GPtrArray *props,
Error **errp);
+void object_set_machine_compat_props(GPtrArray *compat_props);
+void object_set_accelerator_compat_props(GPtrArray *compat_props);
+void object_apply_compat_props(Object *obj);
/**
* object_set_props:
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 89604a8328..6065d9e420 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -110,7 +110,6 @@ extern int old_param;
extern int boot_menu;
extern bool boot_strict;
extern uint8_t *boot_splash_filedata;
-extern size_t boot_splash_filedata_size;
extern bool enable_mlock;
extern bool enable_cpu_pm;
extern QEMUClockType rtc_clock;
diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index 6426151e4f..d1bb863cb6 100644
--- a/migration/block-dirty-bitmap.c
+++ b/migration/block-dirty-bitmap.c
@@ -261,7 +261,7 @@ static void dirty_bitmap_mig_cleanup(void)
while ((dbms = QSIMPLEQ_FIRST(&dirty_bitmap_mig_state.dbms_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&dirty_bitmap_mig_state.dbms_list, entry);
- bdrv_dirty_bitmap_set_qmp_locked(dbms->bitmap, false);
+ bdrv_dirty_bitmap_set_busy(dbms->bitmap, false);
bdrv_unref(dbms->bs);
g_free(dbms);
}
@@ -274,6 +274,7 @@ static int init_dirty_bitmap_migration(void)
BdrvDirtyBitmap *bitmap;
DirtyBitmapMigBitmapState *dbms;
BdrvNextIterator it;
+ Error *local_err = NULL;
dirty_bitmap_mig_state.bulk_completed = false;
dirty_bitmap_mig_state.prev_bs = NULL;
@@ -301,20 +302,14 @@ static int init_dirty_bitmap_migration(void)
goto fail;
}
- if (bdrv_dirty_bitmap_user_locked(bitmap)) {
- error_report("Can't migrate a bitmap that is in use by another operation: '%s'",
- bdrv_dirty_bitmap_name(bitmap));
- goto fail;
- }
-
- if (bdrv_dirty_bitmap_readonly(bitmap)) {
- error_report("Can't migrate read-only dirty bitmap: '%s",
- bdrv_dirty_bitmap_name(bitmap));
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT,
+ &local_err)) {
+ error_report_err(local_err);
goto fail;
}
bdrv_ref(bs);
- bdrv_dirty_bitmap_set_qmp_locked(bitmap, true);
+ bdrv_dirty_bitmap_set_busy(bitmap, true);
dbms = g_new0(DirtyBitmapMigBitmapState, 1);
dbms->bs = bs;
@@ -326,7 +321,7 @@ static int init_dirty_bitmap_migration(void)
if (bdrv_dirty_bitmap_enabled(bitmap)) {
dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED;
}
- if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT;
}
@@ -478,7 +473,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DirtyBitmapLoadState *s)
}
if (flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT) {
- bdrv_dirty_bitmap_set_persistance(s->bitmap, true);
+ bdrv_dirty_bitmap_set_persistence(s->bitmap, true);
}
bdrv_disable_dirty_bitmap(s->bitmap);
@@ -542,7 +537,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DirtyBitmapLoadState *s)
}
}
- if (bdrv_dirty_bitmap_frozen(s->bitmap)) {
+ if (bdrv_dirty_bitmap_has_successor(s->bitmap)) {
bdrv_dirty_bitmap_lock(s->bitmap);
if (enabled_bitmaps == NULL) {
/* in postcopy */
diff --git a/nbd/server.c b/nbd/server.c
index 8ddfd3e319..fd013a2817 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1510,6 +1510,10 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
goto fail;
}
+ if (bdrv_dirty_bitmap_check(bm, BDRV_BITMAP_ALLOW_RO, errp)) {
+ goto fail;
+ }
+
if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) &&
bdrv_dirty_bitmap_enabled(bm)) {
error_setg(errp,
@@ -1518,12 +1522,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
goto fail;
}
- if (bdrv_dirty_bitmap_user_locked(bm)) {
- error_setg(errp, "Bitmap '%s' is in use", bitmap);
- goto fail;
- }
-
- bdrv_dirty_bitmap_set_qmp_locked(bm, true);
+ bdrv_dirty_bitmap_set_busy(bm, true);
exp->export_bitmap = bm;
exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s",
bitmap);
@@ -1641,7 +1640,7 @@ void nbd_export_put(NBDExport *exp)
}
if (exp->export_bitmap) {
- bdrv_dirty_bitmap_set_qmp_locked(exp->export_bitmap, false);
+ bdrv_dirty_bitmap_set_busy(exp->export_bitmap, false);
g_free(exp->export_bitmap_context);
}
diff --git a/net/vhost-user.c b/net/vhost-user.c
index cd9659df87..5a26a24708 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -304,19 +304,14 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
{
Error *err = NULL;
NetClientState *nc, *nc0 = NULL;
- VhostUserState *user = NULL;
NetVhostUserState *s = NULL;
+ VhostUserState *user;
int i;
assert(name);
assert(queues > 0);
- user = vhost_user_init();
- if (!user) {
- error_report("failed to init vhost_user");
- goto err;
- }
-
+ user = g_new0(struct VhostUserState, 1);
for (i = 0; i < queues; i++) {
nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
@@ -325,11 +320,11 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
if (!nc0) {
nc0 = nc;
s = DO_UPCAST(NetVhostUserState, nc, nc);
- if (!qemu_chr_fe_init(&s->chr, chr, &err)) {
+ if (!qemu_chr_fe_init(&s->chr, chr, &err) ||
+ !vhost_user_init(user, &s->chr, &err)) {
error_report_err(err);
goto err;
}
- user->chr = &s->chr;
}
s = DO_UPCAST(NetVhostUserState, nc, nc);
s->vhost_user = user;
diff --git a/pc-bios/u-boot.e500 b/pc-bios/u-boot.e500
index 25537f8fe3..732660f348 100644
--- a/pc-bios/u-boot.e500
+++ b/pc-bios/u-boot.e500
Binary files differ
diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
index 77acca0209..729e5185c5 100644
--- a/qapi/Makefile.objs
+++ b/qapi/Makefile.objs
@@ -5,9 +5,9 @@ util-obj-y += opts-visitor.o qapi-clone-visitor.o
util-obj-y += qmp-event.o
util-obj-y += qapi-util.o
-QAPI_COMMON_MODULES = authz block-core block char common crypto introspect
-QAPI_COMMON_MODULES += job migration misc net rdma rocker run-state
-QAPI_COMMON_MODULES += sockets tpm trace transaction ui
+QAPI_COMMON_MODULES = audio authz block-core block char common crypto
+QAPI_COMMON_MODULES += introspect job migration misc net rdma rocker
+QAPI_COMMON_MODULES += run-state sockets tpm trace transaction ui
QAPI_TARGET_MODULES = target
QAPI_MODULES = $(QAPI_COMMON_MODULES) $(QAPI_TARGET_MODULES)
diff --git a/qapi/audio.json b/qapi/audio.json
new file mode 100644
index 0000000000..97aee37288
--- /dev/null
+++ b/qapi/audio.json
@@ -0,0 +1,304 @@
+# -*- mode: python -*-
+#
+# Copyright (C) 2015-2019 Zoltán Kővágó <DirtY.iCE.hu@gmail.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# @AudiodevPerDirectionOptions:
+#
+# General audio backend options that are used for both playback and
+# recording.
+#
+# @fixed-settings: use fixed settings for host input/output. When off,
+# frequency, channels and format must not be
+# specified (default true)
+#
+# @frequency: frequency to use when using fixed settings
+# (default 44100)
+#
+# @channels: number of channels when using fixed settings (default 2)
+#
+# @voices: number of voices to use (default 1)
+#
+# @format: sample format to use when using fixed settings
+# (default s16)
+#
+# @buffer-length: the buffer length in microseconds
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevPerDirectionOptions',
+ 'data': {
+ '*fixed-settings': 'bool',
+ '*frequency': 'uint32',
+ '*channels': 'uint32',
+ '*voices': 'uint32',
+ '*format': 'AudioFormat',
+ '*buffer-length': 'uint32' } }
+
+##
+# @AudiodevGenericOptions:
+#
+# Generic driver-specific options.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevGenericOptions',
+ 'data': {
+ '*in': 'AudiodevPerDirectionOptions',
+ '*out': 'AudiodevPerDirectionOptions' } }
+
+##
+# @AudiodevAlsaPerDirectionOptions:
+#
+# Options of the ALSA backend that are used for both playback and
+# recording.
+#
+# @dev: the name of the ALSA device to use (default 'default')
+#
+# @period-length: the period length in microseconds
+#
+# @try-poll: attempt to use poll mode, falling back to non-polling
+# access on failure (default true)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevAlsaPerDirectionOptions',
+ 'base': 'AudiodevPerDirectionOptions',
+ 'data': {
+ '*dev': 'str',
+ '*period-length': 'uint32',
+ '*try-poll': 'bool' } }
+
+##
+# @AudiodevAlsaOptions:
+#
+# Options of the ALSA audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# @threshold: set the threshold (in microseconds) when playback starts
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevAlsaOptions',
+ 'data': {
+ '*in': 'AudiodevAlsaPerDirectionOptions',
+ '*out': 'AudiodevAlsaPerDirectionOptions',
+ '*threshold': 'uint32' } }
+
+##
+# @AudiodevCoreaudioPerDirectionOptions:
+#
+# Options of the Core Audio backend that are used for both playback and
+# recording.
+#
+# @buffer-count: number of buffers
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevCoreaudioPerDirectionOptions',
+ 'base': 'AudiodevPerDirectionOptions',
+ 'data': {
+ '*buffer-count': 'uint32' } }
+
+##
+# @AudiodevCoreaudioOptions:
+#
+# Options of the coreaudio audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevCoreaudioOptions',
+ 'data': {
+ '*in': 'AudiodevCoreaudioPerDirectionOptions',
+ '*out': 'AudiodevCoreaudioPerDirectionOptions' } }
+
+##
+# @AudiodevDsoundOptions:
+#
+# Options of the DirectSound audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# @latency: add extra latency to playback in microseconds
+# (default 10000)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevDsoundOptions',
+ 'data': {
+ '*in': 'AudiodevPerDirectionOptions',
+ '*out': 'AudiodevPerDirectionOptions',
+ '*latency': 'uint32' } }
+
+##
+# @AudiodevOssPerDirectionOptions:
+#
+# Options of the OSS backend that are used for both playback and
+# recording.
+#
+# @dev: file name of the OSS device (default '/dev/dsp')
+#
+# @buffer-count: number of buffers
+#
+# @try-poll: attempt to use poll mode, falling back to non-polling
+# access on failure (default true)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevOssPerDirectionOptions',
+ 'base': 'AudiodevPerDirectionOptions',
+ 'data': {
+ '*dev': 'str',
+ '*buffer-count': 'uint32',
+ '*try-poll': 'bool' } }
+
+##
+# @AudiodevOssOptions:
+#
+# Options of the OSS audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# @try-mmap: try using memory-mapped access, falling back to
+# non-memory-mapped access on failure (default true)
+#
+# @exclusive: open device in exclusive mode (vmix won't work)
+# (default false)
+#
+# @dsp-policy: set the timing policy of the device (between 0 and 10,
+# where smaller number means smaller latency but higher
+# CPU usage) or -1 to use fragment mode (option ignored
+# on some platforms) (default 5)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevOssOptions',
+ 'data': {
+ '*in': 'AudiodevOssPerDirectionOptions',
+ '*out': 'AudiodevOssPerDirectionOptions',
+ '*try-mmap': 'bool',
+ '*exclusive': 'bool',
+ '*dsp-policy': 'uint32' } }
+
+##
+# @AudiodevPaPerDirectionOptions:
+#
+# Options of the Pulseaudio backend that are used for both playback and
+# recording.
+#
+# @name: name of the sink/source to use
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevPaPerDirectionOptions',
+ 'base': 'AudiodevPerDirectionOptions',
+ 'data': {
+ '*name': 'str' } }
+
+##
+# @AudiodevPaOptions:
+#
+# Options of the PulseAudio audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# @server: PulseAudio server address (default: let PulseAudio choose)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevPaOptions',
+ 'data': {
+ '*in': 'AudiodevPaPerDirectionOptions',
+ '*out': 'AudiodevPaPerDirectionOptions',
+ '*server': 'str' } }
+
+##
+# @AudiodevWavOptions:
+#
+# Options of the wav audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# @path: name of the wav file to record (default 'qemu.wav')
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevWavOptions',
+ 'data': {
+ '*in': 'AudiodevPerDirectionOptions',
+ '*out': 'AudiodevPerDirectionOptions',
+ '*path': 'str' } }
+
+
+##
+# @AudioFormat:
+#
+# An enumeration of possible audio formats.
+#
+# Since: 4.0
+##
+{ 'enum': 'AudioFormat',
+ 'data': [ 'u8', 's8', 'u16', 's16', 'u32', 's32' ] }
+
+##
+# @AudiodevDriver:
+#
+# An enumeration of possible audio backend drivers.
+#
+# Since: 4.0
+##
+{ 'enum': 'AudiodevDriver',
+ 'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'oss', 'pa', 'sdl',
+ 'spice', 'wav' ] }
+
+##
+# @Audiodev:
+#
+# Options of an audio backend.
+#
+# @id: identifier of the backend
+#
+# @driver: the backend driver to use
+#
+# @timer-period: timer period (in microseconds, 0: use lowest possible)
+#
+# Since: 4.0
+##
+{ 'union': 'Audiodev',
+ 'base': {
+ 'id': 'str',
+ 'driver': 'AudiodevDriver',
+ '*timer-period': 'uint32' },
+ 'discriminator': 'driver',
+ 'data': {
+ 'none': 'AudiodevGenericOptions',
+ 'alsa': 'AudiodevAlsaOptions',
+ 'coreaudio': 'AudiodevCoreaudioOptions',
+ 'dsound': 'AudiodevDsoundOptions',
+ 'oss': 'AudiodevOssOptions',
+ 'pa': 'AudiodevPaOptions',
+ 'sdl': 'AudiodevGenericOptions',
+ 'spice': 'AudiodevGenericOptions',
+ 'wav': 'AudiodevWavOptions' } }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 919d0530b2..12c5e73551 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -451,10 +451,15 @@
# recording new writes. If the bitmap was @disabled, it is not
# recording new writes. (Since 2.12)
#
+# @inconsistent: This is a persistent dirty bitmap that was marked in-use on
+# disk, and is unusable by QEMU. It can only be deleted.
+# Please rely on the inconsistent field in @BlockDirtyInfo
+# instead, as the status field is deprecated. (Since 4.0)
+#
# Since: 2.4
##
{ 'enum': 'DirtyBitmapStatus',
- 'data': ['active', 'disabled', 'frozen', 'locked'] }
+ 'data': ['active', 'disabled', 'frozen', 'locked', 'inconsistent'] }
##
# @BlockDirtyInfo:
@@ -467,16 +472,29 @@
#
# @granularity: granularity of the dirty bitmap in bytes (since 1.4)
#
-# @status: current status of the dirty bitmap (since 2.4)
+# @status: Deprecated in favor of @recording and @locked. (since 2.4)
+#
+# @recording: true if the bitmap is recording new writes from the guest.
+# Replaces `active` and `disabled` statuses. (since 4.0)
+#
+# @busy: true if the bitmap is in-use by some operation (NBD or jobs)
+# and cannot be modified via QMP or used by another operation.
+# Replaces `locked` and `frozen` statuses. (since 4.0)
#
-# @persistent: true if the bitmap will eventually be flushed to persistent
-# storage (since 4.0)
+# @persistent: true if the bitmap was stored on disk, is scheduled to be stored
+# on disk, or both. (since 4.0)
+#
+# @inconsistent: true if this is a persistent bitmap that was improperly
+# stored. Implies @persistent to be true; @recording and
+# @busy to be false. This bitmap cannot be used. To remove
+# it, use @block-dirty-bitmap-remove. (Since 4.0)
#
# Since: 1.3
##
{ 'struct': 'BlockDirtyInfo',
'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32',
- 'status': 'DirtyBitmapStatus', 'persistent': 'bool' } }
+ 'recording': 'bool', 'busy': 'bool', 'status': 'DirtyBitmapStatus',
+ 'persistent': 'bool', '*inconsistent': 'bool' } }
##
# @Qcow2BitmapInfoFlags:
@@ -537,20 +555,20 @@
# +------------------
# 10 50 100
#
-# Since: 2.12
+# Since: 4.0
##
{ 'struct': 'BlockLatencyHistogramInfo',
'data': {'boundaries': ['uint64'], 'bins': ['uint64'] } }
##
-# @x-block-latency-histogram-set:
+# @block-latency-histogram-set:
#
# Manage read, write and flush latency histograms for the device.
#
# If only @device parameter is specified, remove all present latency histograms
# for the device. Otherwise, add/reset some of (or all) latency histograms.
#
-# @device: device name to set latency histogram for.
+# @id: The name or QOM path of the guest device.
#
# @boundaries: list of interval boundary values (see description in
# BlockLatencyHistogramInfo definition). If specified, all
@@ -573,7 +591,7 @@
#
# Returns: error if device is not found or any boundary arrays are invalid.
#
-# Since: 2.12
+# Since: 4.0
#
# Example: set new histograms for all io types with intervals
# [0, 10), [10, 50), [50, 100), [100, +inf):
@@ -607,8 +625,8 @@
# "arguments": { "device": "drive0" } }
# <- { "return": {} }
##
-{ 'command': 'x-block-latency-histogram-set',
- 'data': {'device': 'str',
+{ 'command': 'block-latency-histogram-set',
+ 'data': {'id': 'str',
'*boundaries': ['uint64'],
'*boundaries-read': ['uint64'],
'*boundaries-write': ['uint64'],
@@ -894,11 +912,11 @@
# @timed_stats: Statistics specific to the set of previously defined
# intervals of time (Since 2.5)
#
-# @x_rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
+# @rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
#
-# @x_wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
+# @wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
#
-# @x_flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
+# @flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
#
# Since: 0.14.0
##
@@ -913,9 +931,9 @@
'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int',
'account_invalid': 'bool', 'account_failed': 'bool',
'timed_stats': ['BlockDeviceTimedStats'],
- '*x_rd_latency_histogram': 'BlockLatencyHistogramInfo',
- '*x_wr_latency_histogram': 'BlockLatencyHistogramInfo',
- '*x_flush_latency_histogram': 'BlockLatencyHistogramInfo' } }
+ '*rd_latency_histogram': 'BlockLatencyHistogramInfo',
+ '*wr_latency_histogram': 'BlockLatencyHistogramInfo',
+ '*flush_latency_histogram': 'BlockLatencyHistogramInfo' } }
##
# @BlockStats:
@@ -2816,6 +2834,10 @@
# @locking: whether to enable file locking. If set to 'auto', only enable
# when Open File Descriptor (OFD) locking API is available
# (default: auto, since 2.10)
+# @drop-cache: invalidate page cache during live migration. This prevents
+# stale data on the migration destination with cache.direct=off.
+# Currently only supported on Linux hosts.
+# (default: on, since: 4.0)
# @x-check-cache-dropped: whether to check that page cache was dropped on live
# migration. May cause noticeable delays if the image
# file is large, do not use in production.
@@ -2828,6 +2850,8 @@
'*pr-manager': 'str',
'*locking': 'OnOffAuto',
'*aio': 'BlockdevAioOptions',
+ '*drop-cache': {'type': 'bool',
+ 'if': 'defined(CONFIG_LINUX)'},
'*x-check-cache-dropped': 'bool' } }
##
@@ -3998,6 +4022,48 @@
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true }
##
+# @x-blockdev-reopen:
+#
+# Reopens a block device using the given set of options. Any option
+# not specified will be reset to its default value regardless of its
+# previous status. If an option cannot be changed or a particular
+# driver does not support reopening then the command will return an
+# error.
+#
+# The top-level @node-name option (from BlockdevOptions) must be
+# specified and is used to select the block device to be reopened.
+# Other @node-name options must be either omitted or set to the
+# current name of the appropriate node. This command won't change any
+# node name and any attempt to do it will result in an error.
+#
+# In the case of options that refer to child nodes, the behavior of
+# this command depends on the value:
+#
+# 1) A set of options (BlockdevOptions): the child is reopened with
+# the specified set of options.
+#
+# 2) A reference to the current child: the child is reopened using
+# its existing set of options.
+#
+# 3) A reference to a different node: the current child is replaced
+# with the specified one.
+#
+# 4) NULL: the current child (if any) is detached.
+#
+# Options (1) and (2) are supported in all cases, but at the moment
+# only @backing allows replacing or detaching an existing child.
+#
+# Unlike with blockdev-add, the @backing option must always be present
+# unless the node being reopened does not have a backing file and its
+# image does not have a default backing file name as part of its
+# metadata.
+#
+# Since: 4.0
+##
+{ 'command': 'x-blockdev-reopen',
+ 'data': 'BlockdevOptions', 'boxed': true }
+
+##
# @blockdev-del:
#
# Deletes a block device that has been added using blockdev-add.
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index a34899c626..4bd1223637 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -99,3 +99,4 @@
{ 'include': 'introspect.json' }
{ 'include': 'misc.json' }
{ 'include': 'target.json' }
+{ 'include': 'audio.json' }
diff --git a/qapi/ui.json b/qapi/ui.json
index c5d1d7f099..59e412139a 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1081,6 +1081,19 @@
'data' : [ 'off', 'on', 'core', 'es' ] }
##
+# @DisplayCurses:
+#
+# Curses display options.
+#
+# @charset: Font charset used by guest (default: CP437).
+#
+# Since: 4.0
+#
+##
+{ 'struct' : 'DisplayCurses',
+ 'data' : { '*charset' : 'str' } }
+
+##
# @DisplayType:
#
# Display (user interface) type.
@@ -1142,6 +1155,7 @@
'*gl' : 'DisplayGLMode' },
'discriminator' : 'type',
'data' : { 'gtk' : 'DisplayGTK',
+ 'curses' : 'DisplayCurses',
'egl-headless' : 'DisplayEGLHeadless'} }
##
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 1e15f57e9c..2219386769 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -65,6 +65,13 @@ topologies described with -smp include all possible cpus, i.e.
The @code{acl} option to the @code{-vnc} argument has been replaced
by the @code{tls-authz} and @code{sasl-authz} options.
+@subsection QEMU_AUDIO_ environment variables and -audio-help (since 4.0)
+
+The ``-audiodev'' argument is now the preferred way to specify audio
+backend settings instead of environment variables. To ease migration to
+the new format, the ``-audiodev-help'' option can be used to convert
+the current values of the environment variables to ``-audiodev'' options.
+
@section QEMU Machine Protocol (QMP) commands
@subsection block-dirty-bitmap-add "autoload" parameter (since 2.12.0)
@@ -72,6 +79,12 @@ by the @code{tls-authz} and @code{sasl-authz} options.
"autoload" parameter is now ignored. All bitmaps are automatically loaded
from qcow2 images.
+@subsection query-block result field dirty-bitmaps[i].status (since 4.0)
+
+The ``status'' field of the ``BlockDirtyInfo'' structure, returned by
+the query-block command is deprecated. Two new boolean fields,
+``recording'' and ``busy'' effectively replace it.
+
@subsection query-cpus (since 2.12.0)
The ``query-cpus'' command is replaced by the ``query-cpus-fast'' command.
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index b9f189f09b..35dcdcf413 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -2080,8 +2080,8 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
}
bdrv_subtree_drained_begin(bs);
- brq = bdrv_reopen_queue(NULL, bs, opts);
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
+ brq = bdrv_reopen_queue(NULL, bs, opts, true);
+ bdrv_reopen_multiple(brq, &local_err);
bdrv_subtree_drained_end(bs);
if (local_err) {
diff --git a/qemu-options.hx b/qemu-options.hx
index 7118d90352..08749a3391 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -416,14 +416,244 @@ The default is @code{en-us}.
ETEXI
+HXCOMM Deprecated by -audiodev
DEF("audio-help", 0, QEMU_OPTION_audio_help,
- "-audio-help print list of audio drivers and their options\n",
+ "-audio-help show -audiodev equivalent of the currently specified audio settings\n",
QEMU_ARCH_ALL)
STEXI
@item -audio-help
@findex -audio-help
-Will show the audio subsystem help: list of drivers, tunable
-parameters.
+Will show the -audiodev equivalent of the currently specified
+(deprecated) environment variables.
+ETEXI
+
+DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
+ "-audiodev [driver=]driver,id=id[,prop[=value][,...]]\n"
+ " specifies the audio backend to use\n"
+ " id= identifier of the backend\n"
+ " timer-period= timer period in microseconds\n"
+ " in|out.fixed-settings= use fixed settings for host audio\n"
+ " in|out.frequency= frequency to use with fixed settings\n"
+ " in|out.channels= number of channels to use with fixed settings\n"
+ " in|out.format= sample format to use with fixed settings\n"
+ " valid values: s8, s16, s32, u8, u16, u32\n"
+ " in|out.voices= number of voices to use\n"
+ " in|out.buffer-len= length of buffer in microseconds\n"
+ "-audiodev none,id=id,[,prop[=value][,...]]\n"
+ " dummy driver that discards all output\n"
+#ifdef CONFIG_AUDIO_ALSA
+ "-audiodev alsa,id=id[,prop[=value][,...]]\n"
+ " in|out.dev= name of the audio device to use\n"
+ " in|out.period-len= length of period in microseconds\n"
+ " in|out.try-poll= attempt to use poll mode\n"
+ " threshold= threshold (in microseconds) when playback starts\n"
+#endif
+#ifdef CONFIG_AUDIO_COREAUDIO
+ "-audiodev coreaudio,id=id[,prop[=value][,...]]\n"
+ " in|out.buffer-count= number of buffers\n"
+#endif
+#ifdef CONFIG_AUDIO_DSOUND
+ "-audiodev dsound,id=id[,prop[=value][,...]]\n"
+ " latency= add extra latency to playback in microseconds\n"
+#endif
+#ifdef CONFIG_AUDIO_OSS
+ "-audiodev oss,id=id[,prop[=value][,...]]\n"
+ " in|out.dev= path of the audio device to use\n"
+ " in|out.buffer-count= number of buffers\n"
+ " in|out.try-poll= attempt to use poll mode\n"
+ " try-mmap= try using memory mapped access\n"
+ " exclusive= open device in exclusive mode\n"
+ " dsp-policy= set timing policy (0..10), -1 to use fragment mode\n"
+#endif
+#ifdef CONFIG_AUDIO_PA
+ "-audiodev pa,id=id[,prop[=value][,...]]\n"
+ " server= PulseAudio server address\n"
+ " in|out.name= source/sink device name\n"
+#endif
+#ifdef CONFIG_AUDIO_SDL
+ "-audiodev sdl,id=id[,prop[=value][,...]]\n"
+#endif
+#ifdef CONFIG_SPICE
+ "-audiodev spice,id=id[,prop[=value][,...]]\n"
+#endif
+ "-audiodev wav,id=id[,prop[=value][,...]]\n"
+ " path= path of wav file to record\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -audiodev [driver=]@var{driver},id=@var{id}[,@var{prop}[=@var{value}][,...]]
+@findex -audiodev
+Adds a new audio backend @var{driver} identified by @var{id}. There are
+global and driver specific properties. Some values can be set
+differently for input and output, they're marked with @code{in|out.}.
+You can set the input's property with @code{in.@var{prop}} and the
+output's property with @code{out.@var{prop}}. For example:
+@example
+-audiodev alsa,id=example,in.frequency=44110,out.frequency=8000
+-audiodev alsa,id=example,out.channels=1 # leaves in.channels unspecified
+@end example
+
+Valid global options are:
+
+@table @option
+@item id=@var{identifier}
+Identifies the audio backend.
+
+@item timer-period=@var{period}
+Sets the timer @var{period} used by the audio subsystem in microseconds.
+Default is 10000 (10 ms).
+
+@item in|out.fixed-settings=on|off
+Use fixed settings for host audio. When off, it will change based on
+how the guest opens the sound card. In this case you must not specify
+@var{frequency}, @var{channels} or @var{format}. Default is on.
+
+@item in|out.frequency=@var{frequency}
+Specify the @var{frequency} to use when using @var{fixed-settings}.
+Default is 44100Hz.
+
+@item in|out.channels=@var{channels}
+Specify the number of @var{channels} to use when using
+@var{fixed-settings}. Default is 2 (stereo).
+
+@item in|out.format=@var{format}
+Specify the sample @var{format} to use when using @var{fixed-settings}.
+Valid values are: @code{s8}, @code{s16}, @code{s32}, @code{u8},
+@code{u16}, @code{u32}. Default is @code{s16}.
+
+@item in|out.voices=@var{voices}
+Specify the number of @var{voices} to use. Default is 1.
+
+@item in|out.buffer=@var{usecs}
+Sets the size of the buffer in microseconds.
+
+@end table
+
+@item -audiodev none,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a dummy backend that discards all outputs. This backend has no
+backend specific properties.
+
+@item -audiodev alsa,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates backend using the ALSA. This backend is only available on
+Linux.
+
+ALSA specific options are:
+
+@table @option
+
+@item in|out.dev=@var{device}
+Specify the ALSA @var{device} to use for input and/or output. Default
+is @code{default}.
+
+@item in|out.period-len=@var{usecs}
+Sets the period length in microseconds.
+
+@item in|out.try-poll=on|off
+Attempt to use poll mode with the device. Default is on.
+
+@item threshold=@var{threshold}
+Threshold (in microseconds) when playback starts. Default is 0.
+
+@end table
+
+@item -audiodev coreaudio,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a backend using Apple's Core Audio. This backend is only
+available on Mac OS and only supports playback.
+
+Core Audio specific options are:
+
+@table @option
+
+@item in|out.buffer-count=@var{count}
+Sets the @var{count} of the buffers.
+
+@end table
+
+@item -audiodev dsound,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a backend using Microsoft's DirectSound. This backend is only
+available on Windows and only supports playback.
+
+DirectSound specific options are:
+
+@table @option
+
+@item latency=@var{usecs}
+Add extra @var{usecs} microseconds latency to playback. Default is
+10000 (10 ms).
+
+@end table
+
+@item -audiodev oss,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a backend using OSS. This backend is available on most
+Unix-like systems.
+
+OSS specific options are:
+
+@table @option
+
+@item in|out.dev=@var{device}
+Specify the file name of the OSS @var{device} to use. Default is
+@code{/dev/dsp}.
+
+@item in|out.buffer-count=@var{count}
+Sets the @var{count} of the buffers.
+
+@item in|out.try-poll=on|of
+Attempt to use poll mode with the device. Default is on.
+
+@item try-mmap=on|off
+Try using memory mapped device access. Default is off.
+
+@item exclusive=on|off
+Open the device in exclusive mode (vmix won't work in this case).
+Default is off.
+
+@item dsp-policy=@var{policy}
+Sets the timing policy (between 0 and 10, where smaller number means
+smaller latency but higher CPU usage). Use -1 to use buffer sizes
+specified by @code{buffer} and @code{buffer-count}. This option is
+ignored if you do not have OSS 4. Default is 5.
+
+@end table
+
+@item -audiodev pa,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a backend using PulseAudio. This backend is available on most
+systems.
+
+PulseAudio specific options are:
+
+@table @option
+
+@item server=@var{server}
+Sets the PulseAudio @var{server} to connect to.
+
+@item in|out.name=@var{sink}
+Use the specified source/sink for recording/playback.
+
+@end table
+
+@item -audiodev sdl,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a backend using SDL. This backend is available on most systems,
+but you should use your platform's native backend if possible. This
+backend has no backend specific properties.
+
+@item -audiodev spice,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a backend that sends audio through SPICE. This backend requires
+@code{-spice} and automatically selected in that case, so usually you
+can ignore this option. This backend has no backend specific
+properties.
+
+@item -audiodev wav,id=@var{id}[,@var{prop}[=@var{value}][,...]]
+Creates a backend that writes audio to a WAV file.
+
+Backend specific options are:
+
+@table @option
+
+@item path=@var{path}
+Write recorded audio into the specified file. Default is
+@code{qemu.wav}.
+
+@end table
ETEXI
DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw,
@@ -1216,7 +1446,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
" [,window_close=on|off][,gl=on|core|es|off]\n"
"-display gtk[,grab_on_hover=on|off][,gl=on|off]|\n"
"-display vnc=<display>[,<optargs>]\n"
- "-display curses\n"
+ "-display curses[,charset=<encoding>]\n"
"-display none\n"
"-display egl-headless[,rendernode=<file>]"
" select display type\n"
@@ -1248,6 +1478,9 @@ support a text mode, QEMU can display this output using a
curses/ncurses interface. Nothing is displayed when the graphics
device is in graphical mode or if the graphics device does not support
a text mode. Generally only the VGA device models support text mode.
+The font charset used by the guest can be specified with the
+@code{charset} option, for example @code{charset=CP850} for IBM CP850
+encoding. The default is @code{CP437}.
@item none
Do not display video output. The guest will still see an emulated
graphics card, but its output will not be displayed to the QEMU
diff --git a/qom/object.c b/qom/object.c
index 05a8567041..e3206d6799 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -408,6 +408,45 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp
}
}
+/*
+ * Global property defaults
+ * Slot 0: accelerator's global property defaults
+ * Slot 1: machine's global property defaults
+ * Each is a GPtrArray of of GlobalProperty.
+ * Applied in order, later entries override earlier ones.
+ */
+static GPtrArray *object_compat_props[2];
+
+/*
+ * Set machine's global property defaults to @compat_props.
+ * May be called at most once.
+ */
+void object_set_machine_compat_props(GPtrArray *compat_props)
+{
+ assert(!object_compat_props[1]);
+ object_compat_props[1] = compat_props;
+}
+
+/*
+ * Set accelerator's global property defaults to @compat_props.
+ * May be called at most once.
+ */
+void object_set_accelerator_compat_props(GPtrArray *compat_props)
+{
+ assert(!object_compat_props[0]);
+ object_compat_props[0] = compat_props;
+}
+
+void object_apply_compat_props(Object *obj)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(object_compat_props); i++) {
+ object_apply_global_props(obj, object_compat_props[i],
+ &error_abort);
+ }
+}
+
static void object_initialize_with_type(void *data, size_t size, TypeImpl *type)
{
Object *obj = data;
diff --git a/roms/u-boot b/roms/u-boot
-Subproject d85ca029f257b53a96da6c2fb421e78a003a994
+Subproject d3689267f92c5956e09cc7d1baa4700141662bf
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index e342d278b8..aa790b596a 100755
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -17,139 +17,7 @@
#
# Generate a decoding tree from a specification file.
-#
-# The tree is built from instruction "patterns". A pattern may represent
-# a single architectural instruction or a group of same, depending on what
-# is convenient for further processing.
-#
-# Each pattern has "fixedbits" & "fixedmask", the combination of which
-# describes the condition under which the pattern is matched:
-#
-# (insn & fixedmask) == fixedbits
-#
-# Each pattern may have "fields", which are extracted from the insn and
-# passed along to the translator. Examples of such are registers,
-# immediates, and sub-opcodes.
-#
-# In support of patterns, one may declare fields, argument sets, and
-# formats, each of which may be re-used to simplify further definitions.
-#
-# *** Field syntax:
-#
-# field_def := '%' identifier ( unnamed_field )+ ( !function=identifier )?
-# unnamed_field := number ':' ( 's' ) number
-#
-# For unnamed_field, the first number is the least-significant bit position of
-# the field and the second number is the length of the field. If the 's' is
-# present, the field is considered signed. If multiple unnamed_fields are
-# present, they are concatenated. In this way one can define disjoint fields.
-#
-# If !function is specified, the concatenated result is passed through the
-# named function, taking and returning an integral value.
-#
-# FIXME: the fields of the structure into which this result will be stored
-# is restricted to "int". Which means that we cannot expand 64-bit items.
-#
-# Field examples:
-#
-# %disp 0:s16 -- sextract(i, 0, 16)
-# %imm9 16:6 10:3 -- extract(i, 16, 6) << 3 | extract(i, 10, 3)
-# %disp12 0:s1 1:1 2:10 -- sextract(i, 0, 1) << 11
-# | extract(i, 1, 1) << 10
-# | extract(i, 2, 10)
-# %shimm8 5:s8 13:1 !function=expand_shimm8
-# -- expand_shimm8(sextract(i, 5, 8) << 1
-# | extract(i, 13, 1))
-#
-# *** Argument set syntax:
-#
-# args_def := '&' identifier ( args_elt )+ ( !extern )?
-# args_elt := identifier
-#
-# Each args_elt defines an argument within the argument set.
-# Each argument set will be rendered as a C structure "arg_$name"
-# with each of the fields being one of the member arguments.
-#
-# If !extern is specified, the backing structure is assumed to
-# have been already declared, typically via a second decoder.
-#
-# Argument set examples:
-#
-# &reg3 ra rb rc
-# &loadstore reg base offset
-#
-# *** Format syntax:
-#
-# fmt_def := '@' identifier ( fmt_elt )+
-# fmt_elt := fixedbit_elt | field_elt | field_ref | args_ref
-# fixedbit_elt := [01.-]+
-# field_elt := identifier ':' 's'? number
-# field_ref := '%' identifier | identifier '=' '%' identifier
-# args_ref := '&' identifier
-#
-# Defining a format is a handy way to avoid replicating groups of fields
-# across many instruction patterns.
-#
-# A fixedbit_elt describes a contiguous sequence of bits that must
-# be 1, 0, [.-] for don't care. The difference between '.' and '-'
-# is that '.' means that the bit will be covered with a field or a
-# final [01] from the pattern, and '-' means that the bit is really
-# ignored by the cpu and will not be specified.
-#
-# A field_elt describes a simple field only given a width; the position of
-# the field is implied by its position with respect to other fixedbit_elt
-# and field_elt.
-#
-# If any fixedbit_elt or field_elt appear then all bits must be defined.
-# Padding with a fixedbit_elt of all '.' is an easy way to accomplish that.
-#
-# A field_ref incorporates a field by reference. This is the only way to
-# add a complex field to a format. A field may be renamed in the process
-# via assignment to another identifier. This is intended to allow the
-# same argument set be used with disjoint named fields.
-#
-# A single args_ref may specify an argument set to use for the format.
-# The set of fields in the format must be a subset of the arguments in
-# the argument set. If an argument set is not specified, one will be
-# inferred from the set of fields.
-#
-# It is recommended, but not required, that all field_ref and args_ref
-# appear at the end of the line, not interleaving with fixedbit_elf or
-# field_elt.
-#
-# Format examples:
-#
-# @opr ...... ra:5 rb:5 ... 0 ....... rc:5
-# @opi ...... ra:5 lit:8 1 ....... rc:5
-#
-# *** Pattern syntax:
-#
-# pat_def := identifier ( pat_elt )+
-# pat_elt := fixedbit_elt | field_elt | field_ref
-# | args_ref | fmt_ref | const_elt
-# fmt_ref := '@' identifier
-# const_elt := identifier '=' number
-#
-# The fixedbit_elt and field_elt specifiers are unchanged from formats.
-# A pattern that does not specify a named format will have one inferred
-# from a referenced argument set (if present) and the set of fields.
-#
-# A const_elt allows a argument to be set to a constant value. This may
-# come in handy when fields overlap between patterns and one has to
-# include the values in the fixedbit_elt instead.
-#
-# The decoder will call a translator function for each pattern matched.
-#
-# Pattern examples:
-#
-# addl_r 010000 ..... ..... .... 0000000 ..... @opr
-# addl_i 010000 ..... ..... .... 0000000 ..... @opi
-#
-# which will, in part, invoke
-#
-# trans_addl_r(ctx, &arg_opr, insn)
-# and
-# trans_addl_i(ctx, &arg_opi, insn)
+# See the syntax and semantics in docs/devel/decodetree.rst.
#
import os
@@ -163,6 +31,7 @@ fields = {}
arguments = {}
formats = {}
patterns = []
+allpatterns = []
translate_prefix = 'trans'
translate_scope = 'static '
@@ -432,13 +301,7 @@ class General:
self.fields = flds
def __str__(self):
- r = self.name
- if self.base:
- r = r + ' ' + self.base.name
- else:
- r = r + ' ' + str(self.fields)
- r = r + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
- return r
+ return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
def str1(self, i):
return str_indent(i) + self.__str__()
@@ -449,7 +312,8 @@ class Format(General):
"""Class representing an instruction format"""
def extract_name(self):
- return 'extract_' + self.name
+ global decode_function
+ return decode_function + '_extract_' + self.name
def output_extract(self):
output('static void ', self.extract_name(), '(',
@@ -480,11 +344,52 @@ class Pattern(General):
output(ind, self.base.extract_name(), '(&u.f_', arg, ', insn);\n')
for n, f in self.fields.items():
output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
- output(ind, 'return ', translate_prefix, '_', self.name,
- '(ctx, &u.f_', arg, ');\n')
+ output(ind, 'if (', translate_prefix, '_', self.name,
+ '(ctx, &u.f_', arg, ')) return true;\n')
# end Pattern
+class MultiPattern(General):
+ """Class representing an overlapping set of instruction patterns"""
+
+ def __init__(self, lineno, pats, fixb, fixm, udfm):
+ self.file = input_file
+ self.lineno = lineno
+ self.pats = pats
+ self.base = None
+ self.fixedbits = fixb
+ self.fixedmask = fixm
+ self.undefmask = udfm
+
+ def __str__(self):
+ r = "{"
+ for p in self.pats:
+ r = r + ' ' + str(p)
+ return r + "}"
+
+ def output_decl(self):
+ for p in self.pats:
+ p.output_decl()
+
+ def output_code(self, i, extracted, outerbits, outermask):
+ global translate_prefix
+ ind = str_indent(i)
+ for p in self.pats:
+ if outermask != p.fixedmask:
+ innermask = p.fixedmask & ~outermask
+ innerbits = p.fixedbits & ~outermask
+ output(ind, 'if ((insn & ',
+ '0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits),
+ ') {\n')
+ output(ind, ' /* ',
+ str_match_bits(p.fixedbits, p.fixedmask), ' */\n')
+ p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
+ output(ind, '}\n')
+ else:
+ p.output_code(i, extracted, p.fixedbits, p.fixedmask)
+#end MultiPattern
+
+
def parse_field(lineno, name, toks):
"""Parse one instruction field from TOKS at LINENO"""
global fields
@@ -637,6 +542,7 @@ def parse_generic(lineno, is_format, name, toks):
global arguments
global formats
global patterns
+ global allpatterns
global re_ident
global insnwidth
global insnmask
@@ -684,7 +590,7 @@ def parse_generic(lineno, is_format, name, toks):
continue
# 'Foo=number' sets an argument field to a constant value
- if re_fullmatch(re_ident + '=[0-9]+', t):
+ if re_fullmatch(re_ident + '=[+-]?[0-9]+', t):
(fname, value) = t.split('=')
value = int(value)
flds = add_field(lineno, flds, fname, ConstField(value))
@@ -716,6 +622,8 @@ def parse_generic(lineno, is_format, name, toks):
sign = True
flen = flen[1:]
shift = int(flen, 10)
+ if shift + width > insnwidth:
+ error(lineno, 'field {0} exceeds insnwidth'.format(fname))
f = Field(sign, insnwidth - width - shift, shift)
flds = add_field(lineno, flds, fname, f)
fixedbits <<= shift
@@ -781,6 +689,7 @@ def parse_generic(lineno, is_format, name, toks):
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
undefmask, fieldmask, flds)
patterns.append(pat)
+ allpatterns.append(pat)
# Validate the masks that we have assembled.
if fieldmask & fixedmask:
@@ -799,17 +708,66 @@ def parse_generic(lineno, is_format, name, toks):
.format(allbits ^ insnmask))
# end parse_general
+def build_multi_pattern(lineno, pats):
+ """Validate the Patterns going into a MultiPattern."""
+ global patterns
+ global insnmask
+
+ if len(pats) < 2:
+ error(lineno, 'less than two patterns within braces')
+
+ fixedmask = insnmask
+ undefmask = insnmask
+
+ # Collect fixed/undefmask for all of the children.
+ # Move the defining lineno back to that of the first child.
+ for p in pats:
+ fixedmask &= p.fixedmask
+ undefmask &= p.undefmask
+ if p.lineno < lineno:
+ lineno = p.lineno
+
+ repeat = True
+ while repeat:
+ if fixedmask == 0:
+ error(lineno, 'no overlap in patterns within braces')
+ fixedbits = None
+ for p in pats:
+ thisbits = p.fixedbits & fixedmask
+ if fixedbits is None:
+ fixedbits = thisbits
+ elif fixedbits != thisbits:
+ fixedmask &= ~(fixedbits ^ thisbits)
+ break
+ else:
+ repeat = False
+
+ mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask)
+ patterns.append(mp)
+# end build_multi_pattern
def parse_file(f):
"""Parse all of the patterns within a file"""
+ global patterns
+
# Read all of the lines of the file. Concatenate lines
# ending in backslash; discard empty lines and comments.
toks = []
lineno = 0
+ nesting = 0
+ saved_pats = []
+
for line in f:
lineno += 1
+ # Expand and strip spaces, to find indent.
+ line = line.rstrip()
+ line = line.expandtabs()
+ len1 = len(line)
+ line = line.lstrip()
+ len2 = len(line)
+
# Discard comments
end = line.find('#')
if end >= 0:
@@ -819,10 +777,18 @@ def parse_file(f):
if len(toks) != 0:
# Next line after continuation
toks.extend(t)
- elif len(t) == 0:
- # Empty line
- continue
else:
+ # Allow completely blank lines.
+ if len1 == 0:
+ continue
+ indent = len1 - len2
+ # Empty line due to comment.
+ if len(t) == 0:
+ # Indentation must be correct, even for comment lines.
+ if indent != nesting:
+ error(lineno, 'indentation ', indent, ' != ', nesting)
+ continue
+ start_lineno = lineno
toks = t
# Continuation?
@@ -830,21 +796,47 @@ def parse_file(f):
toks.pop()
continue
- if len(toks) < 2:
- error(lineno, 'short line')
-
name = toks[0]
del toks[0]
+ # End nesting?
+ if name == '}':
+ if nesting == 0:
+ error(start_lineno, 'mismatched close brace')
+ if len(toks) != 0:
+ error(start_lineno, 'extra tokens after close brace')
+ nesting -= 2
+ if indent != nesting:
+ error(start_lineno, 'indentation ', indent, ' != ', nesting)
+ pats = patterns
+ patterns = saved_pats.pop()
+ build_multi_pattern(lineno, pats)
+ toks = []
+ continue
+
+ # Everything else should have current indentation.
+ if indent != nesting:
+ error(start_lineno, 'indentation ', indent, ' != ', nesting)
+
+ # Start nesting?
+ if name == '{':
+ if len(toks) != 0:
+ error(start_lineno, 'extra tokens after open brace')
+ saved_pats.append(patterns)
+ patterns = []
+ nesting += 2
+ toks = []
+ continue
+
# Determine the type of object needing to be parsed.
if name[0] == '%':
- parse_field(lineno, name[1:], toks)
+ parse_field(start_lineno, name[1:], toks)
elif name[0] == '&':
- parse_arguments(lineno, name[1:], toks)
+ parse_arguments(start_lineno, name[1:], toks)
elif name[0] == '@':
- parse_generic(lineno, True, name[1:], toks)
+ parse_generic(start_lineno, True, name[1:], toks)
else:
- parse_generic(lineno, False, name, toks)
+ parse_generic(start_lineno, False, name, toks)
toks = []
# end parse_file
@@ -909,23 +901,22 @@ class Tree:
output(ind, ' /* ',
str_match_bits(innerbits, innermask), ' */\n')
s.output_code(i + 4, extracted, innerbits, innermask)
+ output(ind, ' return false;\n')
output(ind, '}\n')
- output(ind, 'return false;\n')
# end Tree
def build_tree(pats, outerbits, outermask):
# Find the intersection of all remaining fixedmask.
- innermask = ~outermask
+ innermask = ~outermask & insnmask
for i in pats:
innermask &= i.fixedmask
if innermask == 0:
- pnames = []
+ text = 'overlapping patterns:'
for p in pats:
- pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
- error_with_file(pats[0].file, pats[0].lineno,
- 'overlapping patterns:', pnames)
+ text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
+ error_with_file(pats[0].file, pats[0].lineno, text)
fullmask = outermask | innermask
@@ -978,6 +969,7 @@ def main():
global arguments
global formats
global patterns
+ global allpatterns
global translate_scope
global translate_prefix
global output_fd
@@ -990,7 +982,8 @@ def main():
decode_scope = 'static '
- long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=']
+ long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
+ 'static-decode=']
try:
(opts, args) = getopt.getopt(sys.argv[1:], 'o:w:', long_opts)
except getopt.GetoptError as err:
@@ -1001,6 +994,8 @@ def main():
elif o == '--decode':
decode_function = a
decode_scope = ''
+ elif o == '--static-decode':
+ decode_function = a
elif o == '--translate':
translate_prefix = a
translate_scope = ''
@@ -1039,7 +1034,7 @@ def main():
# Make sure that the argument sets are the same, and declare the
# function only once.
out_pats = {}
- for i in patterns:
+ for i in allpatterns:
if i.name in out_pats:
p = out_pats[i.name]
if i.base.base != p.base.base:
@@ -1057,14 +1052,16 @@ def main():
'(DisasContext *ctx, ', insntype, ' insn)\n{\n')
i4 = str_indent(4)
- output(i4, 'union {\n')
- for n in sorted(arguments.keys()):
- f = arguments[n]
- output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
- output(i4, '} u;\n\n')
- t.output_code(4, False, 0, 0)
+ if len(allpatterns) != 0:
+ output(i4, 'union {\n')
+ for n in sorted(arguments.keys()):
+ f = arguments[n]
+ output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
+ output(i4, '} u;\n\n')
+ t.output_code(4, False, 0, 0)
+ output(i4, 'return false;\n')
output('}\n')
if output_file:
diff --git a/scripts/qemugdb/timers.py b/scripts/qemugdb/timers.py
index 51ea04b5e2..f0e132d27a 100644
--- a/scripts/qemugdb/timers.py
+++ b/scripts/qemugdb/timers.py
@@ -6,8 +6,10 @@
#
# Author: Alex Bennée <alex.bennee@linaro.org>
#
-# This work is licensed under the terms of the GNU GPL, version 2. See
-# the COPYING file in the top-level directory.
+# 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
# 'qemu timers' -- display the current timerlists
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index 9fec46e2ed..7776c7b141 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -73,7 +73,7 @@ import sys
import os
import errno
import atexit
-import shlex
+import re
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu import qmp
@@ -222,7 +222,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
< command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
"""
- cmdargs = shlex.split(cmdline)
+ cmdargs = re.findall(r'''(?:[^\s"']|"(?:\\.|[^"])*"|'(?:\\.|[^'])*')+''', cmdline)
# Transactional CLI entry/exit:
if cmdargs[0] == 'transaction(':
diff --git a/slirp/src/state.c b/slirp/src/state.c
index f5dd80cdc8..c3e3f0b671 100644
--- a/slirp/src/state.c
+++ b/slirp/src/state.c
@@ -23,7 +23,6 @@
*/
#include "slirp.h"
#include "vmstate.h"
-#include "state.h"
#include "stream.h"
static int slirp_tcp_post_load(void *opaque, int version)
diff --git a/slirp/src/state.h b/slirp/src/state.h
deleted file mode 100644
index e69de29bb2..0000000000
--- a/slirp/src/state.h
+++ /dev/null
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 861bbb1f16..c062c7969c 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -143,6 +143,10 @@
#endif
#define CR_RC 0
+#define CR_PID1 8
+#define CR_PID2 9
+#define CR_PID3 12
+#define CR_PID4 13
#define CR_SCRCCR 10
#define CR_SAR 11
#define CR_IVA 14
@@ -341,6 +345,12 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env);
void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg);
void cpu_hppa_loaded_fr0(CPUHPPAState *env);
+#ifdef CONFIG_USER_ONLY
+static inline void cpu_hppa_change_prot_id(CPUHPPAState *env) { }
+#else
+void cpu_hppa_change_prot_id(CPUHPPAState *env);
+#endif
+
#define cpu_signal_handler cpu_hppa_signal_handler
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
diff --git a/target/hppa/gdbstub.c b/target/hppa/gdbstub.c
index 3157a690f2..983bf92aaf 100644
--- a/target/hppa/gdbstub.c
+++ b/target/hppa/gdbstub.c
@@ -93,19 +93,19 @@ int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
val = env->cr[CR_RC];
break;
case 52:
- val = env->cr[8];
+ val = env->cr[CR_PID1];
break;
case 53:
- val = env->cr[9];
+ val = env->cr[CR_PID2];
break;
case 54:
val = env->cr[CR_SCRCCR];
break;
case 55:
- val = env->cr[12];
+ val = env->cr[CR_PID3];
break;
case 56:
- val = env->cr[13];
+ val = env->cr[CR_PID4];
break;
case 57:
val = env->cr[24];
@@ -224,19 +224,23 @@ int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->cr[CR_RC] = val;
break;
case 52:
- env->cr[8] = val;
+ env->cr[CR_PID1] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 53:
- env->cr[9] = val;
+ env->cr[CR_PID2] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 54:
env->cr[CR_SCRCCR] = val;
break;
case 55:
- env->cr[12] = val;
+ env->cr[CR_PID3] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 56:
- env->cr[13] = val;
+ env->cr[CR_PID4] = val;
+ cpu_hppa_change_prot_id(env);
break;
case 57:
env->cr[24] = val;
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index 6539061e52..ac750b62ef 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "fpu/softfloat.h"
+#include "exec/exec-all.h"
#include "exec/helper-proto.h"
target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
@@ -49,6 +50,7 @@ target_ureg cpu_hppa_get_psw(CPUHPPAState *env)
void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw)
{
+ target_ureg old_psw = env->psw;
target_ureg cb = 0;
env->psw = psw & ~(PSW_N | PSW_V | PSW_CB);
@@ -64,6 +66,14 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw)
cb |= ((psw >> 9) & 1) << 8;
cb |= ((psw >> 8) & 1) << 4;
env->psw_cb = cb;
+
+ /* If PSW_P changes, it affects how we translate addresses. */
+ if ((psw ^ old_psw) & PSW_P) {
+#ifndef CONFIG_USER_ONLY
+ CPUState *src = CPU(hppa_env_get_cpu(env));
+ tlb_flush_by_mmuidx(src, 0xf);
+#endif
+ }
}
void hppa_cpu_dump_state(CPUState *cs, FILE *f,
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index bfe0dd1db1..38d834ef6b 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -92,4 +92,5 @@ DEF_HELPER_FLAGS_3(itlbp, TCG_CALL_NO_RWG, void, env, tl, tr)
DEF_HELPER_FLAGS_2(ptlb, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tr, env, tl)
+DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env)
#endif
diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode
index 55ff39dd05..098370c2f0 100644
--- a/target/hppa/insns.decode
+++ b/target/hppa/insns.decode
@@ -525,3 +525,6 @@ fmpy_d 001110 ..... ..... 010 ..... ... ..... @f0e_d_3
fdiv_d 001110 ..... ..... 011 ..... ... ..... @f0e_d_3
xmpyu 001110 ..... ..... 010 .0111 .00 t:5 r1=%ra64 r2=%rb64
+
+# diag
+diag 000101 ----- ----- ---- ---- ---- ----
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c
index aecf3075f6..c9b57d07c3 100644
--- a/target/hppa/mem_helper.c
+++ b/target/hppa/mem_helper.c
@@ -22,6 +22,7 @@
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qom/cpu.h"
+#include "trace.h"
#ifdef CONFIG_USER_ONLY
int hppa_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
@@ -43,9 +44,12 @@ static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr)
for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
hppa_tlb_entry *ent = &env->tlb[i];
if (ent->va_b <= addr && addr <= ent->va_e) {
+ trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid,
+ ent->va_b, ent->va_e, ent->pa);
return ent;
}
}
+ trace_hppa_tlb_find_entry_not_found(env, addr);
return NULL;
}
@@ -55,6 +59,8 @@ static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent)
unsigned i, n = 1 << (2 * ent->page_size);
uint64_t addr = ent->va_b;
+ trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa);
+
for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) {
/* Do not flush MMU_PHYS_IDX. */
tlb_flush_page_by_mmuidx(cs, addr, 0xf);
@@ -96,9 +102,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
if (ent == NULL || !ent->entry_valid) {
phys = 0;
prot = 0;
- /* ??? Unconditionally report data tlb miss,
- even if this is an instruction fetch. */
- ret = EXCP_DTLB_MISS;
+ ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
goto egress;
}
@@ -127,7 +131,20 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
break;
}
- /* ??? Check PSW_P and ent->access_prot. This can remove PAGE_WRITE. */
+ /* access_id == 0 means public page and no check is performed */
+ if ((env->psw & PSW_P) && ent->access_id) {
+ /* If bits [31:1] match, and bit 0 is set, suppress write. */
+ int match = ent->access_id * 2 + 1;
+
+ if (match == env->cr[CR_PID1] || match == env->cr[CR_PID2] ||
+ match == env->cr[CR_PID3] || match == env->cr[CR_PID4]) {
+ prot &= PAGE_READ | PAGE_EXEC;
+ if (type == PAGE_WRITE) {
+ ret = EXCP_DMPI;
+ goto egress;
+ }
+ }
+ }
/* No guest access type indicates a non-architectural access from
within QEMU. Bypass checks for access, D, B and T bits. */
@@ -171,6 +188,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
egress:
*pphys = phys;
*pprot = prot;
+ trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
return ret;
}
@@ -200,6 +218,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
MMUAccessType type, int mmu_idx, uintptr_t retaddr)
{
HPPACPU *cpu = HPPA_CPU(cs);
+ CPUHPPAState *env = &cpu->env;
int prot, excp, a_prot;
hwaddr phys;
@@ -215,9 +234,10 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
break;
}
- excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx,
+ excp = hppa_get_physical_address(env, addr, mmu_idx,
a_prot, &phys, &prot);
if (unlikely(excp >= 0)) {
+ trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
/* Failure. Raise the indicated exception. */
cs->exception_index = excp;
if (cpu->env.psw & PSW_Q) {
@@ -228,6 +248,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size,
cpu_loop_exit_restore(cs, retaddr);
}
+ trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK,
+ phys & TARGET_PAGE_MASK, size, type, mmu_idx);
/* Success! Store the translation into the QEMU TLB. */
tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
prot, mmu_idx, TARGET_PAGE_SIZE);
@@ -242,11 +264,13 @@ void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
/* Zap any old entries covering ADDR; notice empty entries on the way. */
for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
hppa_tlb_entry *ent = &env->tlb[i];
- if (!ent->entry_valid) {
- empty = ent;
- } else if (ent->va_b <= addr && addr <= ent->va_e) {
- hppa_flush_tlb_ent(env, ent);
- empty = ent;
+ if (ent->va_b <= addr && addr <= ent->va_e) {
+ if (ent->entry_valid) {
+ hppa_flush_tlb_ent(env, ent);
+ }
+ if (!empty) {
+ empty = ent;
+ }
}
}
@@ -259,6 +283,7 @@ void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
empty->va_b = addr & TARGET_PAGE_MASK;
empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1;
empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS;
+ trace_hppa_tlb_itlba(env, empty, empty->va_b, empty->va_e, empty->pa);
}
/* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */
@@ -266,7 +291,7 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
{
hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
- if (unlikely(ent == NULL || ent->entry_valid)) {
+ if (unlikely(ent == NULL)) {
qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
return;
}
@@ -280,6 +305,8 @@ void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
ent->d = extract32(reg, 28, 1);
ent->t = extract32(reg, 29, 1);
ent->entry_valid = 1;
+ trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u, ent->ar_pl2,
+ ent->ar_pl1, ent->ar_type, ent->b, ent->d, ent->t);
}
/* Purge (Insn/Data) TLB. This is explicitly page-based, and is
@@ -299,6 +326,7 @@ void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
{
CPUState *src = CPU(hppa_env_get_cpu(env));
CPUState *cpu;
+ trace_hppa_tlb_ptlb(env);
run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
CPU_FOREACH(cpu) {
@@ -314,11 +342,24 @@ void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
void HELPER(ptlbe)(CPUHPPAState *env)
{
CPUState *src = CPU(hppa_env_get_cpu(env));
-
+ trace_hppa_tlb_ptlbe(env);
memset(env->tlb, 0, sizeof(env->tlb));
tlb_flush_by_mmuidx(src, 0xf);
}
+void cpu_hppa_change_prot_id(CPUHPPAState *env)
+{
+ if (env->psw & PSW_P) {
+ CPUState *src = CPU(hppa_env_get_cpu(env));
+ tlb_flush_by_mmuidx(src, 0xf);
+ }
+}
+
+void HELPER(change_prot_id)(CPUHPPAState *env)
+{
+ cpu_hppa_change_prot_id(env);
+}
+
target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
{
hwaddr phys;
@@ -335,8 +376,10 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
if (excp == EXCP_DTLB_MISS) {
excp = EXCP_NA_DTLB_MISS;
}
+ trace_hppa_tlb_lpa_failed(env, addr);
hppa_dynamic_excp(env, excp, GETPC());
}
+ trace_hppa_tlb_lpa_success(env, addr, phys);
return phys;
}
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 268caaaa20..a55a5dfc02 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -25,6 +25,7 @@
#include "sysemu/sysemu.h"
#include "qemu/timer.h"
#include "fpu/softfloat.h"
+#include "trace.h"
void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp)
{
@@ -165,6 +166,7 @@ target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr,
int prot, excp;
hwaddr phys;
+ trace_hppa_tlb_probe(addr, level, want);
/* Fail if the requested privilege level is higher than current. */
if (level < (env->iaoq_f & 3)) {
return 0;
@@ -676,11 +678,6 @@ target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm)
void HELPER(rfi)(CPUHPPAState *env)
{
- /* ??? On second reading this condition simply seems
- to be undefined rather than a diagnosed trap. */
- if (env->psw & (PSW_I | PSW_R | PSW_Q)) {
- helper_excp(env, EXCP_ILL);
- }
env->iasq_f = (uint64_t)env->cr[CR_IIASQ] << 32;
env->iasq_b = (uint64_t)env->cr_back[0] << 32;
env->iaoq_f = env->cr[CR_IIAOQ];
diff --git a/target/hppa/trace-events b/target/hppa/trace-events
new file mode 100644
index 0000000000..80dae5bd8b
--- /dev/null
+++ b/target/hppa/trace-events
@@ -0,0 +1,18 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# target/hppa/mem_helper.c
+disable hppa_tlb_flush_ent(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx"
+disable hppa_tlb_find_entry(void *env, void *ent, int valid, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p valid=%d va_b=0x%lx va_e=0x%lx pa=0x%lx"
+disable hppa_tlb_find_entry_not_found(void *env, uint64_t addr) "env=%p addr=%08lx"
+disable hppa_tlb_get_physical_address(void *env, int ret, int prot, uint64_t addr, uint64_t phys) "env=%p ret=%d prot=%d addr=0x%lx phys=0x%lx"
+disable hppa_tlb_fill_excp(void *env, uint64_t addr, int size, int type, int mmu_idx) "env=%p addr=0x%lx size=%d type=%d mmu_idx=%d"
+disable hppa_tlb_fill_success(void *env, uint64_t addr, uint64_t phys, int size, int type, int mmu_idx) "env=%p addr=0x%lx phys=0x%lx size=%d type=%d mmu_idx=%d"
+disable hppa_tlb_itlba(void *env, void *ent, uint64_t va_b, uint64_t va_e, uint64_t pa) "env=%p ent=%p va_b=0x%lx va_e=0x%lx pa=0x%lx"
+disable hppa_tlb_itlbp(void *env, void *ent, int access_id, int u, int pl2, int pl1, int type, int b, int d, int t) "env=%p ent=%p access_id=%x u=%d pl2=%d pl1=%d type=%d b=%d d=%d t=%d"
+disable hppa_tlb_ptlb(void *env) "env=%p"
+disable hppa_tlb_ptlbe(void *env) "env=%p"
+disable hppa_tlb_lpa_success(void *env, uint64_t addr, uint64_t phys) "env=%p addr=0x%lx phys=0x%lx"
+disable hppa_tlb_lpa_failed(void *env, uint64_t addr) "env=%p addr=0x%lx"
+
+# target/hppa/op_helper.c
+disable hppa_tlb_probe(uint64_t addr, int level, int want) "addr=0x%lx level=%d want=%d"
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index dc5636fe94..35c504087f 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -816,12 +816,10 @@ static bool gen_illegal(DisasContext *ctx)
static bool use_goto_tb(DisasContext *ctx, target_ureg dest)
{
- /* Suppress goto_tb in the case of single-steping and IO. */
- if ((tb_cflags(ctx->base.tb) & CF_LAST_IO)
- || ctx->base.singlestep_enabled) {
- return false;
- }
- return true;
+ /* Suppress goto_tb for page crossing, IO, or single-steping. */
+ return !(((ctx->base.pc_first ^ dest) & TARGET_PAGE_MASK)
+ || (tb_cflags(ctx->base.tb) & CF_LAST_IO)
+ || ctx->base.singlestep_enabled);
}
/* If the next insn is to be nullified, and it's on the same page,
@@ -2258,6 +2256,16 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
break;
+ case CR_PID1:
+ case CR_PID2:
+ case CR_PID3:
+ case CR_PID4:
+ tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
+#ifndef CONFIG_USER_ONLY
+ gen_helper_change_prot_id(cpu_env);
+#endif
+ break;
+
default:
tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
break;
@@ -2474,9 +2482,8 @@ static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
gen_helper_itlbp(cpu_env, addr, reg);
}
- /* Exit TB for ITLB change if mmu is enabled. This *should* not be
- the case, since the OS TLB fill handler runs with mmu disabled. */
- if (!a->data && (ctx->tb_flags & PSW_C)) {
+ /* Exit TB for TLB change if mmu is enabled. */
+ if (ctx->tb_flags & PSW_C) {
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
}
return nullify_end(ctx);
@@ -2503,7 +2510,7 @@ static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
}
/* Exit TB for TLB change if mmu is enabled. */
- if (!a->data && (ctx->tb_flags & PSW_C)) {
+ if (ctx->tb_flags & PSW_C) {
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
}
return nullify_end(ctx);
@@ -3033,7 +3040,7 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1,
DisasCond cond;
in2 = load_gpr(ctx, r);
- dest = dest_gpr(ctx, r);
+ dest = tcg_temp_new();
sv = NULL;
cb_msb = NULL;
@@ -3049,6 +3056,8 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1,
}
cond = do_cond(c * 2 + f, dest, cb_msb, sv);
+ save_gpr(ctx, r, dest);
+ tcg_temp_free(dest);
return do_cbranch(ctx, disp, n, &cond);
}
@@ -3446,6 +3455,8 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
{
target_ureg dest = iaoq_dest(ctx, a->disp);
+ nullify_over(ctx);
+
/* Make sure the caller hasn't done something weird with the queue.
* ??? This is not quite the same as the PSW[B] bit, which would be
* expensive to track. Real hardware will trap for
@@ -3483,7 +3494,16 @@ static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
}
#endif
- return do_dbranch(ctx, dest, a->l, a->n);
+ if (a->l) {
+ TCGv_reg tmp = dest_gpr(ctx, a->l);
+ if (ctx->privilege < 3) {
+ tcg_gen_andi_reg(tmp, tmp, -4);
+ }
+ tcg_gen_ori_reg(tmp, tmp, ctx->privilege);
+ save_gpr(ctx, a->l, tmp);
+ }
+
+ return do_dbranch(ctx, dest, 0, a->n);
}
static bool trans_blr(DisasContext *ctx, arg_blr *a)
@@ -4048,6 +4068,13 @@ static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
return nullify_end(ctx);
}
+static bool trans_diag(DisasContext *ctx, arg_diag *a)
+{
+ qemu_log_mask(LOG_UNIMP, "DIAG opcode ignored\n");
+ cond_free(&ctx->null_cond);
+ return true;
+}
+
static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index ae51fe754e..be9b4c30c3 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -190,6 +190,7 @@ typedef struct PowerPCCPUClass {
#endif
const PPCHash64Options *hash64_opts;
struct ppc_radix_page_info *radix_page_info;
+ uint32_t lrg_decr_bits;
void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env);
int (*handle_mmu_fault)(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx);
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 26604ddf98..fc12b4688e 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1321,10 +1321,10 @@ uint32_t cpu_ppc_load_atbu (CPUPPCState *env);
void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value);
void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value);
bool ppc_decr_clear_on_delivery(CPUPPCState *env);
-uint32_t cpu_ppc_load_decr (CPUPPCState *env);
-void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
-uint32_t cpu_ppc_load_hdecr (CPUPPCState *env);
-void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value);
+target_ulong cpu_ppc_load_decr(CPUPPCState *env);
+void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value);
+target_ulong cpu_ppc_load_hdecr(CPUPPCState *env);
+void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value);
uint64_t cpu_ppc_load_purr (CPUPPCState *env);
uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env);
uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env);
@@ -2563,19 +2563,64 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx)
}
/* Accessors for FP, VMX and VSX registers */
+#if defined(HOST_WORDS_BIGENDIAN)
+#define VsrB(i) u8[i]
+#define VsrSB(i) s8[i]
+#define VsrH(i) u16[i]
+#define VsrSH(i) s16[i]
+#define VsrW(i) u32[i]
+#define VsrSW(i) s32[i]
+#define VsrD(i) u64[i]
+#define VsrSD(i) s64[i]
+#else
+#define VsrB(i) u8[15 - (i)]
+#define VsrSB(i) s8[15 - (i)]
+#define VsrH(i) u16[7 - (i)]
+#define VsrSH(i) s16[7 - (i)]
+#define VsrW(i) u32[3 - (i)]
+#define VsrSW(i) s32[3 - (i)]
+#define VsrD(i) u64[1 - (i)]
+#define VsrSD(i) s64[1 - (i)]
+#endif
+
+static inline int vsr64_offset(int i, bool high)
+{
+ return offsetof(CPUPPCState, vsr[i].VsrD(high ? 0 : 1));
+}
+
+static inline int vsr_full_offset(int i)
+{
+ return offsetof(CPUPPCState, vsr[i].u64[0]);
+}
+
+static inline int fpr_offset(int i)
+{
+ return vsr64_offset(i, true);
+}
+
static inline uint64_t *cpu_fpr_ptr(CPUPPCState *env, int i)
{
- return &env->vsr[i].u64[0];
+ return (uint64_t *)((uintptr_t)env + fpr_offset(i));
}
static inline uint64_t *cpu_vsrl_ptr(CPUPPCState *env, int i)
{
- return &env->vsr[i].u64[1];
+ return (uint64_t *)((uintptr_t)env + vsr64_offset(i, false));
+}
+
+static inline long avr64_offset(int i, bool high)
+{
+ return vsr64_offset(i + 32, high);
+}
+
+static inline int avr_full_offset(int i)
+{
+ return vsr_full_offset(i + 32);
}
static inline ppc_avr_t *cpu_avr_ptr(CPUPPCState *env, int i)
{
- return &env->vsr[32 + i];
+ return (ppc_avr_t *)((uintptr_t)env + avr_full_offset(i));
}
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 39bedbb11d..beafcf1ebd 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -107,6 +107,24 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
return POWERPC_EXCP_RESET;
}
+static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail)
+{
+ uint64_t offset = 0;
+
+ switch (ail) {
+ case AIL_0001_8000:
+ offset = 0x18000;
+ break;
+ case AIL_C000_0000_0000_4000:
+ offset = 0xc000000000004000ull;
+ break;
+ default:
+ cpu_abort(cs, "Invalid AIL combination %d\n", ail);
+ break;
+ }
+
+ return offset;
+}
/* Note that this function should be greatly optimized
* when called with a constant excp, from ppc_hw_interrupt
@@ -708,17 +726,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
/* Handle AIL */
if (ail) {
new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
- switch(ail) {
- case AIL_0001_8000:
- vector |= 0x18000;
- break;
- case AIL_C000_0000_0000_4000:
- vector |= 0xc000000000004000ull;
- break;
- default:
- cpu_abort(cs, "Invalid AIL combination %d\n", ail);
- break;
- }
+ vector |= ppc_excp_vector_offset(cs, ail);
}
#if defined(TARGET_PPC64)
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index f26a71ffcf..fb6f64ed1e 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -204,35 +204,16 @@ EXTRACT_HELPER(IMM8, 11, 8);
EXTRACT_HELPER(DCMX, 16, 7);
EXTRACT_HELPER_SPLIT_3(DCMX_XV, 5, 16, 0, 1, 2, 5, 1, 6, 6);
-#if defined(HOST_WORDS_BIGENDIAN)
-#define VsrB(i) u8[i]
-#define VsrSB(i) s8[i]
-#define VsrH(i) u16[i]
-#define VsrSH(i) s16[i]
-#define VsrW(i) u32[i]
-#define VsrSW(i) s32[i]
-#define VsrD(i) u64[i]
-#define VsrSD(i) s64[i]
-#else
-#define VsrB(i) u8[15 - (i)]
-#define VsrSB(i) s8[15 - (i)]
-#define VsrH(i) u16[7 - (i)]
-#define VsrSH(i) s16[7 - (i)]
-#define VsrW(i) u32[3 - (i)]
-#define VsrSW(i) s32[3 - (i)]
-#define VsrD(i) u64[1 - (i)]
-#define VsrSD(i) s64[1 - (i)]
-#endif
static inline void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
{
- vsr->VsrD(0) = env->vsr[n].u64[0];
- vsr->VsrD(1) = env->vsr[n].u64[1];
+ vsr->VsrD(0) = env->vsr[n].VsrD(0);
+ vsr->VsrD(1) = env->vsr[n].VsrD(1);
}
static inline void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
{
- env->vsr[n].u64[0] = vsr->VsrD(0);
- env->vsr[n].u64[1] = vsr->VsrD(1);
+ env->vsr[n].VsrD(0) = vsr->VsrD(0);
+ env->vsr[n].VsrD(1) = vsr->VsrD(1);
}
void helper_compute_fprf_float16(CPUPPCState *env, float16 arg);
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index d01852fe31..2427c8ee13 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -90,7 +90,9 @@ static int cap_ppc_pvr_compat;
static int cap_ppc_safe_cache;
static int cap_ppc_safe_bounds_check;
static int cap_ppc_safe_indirect_branch;
+static int cap_ppc_count_cache_flush_assist;
static int cap_ppc_nested_kvm_hv;
+static int cap_large_decr;
static uint32_t debug_inst_opcode;
@@ -124,6 +126,7 @@ static bool kvmppc_is_pr(KVMState *ks)
static int kvm_ppc_register_host_cpu_type(MachineState *ms);
static void kvmppc_get_cpu_characteristics(KVMState *s);
+static int kvmppc_get_dec_bits(void);
int kvm_arch_init(MachineState *ms, KVMState *s)
{
@@ -151,6 +154,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
kvmppc_get_cpu_characteristics(s);
cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV);
+ cap_large_decr = kvmppc_get_dec_bits();
/*
* Note: setting it to false because there is not such capability
* in KVM at this moment.
@@ -752,7 +756,7 @@ static int kvm_get_fp(CPUState *cs)
static int kvm_get_vpa(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
struct kvm_one_reg reg;
int ret;
@@ -792,7 +796,7 @@ static int kvm_get_vpa(CPUState *cs)
static int kvm_put_vpa(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
- sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
struct kvm_one_reg reg;
int ret;
@@ -1593,70 +1597,93 @@ void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
}
}
-static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
+static int kvm_handle_hw_breakpoint(CPUState *cs,
+ struct kvm_debug_exit_arch *arch_info)
{
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
- struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
int handle = 0;
int n;
int flag = 0;
- if (cs->singlestep_enabled) {
- handle = 1;
- } else if (arch_info->status) {
- if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
- if (arch_info->status & KVMPPC_DEBUG_BREAKPOINT) {
- n = find_hw_breakpoint(arch_info->address, GDB_BREAKPOINT_HW);
- if (n >= 0) {
- handle = 1;
- }
- } else if (arch_info->status & (KVMPPC_DEBUG_WATCH_READ |
- KVMPPC_DEBUG_WATCH_WRITE)) {
- n = find_hw_watchpoint(arch_info->address, &flag);
- if (n >= 0) {
- handle = 1;
- cs->watchpoint_hit = &hw_watchpoint;
- hw_watchpoint.vaddr = hw_debug_points[n].addr;
- hw_watchpoint.flags = flag;
- }
+ if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
+ if (arch_info->status & KVMPPC_DEBUG_BREAKPOINT) {
+ n = find_hw_breakpoint(arch_info->address, GDB_BREAKPOINT_HW);
+ if (n >= 0) {
+ handle = 1;
+ }
+ } else if (arch_info->status & (KVMPPC_DEBUG_WATCH_READ |
+ KVMPPC_DEBUG_WATCH_WRITE)) {
+ n = find_hw_watchpoint(arch_info->address, &flag);
+ if (n >= 0) {
+ handle = 1;
+ cs->watchpoint_hit = &hw_watchpoint;
+ hw_watchpoint.vaddr = hw_debug_points[n].addr;
+ hw_watchpoint.flags = flag;
}
}
- } else if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
- handle = 1;
- } else {
- /* QEMU is not able to handle debug exception, so inject
- * program exception to guest;
- * Yes program exception NOT debug exception !!
- * When QEMU is using debug resources then debug exception must
- * be always set. To achieve this we set MSR_DE and also set
- * MSRP_DEP so guest cannot change MSR_DE.
- * When emulating debug resource for guest we want guest
- * to control MSR_DE (enable/disable debug interrupt on need).
- * Supporting both configurations are NOT possible.
- * So the result is that we cannot share debug resources
- * between QEMU and Guest on BOOKE architecture.
- * In the current design QEMU gets the priority over guest,
- * this means that if QEMU is using debug resources then guest
- * cannot use them;
- * For software breakpoint QEMU uses a privileged instruction;
- * So there cannot be any reason that we are here for guest
- * set debug exception, only possibility is guest executed a
- * privileged / illegal instruction and that's why we are
- * injecting a program interrupt.
- */
+ }
+ return handle;
+}
- cpu_synchronize_state(cs);
- /* env->nip is PC, so increment this by 4 to use
- * ppc_cpu_do_interrupt(), which set srr0 = env->nip - 4.
- */
- env->nip += 4;
- cs->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_INVAL;
- ppc_cpu_do_interrupt(cs);
+static int kvm_handle_singlestep(void)
+{
+ return 1;
+}
+
+static int kvm_handle_sw_breakpoint(void)
+{
+ return 1;
+}
+
+static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
+
+ if (cs->singlestep_enabled) {
+ return kvm_handle_singlestep();
}
- return handle;
+ if (arch_info->status) {
+ return kvm_handle_hw_breakpoint(cs, arch_info);
+ }
+
+ if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
+ return kvm_handle_sw_breakpoint();
+ }
+
+ /*
+ * QEMU is not able to handle debug exception, so inject
+ * program exception to guest;
+ * Yes program exception NOT debug exception !!
+ * When QEMU is using debug resources then debug exception must
+ * be always set. To achieve this we set MSR_DE and also set
+ * MSRP_DEP so guest cannot change MSR_DE.
+ * When emulating debug resource for guest we want guest
+ * to control MSR_DE (enable/disable debug interrupt on need).
+ * Supporting both configurations are NOT possible.
+ * So the result is that we cannot share debug resources
+ * between QEMU and Guest on BOOKE architecture.
+ * In the current design QEMU gets the priority over guest,
+ * this means that if QEMU is using debug resources then guest
+ * cannot use them;
+ * For software breakpoint QEMU uses a privileged instruction;
+ * So there cannot be any reason that we are here for guest
+ * set debug exception, only possibility is guest executed a
+ * privileged / illegal instruction and that's why we are
+ * injecting a program interrupt.
+ */
+ cpu_synchronize_state(cs);
+ /*
+ * env->nip is PC, so increment this by 4 to use
+ * ppc_cpu_do_interrupt(), which set srr0 = env->nip - 4.
+ */
+ env->nip += 4;
+ cs->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_INVAL;
+ ppc_cpu_do_interrupt(cs);
+
+ return 0;
}
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
@@ -1927,6 +1954,16 @@ uint64_t kvmppc_get_clockfreq(void)
return kvmppc_read_int_cpu_dt("clock-frequency");
}
+static int kvmppc_get_dec_bits(void)
+{
+ int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits");
+
+ if (nr_bits > 0) {
+ return nr_bits;
+ }
+ return 0;
+}
+
static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
@@ -2007,6 +2044,11 @@ void kvmppc_enable_clear_ref_mod_hcalls(void)
kvmppc_enable_hcall(kvm_state, H_CLEAR_MOD);
}
+void kvmppc_enable_h_page_init(void)
+{
+ kvmppc_enable_hcall(kvm_state, H_PAGE_INIT);
+}
+
void kvmppc_set_papr(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
@@ -2379,7 +2421,13 @@ static int parse_cap_ppc_safe_bounds_check(struct kvm_ppc_cpu_char c)
static int parse_cap_ppc_safe_indirect_branch(struct kvm_ppc_cpu_char c)
{
- if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) {
+ if ((~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_FLUSH_COUNT_CACHE) &&
+ (~c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) &&
+ (~c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED)) {
+ return SPAPR_CAP_FIXED_NA;
+ } else if (c.behaviour & c.behaviour_mask & H_CPU_BEHAV_FLUSH_COUNT_CACHE) {
+ return SPAPR_CAP_WORKAROUND;
+ } else if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) {
return SPAPR_CAP_FIXED_CCD;
} else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) {
return SPAPR_CAP_FIXED_IBS;
@@ -2388,6 +2436,14 @@ static int parse_cap_ppc_safe_indirect_branch(struct kvm_ppc_cpu_char c)
return 0;
}
+static int parse_cap_ppc_count_cache_flush_assist(struct kvm_ppc_cpu_char c)
+{
+ if (c.character & c.character_mask & H_CPU_CHAR_BCCTR_FLUSH_ASSIST) {
+ return 1;
+ }
+ return 0;
+}
+
static void kvmppc_get_cpu_characteristics(KVMState *s)
{
struct kvm_ppc_cpu_char c;
@@ -2410,6 +2466,8 @@ static void kvmppc_get_cpu_characteristics(KVMState *s)
cap_ppc_safe_cache = parse_cap_ppc_safe_cache(c);
cap_ppc_safe_bounds_check = parse_cap_ppc_safe_bounds_check(c);
cap_ppc_safe_indirect_branch = parse_cap_ppc_safe_indirect_branch(c);
+ cap_ppc_count_cache_flush_assist =
+ parse_cap_ppc_count_cache_flush_assist(c);
}
int kvmppc_get_cap_safe_cache(void)
@@ -2427,6 +2485,11 @@ int kvmppc_get_cap_safe_indirect_branch(void)
return cap_ppc_safe_indirect_branch;
}
+int kvmppc_get_cap_count_cache_flush_assist(void)
+{
+ return cap_ppc_count_cache_flush_assist;
+}
+
bool kvmppc_has_cap_nested_kvm_hv(void)
{
return !!cap_ppc_nested_kvm_hv;
@@ -2442,6 +2505,35 @@ bool kvmppc_has_cap_spapr_vfio(void)
return cap_spapr_vfio;
}
+int kvmppc_get_cap_large_decr(void)
+{
+ return cap_large_decr;
+}
+
+int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
+{
+ CPUState *cs = CPU(cpu);
+ uint64_t lpcr;
+
+ kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+ /* Do we need to modify the LPCR? */
+ if (!!(lpcr & LPCR_LD) != !!enable) {
+ if (enable) {
+ lpcr |= LPCR_LD;
+ } else {
+ lpcr &= ~LPCR_LD;
+ }
+ kvm_set_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+ kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+
+ if (!!(lpcr & LPCR_LD) != !!enable) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
{
uint32_t host_pvr = mfpvr();
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index bdfaa4e70a..2c2ea30e87 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -23,6 +23,7 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
void kvmppc_enable_logical_ci_hcalls(void);
void kvmppc_enable_set_mode_hcall(void);
void kvmppc_enable_clear_ref_mod_hcalls(void);
+void kvmppc_enable_h_page_init(void);
void kvmppc_set_papr(PowerPCCPU *cpu);
int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr);
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
@@ -62,8 +63,11 @@ bool kvmppc_has_cap_mmu_hash_v3(void);
int kvmppc_get_cap_safe_cache(void);
int kvmppc_get_cap_safe_bounds_check(void);
int kvmppc_get_cap_safe_indirect_branch(void);
+int kvmppc_get_cap_count_cache_flush_assist(void);
bool kvmppc_has_cap_nested_kvm_hv(void);
int kvmppc_set_cap_nested_kvm_hv(int enable);
+int kvmppc_get_cap_large_decr(void);
+int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable);
int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
@@ -135,6 +139,10 @@ static inline void kvmppc_enable_clear_ref_mod_hcalls(void)
{
}
+static inline void kvmppc_enable_h_page_init(void)
+{
+}
+
static inline void kvmppc_set_papr(PowerPCCPU *cpu)
{
}
@@ -322,6 +330,11 @@ static inline int kvmppc_get_cap_safe_indirect_branch(void)
return 0;
}
+static inline int kvmppc_get_cap_count_cache_flush_assist(void)
+{
+ return 0;
+}
+
static inline bool kvmppc_has_cap_nested_kvm_hv(void)
{
return false;
@@ -332,6 +345,16 @@ static inline int kvmppc_set_cap_nested_kvm_hv(int enable)
return -1;
}
+static inline int kvmppc_get_cap_large_decr(void)
+{
+ return 0;
+}
+
+static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
+{
+ return -1;
+}
+
static inline int kvmppc_enable_hwrng(void)
{
return -1;
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 756b6d2971..a92d0ad3a3 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -150,7 +150,7 @@ static int get_fpr(QEMUFile *f, void *pv, size_t size,
{
ppc_vsr_t *v = pv;
- v->u64[0] = qemu_get_be64(f);
+ v->VsrD(0) = qemu_get_be64(f);
return 0;
}
@@ -160,7 +160,7 @@ static int put_fpr(QEMUFile *f, void *pv, size_t size,
{
ppc_vsr_t *v = pv;
- qemu_put_be64(f, v->u64[0]);
+ qemu_put_be64(f, v->VsrD(0));
return 0;
}
@@ -181,7 +181,7 @@ static int get_vsr(QEMUFile *f, void *pv, size_t size,
{
ppc_vsr_t *v = pv;
- v->u64[1] = qemu_get_be64(f);
+ v->VsrD(1) = qemu_get_be64(f);
return 0;
}
@@ -191,7 +191,7 @@ static int put_vsr(QEMUFile *f, void *pv, size_t size,
{
ppc_vsr_t *v = pv;
- qemu_put_be64(f, v->u64[1]);
+ qemu_put_be64(f, v->VsrD(1));
return 0;
}
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index c431303eff..a2b1ec5040 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -1109,7 +1109,7 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
case POWERPC_MMU_3_00: /* P9 */
lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
(LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
- LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR |
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
(LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
LPCR_DEE | LPCR_OEE)) | LPCR_MER | LPCR_GTSE | LPCR_TC |
LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE);
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 819221f246..98b37cebc2 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6677,34 +6677,22 @@ GEN_TM_PRIV_NOOP(trechkpt);
static inline void get_fpr(TCGv_i64 dst, int regno)
{
- tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[regno].u64[0]));
+ tcg_gen_ld_i64(dst, cpu_env, fpr_offset(regno));
}
static inline void set_fpr(int regno, TCGv_i64 src)
{
- tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[regno].u64[0]));
+ tcg_gen_st_i64(src, cpu_env, fpr_offset(regno));
}
static inline void get_avr64(TCGv_i64 dst, int regno, bool high)
{
-#ifdef HOST_WORDS_BIGENDIAN
- tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState,
- vsr[32 + regno].u64[(high ? 0 : 1)]));
-#else
- tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState,
- vsr[32 + regno].u64[(high ? 1 : 0)]));
-#endif
+ tcg_gen_ld_i64(dst, cpu_env, avr64_offset(regno, high));
}
static inline void set_avr64(int regno, TCGv_i64 src, bool high)
{
-#ifdef HOST_WORDS_BIGENDIAN
- tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState,
- vsr[32 + regno].u64[(high ? 0 : 1)]));
-#else
- tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState,
- vsr[32 + regno].u64[(high ? 1 : 0)]));
-#endif
+ tcg_gen_st_i64(src, cpu_env, avr64_offset(regno, high));
}
#include "translate/fp-impl.inc.c"
@@ -7417,7 +7405,7 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
#if !defined(NO_TIMER_DUMP)
cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
#if !defined(CONFIG_USER_ONLY)
- " DECR %08" PRIu32
+ " DECR " TARGET_FMT_lu
#endif
"\n",
cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c
index f1b15ae2cb..eb10c533ca 100644
--- a/target/ppc/translate/vmx-impl.inc.c
+++ b/target/ppc/translate/vmx-impl.inc.c
@@ -10,15 +10,10 @@
static inline TCGv_ptr gen_avr_ptr(int reg)
{
TCGv_ptr r = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, vsr[32 + reg].u64[0]));
+ tcg_gen_addi_ptr(r, cpu_env, avr_full_offset(reg));
return r;
}
-static inline long avr64_offset(int reg, bool high)
-{
- return offsetof(CPUPPCState, vsr[32 + reg].u64[(high ? 0 : 1)]);
-}
-
#define GEN_VR_LDX(name, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
@@ -205,7 +200,7 @@ static void gen_mtvscr(DisasContext *ctx)
}
val = tcg_temp_new_i32();
- bofs = avr64_offset(rB(ctx->opcode), true);
+ bofs = avr_full_offset(rB(ctx->opcode));
#ifdef HOST_WORDS_BIGENDIAN
bofs += 3 * 4;
#endif
@@ -284,9 +279,9 @@ static void glue(gen_, name)(DisasContext *ctx) \
} \
\
tcg_op(vece, \
- avr64_offset(rD(ctx->opcode), true), \
- avr64_offset(rA(ctx->opcode), true), \
- avr64_offset(rB(ctx->opcode), true), \
+ avr_full_offset(rD(ctx->opcode)), \
+ avr_full_offset(rA(ctx->opcode)), \
+ avr_full_offset(rB(ctx->opcode)), \
16, 16); \
}
@@ -578,10 +573,10 @@ static void glue(gen_, NAME)(DisasContext *ctx) \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
- tcg_gen_gvec_4(avr64_offset(rD(ctx->opcode), true), \
+ tcg_gen_gvec_4(avr_full_offset(rD(ctx->opcode)), \
offsetof(CPUPPCState, vscr_sat), \
- avr64_offset(rA(ctx->opcode), true), \
- avr64_offset(rB(ctx->opcode), true), \
+ avr_full_offset(rA(ctx->opcode)), \
+ avr_full_offset(rB(ctx->opcode)), \
16, 16, &g); \
}
@@ -755,7 +750,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
return; \
} \
simm = SIMM5(ctx->opcode); \
- tcg_op(avr64_offset(rD(ctx->opcode), true), 16, 16, simm); \
+ tcg_op(avr_full_offset(rD(ctx->opcode)), 16, 16, simm); \
}
GEN_VXFORM_DUPI(vspltisb, tcg_gen_gvec_dup8i, 6, 12);
@@ -850,8 +845,8 @@ static void gen_vsplt(DisasContext *ctx, int vece)
}
uimm = UIMM5(ctx->opcode);
- bofs = avr64_offset(rB(ctx->opcode), true);
- dofs = avr64_offset(rD(ctx->opcode), true);
+ bofs = avr_full_offset(rB(ctx->opcode));
+ dofs = avr_full_offset(rD(ctx->opcode));
/* Experimental testing shows that hardware masks the immediate. */
bofs += (uimm << vece) & 15;
diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c
index e73197e717..508e9199c8 100644
--- a/target/ppc/translate/vsx-impl.inc.c
+++ b/target/ppc/translate/vsx-impl.inc.c
@@ -1,54 +1,23 @@
/*** VSX extension ***/
-static inline void get_vsr(TCGv_i64 dst, int n)
-{
- tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[n].u64[1]));
-}
-
-static inline void set_vsr(int n, TCGv_i64 src)
-{
- tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[n].u64[1]));
-}
-
-static inline int vsr_full_offset(int n)
-{
- return offsetof(CPUPPCState, vsr[n].u64[0]);
-}
-
static inline void get_cpu_vsrh(TCGv_i64 dst, int n)
{
- if (n < 32) {
- get_fpr(dst, n);
- } else {
- get_avr64(dst, n - 32, true);
- }
+ tcg_gen_ld_i64(dst, cpu_env, vsr64_offset(n, true));
}
static inline void get_cpu_vsrl(TCGv_i64 dst, int n)
{
- if (n < 32) {
- get_vsr(dst, n);
- } else {
- get_avr64(dst, n - 32, false);
- }
+ tcg_gen_ld_i64(dst, cpu_env, vsr64_offset(n, false));
}
static inline void set_cpu_vsrh(int n, TCGv_i64 src)
{
- if (n < 32) {
- set_fpr(n, src);
- } else {
- set_avr64(n - 32, src, true);
- }
+ tcg_gen_st_i64(src, cpu_env, vsr64_offset(n, true));
}
static inline void set_cpu_vsrl(int n, TCGv_i64 src)
{
- if (n < 32) {
- set_vsr(n, src);
- } else {
- set_avr64(n - 32, src, false);
- }
+ tcg_gen_st_i64(src, cpu_env, vsr64_offset(n, false));
}
#define VSX_LOAD_SCALAR(name, operation) \
@@ -1618,8 +1587,7 @@ static void gen_xsxsigdp(DisasContext *ctx)
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
get_cpu_vsrh(t1, xB(ctx->opcode));
- tcg_gen_andi_i64(rt, t1, 0x000FFFFFFFFFFFFF);
- tcg_gen_or_i64(rt, rt, t0);
+ tcg_gen_deposit_i64(rt, t0, t1, 0, 52);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(t1);
@@ -1655,8 +1623,7 @@ static void gen_xsxsigqp(DisasContext *ctx)
tcg_gen_movi_i64(t0, 0x0001000000000000);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
- tcg_gen_andi_i64(xth, xbh, 0x0000FFFFFFFFFFFF);
- tcg_gen_or_i64(xth, xth, t0);
+ tcg_gen_deposit_i64(xth, t0, xbh, 0, 48);
set_cpu_vsrh(rD(ctx->opcode) + 32, xth);
tcg_gen_mov_i64(xtl, xbl);
set_cpu_vsrl(rD(ctx->opcode) + 32, xtl);
@@ -1726,7 +1693,6 @@ static void gen_xviexpdp(DisasContext *ctx)
TCGv_i64 xal;
TCGv_i64 xbh;
TCGv_i64 xbl;
- TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
@@ -1742,20 +1708,13 @@ static void gen_xviexpdp(DisasContext *ctx)
get_cpu_vsrl(xal, xA(ctx->opcode));
get_cpu_vsrh(xbh, xB(ctx->opcode));
get_cpu_vsrl(xbl, xB(ctx->opcode));
- t0 = tcg_temp_new_i64();
- tcg_gen_andi_i64(xth, xah, 0x800FFFFFFFFFFFFF);
- tcg_gen_andi_i64(t0, xbh, 0x7FF);
- tcg_gen_shli_i64(t0, t0, 52);
- tcg_gen_or_i64(xth, xth, t0);
+ tcg_gen_deposit_i64(xth, xah, xbh, 52, 11);
set_cpu_vsrh(xT(ctx->opcode), xth);
- tcg_gen_andi_i64(xtl, xal, 0x800FFFFFFFFFFFFF);
- tcg_gen_andi_i64(t0, xbl, 0x7FF);
- tcg_gen_shli_i64(t0, t0, 52);
- tcg_gen_or_i64(xtl, xtl, t0);
+
+ tcg_gen_deposit_i64(xtl, xal, xbl, 52, 11);
set_cpu_vsrl(xT(ctx->opcode), xtl);
- tcg_temp_free_i64(t0);
tcg_temp_free_i64(xth);
tcg_temp_free_i64(xtl);
tcg_temp_free_i64(xah);
@@ -1853,16 +1812,14 @@ static void gen_xvxsigdp(DisasContext *ctx)
tcg_gen_movi_i64(t0, 0x0010000000000000);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
- tcg_gen_andi_i64(xth, xbh, 0x000FFFFFFFFFFFFF);
- tcg_gen_or_i64(xth, xth, t0);
+ tcg_gen_deposit_i64(xth, t0, xbh, 0, 52);
set_cpu_vsrh(xT(ctx->opcode), xth);
tcg_gen_extract_i64(exp, xbl, 52, 11);
tcg_gen_movi_i64(t0, 0x0010000000000000);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
- tcg_gen_andi_i64(xtl, xbl, 0x000FFFFFFFFFFFFF);
- tcg_gen_or_i64(xtl, xtl, t0);
+ tcg_gen_deposit_i64(xth, t0, xbl, 0, 52);
set_cpu_vsrl(xT(ctx->opcode), xtl);
tcg_temp_free_i64(t0);
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 58542c0fe0..0bd555eb19 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -8376,6 +8376,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->hash64_opts = &ppc_hash64_opts_basic;
+ pcc->lrg_decr_bits = 32;
#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
@@ -8550,6 +8551,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->hash64_opts = &ppc_hash64_opts_POWER7;
+ pcc->lrg_decr_bits = 32;
#endif
pcc->excp_model = POWERPC_EXCP_POWER7;
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
@@ -8718,6 +8720,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->hash64_opts = &ppc_hash64_opts_POWER7;
+ pcc->lrg_decr_bits = 32;
#endif
pcc->excp_model = POWERPC_EXCP_POWER8;
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
@@ -8892,7 +8895,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBSYNC |
- PPC_64B | PPC_64BX | PPC_ALTIVEC |
+ PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD |
PPC_CILDST;
@@ -8904,6 +8907,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
pcc->msr_mask = (1ull << MSR_SF) |
+ (1ull << MSR_SHV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -8926,6 +8930,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
/* segment page size remain the same */
pcc->hash64_opts = &ppc_hash64_opts_POWER7;
pcc->radix_page_info = &POWER9_radix_page_info;
+ pcc->lrg_decr_bits = 56;
#endif
pcc->excp_model = POWERPC_EXCP_POWER9;
pcc->bus_model = PPC_FLAGS_INPUT_POWER9;
diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs
index 4072abe3e4..9c6c109327 100644
--- a/target/riscv/Makefile.objs
+++ b/target/riscv/Makefile.objs
@@ -1 +1,20 @@
obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o
+
+DECODETREE = $(SRC_PATH)/scripts/decodetree.py
+
+decode32-y = $(SRC_PATH)/target/riscv/insn32.decode
+decode32-$(TARGET_RISCV64) += $(SRC_PATH)/target/riscv/insn32-64.decode
+
+target/riscv/decode_insn32.inc.c: $(decode32-y) $(DECODETREE)
+ $(call quiet-command, \
+ $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn32 $(decode32-y), \
+ "GEN", $(TARGET_DIR)$@)
+
+target/riscv/decode_insn16.inc.c: \
+ $(SRC_PATH)/target/riscv/insn16.decode $(DECODETREE)
+ $(call quiet-command, \
+ $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn16 --insnwidth 16 $<, \
+ "GEN", $(TARGET_DIR)$@)
+
+target/riscv/translate.o: target/riscv/decode_insn32.inc.c \
+ target/riscv/decode_insn16.inc.c
diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
new file mode 100644
index 0000000000..17cc52cf2a
--- /dev/null
+++ b/target/riscv/insn16.decode
@@ -0,0 +1,129 @@
+#
+# RISC-V translation routines for the RVXI Base Integer Instruction Set.
+#
+# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+#
+# 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 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/>.
+
+# Fields:
+%rd 7:5
+%rs1_3 7:3 !function=ex_rvc_register
+%rs2_3 2:3 !function=ex_rvc_register
+%rs2_5 2:5
+
+# Immediates:
+%imm_ci 12:s1 2:5
+%nzuimm_ciw 7:4 11:2 5:1 6:1 !function=ex_shift_2
+%uimm_cl_d 5:2 10:3 !function=ex_shift_3
+%uimm_cl_w 5:1 10:3 6:1 !function=ex_shift_2
+%imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1
+%imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1
+
+%nzuimm_6bit 12:1 2:5
+%uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3
+%uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2
+%uimm_6bit_sd 7:3 10:3 !function=ex_shift_3
+%uimm_6bit_sw 7:2 9:4 !function=ex_shift_2
+
+%imm_addi16sp 12:s1 3:2 5:1 2:1 6:1 !function=ex_shift_4
+%imm_lui 12:s1 2:5 !function=ex_shift_12
+
+
+
+# Argument sets:
+&cl rs1 rd
+&cl_dw uimm rs1 rd
+&ci imm rd
+&ciw nzuimm rd
+&cs rs1 rs2
+&cs_dw uimm rs1 rs2
+&cb imm rs1
+&cr rd rs2
+&cj imm
+&c_shift shamt rd
+
+&c_ld uimm rd
+&c_sd uimm rs2
+
+&caddi16sp_lui imm_lui imm_addi16sp rd
+&cflwsp_ldsp uimm_flwsp uimm_ldsp rd
+&cfswsp_sdsp uimm_fswsp uimm_sdsp rs2
+
+# Formats 16:
+@cr .... ..... ..... .. &cr rs2=%rs2_5 %rd
+@ci ... . ..... ..... .. &ci imm=%imm_ci %rd
+@ciw ... ........ ... .. &ciw nzuimm=%nzuimm_ciw rd=%rs2_3
+@cl_d ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
+@cl_w ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
+@cl ... ... ... .. ... .. &cl rs1=%rs1_3 rd=%rs2_3
+@cs ... ... ... .. ... .. &cs rs1=%rs1_3 rs2=%rs2_3
+@cs_2 ... ... ... .. ... .. &cr rd=%rs1_3 rs2=%rs2_3
+@cs_d ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3
+@cs_w ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3
+@cb ... ... ... .. ... .. &cb imm=%imm_cb rs1=%rs1_3
+@cj ... ........... .. &cj imm=%imm_cj
+
+@c_ld ... . ..... ..... .. &c_ld uimm=%uimm_6bit_ld %rd
+@c_lw ... . ..... ..... .. &c_ld uimm=%uimm_6bit_lw %rd
+@c_sd ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sd rs2=%rs2_5
+@c_sw ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sw rs2=%rs2_5
+
+@c_addi16sp_lui ... . ..... ..... .. &caddi16sp_lui %imm_lui %imm_addi16sp %rd
+@c_flwsp_ldsp ... . ..... ..... .. &cflwsp_ldsp uimm_flwsp=%uimm_6bit_lw \
+ uimm_ldsp=%uimm_6bit_ld %rd
+@c_fswsp_sdsp ... . ..... ..... .. &cfswsp_sdsp uimm_fswsp=%uimm_6bit_sw \
+ uimm_sdsp=%uimm_6bit_sd rs2=%rs2_5
+
+@c_shift ... . .. ... ..... .. &c_shift rd=%rs1_3 shamt=%nzuimm_6bit
+@c_shift2 ... . .. ... ..... .. &c_shift rd=%rd shamt=%nzuimm_6bit
+
+@c_andi ... . .. ... ..... .. &ci imm=%imm_ci rd=%rs1_3
+
+# *** RV64C Standard Extension (Quadrant 0) ***
+c_addi4spn 000 ........ ... 00 @ciw
+c_fld 001 ... ... .. ... 00 @cl_d
+c_lw 010 ... ... .. ... 00 @cl_w
+c_flw_ld 011 --- ... -- ... 00 @cl #Note: Must parse uimm manually
+c_fsd 101 ... ... .. ... 00 @cs_d
+c_sw 110 ... ... .. ... 00 @cs_w
+c_fsw_sd 111 --- ... -- ... 00 @cs #Note: Must parse uimm manually
+
+# *** RV64C Standard Extension (Quadrant 1) ***
+c_addi 000 . ..... ..... 01 @ci
+c_jal_addiw 001 . ..... ..... 01 @ci #Note: parse rd and/or imm manually
+c_li 010 . ..... ..... 01 @ci
+c_addi16sp_lui 011 . ..... ..... 01 @c_addi16sp_lui # shares opc with C.LUI
+c_srli 100 . 00 ... ..... 01 @c_shift
+c_srai 100 . 01 ... ..... 01 @c_shift
+c_andi 100 . 10 ... ..... 01 @c_andi
+c_sub 100 0 11 ... 00 ... 01 @cs_2
+c_xor 100 0 11 ... 01 ... 01 @cs_2
+c_or 100 0 11 ... 10 ... 01 @cs_2
+c_and 100 0 11 ... 11 ... 01 @cs_2
+c_subw 100 1 11 ... 00 ... 01 @cs_2
+c_addw 100 1 11 ... 01 ... 01 @cs_2
+c_j 101 ........... 01 @cj
+c_beqz 110 ... ... ..... 01 @cb
+c_bnez 111 ... ... ..... 01 @cb
+
+# *** RV64C Standard Extension (Quadrant 2) ***
+c_slli 000 . ..... ..... 10 @c_shift2
+c_fldsp 001 . ..... ..... 10 @c_ld
+c_lwsp 010 . ..... ..... 10 @c_lw
+c_flwsp_ldsp 011 . ..... ..... 10 @c_flwsp_ldsp #C.LDSP:RV64;C.FLWSP:RV32
+c_jr_mv 100 0 ..... ..... 10 @cr
+c_ebreak_jalr_add 100 1 ..... ..... 10 @cr
+c_fsdsp 101 ...... ..... 10 @c_sd
+c_swsp 110 . ..... ..... 10 @c_sw
+c_fswsp_sdsp 111 . ..... ..... 10 @c_fswsp_sdsp #C.SDSP:RV64;C.FSWSP:RV32
diff --git a/target/riscv/insn32-64.decode b/target/riscv/insn32-64.decode
new file mode 100644
index 0000000000..380bf791bc
--- /dev/null
+++ b/target/riscv/insn32-64.decode
@@ -0,0 +1,72 @@
+#
+# RISC-V translation routines for the RV Instruction Set.
+#
+# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+#
+# 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 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/>.
+
+# This is concatenated with insn32.decode for risc64 targets.
+# Most of the fields and formats are there.
+
+%sh5 20:5
+
+@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
+
+# *** RV64I Base Instruction Set (in addition to RV32I) ***
+lwu ............ ..... 110 ..... 0000011 @i
+ld ............ ..... 011 ..... 0000011 @i
+sd ....... ..... ..... 011 ..... 0100011 @s
+addiw ............ ..... 000 ..... 0011011 @i
+slliw 0000000 ..... ..... 001 ..... 0011011 @sh5
+srliw 0000000 ..... ..... 101 ..... 0011011 @sh5
+sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5
+addw 0000000 ..... ..... 000 ..... 0111011 @r
+subw 0100000 ..... ..... 000 ..... 0111011 @r
+sllw 0000000 ..... ..... 001 ..... 0111011 @r
+srlw 0000000 ..... ..... 101 ..... 0111011 @r
+sraw 0100000 ..... ..... 101 ..... 0111011 @r
+
+# *** RV64M Standard Extension (in addition to RV32M) ***
+mulw 0000001 ..... ..... 000 ..... 0111011 @r
+divw 0000001 ..... ..... 100 ..... 0111011 @r
+divuw 0000001 ..... ..... 101 ..... 0111011 @r
+remw 0000001 ..... ..... 110 ..... 0111011 @r
+remuw 0000001 ..... ..... 111 ..... 0111011 @r
+
+# *** RV64A Standard Extension (in addition to RV32A) ***
+lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld
+sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st
+amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st
+amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st
+amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st
+amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st
+amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st
+amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st
+
+# *** RV64F Standard Extension (in addition to RV32F) ***
+fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm
+fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm
+
+# *** RV64D Standard Extension (in addition to RV32D) ***
+fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm
+fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2
+fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm
+fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
new file mode 100644
index 0000000000..6f3ab7aa52
--- /dev/null
+++ b/target/riscv/insn32.decode
@@ -0,0 +1,201 @@
+#
+# RISC-V translation routines for the RVXI Base Integer Instruction Set.
+#
+# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+#
+# 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 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/>.
+
+# Fields:
+%rs3 27:5
+%rs2 20:5
+%rs1 15:5
+%rd 7:5
+
+%sh10 20:10
+%csr 20:12
+%rm 12:3
+
+# immediates:
+%imm_i 20:s12
+%imm_s 25:s7 7:5
+%imm_b 31:s1 7:1 25:6 8:4 !function=ex_shift_1
+%imm_j 31:s1 12:8 20:1 21:10 !function=ex_shift_1
+%imm_u 12:s20 !function=ex_shift_12
+
+# Argument sets:
+&b imm rs2 rs1
+&i imm rs1 rd
+&r rd rs1 rs2
+&shift shamt rs1 rd
+&atomic aq rl rs2 rs1 rd
+
+# Formats 32:
+@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
+@i ............ ..... ... ..... ....... &i imm=%imm_i %rs1 %rd
+@b ....... ..... ..... ... ..... ....... &b imm=%imm_b %rs2 %rs1
+@s ....... ..... ..... ... ..... ....... imm=%imm_s %rs2 %rs1
+@u .................... ..... ....... imm=%imm_u %rd
+@j .................... ..... ....... imm=%imm_j %rd
+
+@sh ...... ...... ..... ... ..... ....... &shift shamt=%sh10 %rs1 %rd
+@csr ............ ..... ... ..... ....... %csr %rs1 %rd
+
+@atom_ld ..... aq:1 rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd
+@atom_st ..... aq:1 rl:1 ..... ........ ..... ....... &atomic %rs2 %rs1 %rd
+
+@r4_rm ..... .. ..... ..... ... ..... ....... %rs3 %rs2 %rs1 %rm %rd
+@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd
+@r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd
+@r2 ....... ..... ..... ... ..... ....... %rs1 %rd
+
+@sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1
+@sfence_vm ....... ..... ..... ... ..... ....... %rs1
+
+
+# *** Privileged Instructions ***
+ecall 000000000000 00000 000 00000 1110011
+ebreak 000000000001 00000 000 00000 1110011
+uret 0000000 00010 00000 000 00000 1110011
+sret 0001000 00010 00000 000 00000 1110011
+hret 0010000 00010 00000 000 00000 1110011
+mret 0011000 00010 00000 000 00000 1110011
+wfi 0001000 00101 00000 000 00000 1110011
+sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma
+sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm
+
+# *** RV32I Base Instruction Set ***
+lui .................... ..... 0110111 @u
+auipc .................... ..... 0010111 @u
+jal .................... ..... 1101111 @j
+jalr ............ ..... 000 ..... 1100111 @i
+beq ....... ..... ..... 000 ..... 1100011 @b
+bne ....... ..... ..... 001 ..... 1100011 @b
+blt ....... ..... ..... 100 ..... 1100011 @b
+bge ....... ..... ..... 101 ..... 1100011 @b
+bltu ....... ..... ..... 110 ..... 1100011 @b
+bgeu ....... ..... ..... 111 ..... 1100011 @b
+lb ............ ..... 000 ..... 0000011 @i
+lh ............ ..... 001 ..... 0000011 @i
+lw ............ ..... 010 ..... 0000011 @i
+lbu ............ ..... 100 ..... 0000011 @i
+lhu ............ ..... 101 ..... 0000011 @i
+sb ....... ..... ..... 000 ..... 0100011 @s
+sh ....... ..... ..... 001 ..... 0100011 @s
+sw ....... ..... ..... 010 ..... 0100011 @s
+addi ............ ..... 000 ..... 0010011 @i
+slti ............ ..... 010 ..... 0010011 @i
+sltiu ............ ..... 011 ..... 0010011 @i
+xori ............ ..... 100 ..... 0010011 @i
+ori ............ ..... 110 ..... 0010011 @i
+andi ............ ..... 111 ..... 0010011 @i
+slli 00.... ...... ..... 001 ..... 0010011 @sh
+srli 00.... ...... ..... 101 ..... 0010011 @sh
+srai 01.... ...... ..... 101 ..... 0010011 @sh
+add 0000000 ..... ..... 000 ..... 0110011 @r
+sub 0100000 ..... ..... 000 ..... 0110011 @r
+sll 0000000 ..... ..... 001 ..... 0110011 @r
+slt 0000000 ..... ..... 010 ..... 0110011 @r
+sltu 0000000 ..... ..... 011 ..... 0110011 @r
+xor 0000000 ..... ..... 100 ..... 0110011 @r
+srl 0000000 ..... ..... 101 ..... 0110011 @r
+sra 0100000 ..... ..... 101 ..... 0110011 @r
+or 0000000 ..... ..... 110 ..... 0110011 @r
+and 0000000 ..... ..... 111 ..... 0110011 @r
+fence ---- pred:4 succ:4 ----- 000 ----- 0001111
+fence_i ---- ---- ---- ----- 001 ----- 0001111
+csrrw ............ ..... 001 ..... 1110011 @csr
+csrrs ............ ..... 010 ..... 1110011 @csr
+csrrc ............ ..... 011 ..... 1110011 @csr
+csrrwi ............ ..... 101 ..... 1110011 @csr
+csrrsi ............ ..... 110 ..... 1110011 @csr
+csrrci ............ ..... 111 ..... 1110011 @csr
+
+# *** RV32M Standard Extension ***
+mul 0000001 ..... ..... 000 ..... 0110011 @r
+mulh 0000001 ..... ..... 001 ..... 0110011 @r
+mulhsu 0000001 ..... ..... 010 ..... 0110011 @r
+mulhu 0000001 ..... ..... 011 ..... 0110011 @r
+div 0000001 ..... ..... 100 ..... 0110011 @r
+divu 0000001 ..... ..... 101 ..... 0110011 @r
+rem 0000001 ..... ..... 110 ..... 0110011 @r
+remu 0000001 ..... ..... 111 ..... 0110011 @r
+
+# *** RV32A Standard Extension ***
+lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld
+sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st
+amoswap_w 00001 . . ..... ..... 010 ..... 0101111 @atom_st
+amoadd_w 00000 . . ..... ..... 010 ..... 0101111 @atom_st
+amoxor_w 00100 . . ..... ..... 010 ..... 0101111 @atom_st
+amoand_w 01100 . . ..... ..... 010 ..... 0101111 @atom_st
+amoor_w 01000 . . ..... ..... 010 ..... 0101111 @atom_st
+amomin_w 10000 . . ..... ..... 010 ..... 0101111 @atom_st
+amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st
+amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st
+amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st
+
+# *** RV32F Standard Extension ***
+flw ............ ..... 010 ..... 0000111 @i
+fsw ....... ..... ..... 010 ..... 0100111 @s
+fmadd_s ..... 00 ..... ..... ... ..... 1000011 @r4_rm
+fmsub_s ..... 00 ..... ..... ... ..... 1000111 @r4_rm
+fnmsub_s ..... 00 ..... ..... ... ..... 1001011 @r4_rm
+fnmadd_s ..... 00 ..... ..... ... ..... 1001111 @r4_rm
+fadd_s 0000000 ..... ..... ... ..... 1010011 @r_rm
+fsub_s 0000100 ..... ..... ... ..... 1010011 @r_rm
+fmul_s 0001000 ..... ..... ... ..... 1010011 @r_rm
+fdiv_s 0001100 ..... ..... ... ..... 1010011 @r_rm
+fsqrt_s 0101100 00000 ..... ... ..... 1010011 @r2_rm
+fsgnj_s 0010000 ..... ..... 000 ..... 1010011 @r
+fsgnjn_s 0010000 ..... ..... 001 ..... 1010011 @r
+fsgnjx_s 0010000 ..... ..... 010 ..... 1010011 @r
+fmin_s 0010100 ..... ..... 000 ..... 1010011 @r
+fmax_s 0010100 ..... ..... 001 ..... 1010011 @r
+fcvt_w_s 1100000 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_wu_s 1100000 00001 ..... ... ..... 1010011 @r2_rm
+fmv_x_w 1110000 00000 ..... 000 ..... 1010011 @r2
+feq_s 1010000 ..... ..... 010 ..... 1010011 @r
+flt_s 1010000 ..... ..... 001 ..... 1010011 @r
+fle_s 1010000 ..... ..... 000 ..... 1010011 @r
+fclass_s 1110000 00000 ..... 001 ..... 1010011 @r2
+fcvt_s_w 1101000 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_s_wu 1101000 00001 ..... ... ..... 1010011 @r2_rm
+fmv_w_x 1111000 00000 ..... 000 ..... 1010011 @r2
+
+# *** RV32D Standard Extension ***
+fld ............ ..... 011 ..... 0000111 @i
+fsd ....... ..... ..... 011 ..... 0100111 @s
+fmadd_d ..... 01 ..... ..... ... ..... 1000011 @r4_rm
+fmsub_d ..... 01 ..... ..... ... ..... 1000111 @r4_rm
+fnmsub_d ..... 01 ..... ..... ... ..... 1001011 @r4_rm
+fnmadd_d ..... 01 ..... ..... ... ..... 1001111 @r4_rm
+fadd_d 0000001 ..... ..... ... ..... 1010011 @r_rm
+fsub_d 0000101 ..... ..... ... ..... 1010011 @r_rm
+fmul_d 0001001 ..... ..... ... ..... 1010011 @r_rm
+fdiv_d 0001101 ..... ..... ... ..... 1010011 @r_rm
+fsqrt_d 0101101 00000 ..... ... ..... 1010011 @r2_rm
+fsgnj_d 0010001 ..... ..... 000 ..... 1010011 @r
+fsgnjn_d 0010001 ..... ..... 001 ..... 1010011 @r
+fsgnjx_d 0010001 ..... ..... 010 ..... 1010011 @r
+fmin_d 0010101 ..... ..... 000 ..... 1010011 @r
+fmax_d 0010101 ..... ..... 001 ..... 1010011 @r
+fcvt_s_d 0100000 00001 ..... ... ..... 1010011 @r2_rm
+fcvt_d_s 0100001 00000 ..... ... ..... 1010011 @r2_rm
+feq_d 1010001 ..... ..... 010 ..... 1010011 @r
+flt_d 1010001 ..... ..... 001 ..... 1010011 @r
+fle_d 1010001 ..... ..... 000 ..... 1010011 @r
+fclass_d 1110001 00000 ..... 001 ..... 1010011 @r2
+fcvt_w_d 1100001 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm
+fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm
diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c
new file mode 100644
index 0000000000..acb605923e
--- /dev/null
+++ b/target/riscv/insn_trans/trans_privileged.inc.c
@@ -0,0 +1,110 @@
+/*
+ * RISC-V translation routines for the RISC-V privileged instructions.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * 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 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/>.
+ */
+
+static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
+{
+ /* always generates U-level ECALL, fixed in do_interrupt handler */
+ generate_exception(ctx, RISCV_EXCP_U_ECALL);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
+{
+ generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool trans_uret(DisasContext *ctx, arg_uret *a)
+{
+ return false;
+}
+
+static bool trans_sret(DisasContext *ctx, arg_sret *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+
+ if (has_ext(ctx, RVS)) {
+ gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ } else {
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_hret(DisasContext *ctx, arg_hret *a)
+{
+ return false;
+}
+
+static bool trans_mret(DisasContext *ctx, arg_mret *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+ gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ gen_helper_wfi(cpu_env);
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
+{
+#ifndef CONFIG_USER_ONLY
+ if (ctx->priv_ver == PRIV_VERSION_1_10_0) {
+ gen_helper_tlb_flush(cpu_env);
+ return true;
+ }
+#endif
+ return false;
+}
+
+static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
+{
+#ifndef CONFIG_USER_ONLY
+ if (ctx->priv_ver <= PRIV_VERSION_1_09_1) {
+ gen_helper_tlb_flush(cpu_env);
+ return true;
+ }
+#endif
+ return false;
+}
diff --git a/target/riscv/insn_trans/trans_rva.inc.c b/target/riscv/insn_trans/trans_rva.inc.c
new file mode 100644
index 0000000000..f6dbbc065e
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rva.inc.c
@@ -0,0 +1,218 @@
+/*
+ * RISC-V translation routines for the RV64A Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * 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 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/>.
+ */
+
+static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
+{
+ TCGv src1 = tcg_temp_new();
+ /* Put addr in load_res, data in load_val. */
+ gen_get_gpr(src1, a->rs1);
+ if (a->rl) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+ tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
+ if (a->aq) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+ tcg_gen_mov_tl(load_res, src1);
+ gen_set_gpr(a->rd, load_val);
+
+ tcg_temp_free(src1);
+ return true;
+}
+
+static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
+{
+ TCGv src1 = tcg_temp_new();
+ TCGv src2 = tcg_temp_new();
+ TCGv dat = tcg_temp_new();
+ TCGLabel *l1 = gen_new_label();
+ TCGLabel *l2 = gen_new_label();
+
+ gen_get_gpr(src1, a->rs1);
+ tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
+
+ gen_get_gpr(src2, a->rs2);
+ /*
+ * Note that the TCG atomic primitives are SC,
+ * so we can ignore AQ/RL along this path.
+ */
+ tcg_gen_atomic_cmpxchg_tl(src1, load_res, load_val, src2,
+ ctx->mem_idx, mop);
+ tcg_gen_setcond_tl(TCG_COND_NE, dat, src1, load_val);
+ gen_set_gpr(a->rd, dat);
+ tcg_gen_br(l2);
+
+ gen_set_label(l1);
+ /*
+ * Address comparion failure. However, we still need to
+ * provide the memory barrier implied by AQ/RL.
+ */
+ tcg_gen_mb(TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL);
+ tcg_gen_movi_tl(dat, 1);
+ gen_set_gpr(a->rd, dat);
+
+ gen_set_label(l2);
+ tcg_temp_free(dat);
+ tcg_temp_free(src1);
+ tcg_temp_free(src2);
+ return true;
+}
+
+static bool gen_amo(DisasContext *ctx, arg_atomic *a,
+ void(*func)(TCGv, TCGv, TCGv, TCGArg, TCGMemOp),
+ TCGMemOp mop)
+{
+ TCGv src1 = tcg_temp_new();
+ TCGv src2 = tcg_temp_new();
+
+ gen_get_gpr(src1, a->rs1);
+ gen_get_gpr(src2, a->rs2);
+
+ (*func)(src2, src1, src2, ctx->mem_idx, mop);
+
+ gen_set_gpr(a->rd, src2);
+ tcg_temp_free(src1);
+ tcg_temp_free(src2);
+ return true;
+}
+
+static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_lr(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_sc(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL));
+}
+
+#ifdef TARGET_RISCV64
+
+static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
+{
+ return gen_lr(ctx, a, MO_ALIGN | MO_TEQ);
+}
+
+static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a)
+{
+ return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
+{
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ));
+}
+#endif
diff --git a/target/riscv/insn_trans/trans_rvc.inc.c b/target/riscv/insn_trans/trans_rvc.inc.c
new file mode 100644
index 0000000000..bcdf64d3b7
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvc.inc.c
@@ -0,0 +1,327 @@
+/*
+ * RISC-V translation routines for the RVC Compressed Instruction Set.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * 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 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/>.
+ */
+
+static bool trans_c_addi4spn(DisasContext *ctx, arg_c_addi4spn *a)
+{
+ if (a->nzuimm == 0) {
+ /* Reserved in ISA */
+ return false;
+ }
+ arg_addi arg = { .rd = a->rd, .rs1 = 2, .imm = a->nzuimm };
+ return trans_addi(ctx, &arg);
+}
+
+static bool trans_c_fld(DisasContext *ctx, arg_c_fld *a)
+{
+ arg_fld arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm };
+ return trans_fld(ctx, &arg);
+}
+
+static bool trans_c_lw(DisasContext *ctx, arg_c_lw *a)
+{
+ arg_lw arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm };
+ return trans_lw(ctx, &arg);
+}
+
+static bool trans_c_flw_ld(DisasContext *ctx, arg_c_flw_ld *a)
+{
+#ifdef TARGET_RISCV32
+ /* C.FLW ( RV32FC-only ) */
+ return false;
+#else
+ /* C.LD ( RV64C/RV128C-only ) */
+ return false;
+#endif
+}
+
+static bool trans_c_fsd(DisasContext *ctx, arg_c_fsd *a)
+{
+ arg_fsd arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm };
+ return trans_fsd(ctx, &arg);
+}
+
+static bool trans_c_sw(DisasContext *ctx, arg_c_sw *a)
+{
+ arg_sw arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm };
+ return trans_sw(ctx, &arg);
+}
+
+static bool trans_c_fsw_sd(DisasContext *ctx, arg_c_fsw_sd *a)
+{
+#ifdef TARGET_RISCV32
+ /* C.FSW ( RV32FC-only ) */
+ return false;
+#else
+ /* C.SD ( RV64C/RV128C-only ) */
+ return false;
+#endif
+}
+
+static bool trans_c_addi(DisasContext *ctx, arg_c_addi *a)
+{
+ if (a->imm == 0) {
+ /* Hint: insn is valid but does not affect state */
+ return true;
+ }
+ arg_addi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
+ return trans_addi(ctx, &arg);
+}
+
+static bool trans_c_jal_addiw(DisasContext *ctx, arg_c_jal_addiw *a)
+{
+#ifdef TARGET_RISCV32
+ /* C.JAL */
+ arg_jal arg = { .rd = 1, .imm = a->imm };
+ return trans_jal(ctx, &arg);
+#else
+ /* C.ADDIW */
+ arg_addiw arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
+ return trans_addiw(ctx, &arg);
+#endif
+}
+
+static bool trans_c_li(DisasContext *ctx, arg_c_li *a)
+{
+ if (a->rd == 0) {
+ /* Hint: insn is valid but does not affect state */
+ return true;
+ }
+ arg_addi arg = { .rd = a->rd, .rs1 = 0, .imm = a->imm };
+ return trans_addi(ctx, &arg);
+}
+
+static bool trans_c_addi16sp_lui(DisasContext *ctx, arg_c_addi16sp_lui *a)
+{
+ if (a->rd == 2) {
+ /* C.ADDI16SP */
+ arg_addi arg = { .rd = 2, .rs1 = 2, .imm = a->imm_addi16sp };
+ return trans_addi(ctx, &arg);
+ } else if (a->imm_lui != 0) {
+ /* C.LUI */
+ if (a->rd == 0) {
+ /* Hint: insn is valid but does not affect state */
+ return true;
+ }
+ arg_lui arg = { .rd = a->rd, .imm = a->imm_lui };
+ return trans_lui(ctx, &arg);
+ }
+ return false;
+}
+
+static bool trans_c_srli(DisasContext *ctx, arg_c_srli *a)
+{
+ int shamt = a->shamt;
+ if (shamt == 0) {
+ /* For RV128 a shamt of 0 means a shift by 64 */
+ shamt = 64;
+ }
+ /* Ensure, that shamt[5] is zero for RV32 */
+ if (shamt >= TARGET_LONG_BITS) {
+ return false;
+ }
+
+ arg_srli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
+ return trans_srli(ctx, &arg);
+}
+
+static bool trans_c_srai(DisasContext *ctx, arg_c_srai *a)
+{
+ int shamt = a->shamt;
+ if (shamt == 0) {
+ /* For RV128 a shamt of 0 means a shift by 64 */
+ shamt = 64;
+ }
+ /* Ensure, that shamt[5] is zero for RV32 */
+ if (shamt >= TARGET_LONG_BITS) {
+ return false;
+ }
+
+ arg_srai arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
+ return trans_srai(ctx, &arg);
+}
+
+static bool trans_c_andi(DisasContext *ctx, arg_c_andi *a)
+{
+ arg_andi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
+ return trans_andi(ctx, &arg);
+}
+
+static bool trans_c_sub(DisasContext *ctx, arg_c_sub *a)
+{
+ arg_sub arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
+ return trans_sub(ctx, &arg);
+}
+
+static bool trans_c_xor(DisasContext *ctx, arg_c_xor *a)
+{
+ arg_xor arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
+ return trans_xor(ctx, &arg);
+}
+
+static bool trans_c_or(DisasContext *ctx, arg_c_or *a)
+{
+ arg_or arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
+ return trans_or(ctx, &arg);
+}
+
+static bool trans_c_and(DisasContext *ctx, arg_c_and *a)
+{
+ arg_and arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
+ return trans_and(ctx, &arg);
+}
+
+static bool trans_c_subw(DisasContext *ctx, arg_c_subw *a)
+{
+#ifdef TARGET_RISCV64
+ arg_subw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
+ return trans_subw(ctx, &arg);
+#else
+ return false;
+#endif
+}
+
+static bool trans_c_addw(DisasContext *ctx, arg_c_addw *a)
+{
+#ifdef TARGET_RISCV64
+ arg_addw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
+ return trans_addw(ctx, &arg);
+#else
+ return false;
+#endif
+}
+
+static bool trans_c_j(DisasContext *ctx, arg_c_j *a)
+{
+ arg_jal arg = { .rd = 0, .imm = a->imm };
+ return trans_jal(ctx, &arg);
+}
+
+static bool trans_c_beqz(DisasContext *ctx, arg_c_beqz *a)
+{
+ arg_beq arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm };
+ return trans_beq(ctx, &arg);
+}
+
+static bool trans_c_bnez(DisasContext *ctx, arg_c_bnez *a)
+{
+ arg_bne arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm };
+ return trans_bne(ctx, &arg);
+}
+
+static bool trans_c_slli(DisasContext *ctx, arg_c_slli *a)
+{
+ int shamt = a->shamt;
+ if (shamt == 0) {
+ /* For RV128 a shamt of 0 means a shift by 64 */
+ shamt = 64;
+ }
+ /* Ensure, that shamt[5] is zero for RV32 */
+ if (shamt >= TARGET_LONG_BITS) {
+ return false;
+ }
+
+ arg_slli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
+ return trans_slli(ctx, &arg);
+}
+
+static bool trans_c_fldsp(DisasContext *ctx, arg_c_fldsp *a)
+{
+ arg_fld arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm };
+ return trans_fld(ctx, &arg);
+}
+
+static bool trans_c_lwsp(DisasContext *ctx, arg_c_lwsp *a)
+{
+ arg_lw arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm };
+ return trans_lw(ctx, &arg);
+}
+
+static bool trans_c_flwsp_ldsp(DisasContext *ctx, arg_c_flwsp_ldsp *a)
+{
+#ifdef TARGET_RISCV32
+ /* C.FLWSP */
+ arg_flw arg_flw = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_flwsp };
+ return trans_flw(ctx, &arg_flw);
+#else
+ /* C.LDSP */
+ arg_ld arg_ld = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_ldsp };
+ return trans_ld(ctx, &arg_ld);
+#endif
+ return false;
+}
+
+static bool trans_c_jr_mv(DisasContext *ctx, arg_c_jr_mv *a)
+{
+ if (a->rd != 0 && a->rs2 == 0) {
+ /* C.JR */
+ arg_jalr arg = { .rd = 0, .rs1 = a->rd, .imm = 0 };
+ return trans_jalr(ctx, &arg);
+ } else if (a->rd != 0 && a->rs2 != 0) {
+ /* C.MV */
+ arg_add arg = { .rd = a->rd, .rs1 = 0, .rs2 = a->rs2 };
+ return trans_add(ctx, &arg);
+ }
+ return false;
+}
+
+static bool trans_c_ebreak_jalr_add(DisasContext *ctx, arg_c_ebreak_jalr_add *a)
+{
+ if (a->rd == 0 && a->rs2 == 0) {
+ /* C.EBREAK */
+ arg_ebreak arg = { };
+ return trans_ebreak(ctx, &arg);
+ } else if (a->rd != 0) {
+ if (a->rs2 == 0) {
+ /* C.JALR */
+ arg_jalr arg = { .rd = 1, .rs1 = a->rd, .imm = 0 };
+ return trans_jalr(ctx, &arg);
+ } else {
+ /* C.ADD */
+ arg_add arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
+ return trans_add(ctx, &arg);
+ }
+ }
+ return false;
+}
+
+static bool trans_c_fsdsp(DisasContext *ctx, arg_c_fsdsp *a)
+{
+ arg_fsd arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm };
+ return trans_fsd(ctx, &arg);
+}
+
+static bool trans_c_swsp(DisasContext *ctx, arg_c_swsp *a)
+{
+ arg_sw arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm };
+ return trans_sw(ctx, &arg);
+}
+
+static bool trans_c_fswsp_sdsp(DisasContext *ctx, arg_c_fswsp_sdsp *a)
+{
+#ifdef TARGET_RISCV32
+ /* C.FSWSP */
+ arg_fsw a_fsw = { .rs1 = a->rs2, .rs2 = 2, .imm = a->uimm_fswsp };
+ return trans_fsw(ctx, &a_fsw);
+#else
+ /* C.SDSP */
+ arg_sd a_sd = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_sdsp };
+ return trans_sd(ctx, &a_sd);
+#endif
+}
diff --git a/target/riscv/insn_trans/trans_rvd.inc.c b/target/riscv/insn_trans/trans_rvd.inc.c
new file mode 100644
index 0000000000..393fa0248c
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvd.inc.c
@@ -0,0 +1,442 @@
+/*
+ * RISC-V translation routines for the RV64D Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * 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 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/>.
+ */
+
+static bool trans_fld(DisasContext *ctx, arg_fld *a)
+{
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ tcg_gen_addi_tl(t0, t0, a->imm);
+
+ tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEQ);
+
+ mark_fs_dirty(ctx);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
+{
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ tcg_gen_addi_tl(t0, t0, a->imm);
+
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ);
+
+ mark_fs_dirty(ctx);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fadd_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsub_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmul_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fdiv_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsqrt_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
+{
+ if (a->rs1 == a->rs2) { /* FMOV */
+ tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
+ } else {
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2],
+ cpu_fpr[a->rs1], 0, 63);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ if (a->rs1 == a->rs2) { /* FNEG */
+ tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT64_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 63);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ if (a->rs1 == a->rs2) { /* FABS */
+ tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT64_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT64_MIN);
+ tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_helper_fmin_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_helper_fmax_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_helper_feq_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_helper_flt_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_helper_fle_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_helper_fclass_d(t0, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_w_d(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_wu_d(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, t0);
+ tcg_temp_free(t0);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, t0);
+ tcg_temp_free(t0);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+#ifdef TARGET_RISCV64
+
+static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_l_d(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_lu_d(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_gpr(a->rd, cpu_fpr[a->rs1]);
+ return true;
+}
+
+static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, t0);
+ tcg_temp_free(t0);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, t0);
+ tcg_temp_free(t0);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ tcg_gen_mov_tl(cpu_fpr[a->rd], t0);
+ tcg_temp_free(t0);
+ mark_fs_dirty(ctx);
+ return true;
+}
+#endif
diff --git a/target/riscv/insn_trans/trans_rvf.inc.c b/target/riscv/insn_trans/trans_rvf.inc.c
new file mode 100644
index 0000000000..172dbfa919
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvf.inc.c
@@ -0,0 +1,439 @@
+/*
+ * RISC-V translation routines for the RV64F Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * 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 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/>.
+ */
+
+#define REQUIRE_FPU do {\
+ if (ctx->mstatus_fs == 0) \
+ return false; \
+} while (0)
+
+static bool trans_flw(DisasContext *ctx, arg_flw *a)
+{
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ tcg_gen_addi_tl(t0, t0, a->imm);
+
+ tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL);
+ /* RISC-V requires NaN-boxing of narrower width floating point values */
+ tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 0xffffffff00000000ULL);
+
+ tcg_temp_free(t0);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
+{
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ tcg_gen_addi_tl(t0, t0, a->imm);
+
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL);
+
+ tcg_temp_free(t0);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fadd_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsub_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmul_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fdiv_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsqrt_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ if (a->rs1 == a->rs2) { /* FMOV */
+ tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
+ } else { /* FSGNJ */
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2], cpu_fpr[a->rs1],
+ 0, 31);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ if (a->rs1 == a->rs2) { /* FNEG */
+ tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT32_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 31);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ if (a->rs1 == a->rs2) { /* FABS */
+ tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT32_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT32_MIN);
+ tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_helper_fmin_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_helper_fmax_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a)
+{
+ /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+
+#if defined(TARGET_RISCV64)
+ tcg_gen_ext32s_tl(t0, cpu_fpr[a->rs1]);
+#else
+ tcg_gen_extrl_i64_i32(t0, cpu_fpr[a->rs1]);
+#endif
+
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ TCGv t0 = tcg_temp_new();
+ gen_helper_feq_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ TCGv t0 = tcg_temp_new();
+ gen_helper_flt_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ TCGv t0 = tcg_temp_new();
+ gen_helper_fle_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+
+ gen_helper_fclass_s(t0, cpu_fpr[a->rs1]);
+
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, t0);
+
+ mark_fs_dirty(ctx);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, t0);
+
+ mark_fs_dirty(ctx);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
+{
+ /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+#if defined(TARGET_RISCV64)
+ tcg_gen_mov_i64(cpu_fpr[a->rd], t0);
+#else
+ tcg_gen_extu_i32_i64(cpu_fpr[a->rd], t0);
+#endif
+
+ mark_fs_dirty(ctx);
+ tcg_temp_free(t0);
+
+ return true;
+}
+
+#ifdef TARGET_RISCV64
+static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(a->rd, t0);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, t0);
+
+ mark_fs_dirty(ctx);
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, t0);
+
+ mark_fs_dirty(ctx);
+ tcg_temp_free(t0);
+ return true;
+}
+#endif
diff --git a/target/riscv/insn_trans/trans_rvi.inc.c b/target/riscv/insn_trans/trans_rvi.inc.c
new file mode 100644
index 0000000000..d420a4d8b2
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvi.inc.c
@@ -0,0 +1,568 @@
+/*
+ * RISC-V translation routines for the RVXI Base Integer Instruction Set.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * 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 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/>.
+ */
+
+static bool trans_lui(DisasContext *ctx, arg_lui *a)
+{
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm);
+ }
+ return true;
+}
+
+static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
+{
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm + ctx->base.pc_next);
+ }
+ return true;
+}
+
+static bool trans_jal(DisasContext *ctx, arg_jal *a)
+{
+ gen_jal(ctx, a->rd, a->imm);
+ return true;
+}
+
+static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
+{
+ /* no chaining with JALR */
+ TCGLabel *misaligned = NULL;
+ TCGv t0 = tcg_temp_new();
+
+
+ gen_get_gpr(cpu_pc, a->rs1);
+ tcg_gen_addi_tl(cpu_pc, cpu_pc, a->imm);
+ tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
+
+ if (!has_ext(ctx, RVC)) {
+ misaligned = gen_new_label();
+ tcg_gen_andi_tl(t0, cpu_pc, 0x2);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
+ }
+
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
+ }
+ tcg_gen_lookup_and_goto_ptr();
+
+ if (misaligned) {
+ gen_set_label(misaligned);
+ gen_exception_inst_addr_mis(ctx);
+ }
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ tcg_temp_free(t0);
+ return true;
+}
+
+static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
+{
+ TCGLabel *l = gen_new_label();
+ TCGv source1, source2;
+ source1 = tcg_temp_new();
+ source2 = tcg_temp_new();
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ tcg_gen_brcond_tl(cond, source1, source2, l);
+ gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
+ gen_set_label(l); /* branch taken */
+
+ if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) {
+ /* misaligned */
+ gen_exception_inst_addr_mis(ctx);
+ } else {
+ gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm);
+ }
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+
+ return true;
+}
+
+static bool trans_beq(DisasContext *ctx, arg_beq *a)
+{
+ return gen_branch(ctx, a, TCG_COND_EQ);
+}
+
+static bool trans_bne(DisasContext *ctx, arg_bne *a)
+{
+ return gen_branch(ctx, a, TCG_COND_NE);
+}
+
+static bool trans_blt(DisasContext *ctx, arg_blt *a)
+{
+ return gen_branch(ctx, a, TCG_COND_LT);
+}
+
+static bool trans_bge(DisasContext *ctx, arg_bge *a)
+{
+ return gen_branch(ctx, a, TCG_COND_GE);
+}
+
+static bool trans_bltu(DisasContext *ctx, arg_bltu *a)
+{
+ return gen_branch(ctx, a, TCG_COND_LTU);
+}
+
+static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
+{
+ return gen_branch(ctx, a, TCG_COND_GEU);
+}
+
+static bool gen_load(DisasContext *ctx, arg_lb *a, TCGMemOp memop)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+ tcg_gen_addi_tl(t0, t0, a->imm);
+
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop);
+ gen_set_gpr(a->rd, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ return true;
+}
+
+static bool trans_lb(DisasContext *ctx, arg_lb *a)
+{
+ return gen_load(ctx, a, MO_SB);
+}
+
+static bool trans_lh(DisasContext *ctx, arg_lh *a)
+{
+ return gen_load(ctx, a, MO_TESW);
+}
+
+static bool trans_lw(DisasContext *ctx, arg_lw *a)
+{
+ return gen_load(ctx, a, MO_TESL);
+}
+
+static bool trans_lbu(DisasContext *ctx, arg_lbu *a)
+{
+ return gen_load(ctx, a, MO_UB);
+}
+
+static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
+{
+ return gen_load(ctx, a, MO_TEUW);
+}
+
+static bool gen_store(DisasContext *ctx, arg_sb *a, TCGMemOp memop)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv dat = tcg_temp_new();
+ gen_get_gpr(t0, a->rs1);
+ tcg_gen_addi_tl(t0, t0, a->imm);
+ gen_get_gpr(dat, a->rs2);
+
+ tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, memop);
+ tcg_temp_free(t0);
+ tcg_temp_free(dat);
+ return true;
+}
+
+
+static bool trans_sb(DisasContext *ctx, arg_sb *a)
+{
+ return gen_store(ctx, a, MO_SB);
+}
+
+static bool trans_sh(DisasContext *ctx, arg_sh *a)
+{
+ return gen_store(ctx, a, MO_TESW);
+}
+
+static bool trans_sw(DisasContext *ctx, arg_sw *a)
+{
+ return gen_store(ctx, a, MO_TESL);
+}
+
+#ifdef TARGET_RISCV64
+static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
+{
+ return gen_load(ctx, a, MO_TEUL);
+}
+
+static bool trans_ld(DisasContext *ctx, arg_ld *a)
+{
+ return gen_load(ctx, a, MO_TEQ);
+}
+
+static bool trans_sd(DisasContext *ctx, arg_sd *a)
+{
+ return gen_store(ctx, a, MO_TEQ);
+}
+#endif
+
+static bool trans_addi(DisasContext *ctx, arg_addi *a)
+{
+ return gen_arith_imm(ctx, a, &tcg_gen_add_tl);
+}
+
+static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LT, ret, s1, s2);
+}
+
+static void gen_sltu(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2);
+}
+
+
+static bool trans_slti(DisasContext *ctx, arg_slti *a)
+{
+ return gen_arith_imm(ctx, a, &gen_slt);
+}
+
+static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
+{
+ return gen_arith_imm(ctx, a, &gen_sltu);
+}
+
+static bool trans_xori(DisasContext *ctx, arg_xori *a)
+{
+ return gen_arith_imm(ctx, a, &tcg_gen_xor_tl);
+}
+static bool trans_ori(DisasContext *ctx, arg_ori *a)
+{
+ return gen_arith_imm(ctx, a, &tcg_gen_or_tl);
+}
+static bool trans_andi(DisasContext *ctx, arg_andi *a)
+{
+ return gen_arith_imm(ctx, a, &tcg_gen_and_tl);
+}
+static bool trans_slli(DisasContext *ctx, arg_slli *a)
+{
+ if (a->shamt >= TARGET_LONG_BITS) {
+ return false;
+ }
+
+ if (a->rd != 0) {
+ TCGv t = tcg_temp_new();
+ gen_get_gpr(t, a->rs1);
+
+ tcg_gen_shli_tl(t, t, a->shamt);
+
+ gen_set_gpr(a->rd, t);
+ tcg_temp_free(t);
+ } /* NOP otherwise */
+ return true;
+}
+
+static bool trans_srli(DisasContext *ctx, arg_srli *a)
+{
+ if (a->shamt >= TARGET_LONG_BITS) {
+ return false;
+ }
+
+ if (a->rd != 0) {
+ TCGv t = tcg_temp_new();
+ gen_get_gpr(t, a->rs1);
+
+ tcg_gen_shri_tl(t, t, a->shamt);
+ gen_set_gpr(a->rd, t);
+ tcg_temp_free(t);
+ } /* NOP otherwise */
+ return true;
+}
+
+static bool trans_srai(DisasContext *ctx, arg_srai *a)
+{
+ if (a->shamt >= TARGET_LONG_BITS) {
+ return false;
+ }
+
+ if (a->rd != 0) {
+ TCGv t = tcg_temp_new();
+ gen_get_gpr(t, a->rs1);
+
+ tcg_gen_sari_tl(t, t, a->shamt);
+ gen_set_gpr(a->rd, t);
+ tcg_temp_free(t);
+ } /* NOP otherwise */
+ return true;
+}
+
+static bool trans_add(DisasContext *ctx, arg_add *a)
+{
+ return gen_arith(ctx, a, &tcg_gen_add_tl);
+}
+
+static bool trans_sub(DisasContext *ctx, arg_sub *a)
+{
+ return gen_arith(ctx, a, &tcg_gen_sub_tl);
+}
+
+static bool trans_sll(DisasContext *ctx, arg_sll *a)
+{
+ return gen_shift(ctx, a, &tcg_gen_shl_tl);
+}
+
+static bool trans_slt(DisasContext *ctx, arg_slt *a)
+{
+ return gen_arith(ctx, a, &gen_slt);
+}
+
+static bool trans_sltu(DisasContext *ctx, arg_sltu *a)
+{
+ return gen_arith(ctx, a, &gen_sltu);
+}
+
+static bool trans_xor(DisasContext *ctx, arg_xor *a)
+{
+ return gen_arith(ctx, a, &tcg_gen_xor_tl);
+}
+
+static bool trans_srl(DisasContext *ctx, arg_srl *a)
+{
+ return gen_shift(ctx, a, &tcg_gen_shr_tl);
+}
+
+static bool trans_sra(DisasContext *ctx, arg_sra *a)
+{
+ return gen_shift(ctx, a, &tcg_gen_sar_tl);
+}
+
+static bool trans_or(DisasContext *ctx, arg_or *a)
+{
+ return gen_arith(ctx, a, &tcg_gen_or_tl);
+}
+
+static bool trans_and(DisasContext *ctx, arg_and *a)
+{
+ return gen_arith(ctx, a, &tcg_gen_and_tl);
+}
+
+#ifdef TARGET_RISCV64
+static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
+{
+ return gen_arith_imm(ctx, a, &gen_addw);
+}
+
+static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
+{
+ TCGv source1;
+ source1 = tcg_temp_new();
+ gen_get_gpr(source1, a->rs1);
+
+ tcg_gen_shli_tl(source1, source1, a->shamt);
+ tcg_gen_ext32s_tl(source1, source1);
+ gen_set_gpr(a->rd, source1);
+
+ tcg_temp_free(source1);
+ return true;
+}
+
+static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
+{
+ TCGv t = tcg_temp_new();
+ gen_get_gpr(t, a->rs1);
+ tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt);
+ /* sign-extend for W instructions */
+ tcg_gen_ext32s_tl(t, t);
+ gen_set_gpr(a->rd, t);
+ tcg_temp_free(t);
+ return true;
+}
+
+static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
+{
+ TCGv t = tcg_temp_new();
+ gen_get_gpr(t, a->rs1);
+ tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt);
+ gen_set_gpr(a->rd, t);
+ tcg_temp_free(t);
+ return true;
+}
+
+static bool trans_addw(DisasContext *ctx, arg_addw *a)
+{
+ return gen_arith(ctx, a, &gen_addw);
+}
+
+static bool trans_subw(DisasContext *ctx, arg_subw *a)
+{
+ return gen_arith(ctx, a, &gen_subw);
+}
+
+static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
+{
+ TCGv source1 = tcg_temp_new();
+ TCGv source2 = tcg_temp_new();
+
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ tcg_gen_andi_tl(source2, source2, 0x1F);
+ tcg_gen_shl_tl(source1, source1, source2);
+
+ tcg_gen_ext32s_tl(source1, source1);
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
+}
+
+static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
+{
+ TCGv source1 = tcg_temp_new();
+ TCGv source2 = tcg_temp_new();
+
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ /* clear upper 32 */
+ tcg_gen_ext32u_tl(source1, source1);
+ tcg_gen_andi_tl(source2, source2, 0x1F);
+ tcg_gen_shr_tl(source1, source1, source2);
+
+ tcg_gen_ext32s_tl(source1, source1);
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
+}
+
+static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
+{
+ TCGv source1 = tcg_temp_new();
+ TCGv source2 = tcg_temp_new();
+
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ /*
+ * first, trick to get it to act like working on 32 bits (get rid of
+ * upper 32, sign extend to fill space)
+ */
+ tcg_gen_ext32s_tl(source1, source1);
+ tcg_gen_andi_tl(source2, source2, 0x1F);
+ tcg_gen_sar_tl(source1, source1, source2);
+
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+
+ return true;
+}
+#endif
+
+static bool trans_fence(DisasContext *ctx, arg_fence *a)
+{
+ /* FENCE is a full memory barrier. */
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
+ return true;
+}
+
+static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
+{
+ /*
+ * FENCE_I is a no-op in QEMU,
+ * however we need to end the translation block
+ */
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ tcg_gen_exit_tb(NULL, 0);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+#define RISCV_OP_CSR_PRE do {\
+ source1 = tcg_temp_new(); \
+ csr_store = tcg_temp_new(); \
+ dest = tcg_temp_new(); \
+ rs1_pass = tcg_temp_new(); \
+ gen_get_gpr(source1, a->rs1); \
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \
+ tcg_gen_movi_tl(rs1_pass, a->rs1); \
+ tcg_gen_movi_tl(csr_store, a->csr); \
+ gen_io_start();\
+} while (0)
+
+#define RISCV_OP_CSR_POST do {\
+ gen_io_end(); \
+ gen_set_gpr(a->rd, dest); \
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
+ tcg_gen_exit_tb(NULL, 0); \
+ ctx->base.is_jmp = DISAS_NORETURN; \
+ tcg_temp_free(source1); \
+ tcg_temp_free(csr_store); \
+ tcg_temp_free(dest); \
+ tcg_temp_free(rs1_pass); \
+} while (0)
+
+
+static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
+{
+ TCGv source1, csr_store, dest, rs1_pass;
+ RISCV_OP_CSR_PRE;
+ gen_helper_csrrw(dest, cpu_env, source1, csr_store);
+ RISCV_OP_CSR_POST;
+ return true;
+}
+
+static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
+{
+ TCGv source1, csr_store, dest, rs1_pass;
+ RISCV_OP_CSR_PRE;
+ gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass);
+ RISCV_OP_CSR_POST;
+ return true;
+}
+
+static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
+{
+ TCGv source1, csr_store, dest, rs1_pass;
+ RISCV_OP_CSR_PRE;
+ gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass);
+ RISCV_OP_CSR_POST;
+ return true;
+}
+
+static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
+{
+ TCGv source1, csr_store, dest, rs1_pass;
+ RISCV_OP_CSR_PRE;
+ gen_helper_csrrw(dest, cpu_env, rs1_pass, csr_store);
+ RISCV_OP_CSR_POST;
+ return true;
+}
+
+static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
+{
+ TCGv source1, csr_store, dest, rs1_pass;
+ RISCV_OP_CSR_PRE;
+ gen_helper_csrrs(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
+ RISCV_OP_CSR_POST;
+ return true;
+}
+
+static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
+{
+ TCGv source1, csr_store, dest, rs1_pass;
+ RISCV_OP_CSR_PRE;
+ gen_helper_csrrc(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
+ RISCV_OP_CSR_POST;
+ return true;
+}
diff --git a/target/riscv/insn_trans/trans_rvm.inc.c b/target/riscv/insn_trans/trans_rvm.inc.c
new file mode 100644
index 0000000000..204af225f8
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvm.inc.c
@@ -0,0 +1,120 @@
+/*
+ * RISC-V translation routines for the RV64M Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * 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 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/>.
+ */
+
+
+static bool trans_mul(DisasContext *ctx, arg_mul *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, &tcg_gen_mul_tl);
+}
+
+static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ TCGv source1 = tcg_temp_new();
+ TCGv source2 = tcg_temp_new();
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ tcg_gen_muls2_tl(source2, source1, source1, source2);
+
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
+}
+
+static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, &gen_mulhsu);
+}
+
+static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ TCGv source1 = tcg_temp_new();
+ TCGv source2 = tcg_temp_new();
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ tcg_gen_mulu2_tl(source2, source1, source1, source2);
+
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
+}
+
+static bool trans_div(DisasContext *ctx, arg_div *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, &gen_div);
+}
+
+static bool trans_divu(DisasContext *ctx, arg_divu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, &gen_divu);
+}
+
+static bool trans_rem(DisasContext *ctx, arg_rem *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, &gen_rem);
+}
+
+static bool trans_remu(DisasContext *ctx, arg_remu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, &gen_remu);
+}
+
+#ifdef TARGET_RISCV64
+static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, &gen_mulw);
+}
+
+static bool trans_divw(DisasContext *ctx, arg_divw *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_div_w(ctx, a, &gen_div);
+}
+
+static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_div_w(ctx, a, &gen_divu);
+}
+
+static bool trans_remw(DisasContext *ctx, arg_remw *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_div_w(ctx, a, &gen_rem);
+}
+
+static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_div_w(ctx, a, &gen_remu);
+}
+#endif
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index b7176cbf98..049fa65c66 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -56,6 +56,7 @@ typedef struct DisasContext {
int frm;
} DisasContext;
+#ifdef TARGET_RISCV64
/* convert riscv funct3 to qemu memop for load/store */
static const int tcg_memop_lookup[8] = {
[0 ... 7] = -1,
@@ -69,6 +70,7 @@ static const int tcg_memop_lookup[8] = {
[6] = MO_TEUL,
#endif
};
+#endif
#ifdef TARGET_RISCV64
#define CASE_OP_32_64(X) case X: case glue(X, W)
@@ -186,367 +188,112 @@ static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
tcg_temp_free(rh);
}
-static void gen_fsgnj(DisasContext *ctx, uint32_t rd, uint32_t rs1,
- uint32_t rs2, int rm, uint64_t min)
-{
- switch (rm) {
- case 0: /* fsgnj */
- if (rs1 == rs2) { /* FMOV */
- tcg_gen_mov_i64(cpu_fpr[rd], cpu_fpr[rs1]);
- } else {
- tcg_gen_deposit_i64(cpu_fpr[rd], cpu_fpr[rs2], cpu_fpr[rs1],
- 0, min == INT32_MIN ? 31 : 63);
- }
- break;
- case 1: /* fsgnjn */
- if (rs1 == rs2) { /* FNEG */
- tcg_gen_xori_i64(cpu_fpr[rd], cpu_fpr[rs1], min);
- } else {
- TCGv_i64 t0 = tcg_temp_new_i64();
- tcg_gen_not_i64(t0, cpu_fpr[rs2]);
- tcg_gen_deposit_i64(cpu_fpr[rd], t0, cpu_fpr[rs1],
- 0, min == INT32_MIN ? 31 : 63);
- tcg_temp_free_i64(t0);
- }
- break;
- case 2: /* fsgnjx */
- if (rs1 == rs2) { /* FABS */
- tcg_gen_andi_i64(cpu_fpr[rd], cpu_fpr[rs1], ~min);
- } else {
- TCGv_i64 t0 = tcg_temp_new_i64();
- tcg_gen_andi_i64(t0, cpu_fpr[rs2], min);
- tcg_gen_xor_i64(cpu_fpr[rd], cpu_fpr[rs1], t0);
- tcg_temp_free_i64(t0);
- }
- break;
- default:
- gen_exception_illegal(ctx);
- }
-}
-
-static void gen_arith(DisasContext *ctx, uint32_t opc, int rd, int rs1,
- int rs2)
-{
- TCGv source1, source2, cond1, cond2, zeroreg, resultopt1;
- source1 = tcg_temp_new();
- source2 = tcg_temp_new();
- gen_get_gpr(source1, rs1);
- gen_get_gpr(source2, rs2);
-
- switch (opc) {
- CASE_OP_32_64(OPC_RISC_ADD):
- tcg_gen_add_tl(source1, source1, source2);
- break;
- CASE_OP_32_64(OPC_RISC_SUB):
- tcg_gen_sub_tl(source1, source1, source2);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_SLLW:
- tcg_gen_andi_tl(source2, source2, 0x1F);
- tcg_gen_shl_tl(source1, source1, source2);
- break;
-#endif
- case OPC_RISC_SLL:
- tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
- tcg_gen_shl_tl(source1, source1, source2);
- break;
- case OPC_RISC_SLT:
- tcg_gen_setcond_tl(TCG_COND_LT, source1, source1, source2);
- break;
- case OPC_RISC_SLTU:
- tcg_gen_setcond_tl(TCG_COND_LTU, source1, source1, source2);
- break;
- case OPC_RISC_XOR:
- tcg_gen_xor_tl(source1, source1, source2);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_SRLW:
- /* clear upper 32 */
- tcg_gen_ext32u_tl(source1, source1);
- tcg_gen_andi_tl(source2, source2, 0x1F);
- tcg_gen_shr_tl(source1, source1, source2);
- break;
-#endif
- case OPC_RISC_SRL:
- tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
- tcg_gen_shr_tl(source1, source1, source2);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_SRAW:
- /* first, trick to get it to act like working on 32 bits (get rid of
- upper 32, sign extend to fill space) */
- tcg_gen_ext32s_tl(source1, source1);
- tcg_gen_andi_tl(source2, source2, 0x1F);
- tcg_gen_sar_tl(source1, source1, source2);
- break;
-#endif
- case OPC_RISC_SRA:
- tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
- tcg_gen_sar_tl(source1, source1, source2);
- break;
- case OPC_RISC_OR:
- tcg_gen_or_tl(source1, source1, source2);
- break;
- case OPC_RISC_AND:
- tcg_gen_and_tl(source1, source1, source2);
- break;
- CASE_OP_32_64(OPC_RISC_MUL):
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- tcg_gen_mul_tl(source1, source1, source2);
- break;
- case OPC_RISC_MULH:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- tcg_gen_muls2_tl(source2, source1, source1, source2);
- break;
- case OPC_RISC_MULHSU:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- gen_mulhsu(source1, source1, source2);
- break;
- case OPC_RISC_MULHU:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- tcg_gen_mulu2_tl(source2, source1, source1, source2);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_DIVW:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- tcg_gen_ext32s_tl(source1, source1);
- tcg_gen_ext32s_tl(source2, source2);
- /* fall through to DIV */
-#endif
- case OPC_RISC_DIV:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- /* Handle by altering args to tcg_gen_div to produce req'd results:
- * For overflow: want source1 in source1 and 1 in source2
- * For div by zero: want -1 in source1 and 1 in source2 -> -1 result */
- cond1 = tcg_temp_new();
- cond2 = tcg_temp_new();
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
- ((target_ulong)1) << (TARGET_LONG_BITS - 1));
- tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
- /* if div by zero, set source1 to -1, otherwise don't change */
- tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
- resultopt1);
- /* if overflow or div by zero, set source2 to 1, else don't change */
- tcg_gen_or_tl(cond1, cond1, cond2);
- tcg_gen_movi_tl(resultopt1, (target_ulong)1);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
- resultopt1);
- tcg_gen_div_tl(source1, source1, source2);
-
- tcg_temp_free(cond1);
- tcg_temp_free(cond2);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_DIVUW:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- tcg_gen_ext32u_tl(source1, source1);
- tcg_gen_ext32u_tl(source2, source2);
- /* fall through to DIVU */
-#endif
- case OPC_RISC_DIVU:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- cond1 = tcg_temp_new();
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
- tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
- tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
- resultopt1);
- tcg_gen_movi_tl(resultopt1, (target_ulong)1);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
- resultopt1);
- tcg_gen_divu_tl(source1, source1, source2);
-
- tcg_temp_free(cond1);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_REMW:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- tcg_gen_ext32s_tl(source1, source1);
- tcg_gen_ext32s_tl(source2, source2);
- /* fall through to REM */
-#endif
- case OPC_RISC_REM:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- cond1 = tcg_temp_new();
- cond2 = tcg_temp_new();
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_movi_tl(resultopt1, 1L);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
- (target_ulong)1 << (TARGET_LONG_BITS - 1));
- tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
- /* if overflow or div by zero, set source2 to 1, else don't change */
- tcg_gen_or_tl(cond2, cond1, cond2);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
- resultopt1);
- tcg_gen_rem_tl(resultopt1, source1, source2);
- /* if div by zero, just return the original dividend */
- tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
- source1);
-
- tcg_temp_free(cond1);
- tcg_temp_free(cond2);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_REMUW:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- tcg_gen_ext32u_tl(source1, source1);
- tcg_gen_ext32u_tl(source2, source2);
- /* fall through to REMU */
-#endif
- case OPC_RISC_REMU:
- if (!has_ext(ctx, RVM)) {
- goto do_illegal;
- }
- cond1 = tcg_temp_new();
- zeroreg = tcg_const_tl(0);
- resultopt1 = tcg_temp_new();
-
- tcg_gen_movi_tl(resultopt1, (target_ulong)1);
- tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
- tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
- resultopt1);
- tcg_gen_remu_tl(resultopt1, source1, source2);
- /* if div by zero, just return the original dividend */
- tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, resultopt1,
- source1);
-
- tcg_temp_free(cond1);
- tcg_temp_free(zeroreg);
- tcg_temp_free(resultopt1);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- return;
- }
-
- if (opc & 0x8) { /* sign extend for W instructions */
- tcg_gen_ext32s_tl(source1, source1);
- }
-
- gen_set_gpr(rd, source1);
- tcg_temp_free(source1);
- tcg_temp_free(source2);
-}
-
-static void gen_arith_imm(DisasContext *ctx, uint32_t opc, int rd,
- int rs1, target_long imm)
-{
- TCGv source1 = tcg_temp_new();
- int shift_len = TARGET_LONG_BITS;
- int shift_a;
-
- gen_get_gpr(source1, rs1);
-
- switch (opc) {
- case OPC_RISC_ADDI:
-#if defined(TARGET_RISCV64)
- case OPC_RISC_ADDIW:
-#endif
- tcg_gen_addi_tl(source1, source1, imm);
- break;
- case OPC_RISC_SLTI:
- tcg_gen_setcondi_tl(TCG_COND_LT, source1, source1, imm);
- break;
- case OPC_RISC_SLTIU:
- tcg_gen_setcondi_tl(TCG_COND_LTU, source1, source1, imm);
- break;
- case OPC_RISC_XORI:
- tcg_gen_xori_tl(source1, source1, imm);
- break;
- case OPC_RISC_ORI:
- tcg_gen_ori_tl(source1, source1, imm);
- break;
- case OPC_RISC_ANDI:
- tcg_gen_andi_tl(source1, source1, imm);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_SLLIW:
- shift_len = 32;
- /* FALLTHRU */
-#endif
- case OPC_RISC_SLLI:
- if (imm >= shift_len) {
- goto do_illegal;
- }
- tcg_gen_shli_tl(source1, source1, imm);
- break;
-#if defined(TARGET_RISCV64)
- case OPC_RISC_SHIFT_RIGHT_IW:
- shift_len = 32;
- /* FALLTHRU */
-#endif
- case OPC_RISC_SHIFT_RIGHT_I:
- /* differentiate on IMM */
- shift_a = imm & 0x400;
- imm &= 0x3ff;
- if (imm >= shift_len) {
- goto do_illegal;
- }
- if (imm != 0) {
- if (shift_a) {
- /* SRAI[W] */
- tcg_gen_sextract_tl(source1, source1, imm, shift_len - imm);
- } else {
- /* SRLI[W] */
- tcg_gen_extract_tl(source1, source1, imm, shift_len - imm);
- }
- /* No further sign-extension needed for W instructions. */
- opc &= ~0x8;
- }
- break;
- default:
- do_illegal:
- gen_exception_illegal(ctx);
- return;
- }
-
- if (opc & 0x8) { /* sign-extend for W instructions */
- tcg_gen_ext32s_tl(source1, source1);
- }
-
- gen_set_gpr(rd, source1);
- tcg_temp_free(source1);
+static void gen_div(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv cond1, cond2, zeroreg, resultopt1;
+ /*
+ * Handle by altering args to tcg_gen_div to produce req'd results:
+ * For overflow: want source1 in source1 and 1 in source2
+ * For div by zero: want -1 in source1 and 1 in source2 -> -1 result
+ */
+ cond1 = tcg_temp_new();
+ cond2 = tcg_temp_new();
+ zeroreg = tcg_const_tl(0);
+ resultopt1 = tcg_temp_new();
+
+ tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)(~0L));
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
+ ((target_ulong)1) << (TARGET_LONG_BITS - 1));
+ tcg_gen_and_tl(cond1, cond1, cond2); /* cond1 = overflow */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, 0); /* cond2 = div 0 */
+ /* if div by zero, set source1 to -1, otherwise don't change */
+ tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond2, zeroreg, source1,
+ resultopt1);
+ /* if overflow or div by zero, set source2 to 1, else don't change */
+ tcg_gen_or_tl(cond1, cond1, cond2);
+ tcg_gen_movi_tl(resultopt1, (target_ulong)1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
+ resultopt1);
+ tcg_gen_div_tl(ret, source1, source2);
+
+ tcg_temp_free(cond1);
+ tcg_temp_free(cond2);
+ tcg_temp_free(zeroreg);
+ tcg_temp_free(resultopt1);
+}
+
+static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv cond1, zeroreg, resultopt1;
+ cond1 = tcg_temp_new();
+
+ zeroreg = tcg_const_tl(0);
+ resultopt1 = tcg_temp_new();
+
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
+ tcg_gen_movi_tl(resultopt1, (target_ulong)-1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, source1, cond1, zeroreg, source1,
+ resultopt1);
+ tcg_gen_movi_tl(resultopt1, (target_ulong)1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
+ resultopt1);
+ tcg_gen_divu_tl(ret, source1, source2);
+
+ tcg_temp_free(cond1);
+ tcg_temp_free(zeroreg);
+ tcg_temp_free(resultopt1);
+}
+
+static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv cond1, cond2, zeroreg, resultopt1;
+
+ cond1 = tcg_temp_new();
+ cond2 = tcg_temp_new();
+ zeroreg = tcg_const_tl(0);
+ resultopt1 = tcg_temp_new();
+
+ tcg_gen_movi_tl(resultopt1, 1L);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, source2, (target_ulong)-1);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source1,
+ (target_ulong)1 << (TARGET_LONG_BITS - 1));
+ tcg_gen_and_tl(cond2, cond1, cond2); /* cond1 = overflow */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0); /* cond2 = div 0 */
+ /* if overflow or div by zero, set source2 to 1, else don't change */
+ tcg_gen_or_tl(cond2, cond1, cond2);
+ tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond2, zeroreg, source2,
+ resultopt1);
+ tcg_gen_rem_tl(resultopt1, source1, source2);
+ /* if div by zero, just return the original dividend */
+ tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
+ source1);
+
+ tcg_temp_free(cond1);
+ tcg_temp_free(cond2);
+ tcg_temp_free(zeroreg);
+ tcg_temp_free(resultopt1);
+}
+
+static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv cond1, zeroreg, resultopt1;
+ cond1 = tcg_temp_new();
+ zeroreg = tcg_const_tl(0);
+ resultopt1 = tcg_temp_new();
+
+ tcg_gen_movi_tl(resultopt1, (target_ulong)1);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, source2, 0);
+ tcg_gen_movcond_tl(TCG_COND_EQ, source2, cond1, zeroreg, source2,
+ resultopt1);
+ tcg_gen_remu_tl(resultopt1, source1, source2);
+ /* if div by zero, just return the original dividend */
+ tcg_gen_movcond_tl(TCG_COND_EQ, ret, cond1, zeroreg, resultopt1,
+ source1);
+
+ tcg_temp_free(cond1);
+ tcg_temp_free(zeroreg);
+ tcg_temp_free(resultopt1);
}
static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
@@ -569,92 +316,8 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
ctx->base.is_jmp = DISAS_NORETURN;
}
-static void gen_jalr(DisasContext *ctx, uint32_t opc, int rd, int rs1,
- target_long imm)
-{
- /* no chaining with JALR */
- TCGLabel *misaligned = NULL;
- TCGv t0 = tcg_temp_new();
-
- switch (opc) {
- case OPC_RISC_JALR:
- gen_get_gpr(cpu_pc, rs1);
- tcg_gen_addi_tl(cpu_pc, cpu_pc, imm);
- tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
-
- if (!has_ext(ctx, RVC)) {
- misaligned = gen_new_label();
- tcg_gen_andi_tl(t0, cpu_pc, 0x2);
- tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
- }
-
- if (rd != 0) {
- tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc_succ_insn);
- }
- tcg_gen_lookup_and_goto_ptr();
-
- if (misaligned) {
- gen_set_label(misaligned);
- gen_exception_inst_addr_mis(ctx);
- }
- ctx->base.is_jmp = DISAS_NORETURN;
- break;
-
- default:
- gen_exception_illegal(ctx);
- break;
- }
- tcg_temp_free(t0);
-}
-
-static void gen_branch(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
- target_long bimm)
-{
- TCGLabel *l = gen_new_label();
- TCGv source1, source2;
- source1 = tcg_temp_new();
- source2 = tcg_temp_new();
- gen_get_gpr(source1, rs1);
- gen_get_gpr(source2, rs2);
-
- switch (opc) {
- case OPC_RISC_BEQ:
- tcg_gen_brcond_tl(TCG_COND_EQ, source1, source2, l);
- break;
- case OPC_RISC_BNE:
- tcg_gen_brcond_tl(TCG_COND_NE, source1, source2, l);
- break;
- case OPC_RISC_BLT:
- tcg_gen_brcond_tl(TCG_COND_LT, source1, source2, l);
- break;
- case OPC_RISC_BGE:
- tcg_gen_brcond_tl(TCG_COND_GE, source1, source2, l);
- break;
- case OPC_RISC_BLTU:
- tcg_gen_brcond_tl(TCG_COND_LTU, source1, source2, l);
- break;
- case OPC_RISC_BGEU:
- tcg_gen_brcond_tl(TCG_COND_GEU, source1, source2, l);
- break;
- default:
- gen_exception_illegal(ctx);
- return;
- }
- tcg_temp_free(source1);
- tcg_temp_free(source2);
-
- gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
- gen_set_label(l); /* branch taken */
- if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + bimm) & 0x3)) {
- /* misaligned */
- gen_exception_inst_addr_mis(ctx);
- } else {
- gen_goto_tb(ctx, 0, ctx->base.pc_next + bimm);
- }
- ctx->base.is_jmp = DISAS_NORETURN;
-}
-
-static void gen_load(DisasContext *ctx, uint32_t opc, int rd, int rs1,
+#ifdef TARGET_RISCV64
+static void gen_load_c(DisasContext *ctx, uint32_t opc, int rd, int rs1,
target_long imm)
{
TCGv t0 = tcg_temp_new();
@@ -674,7 +337,7 @@ static void gen_load(DisasContext *ctx, uint32_t opc, int rd, int rs1,
tcg_temp_free(t1);
}
-static void gen_store(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
+static void gen_store_c(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
target_long imm)
{
TCGv t0 = tcg_temp_new();
@@ -693,6 +356,7 @@ static void gen_store(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
tcg_temp_free(t0);
tcg_temp_free(dat);
}
+#endif
#ifndef CONFIG_USER_ONLY
/* The states of mstatus_fs are:
@@ -719,6 +383,7 @@ static void mark_fs_dirty(DisasContext *ctx)
static inline void mark_fs_dirty(DisasContext *ctx) { }
#endif
+#if !defined(TARGET_RISCV64)
static void gen_fp_load(DisasContext *ctx, uint32_t opc, int rd,
int rs1, target_long imm)
{
@@ -793,143 +458,7 @@ static void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1,
tcg_temp_free(t0);
}
-
-static void gen_atomic(DisasContext *ctx, uint32_t opc,
- int rd, int rs1, int rs2)
-{
- TCGv src1, src2, dat;
- TCGLabel *l1, *l2;
- TCGMemOp mop;
- bool aq, rl;
-
- /* Extract the size of the atomic operation. */
- switch (extract32(opc, 12, 3)) {
- case 2: /* 32-bit */
- mop = MO_ALIGN | MO_TESL;
- break;
-#if defined(TARGET_RISCV64)
- case 3: /* 64-bit */
- mop = MO_ALIGN | MO_TEQ;
- break;
#endif
- default:
- gen_exception_illegal(ctx);
- return;
- }
- rl = extract32(opc, 25, 1);
- aq = extract32(opc, 26, 1);
-
- src1 = tcg_temp_new();
- src2 = tcg_temp_new();
-
- switch (MASK_OP_ATOMIC_NO_AQ_RL_SZ(opc)) {
- case OPC_RISC_LR:
- /* Put addr in load_res, data in load_val. */
- gen_get_gpr(src1, rs1);
- if (rl) {
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
- }
- tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
- if (aq) {
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
- }
- tcg_gen_mov_tl(load_res, src1);
- gen_set_gpr(rd, load_val);
- break;
-
- case OPC_RISC_SC:
- l1 = gen_new_label();
- l2 = gen_new_label();
- dat = tcg_temp_new();
-
- gen_get_gpr(src1, rs1);
- tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
-
- gen_get_gpr(src2, rs2);
- /* Note that the TCG atomic primitives are SC,
- so we can ignore AQ/RL along this path. */
- tcg_gen_atomic_cmpxchg_tl(src1, load_res, load_val, src2,
- ctx->mem_idx, mop);
- tcg_gen_setcond_tl(TCG_COND_NE, dat, src1, load_val);
- gen_set_gpr(rd, dat);
- tcg_gen_br(l2);
-
- gen_set_label(l1);
- /* Address comparion failure. However, we still need to
- provide the memory barrier implied by AQ/RL. */
- tcg_gen_mb(TCG_MO_ALL + aq * TCG_BAR_LDAQ + rl * TCG_BAR_STRL);
- tcg_gen_movi_tl(dat, 1);
- gen_set_gpr(rd, dat);
-
- gen_set_label(l2);
- tcg_temp_free(dat);
- break;
-
- case OPC_RISC_AMOSWAP:
- /* Note that the TCG atomic primitives are SC,
- so we can ignore AQ/RL along this path. */
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_xchg_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOADD:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_add_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOXOR:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_xor_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOAND:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_and_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOOR:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_or_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOMIN:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_smin_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOMAX:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_smax_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOMINU:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_umin_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
- case OPC_RISC_AMOMAXU:
- gen_get_gpr(src1, rs1);
- gen_get_gpr(src2, rs2);
- tcg_gen_atomic_fetch_umax_tl(src2, src1, src2, ctx->mem_idx, mop);
- gen_set_gpr(rd, src2);
- break;
-
- default:
- gen_exception_illegal(ctx);
- break;
- }
-
- tcg_temp_free(src1);
- tcg_temp_free(src2);
-}
static void gen_set_rm(DisasContext *ctx, int rm)
{
@@ -944,659 +473,6 @@ static void gen_set_rm(DisasContext *ctx, int rm)
tcg_temp_free_i32(t0);
}
-static void gen_fp_fmadd(DisasContext *ctx, uint32_t opc, int rd,
- int rs1, int rs2, int rs3, int rm)
-{
- switch (opc) {
- case OPC_RISC_FMADD_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- case OPC_RISC_FMADD_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- break;
- }
-}
-
-static void gen_fp_fmsub(DisasContext *ctx, uint32_t opc, int rd,
- int rs1, int rs2, int rs3, int rm)
-{
- switch (opc) {
- case OPC_RISC_FMSUB_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- case OPC_RISC_FMSUB_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- break;
- }
-}
-
-static void gen_fp_fnmsub(DisasContext *ctx, uint32_t opc, int rd,
- int rs1, int rs2, int rs3, int rm)
-{
- switch (opc) {
- case OPC_RISC_FNMSUB_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fnmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- case OPC_RISC_FNMSUB_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fnmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- break;
- }
-}
-
-static void gen_fp_fnmadd(DisasContext *ctx, uint32_t opc, int rd,
- int rs1, int rs2, int rs3, int rm)
-{
- switch (opc) {
- case OPC_RISC_FNMADD_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fnmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- case OPC_RISC_FNMADD_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fnmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
- cpu_fpr[rs2], cpu_fpr[rs3]);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- break;
- }
-}
-
-static void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd,
- int rs1, int rs2, int rm)
-{
- TCGv t0 = NULL;
- bool fp_output = true;
-
- if (ctx->mstatus_fs == 0) {
- goto do_illegal;
- }
-
- switch (opc) {
- case OPC_RISC_FADD_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FSUB_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FMUL_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fmul_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FDIV_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fdiv_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FSQRT_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fsqrt_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]);
- break;
- case OPC_RISC_FSGNJ_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- gen_fsgnj(ctx, rd, rs1, rs2, rm, INT32_MIN);
- break;
-
- case OPC_RISC_FMIN_S:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- /* also handles: OPC_RISC_FMAX_S */
- switch (rm) {
- case 0x0:
- gen_helper_fmin_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case 0x1:
- gen_helper_fmax_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- default:
- goto do_illegal;
- }
- break;
-
- case OPC_RISC_FEQ_S:
- /* also handles: OPC_RISC_FLT_S, OPC_RISC_FLE_S */
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- switch (rm) {
- case 0x0:
- gen_helper_fle_s(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case 0x1:
- gen_helper_flt_s(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case 0x2:
- gen_helper_feq_s(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- default:
- goto do_illegal;
- }
- gen_set_gpr(rd, t0);
- tcg_temp_free(t0);
- fp_output = false;
- break;
-
- case OPC_RISC_FCVT_W_S:
- /* also OPC_RISC_FCVT_WU_S, OPC_RISC_FCVT_L_S, OPC_RISC_FCVT_LU_S */
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- switch (rs2) {
- case 0: /* FCVT_W_S */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[rs1]);
- break;
- case 1: /* FCVT_WU_S */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[rs1]);
- break;
-#if defined(TARGET_RISCV64)
- case 2: /* FCVT_L_S */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[rs1]);
- break;
- case 3: /* FCVT_LU_S */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[rs1]);
- break;
-#endif
- default:
- goto do_illegal;
- }
- gen_set_gpr(rd, t0);
- tcg_temp_free(t0);
- fp_output = false;
- break;
-
- case OPC_RISC_FCVT_S_W:
- /* also OPC_RISC_FCVT_S_WU, OPC_RISC_FCVT_S_L, OPC_RISC_FCVT_S_LU */
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- gen_get_gpr(t0, rs1);
- switch (rs2) {
- case 0: /* FCVT_S_W */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_s_w(cpu_fpr[rd], cpu_env, t0);
- break;
- case 1: /* FCVT_S_WU */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_s_wu(cpu_fpr[rd], cpu_env, t0);
- break;
-#if defined(TARGET_RISCV64)
- case 2: /* FCVT_S_L */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_s_l(cpu_fpr[rd], cpu_env, t0);
- break;
- case 3: /* FCVT_S_LU */
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_s_lu(cpu_fpr[rd], cpu_env, t0);
- break;
-#endif
- default:
- goto do_illegal;
- }
- tcg_temp_free(t0);
- break;
-
- case OPC_RISC_FMV_X_S:
- /* also OPC_RISC_FCLASS_S */
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- switch (rm) {
- case 0: /* FMV */
-#if defined(TARGET_RISCV64)
- tcg_gen_ext32s_tl(t0, cpu_fpr[rs1]);
-#else
- tcg_gen_extrl_i64_i32(t0, cpu_fpr[rs1]);
-#endif
- break;
- case 1:
- gen_helper_fclass_s(t0, cpu_fpr[rs1]);
- break;
- default:
- goto do_illegal;
- }
- gen_set_gpr(rd, t0);
- tcg_temp_free(t0);
- fp_output = false;
- break;
-
- case OPC_RISC_FMV_S_X:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- gen_get_gpr(t0, rs1);
-#if defined(TARGET_RISCV64)
- tcg_gen_mov_i64(cpu_fpr[rd], t0);
-#else
- tcg_gen_extu_i32_i64(cpu_fpr[rd], t0);
-#endif
- tcg_temp_free(t0);
- break;
-
- /* double */
- case OPC_RISC_FADD_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FSUB_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FMUL_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fmul_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FDIV_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fdiv_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case OPC_RISC_FSQRT_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- gen_set_rm(ctx, rm);
- gen_helper_fsqrt_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]);
- break;
- case OPC_RISC_FSGNJ_D:
- gen_fsgnj(ctx, rd, rs1, rs2, rm, INT64_MIN);
- break;
-
- case OPC_RISC_FMIN_D:
- /* also OPC_RISC_FMAX_D */
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- switch (rm) {
- case 0:
- gen_helper_fmin_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case 1:
- gen_helper_fmax_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- default:
- goto do_illegal;
- }
- break;
-
- case OPC_RISC_FCVT_S_D:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- switch (rs2) {
- case 1:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_s_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]);
- break;
- default:
- goto do_illegal;
- }
- break;
-
- case OPC_RISC_FCVT_D_S:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- switch (rs2) {
- case 0:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_d_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1]);
- break;
- default:
- goto do_illegal;
- }
- break;
-
- case OPC_RISC_FEQ_D:
- /* also OPC_RISC_FLT_D, OPC_RISC_FLE_D */
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- switch (rm) {
- case 0:
- gen_helper_fle_d(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case 1:
- gen_helper_flt_d(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- case 2:
- gen_helper_feq_d(t0, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
- break;
- default:
- goto do_illegal;
- }
- gen_set_gpr(rd, t0);
- tcg_temp_free(t0);
- fp_output = false;
- break;
-
- case OPC_RISC_FCVT_W_D:
- /* also OPC_RISC_FCVT_WU_D, OPC_RISC_FCVT_L_D, OPC_RISC_FCVT_LU_D */
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- switch (rs2) {
- case 0:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_w_d(t0, cpu_env, cpu_fpr[rs1]);
- break;
- case 1:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_wu_d(t0, cpu_env, cpu_fpr[rs1]);
- break;
-#if defined(TARGET_RISCV64)
- case 2:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_l_d(t0, cpu_env, cpu_fpr[rs1]);
- break;
- case 3:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_lu_d(t0, cpu_env, cpu_fpr[rs1]);
- break;
-#endif
- default:
- goto do_illegal;
- }
- gen_set_gpr(rd, t0);
- tcg_temp_free(t0);
- fp_output = false;
- break;
-
- case OPC_RISC_FCVT_D_W:
- /* also OPC_RISC_FCVT_D_WU, OPC_RISC_FCVT_D_L, OPC_RISC_FCVT_D_LU */
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- gen_get_gpr(t0, rs1);
- switch (rs2) {
- case 0:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_d_w(cpu_fpr[rd], cpu_env, t0);
- break;
- case 1:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_d_wu(cpu_fpr[rd], cpu_env, t0);
- break;
-#if defined(TARGET_RISCV64)
- case 2:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_d_l(cpu_fpr[rd], cpu_env, t0);
- break;
- case 3:
- gen_set_rm(ctx, rm);
- gen_helper_fcvt_d_lu(cpu_fpr[rd], cpu_env, t0);
- break;
-#endif
- default:
- goto do_illegal;
- }
- tcg_temp_free(t0);
- break;
-
- case OPC_RISC_FMV_X_D:
- /* also OPC_RISC_FCLASS_D */
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- switch (rm) {
-#if defined(TARGET_RISCV64)
- case 0: /* FMV */
- gen_set_gpr(rd, cpu_fpr[rs1]);
- break;
-#endif
- case 1:
- t0 = tcg_temp_new();
- gen_helper_fclass_d(t0, cpu_fpr[rs1]);
- gen_set_gpr(rd, t0);
- tcg_temp_free(t0);
- break;
- default:
- goto do_illegal;
- }
- fp_output = false;
- break;
-
-#if defined(TARGET_RISCV64)
- case OPC_RISC_FMV_D_X:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- t0 = tcg_temp_new();
- gen_get_gpr(t0, rs1);
- tcg_gen_mov_tl(cpu_fpr[rd], t0);
- tcg_temp_free(t0);
- break;
-#endif
-
- default:
- do_illegal:
- if (t0) {
- tcg_temp_free(t0);
- }
- gen_exception_illegal(ctx);
- return;
- }
-
- if (fp_output) {
- mark_fs_dirty(ctx);
- }
-}
-
-static void gen_system(DisasContext *ctx, uint32_t opc, int rd, int rs1,
- int csr)
-{
- TCGv source1, csr_store, dest, rs1_pass, imm_rs1;
- source1 = tcg_temp_new();
- csr_store = tcg_temp_new();
- dest = tcg_temp_new();
- rs1_pass = tcg_temp_new();
- imm_rs1 = tcg_temp_new();
- gen_get_gpr(source1, rs1);
- tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
- tcg_gen_movi_tl(rs1_pass, rs1);
- tcg_gen_movi_tl(csr_store, csr); /* copy into temp reg to feed to helper */
-
-#ifndef CONFIG_USER_ONLY
- /* Extract funct7 value and check whether it matches SFENCE.VMA */
- if ((opc == OPC_RISC_ECALL) && ((csr >> 5) == 9)) {
- if (ctx->priv_ver == PRIV_VERSION_1_10_0) {
- /* sfence.vma */
- /* TODO: handle ASID specific fences */
- gen_helper_tlb_flush(cpu_env);
- return;
- } else {
- gen_exception_illegal(ctx);
- }
- }
-#endif
-
- switch (opc) {
- case OPC_RISC_ECALL:
- switch (csr) {
- case 0x0: /* ECALL */
- /* always generates U-level ECALL, fixed in do_interrupt handler */
- generate_exception(ctx, RISCV_EXCP_U_ECALL);
- tcg_gen_exit_tb(NULL, 0); /* no chaining */
- ctx->base.is_jmp = DISAS_NORETURN;
- break;
- case 0x1: /* EBREAK */
- generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
- tcg_gen_exit_tb(NULL, 0); /* no chaining */
- ctx->base.is_jmp = DISAS_NORETURN;
- break;
-#ifndef CONFIG_USER_ONLY
- case 0x002: /* URET */
- gen_exception_illegal(ctx);
- break;
- case 0x102: /* SRET */
- if (has_ext(ctx, RVS)) {
- gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
- tcg_gen_exit_tb(NULL, 0); /* no chaining */
- ctx->base.is_jmp = DISAS_NORETURN;
- } else {
- gen_exception_illegal(ctx);
- }
- break;
- case 0x202: /* HRET */
- gen_exception_illegal(ctx);
- break;
- case 0x302: /* MRET */
- gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
- tcg_gen_exit_tb(NULL, 0); /* no chaining */
- ctx->base.is_jmp = DISAS_NORETURN;
- break;
- case 0x7b2: /* DRET */
- gen_exception_illegal(ctx);
- break;
- case 0x105: /* WFI */
- tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
- gen_helper_wfi(cpu_env);
- break;
- case 0x104: /* SFENCE.VM */
- if (ctx->priv_ver <= PRIV_VERSION_1_09_1) {
- gen_helper_tlb_flush(cpu_env);
- } else {
- gen_exception_illegal(ctx);
- }
- break;
-#endif
- default:
- gen_exception_illegal(ctx);
- break;
- }
- break;
- default:
- tcg_gen_movi_tl(imm_rs1, rs1);
- gen_io_start();
- switch (opc) {
- case OPC_RISC_CSRRW:
- gen_helper_csrrw(dest, cpu_env, source1, csr_store);
- break;
- case OPC_RISC_CSRRS:
- gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass);
- break;
- case OPC_RISC_CSRRC:
- gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass);
- break;
- case OPC_RISC_CSRRWI:
- gen_helper_csrrw(dest, cpu_env, imm_rs1, csr_store);
- break;
- case OPC_RISC_CSRRSI:
- gen_helper_csrrs(dest, cpu_env, imm_rs1, csr_store, rs1_pass);
- break;
- case OPC_RISC_CSRRCI:
- gen_helper_csrrc(dest, cpu_env, imm_rs1, csr_store, rs1_pass);
- break;
- default:
- gen_exception_illegal(ctx);
- return;
- }
- gen_io_end();
- gen_set_gpr(rd, dest);
- /* end tb since we may be changing priv modes, to get mmu_index right */
- tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
- tcg_gen_exit_tb(NULL, 0); /* no chaining */
- ctx->base.is_jmp = DISAS_NORETURN;
- break;
- }
- tcg_temp_free(source1);
- tcg_temp_free(csr_store);
- tcg_temp_free(dest);
- tcg_temp_free(rs1_pass);
- tcg_temp_free(imm_rs1);
-}
-
static void decode_RV32_64C0(DisasContext *ctx)
{
uint8_t funct3 = extract32(ctx->opcode, 13, 3);
@@ -1604,31 +480,10 @@ static void decode_RV32_64C0(DisasContext *ctx)
uint8_t rs1s = GET_C_RS1S(ctx->opcode);
switch (funct3) {
- case 0:
- /* illegal */
- if (ctx->opcode == 0) {
- gen_exception_illegal(ctx);
- } else {
- /* C.ADDI4SPN -> addi rd', x2, zimm[9:2]*/
- gen_arith_imm(ctx, OPC_RISC_ADDI, rd_rs2, 2,
- GET_C_ADDI4SPN_IMM(ctx->opcode));
- }
- break;
- case 1:
- /* C.FLD -> fld rd', offset[7:3](rs1')*/
- gen_fp_load(ctx, OPC_RISC_FLD, rd_rs2, rs1s,
- GET_C_LD_IMM(ctx->opcode));
- /* C.LQ(RV128) */
- break;
- case 2:
- /* C.LW -> lw rd', offset[6:2](rs1') */
- gen_load(ctx, OPC_RISC_LW, rd_rs2, rs1s,
- GET_C_LW_IMM(ctx->opcode));
- break;
case 3:
#if defined(TARGET_RISCV64)
/* C.LD(RV64/128) -> ld rd', offset[7:3](rs1')*/
- gen_load(ctx, OPC_RISC_LD, rd_rs2, rs1s,
+ gen_load_c(ctx, OPC_RISC_LD, rd_rs2, rs1s,
GET_C_LD_IMM(ctx->opcode));
#else
/* C.FLW (RV32) -> flw rd', offset[6:2](rs1')*/
@@ -1636,25 +491,10 @@ static void decode_RV32_64C0(DisasContext *ctx)
GET_C_LW_IMM(ctx->opcode));
#endif
break;
- case 4:
- /* reserved */
- gen_exception_illegal(ctx);
- break;
- case 5:
- /* C.FSD(RV32/64) -> fsd rs2', offset[7:3](rs1') */
- gen_fp_store(ctx, OPC_RISC_FSD, rs1s, rd_rs2,
- GET_C_LD_IMM(ctx->opcode));
- /* C.SQ (RV128) */
- break;
- case 6:
- /* C.SW -> sw rs2', offset[6:2](rs1')*/
- gen_store(ctx, OPC_RISC_SW, rs1s, rd_rs2,
- GET_C_LW_IMM(ctx->opcode));
- break;
case 7:
#if defined(TARGET_RISCV64)
/* C.SD (RV64/128) -> sd rs2', offset[7:3](rs1')*/
- gen_store(ctx, OPC_RISC_SD, rs1s, rd_rs2,
+ gen_store_c(ctx, OPC_RISC_SD, rs1s, rd_rs2,
GET_C_LD_IMM(ctx->opcode));
#else
/* C.FSW (RV32) -> fsw rs2', offset[6:2](rs1')*/
@@ -1665,340 +505,152 @@ static void decode_RV32_64C0(DisasContext *ctx)
}
}
-static void decode_RV32_64C1(DisasContext *ctx)
+static void decode_RV32_64C(DisasContext *ctx)
{
- uint8_t funct3 = extract32(ctx->opcode, 13, 3);
- uint8_t rd_rs1 = GET_C_RS1(ctx->opcode);
- uint8_t rs1s, rs2s;
- uint8_t funct2;
+ uint8_t op = extract32(ctx->opcode, 0, 2);
- switch (funct3) {
+ switch (op) {
case 0:
- /* C.ADDI -> addi rd, rd, nzimm[5:0] */
- gen_arith_imm(ctx, OPC_RISC_ADDI, rd_rs1, rd_rs1,
- GET_C_IMM(ctx->opcode));
- break;
- case 1:
-#if defined(TARGET_RISCV64)
- /* C.ADDIW (RV64/128) -> addiw rd, rd, imm[5:0]*/
- gen_arith_imm(ctx, OPC_RISC_ADDIW, rd_rs1, rd_rs1,
- GET_C_IMM(ctx->opcode));
-#else
- /* C.JAL(RV32) -> jal x1, offset[11:1] */
- gen_jal(ctx, 1, GET_C_J_IMM(ctx->opcode));
-#endif
- break;
- case 2:
- /* C.LI -> addi rd, x0, imm[5:0]*/
- gen_arith_imm(ctx, OPC_RISC_ADDI, rd_rs1, 0, GET_C_IMM(ctx->opcode));
- break;
- case 3:
- if (rd_rs1 == 2) {
- /* C.ADDI16SP -> addi x2, x2, nzimm[9:4]*/
- gen_arith_imm(ctx, OPC_RISC_ADDI, 2, 2,
- GET_C_ADDI16SP_IMM(ctx->opcode));
- } else if (rd_rs1 != 0) {
- /* C.LUI (rs1/rd =/= {0,2}) -> lui rd, nzimm[17:12]*/
- tcg_gen_movi_tl(cpu_gpr[rd_rs1],
- GET_C_IMM(ctx->opcode) << 12);
- }
- break;
- case 4:
- funct2 = extract32(ctx->opcode, 10, 2);
- rs1s = GET_C_RS1S(ctx->opcode);
- switch (funct2) {
- case 0: /* C.SRLI(RV32) -> srli rd', rd', shamt[5:0] */
- gen_arith_imm(ctx, OPC_RISC_SHIFT_RIGHT_I, rs1s, rs1s,
- GET_C_ZIMM(ctx->opcode));
- /* C.SRLI64(RV128) */
- break;
- case 1:
- /* C.SRAI -> srai rd', rd', shamt[5:0]*/
- gen_arith_imm(ctx, OPC_RISC_SHIFT_RIGHT_I, rs1s, rs1s,
- GET_C_ZIMM(ctx->opcode) | 0x400);
- /* C.SRAI64(RV128) */
- break;
- case 2:
- /* C.ANDI -> andi rd', rd', imm[5:0]*/
- gen_arith_imm(ctx, OPC_RISC_ANDI, rs1s, rs1s,
- GET_C_IMM(ctx->opcode));
- break;
- case 3:
- funct2 = extract32(ctx->opcode, 5, 2);
- rs2s = GET_C_RS2S(ctx->opcode);
- switch (funct2) {
- case 0:
- /* C.SUB -> sub rd', rd', rs2' */
- if (extract32(ctx->opcode, 12, 1) == 0) {
- gen_arith(ctx, OPC_RISC_SUB, rs1s, rs1s, rs2s);
- }
-#if defined(TARGET_RISCV64)
- else {
- gen_arith(ctx, OPC_RISC_SUBW, rs1s, rs1s, rs2s);
- }
-#endif
- break;
- case 1:
- /* C.XOR -> xor rs1', rs1', rs2' */
- if (extract32(ctx->opcode, 12, 1) == 0) {
- gen_arith(ctx, OPC_RISC_XOR, rs1s, rs1s, rs2s);
- }
-#if defined(TARGET_RISCV64)
- else {
- /* C.ADDW (RV64/128) */
- gen_arith(ctx, OPC_RISC_ADDW, rs1s, rs1s, rs2s);
- }
-#endif
- break;
- case 2:
- /* C.OR -> or rs1', rs1', rs2' */
- gen_arith(ctx, OPC_RISC_OR, rs1s, rs1s, rs2s);
- break;
- case 3:
- /* C.AND -> and rs1', rs1', rs2' */
- gen_arith(ctx, OPC_RISC_AND, rs1s, rs1s, rs2s);
- break;
- }
- break;
- }
- break;
- case 5:
- /* C.J -> jal x0, offset[11:1]*/
- gen_jal(ctx, 0, GET_C_J_IMM(ctx->opcode));
- break;
- case 6:
- /* C.BEQZ -> beq rs1', x0, offset[8:1]*/
- rs1s = GET_C_RS1S(ctx->opcode);
- gen_branch(ctx, OPC_RISC_BEQ, rs1s, 0, GET_C_B_IMM(ctx->opcode));
- break;
- case 7:
- /* C.BNEZ -> bne rs1', x0, offset[8:1]*/
- rs1s = GET_C_RS1S(ctx->opcode);
- gen_branch(ctx, OPC_RISC_BNE, rs1s, 0, GET_C_B_IMM(ctx->opcode));
+ decode_RV32_64C0(ctx);
break;
}
}
-static void decode_RV32_64C2(DisasContext *ctx)
+#define EX_SH(amount) \
+ static int ex_shift_##amount(int imm) \
+ { \
+ return imm << amount; \
+ }
+EX_SH(1)
+EX_SH(2)
+EX_SH(3)
+EX_SH(4)
+EX_SH(12)
+
+#define REQUIRE_EXT(ctx, ext) do { \
+ if (!has_ext(ctx, ext)) { \
+ return false; \
+ } \
+} while (0)
+
+static int ex_rvc_register(int reg)
+{
+ return 8 + reg;
+}
+
+bool decode_insn32(DisasContext *ctx, uint32_t insn);
+/* Include the auto-generated decoder for 32 bit insn */
+#include "decode_insn32.inc.c"
+
+static bool gen_arith_imm(DisasContext *ctx, arg_i *a,
+ void(*func)(TCGv, TCGv, TCGv))
{
- uint8_t rd, rs2;
- uint8_t funct3 = extract32(ctx->opcode, 13, 3);
+ TCGv source1, source2;
+ source1 = tcg_temp_new();
+ source2 = tcg_temp_new();
+ gen_get_gpr(source1, a->rs1);
+ tcg_gen_movi_tl(source2, a->imm);
- rd = GET_RD(ctx->opcode);
+ (*func)(source1, source1, source2);
- switch (funct3) {
- case 0: /* C.SLLI -> slli rd, rd, shamt[5:0]
- C.SLLI64 -> */
- gen_arith_imm(ctx, OPC_RISC_SLLI, rd, rd, GET_C_ZIMM(ctx->opcode));
- break;
- case 1: /* C.FLDSP(RV32/64DC) -> fld rd, offset[8:3](x2) */
- gen_fp_load(ctx, OPC_RISC_FLD, rd, 2, GET_C_LDSP_IMM(ctx->opcode));
- break;
- case 2: /* C.LWSP -> lw rd, offset[7:2](x2) */
- gen_load(ctx, OPC_RISC_LW, rd, 2, GET_C_LWSP_IMM(ctx->opcode));
- break;
- case 3:
-#if defined(TARGET_RISCV64)
- /* C.LDSP(RVC64) -> ld rd, offset[8:3](x2) */
- gen_load(ctx, OPC_RISC_LD, rd, 2, GET_C_LDSP_IMM(ctx->opcode));
-#else
- /* C.FLWSP(RV32FC) -> flw rd, offset[7:2](x2) */
- gen_fp_load(ctx, OPC_RISC_FLW, rd, 2, GET_C_LWSP_IMM(ctx->opcode));
-#endif
- break;
- case 4:
- rs2 = GET_C_RS2(ctx->opcode);
-
- if (extract32(ctx->opcode, 12, 1) == 0) {
- if (rs2 == 0) {
- /* C.JR -> jalr x0, rs1, 0*/
- gen_jalr(ctx, OPC_RISC_JALR, 0, rd, 0);
- } else {
- /* C.MV -> add rd, x0, rs2 */
- gen_arith(ctx, OPC_RISC_ADD, rd, 0, rs2);
- }
- } else {
- if (rd == 0) {
- /* C.EBREAK -> ebreak*/
- gen_system(ctx, OPC_RISC_ECALL, 0, 0, 0x1);
- } else {
- if (rs2 == 0) {
- /* C.JALR -> jalr x1, rs1, 0*/
- gen_jalr(ctx, OPC_RISC_JALR, 1, rd, 0);
- } else {
- /* C.ADD -> add rd, rd, rs2 */
- gen_arith(ctx, OPC_RISC_ADD, rd, rd, rs2);
- }
- }
- }
- break;
- case 5:
- /* C.FSDSP -> fsd rs2, offset[8:3](x2)*/
- gen_fp_store(ctx, OPC_RISC_FSD, 2, GET_C_RS2(ctx->opcode),
- GET_C_SDSP_IMM(ctx->opcode));
- /* C.SQSP */
- break;
- case 6: /* C.SWSP -> sw rs2, offset[7:2](x2)*/
- gen_store(ctx, OPC_RISC_SW, 2, GET_C_RS2(ctx->opcode),
- GET_C_SWSP_IMM(ctx->opcode));
- break;
- case 7:
-#if defined(TARGET_RISCV64)
- /* C.SDSP(Rv64/128) -> sd rs2, offset[8:3](x2)*/
- gen_store(ctx, OPC_RISC_SD, 2, GET_C_RS2(ctx->opcode),
- GET_C_SDSP_IMM(ctx->opcode));
-#else
- /* C.FSWSP(RV32) -> fsw rs2, offset[7:2](x2) */
- gen_fp_store(ctx, OPC_RISC_FSW, 2, GET_C_RS2(ctx->opcode),
- GET_C_SWSP_IMM(ctx->opcode));
-#endif
- break;
- }
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
}
-static void decode_RV32_64C(DisasContext *ctx)
+#ifdef TARGET_RISCV64
+static void gen_addw(TCGv ret, TCGv arg1, TCGv arg2)
{
- uint8_t op = extract32(ctx->opcode, 0, 2);
+ tcg_gen_add_tl(ret, arg1, arg2);
+ tcg_gen_ext32s_tl(ret, ret);
+}
- switch (op) {
- case 0:
- decode_RV32_64C0(ctx);
- break;
- case 1:
- decode_RV32_64C1(ctx);
- break;
- case 2:
- decode_RV32_64C2(ctx);
- break;
- }
+static void gen_subw(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ tcg_gen_sub_tl(ret, arg1, arg2);
+ tcg_gen_ext32s_tl(ret, ret);
}
-static void decode_RV32_64G(DisasContext *ctx)
+static void gen_mulw(TCGv ret, TCGv arg1, TCGv arg2)
{
- int rs1;
- int rs2;
- int rd;
- uint32_t op;
- target_long imm;
-
- /* We do not do misaligned address check here: the address should never be
- * misaligned at this point. Instructions that set PC must do the check,
- * since epc must be the address of the instruction that caused us to
- * perform the misaligned instruction fetch */
-
- op = MASK_OP_MAJOR(ctx->opcode);
- rs1 = GET_RS1(ctx->opcode);
- rs2 = GET_RS2(ctx->opcode);
- rd = GET_RD(ctx->opcode);
- imm = GET_IMM(ctx->opcode);
+ tcg_gen_mul_tl(ret, arg1, arg2);
+ tcg_gen_ext32s_tl(ret, ret);
+}
+
+static bool gen_arith_div_w(DisasContext *ctx, arg_r *a,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ TCGv source1, source2;
+ source1 = tcg_temp_new();
+ source2 = tcg_temp_new();
+
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+ tcg_gen_ext32s_tl(source1, source1);
+ tcg_gen_ext32s_tl(source2, source2);
+
+ (*func)(source1, source1, source2);
+
+ tcg_gen_ext32s_tl(source1, source1);
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
+}
- switch (op) {
- case OPC_RISC_LUI:
- if (rd == 0) {
- break; /* NOP */
- }
- tcg_gen_movi_tl(cpu_gpr[rd], sextract64(ctx->opcode, 12, 20) << 12);
- break;
- case OPC_RISC_AUIPC:
- if (rd == 0) {
- break; /* NOP */
- }
- tcg_gen_movi_tl(cpu_gpr[rd], (sextract64(ctx->opcode, 12, 20) << 12) +
- ctx->base.pc_next);
- break;
- case OPC_RISC_JAL:
- imm = GET_JAL_IMM(ctx->opcode);
- gen_jal(ctx, rd, imm);
- break;
- case OPC_RISC_JALR:
- gen_jalr(ctx, MASK_OP_JALR(ctx->opcode), rd, rs1, imm);
- break;
- case OPC_RISC_BRANCH:
- gen_branch(ctx, MASK_OP_BRANCH(ctx->opcode), rs1, rs2,
- GET_B_IMM(ctx->opcode));
- break;
- case OPC_RISC_LOAD:
- gen_load(ctx, MASK_OP_LOAD(ctx->opcode), rd, rs1, imm);
- break;
- case OPC_RISC_STORE:
- gen_store(ctx, MASK_OP_STORE(ctx->opcode), rs1, rs2,
- GET_STORE_IMM(ctx->opcode));
- break;
- case OPC_RISC_ARITH_IMM:
-#if defined(TARGET_RISCV64)
- case OPC_RISC_ARITH_IMM_W:
-#endif
- if (rd == 0) {
- break; /* NOP */
- }
- gen_arith_imm(ctx, MASK_OP_ARITH_IMM(ctx->opcode), rd, rs1, imm);
- break;
- case OPC_RISC_ARITH:
-#if defined(TARGET_RISCV64)
- case OPC_RISC_ARITH_W:
#endif
- if (rd == 0) {
- break; /* NOP */
- }
- gen_arith(ctx, MASK_OP_ARITH(ctx->opcode), rd, rs1, rs2);
- break;
- case OPC_RISC_FP_LOAD:
- gen_fp_load(ctx, MASK_OP_FP_LOAD(ctx->opcode), rd, rs1, imm);
- break;
- case OPC_RISC_FP_STORE:
- gen_fp_store(ctx, MASK_OP_FP_STORE(ctx->opcode), rs1, rs2,
- GET_STORE_IMM(ctx->opcode));
- break;
- case OPC_RISC_ATOMIC:
- if (!has_ext(ctx, RVA)) {
- goto do_illegal;
- }
- gen_atomic(ctx, MASK_OP_ATOMIC(ctx->opcode), rd, rs1, rs2);
- break;
- case OPC_RISC_FMADD:
- gen_fp_fmadd(ctx, MASK_OP_FP_FMADD(ctx->opcode), rd, rs1, rs2,
- GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
- break;
- case OPC_RISC_FMSUB:
- gen_fp_fmsub(ctx, MASK_OP_FP_FMSUB(ctx->opcode), rd, rs1, rs2,
- GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
- break;
- case OPC_RISC_FNMSUB:
- gen_fp_fnmsub(ctx, MASK_OP_FP_FNMSUB(ctx->opcode), rd, rs1, rs2,
- GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
- break;
- case OPC_RISC_FNMADD:
- gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2,
- GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
- break;
- case OPC_RISC_FP_ARITH:
- gen_fp_arith(ctx, MASK_OP_FP_ARITH(ctx->opcode), rd, rs1, rs2,
- GET_RM(ctx->opcode));
- break;
- case OPC_RISC_FENCE:
- if (ctx->opcode & 0x1000) {
- /* FENCE_I is a no-op in QEMU,
- * however we need to end the translation block */
- tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
- tcg_gen_exit_tb(NULL, 0);
- ctx->base.is_jmp = DISAS_NORETURN;
- } else {
- /* FENCE is a full memory barrier. */
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
- }
- break;
- case OPC_RISC_SYSTEM:
- gen_system(ctx, MASK_OP_SYSTEM(ctx->opcode), rd, rs1,
- (ctx->opcode & 0xFFF00000) >> 20);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- break;
- }
+
+static bool gen_arith(DisasContext *ctx, arg_r *a,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ TCGv source1, source2;
+ source1 = tcg_temp_new();
+ source2 = tcg_temp_new();
+
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ (*func)(source1, source1, source2);
+
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
+}
+
+static bool gen_shift(DisasContext *ctx, arg_r *a,
+ void(*func)(TCGv, TCGv, TCGv))
+{
+ TCGv source1 = tcg_temp_new();
+ TCGv source2 = tcg_temp_new();
+
+ gen_get_gpr(source1, a->rs1);
+ gen_get_gpr(source2, a->rs2);
+
+ tcg_gen_andi_tl(source2, source2, TARGET_LONG_BITS - 1);
+ (*func)(source1, source1, source2);
+
+ gen_set_gpr(a->rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ return true;
}
+/* Include insn module translation function */
+#include "insn_trans/trans_rvi.inc.c"
+#include "insn_trans/trans_rvm.inc.c"
+#include "insn_trans/trans_rva.inc.c"
+#include "insn_trans/trans_rvf.inc.c"
+#include "insn_trans/trans_rvd.inc.c"
+#include "insn_trans/trans_privileged.inc.c"
+
+bool decode_insn16(DisasContext *ctx, uint16_t insn);
+/* auto-generated decoder*/
+#include "decode_insn16.inc.c"
+#include "insn_trans/trans_rvc.inc.c"
+
static void decode_opc(DisasContext *ctx)
{
/* check for compressed insn */
@@ -2007,11 +659,16 @@ static void decode_opc(DisasContext *ctx)
gen_exception_illegal(ctx);
} else {
ctx->pc_succ_insn = ctx->base.pc_next + 2;
- decode_RV32_64C(ctx);
+ if (!decode_insn16(ctx, ctx->opcode)) {
+ /* fall back to old decoder */
+ decode_RV32_64C(ctx);
+ }
}
} else {
ctx->pc_succ_insn = ctx->base.pc_next + 4;
- decode_RV32_64G(ctx);
+ if (!decode_insn32(ctx, ctx->opcode)) {
+ gen_exception_illegal(ctx);
+ }
}
}
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 9f07e6f2ce..086811e602 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -38,7 +38,7 @@
#include "hw/pci/pci_regs.h"
/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+#define qmp_discard_response(s, ...) qobject_unref(qtest_qmp(s, __VA_ARGS__))
/* Test images sizes in MB */
#define TEST_IMAGE_SIZE_MB_LARGE (200 * 1024)
@@ -161,7 +161,6 @@ static AHCIQState *ahci_vboot(const char *cli, va_list ap)
s = g_new0(AHCIQState, 1);
s->parent = qtest_pc_vboot(cli, ap);
- global_qtest = s->parent->qts;
alloc_set_flags(&s->parent->alloc, ALLOC_LEAK_ASSERT);
/* Verify that we have an AHCI device present. */
@@ -201,7 +200,7 @@ static void ahci_shutdown(AHCIQState *ahci)
{
QOSState *qs = ahci->parent;
- set_context(qs);
+ assert(!global_qtest);
ahci_clean_mem(ahci);
free_ahci_device(ahci->dev);
g_free(ahci);
@@ -874,15 +873,15 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
/* Write some indicative pattern to our buffer. */
generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
- bufwrite(ptr, tx, bufsize);
+ qtest_bufwrite(ahci->parent->qts, ptr, tx, bufsize);
/* Write this buffer to disk, then read it back to the DMA buffer. */
ahci_guest_io(ahci, port, write_cmd, ptr, bufsize, sector);
- qmemset(ptr, 0x00, bufsize);
+ qtest_memset(ahci->parent->qts, ptr, 0x00, bufsize);
ahci_guest_io(ahci, port, read_cmd, ptr, bufsize, sector);
/*** Read back the Data ***/
- bufread(ptr, rx, bufsize);
+ qtest_bufread(ahci->parent->qts, ptr, rx, bufsize);
g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
ahci_free(ahci, ptr);
@@ -923,7 +922,7 @@ static void ahci_test_max(AHCIQState *ahci)
}
port = ahci_test_nondata(ahci, cmd);
- memread(ahci->port[port].fb + 0x40, d2h, 0x20);
+ qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x40, d2h, 0x20);
nsect = (uint64_t)d2h->lba_hi[2] << 40 |
(uint64_t)d2h->lba_hi[1] << 32 |
(uint64_t)d2h->lba_hi[0] << 24 |
@@ -1041,7 +1040,7 @@ static void test_dma_fragmented(void)
/* Create a DMA buffer in guest memory, and write our pattern to it. */
ptr = guest_alloc(&ahci->parent->alloc, bufsize);
g_assert(ptr);
- bufwrite(ptr, tx, bufsize);
+ qtest_bufwrite(ahci->parent->qts, ptr, tx, bufsize);
cmd = ahci_command_create(CMD_WRITE_DMA);
ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
@@ -1058,7 +1057,7 @@ static void test_dma_fragmented(void)
ahci_command_free(cmd);
/* Read back the guest's receive buffer into local memory */
- bufread(ptr, rx, bufsize);
+ qtest_bufread(ahci->parent->qts, ptr, rx, bufsize);
guest_free(&ahci->parent->alloc, ptr);
g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
@@ -1169,8 +1168,6 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write)
"-drive if=ide,format=%s,file=%s "
"-incoming %s", imgfmt, tmp_path, uri);
- set_context(src->parent);
-
/* initialize */
px = ahci_port_select(src);
ahci_port_clear(src, px);
@@ -1238,7 +1235,7 @@ static void ahci_halted_io_test(uint8_t cmd_read, uint8_t cmd_write)
generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
ptr = ahci_alloc(ahci, bufsize);
g_assert(ptr);
- memwrite(ptr, tx, bufsize);
+ qtest_memwrite(ahci->parent->qts, ptr, tx, bufsize);
/* Attempt to write (and fail) */
cmd = ahci_guest_io_halt(ahci, port, cmd_write,
@@ -1304,8 +1301,6 @@ static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write)
"-incoming %s",
tmp_path, imgfmt, uri);
- set_context(src->parent);
-
/* Initialize and prepare */
port = ahci_port_select(src);
ahci_port_clear(src, port);
@@ -1314,7 +1309,7 @@ static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write)
/* create DMA source buffer and write pattern */
ptr = ahci_alloc(src, bufsize);
g_assert(ptr);
- memwrite(ptr, tx, bufsize);
+ qtest_memwrite(src->parent->qts, ptr, tx, bufsize);
/* Write, trigger the VM to stop, migrate, then resume. */
cmd = ahci_guest_io_halt(src, port, cmd_write,
@@ -1372,8 +1367,6 @@ static void test_flush_migrate(void)
"-device ide-hd,drive=drive0 "
"-incoming %s", tmp_path, imgfmt, uri);
- set_context(src->parent);
-
px = ahci_port_select(src);
ahci_port_clear(src, px);
@@ -1384,14 +1377,14 @@ static void test_flush_migrate(void)
cmd = ahci_command_create(CMD_FLUSH_CACHE);
ahci_command_commit(src, cmd, px);
ahci_command_issue_async(src, cmd);
- qmp_eventwait("STOP");
+ qtest_qmp_eventwait(src->parent->qts, "STOP");
/* Migrate over */
ahci_migrate(src, dst, uri);
/* Complete the command */
- qmp_send("{'execute':'cont' }");
- qmp_eventwait("RESUME");
+ qtest_qmp_send(dst->parent->qts, "{'execute':'cont' }");
+ qtest_qmp_eventwait(dst->parent->qts, "RESUME");
ahci_command_wait(dst, cmd);
ahci_command_verify(dst, cmd);
@@ -1483,7 +1476,7 @@ static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd,
}
rx = g_malloc0(opts->size);
- bufread(opts->buffer, rx, opts->size);
+ qtest_bufread(ahci->parent->qts, opts->buffer, rx, opts->size);
g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0);
g_free(rx);
@@ -1558,9 +1551,10 @@ static void test_atapi_bcl(void)
}
-static void atapi_wait_tray(bool open)
+static void atapi_wait_tray(AHCIQState *ahci, bool open)
{
- QDict *rsp = qmp_eventwait_ref("DEVICE_TRAY_MOVED");
+ QDict *rsp = qtest_qmp_eventwait_ref(ahci->parent->qts,
+ "DEVICE_TRAY_MOVED");
QDict *data = qdict_get_qdict(rsp, "data");
if (open) {
g_assert(qdict_get_bool(data, "tray-open"));
@@ -1587,43 +1581,46 @@ static void test_atapi_tray(void)
port = ahci_port_select(ahci);
ahci_atapi_eject(ahci, port);
- atapi_wait_tray(true);
+ atapi_wait_tray(ahci, true);
ahci_atapi_load(ahci, port);
- atapi_wait_tray(false);
+ atapi_wait_tray(ahci, false);
/* Remove media */
- qmp_send("{'execute': 'blockdev-open-tray',"
- " 'arguments': {'id': 'cd0'}}");
- atapi_wait_tray(true);
- rsp = qmp_receive();
+ qtest_qmp_send(ahci->parent->qts, "{'execute': 'blockdev-open-tray', "
+ "'arguments': {'id': 'cd0'}}");
+ atapi_wait_tray(ahci, true);
+ rsp = qtest_qmp_receive(ahci->parent->qts);
qobject_unref(rsp);
- qmp_discard_response("{'execute': 'blockdev-remove-medium', "
+ qmp_discard_response(ahci->parent->qts,
+ "{'execute': 'blockdev-remove-medium', "
"'arguments': {'id': 'cd0'}}");
/* Test the tray without a medium */
ahci_atapi_load(ahci, port);
- atapi_wait_tray(false);
+ atapi_wait_tray(ahci, false);
ahci_atapi_eject(ahci, port);
- atapi_wait_tray(true);
+ atapi_wait_tray(ahci, true);
/* Re-insert media */
- qmp_discard_response("{'execute': 'blockdev-add', "
- "'arguments': {'node-name': 'node0', "
+ qmp_discard_response(ahci->parent->qts,
+ "{'execute': 'blockdev-add', "
+ "'arguments': {'node-name': 'node0', "
"'driver': 'raw', "
"'file': { 'driver': 'file', "
"'filename': %s }}}", iso);
- qmp_discard_response("{'execute': 'blockdev-insert-medium',"
- "'arguments': { 'id': 'cd0', "
+ qmp_discard_response(ahci->parent->qts,
+ "{'execute': 'blockdev-insert-medium',"
+ "'arguments': { 'id': 'cd0', "
"'node-name': 'node0' }}");
/* Again, the event shows up first */
- qmp_send("{'execute': 'blockdev-close-tray',"
- " 'arguments': {'id': 'cd0'}}");
- atapi_wait_tray(false);
- rsp = qmp_receive();
+ qtest_qmp_send(ahci->parent->qts, "{'execute': 'blockdev-close-tray', "
+ "'arguments': {'id': 'cd0'}}");
+ atapi_wait_tray(ahci, false);
+ rsp = qtest_qmp_receive(ahci->parent->qts);
qobject_unref(rsp);
/* Now, to convince ATAPI we understand the media has changed... */
@@ -1643,10 +1640,10 @@ static void test_atapi_tray(void)
/* Final tray test. */
ahci_atapi_eject(ahci, port);
- atapi_wait_tray(true);
+ atapi_wait_tray(ahci, true);
ahci_atapi_load(ahci, port);
- atapi_wait_tray(false);
+ atapi_wait_tray(ahci, false);
/* Cleanup */
g_free(tx);
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
index 58a48f39bf..c591748aaf 100644
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -100,7 +100,9 @@ static testdef_t tests[] = {
{ "ppc64", "ppce500", "", "U-Boot" },
{ "ppc64", "40p", "-m 192", "Memory: 192M" },
{ "ppc64", "mac99", "", "PowerPC,970FX" },
- { "ppc64", "pseries", "", "Open Firmware" },
+ { "ppc64", "pseries",
+ "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken",
+ "Open Firmware" },
{ "ppc64", "powernv", "-cpu POWER8", "OPAL" },
{ "ppc64", "sam460ex", "-device e1000", "8086 100e" },
{ "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
diff --git a/tests/decode/check.sh b/tests/decode/check.sh
index 79a06c37cd..95445a0115 100755
--- a/tests/decode/check.sh
+++ b/tests/decode/check.sh
@@ -15,4 +15,10 @@ for i in err_*.decode; do
fi
done
+for i in succ_*.decode; do
+ if ! $PYTHON $DECODETREE $i > /dev/null 2> /dev/null; then
+ echo FAIL:$i 1>&2
+ fi
+done
+
exit $E
diff --git a/tests/decode/err_pattern_group_empty.decode b/tests/decode/err_pattern_group_empty.decode
new file mode 100644
index 0000000000..abbff6b528
--- /dev/null
+++ b/tests/decode/err_pattern_group_empty.decode
@@ -0,0 +1,6 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+# empty groups are not allowed
+{
+}
diff --git a/tests/decode/err_pattern_group_ident1.decode b/tests/decode/err_pattern_group_ident1.decode
new file mode 100644
index 0000000000..3e65fab2f9
--- /dev/null
+++ b/tests/decode/err_pattern_group_ident1.decode
@@ -0,0 +1,10 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+%sub1 0:8
+
+# Make sure that indentation is enforced
+{
+ top 00000000 00000000 00000000 00000000
+ sub1 00000000 00000000 00000000 ........ %sub1
+}
diff --git a/tests/decode/err_pattern_group_ident2.decode b/tests/decode/err_pattern_group_ident2.decode
new file mode 100644
index 0000000000..bc859233b1
--- /dev/null
+++ b/tests/decode/err_pattern_group_ident2.decode
@@ -0,0 +1,11 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+%sub1 0:8
+
+# Make sure that indentation is enforced
+{
+ top 00000000 00000000 00000000 00000000
+ sub1 00000000 00000000 00000000 ........ %sub1
+# comments are suposed to be indented
+}
diff --git a/tests/decode/err_pattern_group_nest1.decode b/tests/decode/err_pattern_group_nest1.decode
new file mode 100644
index 0000000000..92e971c3c5
--- /dev/null
+++ b/tests/decode/err_pattern_group_nest1.decode
@@ -0,0 +1,13 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+%sub1 0:8
+%sub2 8:8
+%sub3 16:8
+%sub4 24:8
+
+# Groups with no overlap are supposed to fail
+{
+ top 00000000 00000000 00000000 00000000
+ sub4 ........ ........ ........ ........ %sub1 %sub2 %sub3 %sub4
+}
diff --git a/tests/decode/err_pattern_group_overlap1.decode b/tests/decode/err_pattern_group_overlap1.decode
new file mode 100644
index 0000000000..ebe3030d26
--- /dev/null
+++ b/tests/decode/err_pattern_group_overlap1.decode
@@ -0,0 +1,6 @@
+one 00000000000000000000000000000000
+{
+ two 0000000000000000000000000000000 s:1
+ three 000000000000000000000000000000 s:1 0
+}
+
diff --git a/tests/decode/err_width1.decode b/tests/decode/err_width1.decode
new file mode 100644
index 0000000000..0c14f6d73b
--- /dev/null
+++ b/tests/decode/err_width1.decode
@@ -0,0 +1,5 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+# Diagnose too many bits (33 of 32)
+one 000000000000000000000000000000000
diff --git a/tests/decode/err_width2.decode b/tests/decode/err_width2.decode
new file mode 100644
index 0000000000..47f0acf322
--- /dev/null
+++ b/tests/decode/err_width2.decode
@@ -0,0 +1,5 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+# Diagnose too few bits (31 of 32)
+one 0000000000000000000000000000000
diff --git a/tests/decode/err_width3.decode b/tests/decode/err_width3.decode
new file mode 100644
index 0000000000..c5fb6b3699
--- /dev/null
+++ b/tests/decode/err_width3.decode
@@ -0,0 +1,5 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+# Diagnose too many bits (33 of 32)
+one 0 s:32
diff --git a/tests/decode/err_width4.decode b/tests/decode/err_width4.decode
new file mode 100644
index 0000000000..1588a63698
--- /dev/null
+++ b/tests/decode/err_width4.decode
@@ -0,0 +1,5 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+# Diagnose too few bits (31 of 32)
+one 0 s:30
diff --git a/tests/decode/succ_pattern_group_nest1.decode b/tests/decode/succ_pattern_group_nest1.decode
new file mode 100644
index 0000000000..77b0f48b49
--- /dev/null
+++ b/tests/decode/succ_pattern_group_nest1.decode
@@ -0,0 +1,22 @@
+# This work is licensed under the terms of the GNU LGPL, version 2 or later.
+# See the COPYING.LIB file in the top-level directory.
+
+%sub1 0:8
+%sub2 8:8
+%sub3 16:8
+%sub4 24:7
+
+# Make sure deep netsting works, as few targets will actually exercise it
+{
+ top 00000000 00000000 00000000 00000000
+ {
+ sub1 00000000 00000000 00000000 ........ %sub1
+ {
+ sub2 00000000 00000000 ........ ........ %sub1 %sub2
+ {
+ sub3 00000000 ........ ........ ........ %sub1 %sub2 %sub3
+ sub4 0....... ........ ........ ........ %sub1 %sub2 %sub3 %sub4
+ }
+ }
+ }
+}
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index 636a111a6f..d71557c5cb 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -73,11 +73,6 @@ void qtest_shutdown(QOSState *qs)
}
}
-void set_context(QOSState *s)
-{
- global_qtest = s->qts;
-}
-
static QDict *qmp_execute(QTestState *qts, const char *command)
{
return qtest_qmp(qts, "{ 'execute': %s }", command);
@@ -89,8 +84,6 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
QDict *rsp, *sub;
bool running;
- set_context(from);
-
/* Is the machine currently running? */
rsp = qmp_execute(from->qts, "query-status");
g_assert(qdict_haskey(rsp, "return"));
@@ -114,7 +107,6 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
/* If we were running, we can wait for an event. */
if (running) {
migrate_allocator(&from->alloc, &to->alloc);
- set_context(to);
qtest_qmp_eventwait(to->qts, "RESUME");
return;
}
@@ -144,7 +136,6 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
}
migrate_allocator(&from->alloc, &to->alloc);
- set_context(to);
}
bool have_qemu_img(void)
diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h
index 149b0be8bc..8e971c25a3 100644
--- a/tests/libqos/libqos.h
+++ b/tests/libqos/libqos.h
@@ -28,7 +28,6 @@ void qtest_shutdown(QOSState *qs);
bool have_qemu_img(void);
void mkimg(const char *file, const char *fmt, unsigned size_mb);
void mkqcow2(const char *file, unsigned size_mb);
-void set_context(QOSState *s);
void migrate(QOSState *from, QOSState *to, const char *uri);
void prepare_blkdebug_script(const char *debug_fn, const char *event);
void generate_pattern(void *buffer, size_t len, size_t cycle_len);
diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c
index 974f8da5b2..63d464048d 100644
--- a/tests/pnv-xscom-test.c
+++ b/tests/pnv-xscom-test.c
@@ -39,7 +39,6 @@ static const PnvChip pnv_chips[] = {
.cfam_id = 0x120d304980000000ull,
.first_core = 0x1,
},
-#if 0 /* POWER9 support is not ready yet */
{
.chip_type = PNV_CHIP_POWER9,
.cpu_model = "POWER9",
@@ -47,7 +46,6 @@ static const PnvChip pnv_chips[] = {
.cfam_id = 0x220d104900008000ull,
.first_core = 0x0,
},
-#endif
};
static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
diff --git a/tests/prom-env-test.c b/tests/prom-env-test.c
index 4821254b7e..61bc1d1e7b 100644
--- a/tests/prom-env-test.c
+++ b/tests/prom-env-test.c
@@ -44,11 +44,18 @@ static void check_guest_memory(QTestState *qts)
static void test_machine(const void *machine)
{
- const char *extra_args;
+ const char *extra_args = "";
QTestState *qts;
- /* The pseries firmware boots much faster without the default devices */
- extra_args = strcmp(machine, "pseries") == 0 ? "-nodefaults" : "";
+ /*
+ * The pseries firmware boots much faster without the default
+ * devices, it also needs Spectre/Meltdown workarounds disabled to
+ * avoid warnings with TCG
+ */
+ if (strcmp(machine, "pseries") == 0) {
+ extra_args = "-nodefaults"
+ " -machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken";
+ }
qts = qtest_initf("-M %s,accel=tcg %s -prom-env 'use-nvramrc?=true' "
"-prom-env 'nvramrc=%x %x l!' ", (const char *)machine,
diff --git a/tests/pxe-test.c b/tests/pxe-test.c
index 73ac1d1c61..948b0fbdc7 100644
--- a/tests/pxe-test.c
+++ b/tests/pxe-test.c
@@ -25,6 +25,7 @@ static char disk[] = "tests/pxe-test-disk-XXXXXX";
typedef struct testdef {
const char *machine; /* Machine type */
const char *model; /* NIC device model */
+ const char *extra; /* Any additional parameters */
} testdef_t;
static testdef_t x86_tests[] = {
@@ -44,13 +45,16 @@ static testdef_t x86_tests_slow[] = {
};
static testdef_t ppc64_tests[] = {
- { "pseries", "spapr-vlan" },
- { "pseries", "virtio-net-pci", },
+ { "pseries", "spapr-vlan",
+ "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken" },
+ { "pseries", "virtio-net-pci",
+ "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken" },
{ NULL },
};
static testdef_t ppc64_tests_slow[] = {
- { "pseries", "e1000" },
+ { "pseries", "e1000",
+ "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken" },
{ NULL },
};
@@ -63,13 +67,18 @@ static void test_pxe_one(const testdef_t *test, bool ipv6)
{
QTestState *qts;
char *args;
+ const char *extra = test->extra;
+
+ if (!extra) {
+ extra = "";
+ }
args = g_strdup_printf(
"-machine %s,accel=kvm:tcg -nodefaults -boot order=n "
"-netdev user,id=" NETNAME ",tftp=./,bootfile=%s,ipv4=%s,ipv6=%s "
- "-device %s,bootindex=1,netdev=" NETNAME,
+ "-device %s,bootindex=1,netdev=" NETNAME " %s",
test->machine, disk, ipv6 ? "off" : "on", ipv6 ? "on" : "off",
- test->model);
+ test->model, extra);
qts = qtest_init(args);
boot_sector_test(qts);
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 3b50c7f188..6a3b7c2b89 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -356,6 +356,13 @@ $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io
# Using snapshot=on with a non-existent TMPDIR
TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on
+# Using snapshot=on together with read-only=on
+echo "info block" |
+ run_qemu -drive file="$TEST_IMG",snapshot=on,read-only=on,if=none,id=$device_id |
+ _filter_qemu_io |
+ sed -e 's#"/[^"]*/vl\.[A-Za-z0-9]\{6\}"#SNAPSHOT_PATH#g'
+
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index b900935fbc..9f1cf22608 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -458,4 +458,13 @@ read 4096/4096 bytes at offset 0
Testing: -drive driver=null-co,snapshot=on
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2", "file": {"driver": "file", "filename": SNAPSHOT_PATH}} (qcow2, read-only)
+ Removable device: not locked, tray closed
+ Cache mode: writeback, ignore flushes
+ Backing file: TEST_DIR/t.qcow2 (chain depth: 1)
+(qemu) quit
+
*** done
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
index 8c5c735dfd..c4743cc31c 100644
--- a/tests/qemu-iotests/051.pc.out
+++ b/tests/qemu-iotests/051.pc.out
@@ -530,4 +530,13 @@ read 4096/4096 bytes at offset 0
Testing: -drive driver=null-co,snapshot=on
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2", "file": {"driver": "file", "filename": SNAPSHOT_PATH}} (qcow2, read-only)
+ Removable device: not locked, tray closed
+ Cache mode: writeback, ignore flushes
+ Backing file: TEST_DIR/t.qcow2 (chain depth: 1)
+(qemu) quit
+
*** done
diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124
index 5aa1bf1bd6..80b356f7bb 100755
--- a/tests/qemu-iotests/124
+++ b/tests/qemu-iotests/124
@@ -634,6 +634,119 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
self.vm.shutdown()
self.check_backups()
+ def test_incremental_pause(self):
+ """
+ Test an incremental backup that errors into a pause and is resumed.
+ """
+
+ drive0 = self.drives[0]
+ # NB: The blkdebug script here looks for a "flush, read, read" pattern.
+ # The flush occurs in hmp_io_writes, the first read in device_add, and
+ # the last read during the block job.
+ result = self.vm.qmp('blockdev-add',
+ node_name=drive0['id'],
+ driver=drive0['fmt'],
+ file={
+ 'driver': 'blkdebug',
+ 'image': {
+ 'driver': 'file',
+ 'filename': drive0['file']
+ },
+ 'set-state': [{
+ 'event': 'flush_to_disk',
+ 'state': 1,
+ 'new_state': 2
+ },{
+ 'event': 'read_aio',
+ 'state': 2,
+ 'new_state': 3
+ }],
+ 'inject-error': [{
+ 'event': 'read_aio',
+ 'errno': 5,
+ 'state': 3,
+ 'immediately': False,
+ 'once': True
+ }],
+ })
+ self.assert_qmp(result, 'return', {})
+ self.create_anchor_backup(drive0)
+ bitmap = self.add_bitmap('bitmap0', drive0)
+
+ # Emulate guest activity
+ self.hmp_io_writes(drive0['id'], (('0xab', 0, 512),
+ ('0xfe', '16M', '256k'),
+ ('0x64', '32736k', '64k')))
+
+ # For the purposes of query-block visibility of bitmaps, add a drive
+ # frontend after we've written data; otherwise we can't use hmp-io
+ result = self.vm.qmp("device_add",
+ id="device0",
+ drive=drive0['id'],
+ driver="virtio-blk")
+ self.assert_qmp(result, 'return', {})
+
+ # Bitmap Status Check
+ query = self.vm.qmp('query-block')
+ ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
+ if bmap.get('name') == bitmap.name][0]
+ self.assert_qmp(ret, 'count', 458752)
+ self.assert_qmp(ret, 'granularity', 65536)
+ self.assert_qmp(ret, 'status', 'active')
+ self.assert_qmp(ret, 'busy', False)
+ self.assert_qmp(ret, 'recording', True)
+
+ # Start backup
+ parent, _ = bitmap.last_target()
+ target = self.prepare_backup(bitmap, parent)
+ res = self.vm.qmp('drive-backup',
+ job_id=bitmap.drive['id'],
+ device=bitmap.drive['id'],
+ sync='incremental',
+ bitmap=bitmap.name,
+ format=bitmap.drive['fmt'],
+ target=target,
+ mode='existing',
+ on_source_error='stop')
+ self.assert_qmp(res, 'return', {})
+
+ # Wait for the error
+ event = self.vm.event_wait(name="BLOCK_JOB_ERROR",
+ match={"data":{"device":bitmap.drive['id']}})
+ self.assert_qmp(event, 'data', {'device': bitmap.drive['id'],
+ 'action': 'stop',
+ 'operation': 'read'})
+
+ # Bitmap Status Check
+ query = self.vm.qmp('query-block')
+ ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
+ if bmap.get('name') == bitmap.name][0]
+ self.assert_qmp(ret, 'count', 458752)
+ self.assert_qmp(ret, 'granularity', 65536)
+ self.assert_qmp(ret, 'status', 'frozen')
+ self.assert_qmp(ret, 'busy', True)
+ self.assert_qmp(ret, 'recording', True)
+
+ # Resume and check incremental backup for consistency
+ res = self.vm.qmp('block-job-resume', device=bitmap.drive['id'])
+ self.assert_qmp(res, 'return', {})
+ self.wait_qmp_backup(bitmap.drive['id'])
+
+ # Bitmap Status Check
+ query = self.vm.qmp('query-block')
+ ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
+ if bmap.get('name') == bitmap.name][0]
+ self.assert_qmp(ret, 'count', 0)
+ self.assert_qmp(ret, 'granularity', 65536)
+ self.assert_qmp(ret, 'status', 'active')
+ self.assert_qmp(ret, 'busy', False)
+ self.assert_qmp(ret, 'recording', True)
+
+ # Finalize / Cleanup
+ self.make_reference_backup(bitmap)
+ self.vm.shutdown()
+ self.check_backups()
+
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'])
diff --git a/tests/qemu-iotests/124.out b/tests/qemu-iotests/124.out
index e56cae021b..281b69efea 100644
--- a/tests/qemu-iotests/124.out
+++ b/tests/qemu-iotests/124.out
@@ -1,5 +1,5 @@
-...........
+............
----------------------------------------------------------------------
-Ran 11 tests
+Ran 12 tests
OK
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
index 71fd48eff0..0de097fc88 100755
--- a/tests/qemu-iotests/232
+++ b/tests/qemu-iotests/232
@@ -29,6 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
+ rm -f $TEST_IMG.[01234]
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -143,6 +144,36 @@ run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,a
run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
+echo
+echo "=== Try commit to backing file with auto-read-only ==="
+echo
+
+TEST_IMG="$TEST_IMG.0" _make_test_img $size
+TEST_IMG="$TEST_IMG.1" _make_test_img $size
+TEST_IMG="$TEST_IMG.2" _make_test_img $size
+TEST_IMG="$TEST_IMG.3" _make_test_img $size
+TEST_IMG="$TEST_IMG.4" _make_test_img $size
+
+(cat <<EOF
+{"execute":"qmp_capabilities"}
+{"execute":"block-commit",
+ "arguments":{"device":"format-4", "top-node": "format-2", "base-node":"format-0", "job-id":"job0"}}
+EOF
+sleep 1
+echo '{"execute":"quit"}'
+) | $QEMU -qmp stdio -nographic -nodefaults \
+ -blockdev file,node-name=file-0,filename=$TEST_IMG.0,auto-read-only=on \
+ -blockdev qcow2,node-name=format-0,file=file-0,read-only=on \
+ -blockdev file,node-name=file-1,filename=$TEST_IMG.1,auto-read-only=on \
+ -blockdev qcow2,node-name=format-1,file=file-1,read-only=on,backing=format-0 \
+ -blockdev file,node-name=file-2,filename=$TEST_IMG.2,auto-read-only=on \
+ -blockdev qcow2,node-name=format-2,file=file-2,read-only=on,backing=format-1 \
+ -blockdev file,node-name=file-3,filename=$TEST_IMG.3,auto-read-only=on \
+ -blockdev qcow2,node-name=format-3,file=file-3,read-only=on,backing=format-2 \
+ -blockdev file,node-name=file-4,filename=$TEST_IMG.4,auto-read-only=on \
+ -blockdev qcow2,node-name=format-4,file=file-4,read-only=on,backing=format-3 |
+ _filter_qmp
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out
index dcb683afa3..5bcc44bb62 100644
--- a/tests/qemu-iotests/232.out
+++ b/tests/qemu-iotests/232.out
@@ -22,12 +22,12 @@ NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
=== -blockdev with read-write image: read-only/auto-read-only combinations ===
@@ -50,10 +50,30 @@ node0: TEST_DIR/t.IMGFMT (file, read-only)
node0: TEST_DIR/t.IMGFMT (file, read-only)
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
-node0: TEST_DIR/t.IMGFMT (file, read-only)
+node0: TEST_DIR/t.IMGFMT (file)
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
-node0: TEST_DIR/t.IMGFMT (file, read-only)
+node0: TEST_DIR/t.IMGFMT (file)
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
+
+=== Try commit to backing file with auto-read-only ===
+
+Formatting 'TEST_DIR/t.IMGFMT.0', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.3', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.4', fmt=IMGFMT size=134217728
+QMP_VERSION
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out
index 5006f7bca1..815cd053f0 100644
--- a/tests/qemu-iotests/236.out
+++ b/tests/qemu-iotests/236.out
@@ -22,17 +22,21 @@ write -P0xcd 0x3ff0000 64k
"bitmaps": {
"drive0": [
{
+ "busy": false,
"count": 262144,
"granularity": 65536,
"name": "bitmapB",
"persistent": false,
+ "recording": true,
"status": "active"
},
{
+ "busy": false,
"count": 262144,
"granularity": 65536,
"name": "bitmapA",
"persistent": false,
+ "recording": true,
"status": "active"
}
]
@@ -84,17 +88,21 @@ write -P0xcd 0x3ff0000 64k
"bitmaps": {
"drive0": [
{
+ "busy": false,
"count": 262144,
"granularity": 65536,
"name": "bitmapB",
"persistent": false,
+ "recording": true,
"status": "active"
},
{
+ "busy": false,
"count": 262144,
"granularity": 65536,
"name": "bitmapA",
"persistent": false,
+ "recording": true,
"status": "active"
}
]
@@ -184,24 +192,30 @@ write -P0xea 0x3fe0000 64k
"bitmaps": {
"drive0": [
{
+ "busy": false,
"count": 393216,
"granularity": 65536,
"name": "bitmapC",
"persistent": false,
+ "recording": false,
"status": "disabled"
},
{
+ "busy": false,
"count": 262144,
"granularity": 65536,
"name": "bitmapB",
"persistent": false,
+ "recording": false,
"status": "disabled"
},
{
+ "busy": false,
"count": 458752,
"granularity": 65536,
"name": "bitmapA",
"persistent": false,
+ "recording": false,
"status": "disabled"
}
]
@@ -251,24 +265,30 @@ write -P0xea 0x3fe0000 64k
"bitmaps": {
"drive0": [
{
+ "busy": false,
"count": 393216,
"granularity": 65536,
"name": "bitmapC",
"persistent": false,
+ "recording": false,
"status": "disabled"
},
{
+ "busy": false,
"count": 262144,
"granularity": 65536,
"name": "bitmapB",
"persistent": false,
+ "recording": false,
"status": "disabled"
},
{
+ "busy": false,
"count": 458752,
"granularity": 65536,
"name": "bitmapA",
"persistent": false,
+ "recording": false,
"status": "disabled"
}
]
@@ -311,31 +331,39 @@ write -P0xea 0x3fe0000 64k
"bitmaps": {
"drive0": [
{
+ "busy": false,
"count": 458752,
"granularity": 65536,
"name": "bitmapD",
"persistent": false,
+ "recording": false,
"status": "disabled"
},
{
+ "busy": false,
"count": 393216,
"granularity": 65536,
"name": "bitmapC",
"persistent": false,
+ "recording": false,
"status": "disabled"
},
{
+ "busy": false,
"count": 262144,
"granularity": 65536,
"name": "bitmapB",
"persistent": false,
+ "recording": false,
"status": "disabled"
},
{
+ "busy": false,
"count": 458752,
"granularity": 65536,
"name": "bitmapA",
"persistent": false,
+ "recording": false,
"status": "disabled"
}
]
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
new file mode 100644
index 0000000000..7891a210c1
--- /dev/null
+++ b/tests/qemu-iotests/245
@@ -0,0 +1,991 @@
+#!/usr/bin/env python
+#
+# Test cases for the QMP 'x-blockdev-reopen' command
+#
+# Copyright (C) 2018-2019 Igalia, S.L.
+# Author: Alberto Garcia <berto@igalia.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/>.
+#
+
+import os
+import re
+import iotests
+import copy
+import json
+from iotests import qemu_img, qemu_io
+
+hd_path = [
+ os.path.join(iotests.test_dir, 'hd0.img'),
+ os.path.join(iotests.test_dir, 'hd1.img'),
+ os.path.join(iotests.test_dir, 'hd2.img')
+]
+
+def hd_opts(idx):
+ return {'driver': iotests.imgfmt,
+ 'node-name': 'hd%d' % idx,
+ 'file': {'driver': 'file',
+ 'node-name': 'hd%d-file' % idx,
+ 'filename': hd_path[idx] } }
+
+class TestBlockdevReopen(iotests.QMPTestCase):
+ total_io_cmds = 0
+
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, hd_path[0], '3M')
+ qemu_img('create', '-f', iotests.imgfmt, '-b', hd_path[0], hd_path[1])
+ qemu_img('create', '-f', iotests.imgfmt, hd_path[2], '3M')
+ qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xa0 0 1M', hd_path[0])
+ qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xa1 1M 1M', hd_path[1])
+ qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xa2 2M 1M', hd_path[2])
+ self.vm = iotests.VM()
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ self.check_qemu_io_errors()
+ os.remove(hd_path[0])
+ os.remove(hd_path[1])
+ os.remove(hd_path[2])
+
+ # The output of qemu-io is not returned by vm.hmp_qemu_io() but
+ # it's stored in the log and can only be read when the VM has been
+ # shut down. This function runs qemu-io and keeps track of the
+ # number of times it's been called.
+ def run_qemu_io(self, img, cmd):
+ result = self.vm.hmp_qemu_io(img, cmd)
+ self.assert_qmp(result, 'return', '')
+ self.total_io_cmds += 1
+
+ # Once the VM is shut down we can parse the log and see if qemu-io
+ # ran without errors.
+ def check_qemu_io_errors(self):
+ self.assertFalse(self.vm.is_running())
+ found = 0
+ log = self.vm.get_log()
+ for line in log.split("\n"):
+ if line.startswith("Pattern verification failed"):
+ raise Exception("%s (command #%d)" % (line, found))
+ if re.match("read .*/.* bytes at offset", line):
+ found += 1
+ self.assertEqual(found, self.total_io_cmds,
+ "Expected output of %d qemu-io commands, found %d" %
+ (found, self.total_io_cmds))
+
+ # Run x-blockdev-reopen with 'opts' but applying 'newopts'
+ # on top of it. The original 'opts' dict is unmodified
+ def reopen(self, opts, newopts = {}, errmsg = None):
+ opts = copy.deepcopy(opts)
+
+ # Apply the changes from 'newopts' on top of 'opts'
+ for key in newopts:
+ value = newopts[key]
+ # If key has the form "foo.bar" then we need to do
+ # opts["foo"]["bar"] = value, not opts["foo.bar"] = value
+ subdict = opts
+ while key.find('.') != -1:
+ [prefix, key] = key.split('.', 1)
+ subdict = opts[prefix]
+ subdict[key] = value
+
+ result = self.vm.qmp('x-blockdev-reopen', conv_keys = False, **opts)
+ if errmsg:
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc', errmsg)
+ else:
+ self.assert_qmp(result, 'return', {})
+
+
+ # Run query-named-block-nodes and return the specified entry
+ def get_node(self, node_name):
+ result = self.vm.qmp('query-named-block-nodes')
+ for node in result['return']:
+ if node['node-name'] == node_name:
+ return node
+ return None
+
+ # Run 'query-named-block-nodes' and compare its output with the
+ # value passed by the user in 'graph'
+ def check_node_graph(self, graph):
+ result = self.vm.qmp('query-named-block-nodes')
+ self.assertEqual(json.dumps(graph, sort_keys=True),
+ json.dumps(result, sort_keys=True))
+
+ # This test opens one single disk image (without backing files)
+ # and tries to reopen it with illegal / incorrect parameters.
+ def test_incorrect_parameters_single_file(self):
+ # Open 'hd0' only (no backing files)
+ opts = hd_opts(0)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+ original_graph = self.vm.qmp('query-named-block-nodes')
+
+ # We can reopen the image passing the same options
+ self.reopen(opts)
+
+ # We can also reopen passing a child reference in 'file'
+ self.reopen(opts, {'file': 'hd0-file'})
+
+ # We cannot change any of these
+ self.reopen(opts, {'node-name': 'not-found'}, "Cannot find node named 'not-found'")
+ self.reopen(opts, {'node-name': ''}, "Cannot find node named ''")
+ self.reopen(opts, {'node-name': None}, "Invalid parameter type for 'node-name', expected: string")
+ self.reopen(opts, {'driver': 'raw'}, "Cannot change the option 'driver'")
+ self.reopen(opts, {'driver': ''}, "Invalid parameter ''")
+ self.reopen(opts, {'driver': None}, "Invalid parameter type for 'driver', expected: string")
+ self.reopen(opts, {'file': 'not-found'}, "Cannot change the option 'file'")
+ self.reopen(opts, {'file': ''}, "Cannot change the option 'file'")
+ self.reopen(opts, {'file': None}, "Invalid parameter type for 'file', expected: BlockdevRef")
+ self.reopen(opts, {'file.node-name': 'newname'}, "Cannot change the option 'node-name'")
+ self.reopen(opts, {'file.driver': 'host_device'}, "Cannot change the option 'driver'")
+ self.reopen(opts, {'file.filename': hd_path[1]}, "Cannot change the option 'filename'")
+ self.reopen(opts, {'file.aio': 'native'}, "Cannot change the option 'aio'")
+ self.reopen(opts, {'file.locking': 'off'}, "Cannot change the option 'locking'")
+ self.reopen(opts, {'file.filename': None}, "Invalid parameter type for 'file.filename', expected: string")
+
+ # node-name is optional in BlockdevOptions, but x-blockdev-reopen needs it
+ del opts['node-name']
+ self.reopen(opts, {}, "Node name not specified")
+
+ # Check that nothing has changed
+ self.check_node_graph(original_graph)
+
+ # Remove the node
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+
+ # This test opens an image with a backing file and tries to reopen
+ # it with illegal / incorrect parameters.
+ def test_incorrect_parameters_backing_file(self):
+ # Open hd1 omitting the backing options (hd0 will be opened
+ # with the default options)
+ opts = hd_opts(1)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+ original_graph = self.vm.qmp('query-named-block-nodes')
+
+ # We can't reopen the image passing the same options, 'backing' is mandatory
+ self.reopen(opts, {}, "backing is missing for 'hd1'")
+
+ # Everything works if we pass 'backing' using the existing node name
+ for node in original_graph['return']:
+ if node['drv'] == iotests.imgfmt and node['file'] == hd_path[0]:
+ backing_node_name = node['node-name']
+ self.reopen(opts, {'backing': backing_node_name})
+
+ # We can't use a non-existing or empty (non-NULL) node as the backing image
+ self.reopen(opts, {'backing': 'not-found'}, "Cannot find device= nor node_name=not-found")
+ self.reopen(opts, {'backing': ''}, "Cannot find device= nor node_name=")
+
+ # We can reopen the image just fine if we specify the backing options
+ opts['backing'] = {'driver': iotests.imgfmt,
+ 'file': {'driver': 'file',
+ 'filename': hd_path[0]}}
+ self.reopen(opts)
+
+ # We cannot change any of these options
+ self.reopen(opts, {'backing.node-name': 'newname'}, "Cannot change the option 'node-name'")
+ self.reopen(opts, {'backing.driver': 'raw'}, "Cannot change the option 'driver'")
+ self.reopen(opts, {'backing.file.node-name': 'newname'}, "Cannot change the option 'node-name'")
+ self.reopen(opts, {'backing.file.driver': 'host_device'}, "Cannot change the option 'driver'")
+
+ # Check that nothing has changed since the beginning
+ self.check_node_graph(original_graph)
+
+ # Remove the node
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1')
+ self.assert_qmp(result, 'return', {})
+
+ # Reopen an image several times changing some of its options
+ def test_reopen(self):
+ # Open the hd1 image passing all backing options
+ opts = hd_opts(1)
+ opts['backing'] = hd_opts(0)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+ original_graph = self.vm.qmp('query-named-block-nodes')
+
+ # We can reopen the image passing the same options
+ self.reopen(opts)
+
+ # Reopen in read-only mode
+ self.assert_qmp(self.get_node('hd1'), 'ro', False)
+
+ self.reopen(opts, {'read-only': True})
+ self.assert_qmp(self.get_node('hd1'), 'ro', True)
+ self.reopen(opts)
+ self.assert_qmp(self.get_node('hd1'), 'ro', False)
+
+ # Change the cache options
+ self.assert_qmp(self.get_node('hd1'), 'cache/writeback', True)
+ self.assert_qmp(self.get_node('hd1'), 'cache/direct', False)
+ self.assert_qmp(self.get_node('hd1'), 'cache/no-flush', False)
+ self.reopen(opts, {'cache': { 'direct': True, 'no-flush': True }})
+ self.assert_qmp(self.get_node('hd1'), 'cache/writeback', True)
+ self.assert_qmp(self.get_node('hd1'), 'cache/direct', True)
+ self.assert_qmp(self.get_node('hd1'), 'cache/no-flush', True)
+
+ # Reopen again with the original options
+ self.reopen(opts)
+ self.assert_qmp(self.get_node('hd1'), 'cache/writeback', True)
+ self.assert_qmp(self.get_node('hd1'), 'cache/direct', False)
+ self.assert_qmp(self.get_node('hd1'), 'cache/no-flush', False)
+
+ # Change 'detect-zeroes' and 'discard'
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'off')
+ self.reopen(opts, {'detect-zeroes': 'on'})
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'on')
+ self.reopen(opts, {'detect-zeroes': 'unmap'},
+ "setting detect-zeroes to unmap is not allowed " +
+ "without setting discard operation to unmap")
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'on')
+ self.reopen(opts, {'detect-zeroes': 'unmap', 'discard': 'unmap'})
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'unmap')
+ self.reopen(opts)
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'off')
+
+ # Changing 'force-share' is currently not supported
+ self.reopen(opts, {'force-share': True}, "Cannot change the option 'force-share'")
+
+ # Change some qcow2-specific options
+ # No way to test for success other than checking the return message
+ if iotests.imgfmt == 'qcow2':
+ self.reopen(opts, {'l2-cache-entry-size': 128 * 1024},
+ "L2 cache entry size must be a power of two "+
+ "between 512 and the cluster size (65536)")
+ self.reopen(opts, {'l2-cache-size': 1024 * 1024,
+ 'cache-size': 512 * 1024},
+ "l2-cache-size may not exceed cache-size")
+ self.reopen(opts, {'l2-cache-size': 4 * 1024 * 1024,
+ 'refcount-cache-size': 4 * 1024 * 1024,
+ 'l2-cache-entry-size': 32 * 1024})
+ self.reopen(opts, {'pass-discard-request': True})
+
+ # Check that nothing has changed since the beginning
+ # (from the parameters that we can check)
+ self.check_node_graph(original_graph)
+
+ # Check that the node names (other than the top-level one) are optional
+ del opts['file']['node-name']
+ del opts['backing']['node-name']
+ del opts['backing']['file']['node-name']
+ self.reopen(opts)
+ self.check_node_graph(original_graph)
+
+ # Reopen setting backing = null, this removes the backing image from the chain
+ self.reopen(opts, {'backing': None})
+ self.assert_qmp_absent(self.get_node('hd1'), 'image/backing-image')
+
+ # Open the 'hd0' image
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **hd_opts(0))
+ self.assert_qmp(result, 'return', {})
+
+ # Reopen the hd1 image setting 'hd0' as its backing image
+ self.reopen(opts, {'backing': 'hd0'})
+ self.assert_qmp(self.get_node('hd1'), 'image/backing-image/filename', hd_path[0])
+
+ # Check that nothing has changed since the beginning
+ self.reopen(hd_opts(0), {'read-only': True})
+ self.check_node_graph(original_graph)
+
+ # The backing file (hd0) is now a reference, we cannot change backing.* anymore
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
+
+ # We can't remove 'hd0' while it's a backing image of 'hd1'
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc', "Node 'hd0' is busy: node is used as backing hd of 'hd1'")
+
+ # But we can remove both nodes if done in the proper order
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1')
+ self.assert_qmp(result, 'return', {})
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+
+ # Reopen a raw image and see the effect of changing the 'offset' option
+ def test_reopen_raw(self):
+ opts = {'driver': 'raw', 'node-name': 'hd0',
+ 'file': { 'driver': 'file',
+ 'filename': hd_path[0],
+ 'node-name': 'hd0-file' } }
+
+ # First we create a 2MB raw file, and fill each half with a
+ # different value
+ qemu_img('create', '-f', 'raw', hd_path[0], '2M')
+ qemu_io('-f', 'raw', '-c', 'write -P 0xa0 0 1M', hd_path[0])
+ qemu_io('-f', 'raw', '-c', 'write -P 0xa1 1M 1M', hd_path[0])
+
+ # Open the raw file with QEMU
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # Read 1MB from offset 0
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
+
+ # Reopen the image with a 1MB offset.
+ # Now the results are different
+ self.reopen(opts, {'offset': 1024*1024})
+ self.run_qemu_io("hd0", "read -P 0xa1 0 1M")
+
+ # Reopen again with the original options.
+ # We get the original results again
+ self.reopen(opts)
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
+
+ # Remove the block device
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+
+ # Omitting an option should reset it to the default value, but if
+ # an option cannot be changed it shouldn't be possible to reset it
+ # to its default value either
+ def test_reset_default_values(self):
+ opts = {'driver': 'qcow2', 'node-name': 'hd0',
+ 'file': { 'driver': 'file',
+ 'filename': hd_path[0],
+ 'x-check-cache-dropped': True, # This one can be changed
+ 'locking': 'off', # This one can NOT be changed
+ 'node-name': 'hd0-file' } }
+
+ # Open the file with QEMU
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # file.x-check-cache-dropped can be changed...
+ self.reopen(opts, { 'file.x-check-cache-dropped': False })
+ # ...and dropped completely (resetting to the default value)
+ del opts['file']['x-check-cache-dropped']
+ self.reopen(opts)
+
+ # file.locking cannot be changed nor reset to the default value
+ self.reopen(opts, { 'file.locking': 'on' }, "Cannot change the option 'locking'")
+ del opts['file']['locking']
+ self.reopen(opts, {}, "Option 'locking' cannot be reset to its default value")
+ # But we can reopen it if we maintain its previous value
+ self.reopen(opts, { 'file.locking': 'off' })
+
+ # Remove the block device
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+
+ # This test modifies the node graph a few times by changing the
+ # 'backing' option on reopen and verifies that the guest data that
+ # is read afterwards is consistent with the graph changes.
+ def test_io_with_graph_changes(self):
+ opts = []
+
+ # Open hd0, hd1 and hd2 without any backing image
+ for i in range(3):
+ opts.append(hd_opts(i))
+ opts[i]['backing'] = None
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts[i])
+ self.assert_qmp(result, 'return', {})
+
+ # hd0
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
+ self.run_qemu_io("hd0", "read -P 0 1M 1M")
+ self.run_qemu_io("hd0", "read -P 0 2M 1M")
+
+ # hd1 <- hd0
+ self.reopen(opts[0], {'backing': 'hd1'})
+
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
+ self.run_qemu_io("hd0", "read -P 0xa1 1M 1M")
+ self.run_qemu_io("hd0", "read -P 0 2M 1M")
+
+ # hd1 <- hd0 , hd1 <- hd2
+ self.reopen(opts[2], {'backing': 'hd1'})
+
+ self.run_qemu_io("hd2", "read -P 0 0 1M")
+ self.run_qemu_io("hd2", "read -P 0xa1 1M 1M")
+ self.run_qemu_io("hd2", "read -P 0xa2 2M 1M")
+
+ # hd1 <- hd2 <- hd0
+ self.reopen(opts[0], {'backing': 'hd2'})
+
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
+ self.run_qemu_io("hd0", "read -P 0xa1 1M 1M")
+ self.run_qemu_io("hd0", "read -P 0xa2 2M 1M")
+
+ # hd2 <- hd0
+ self.reopen(opts[2], {'backing': None})
+
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
+ self.run_qemu_io("hd0", "read -P 0 1M 1M")
+ self.run_qemu_io("hd0", "read -P 0xa2 2M 1M")
+
+ # hd2 <- hd1 <- hd0
+ self.reopen(opts[1], {'backing': 'hd2'})
+ self.reopen(opts[0], {'backing': 'hd1'})
+
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
+ self.run_qemu_io("hd0", "read -P 0xa1 1M 1M")
+ self.run_qemu_io("hd0", "read -P 0xa2 2M 1M")
+
+ # Illegal operation: hd2 is a child of hd1
+ self.reopen(opts[2], {'backing': 'hd1'},
+ "Making 'hd1' a backing file of 'hd2' would create a cycle")
+
+ # hd2 <- hd0, hd2 <- hd1
+ self.reopen(opts[0], {'backing': 'hd2'})
+
+ self.run_qemu_io("hd1", "read -P 0 0 1M")
+ self.run_qemu_io("hd1", "read -P 0xa1 1M 1M")
+ self.run_qemu_io("hd1", "read -P 0xa2 2M 1M")
+
+ # More illegal operations
+ self.reopen(opts[2], {'backing': 'hd1'},
+ "Making 'hd1' a backing file of 'hd2' would create a cycle")
+ self.reopen(opts[2], {'file': 'hd0-file'}, "Cannot change the option 'file'")
+
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd2')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc', "Node 'hd2' is busy: node is used as backing hd of 'hd0'")
+
+ # hd1 doesn't have a backing file now
+ self.reopen(opts[1], {'backing': None})
+
+ self.run_qemu_io("hd1", "read -P 0 0 1M")
+ self.run_qemu_io("hd1", "read -P 0xa1 1M 1M")
+ self.run_qemu_io("hd1", "read -P 0 2M 1M")
+
+ # We can't remove the 'backing' option if the image has a
+ # default backing file
+ del opts[1]['backing']
+ self.reopen(opts[1], {}, "backing is missing for 'hd1'")
+
+ self.run_qemu_io("hd1", "read -P 0 0 1M")
+ self.run_qemu_io("hd1", "read -P 0xa1 1M 1M")
+ self.run_qemu_io("hd1", "read -P 0 2M 1M")
+
+ # This test verifies that we can't change the children of a block
+ # device during a reopen operation in a way that would create
+ # cycles in the node graph
+ def test_graph_cycles(self):
+ opts = []
+
+ # Open all three images without backing file
+ for i in range(3):
+ opts.append(hd_opts(i))
+ opts[i]['backing'] = None
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts[i])
+ self.assert_qmp(result, 'return', {})
+
+ # hd1 <- hd0, hd1 <- hd2
+ self.reopen(opts[0], {'backing': 'hd1'})
+ self.reopen(opts[2], {'backing': 'hd1'})
+
+ # Illegal: hd2 is backed by hd1
+ self.reopen(opts[1], {'backing': 'hd2'},
+ "Making 'hd2' a backing file of 'hd1' would create a cycle")
+
+ # hd1 <- hd0 <- hd2
+ self.reopen(opts[2], {'backing': 'hd0'})
+
+ # Illegal: hd2 is backed by hd0, which is backed by hd1
+ self.reopen(opts[1], {'backing': 'hd2'},
+ "Making 'hd2' a backing file of 'hd1' would create a cycle")
+
+ # Illegal: hd1 cannot point to itself
+ self.reopen(opts[1], {'backing': 'hd1'},
+ "Making 'hd1' a backing file of 'hd1' would create a cycle")
+
+ # Remove all backing files
+ self.reopen(opts[0])
+ self.reopen(opts[2])
+
+ ##########################################
+ # Add a blkverify node using hd0 and hd1 #
+ ##########################################
+ bvopts = {'driver': 'blkverify',
+ 'node-name': 'bv',
+ 'test': 'hd0',
+ 'raw': 'hd1'}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **bvopts)
+ self.assert_qmp(result, 'return', {})
+
+ # blkverify doesn't currently allow reopening. TODO: implement this
+ self.reopen(bvopts, {}, "Block format 'blkverify' used by node 'bv'" +
+ " does not support reopening files")
+
+ # Illegal: hd0 is a child of the blkverify node
+ self.reopen(opts[0], {'backing': 'bv'},
+ "Making 'bv' a backing file of 'hd0' would create a cycle")
+
+ # Delete the blkverify node
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'bv')
+ self.assert_qmp(result, 'return', {})
+
+ # Misc reopen tests with different block drivers
+ def test_misc_drivers(self):
+ ####################
+ ###### quorum ######
+ ####################
+ for i in range(3):
+ opts = hd_opts(i)
+ # Open all three images without backing file
+ opts['backing'] = None
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ opts = {'driver': 'quorum',
+ 'node-name': 'quorum0',
+ 'children': ['hd0', 'hd1', 'hd2'],
+ 'vote-threshold': 2}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # Quorum doesn't currently allow reopening. TODO: implement this
+ self.reopen(opts, {}, "Block format 'quorum' used by node 'quorum0'" +
+ " does not support reopening files")
+
+ # You can't make quorum0 a backing file of hd0:
+ # hd0 is already a child of quorum0.
+ self.reopen(hd_opts(0), {'backing': 'quorum0'},
+ "Making 'quorum0' a backing file of 'hd0' would create a cycle")
+
+ # Delete quorum0
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'quorum0')
+ self.assert_qmp(result, 'return', {})
+
+ # Delete hd0, hd1 and hd2
+ for i in range(3):
+ result = self.vm.qmp('blockdev-del', conv_keys = True,
+ node_name = 'hd%d' % i)
+ self.assert_qmp(result, 'return', {})
+
+ ######################
+ ###### blkdebug ######
+ ######################
+ opts = {'driver': 'blkdebug',
+ 'node-name': 'bd',
+ 'config': '/dev/null',
+ 'image': hd_opts(0)}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # blkdebug allows reopening if we keep the same options
+ self.reopen(opts)
+
+ # but it currently does not allow changes
+ self.reopen(opts, {'image': 'hd1'}, "Cannot change the option 'image'")
+ self.reopen(opts, {'align': 33554432}, "Cannot change the option 'align'")
+ self.reopen(opts, {'config': '/non/existent'}, "Cannot change the option 'config'")
+ del opts['config']
+ self.reopen(opts, {}, "Option 'config' cannot be reset to its default value")
+
+ # Delete the blkdebug node
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'bd')
+ self.assert_qmp(result, 'return', {})
+
+ ##################
+ ###### null ######
+ ##################
+ opts = {'driver': 'null-aio', 'node-name': 'root', 'size': 1024}
+
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # 1 << 30 is the default value, but we cannot change it explicitly
+ self.reopen(opts, {'size': (1 << 30)}, "Cannot change the option 'size'")
+
+ # We cannot change 'size' back to its default value either
+ del opts['size']
+ self.reopen(opts, {}, "Option 'size' cannot be reset to its default value")
+
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'root')
+ self.assert_qmp(result, 'return', {})
+
+ ##################
+ ###### file ######
+ ##################
+ opts = hd_opts(0)
+ opts['file']['locking'] = 'on'
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # 'locking' cannot be changed
+ del opts['file']['locking']
+ self.reopen(opts, {'file.locking': 'on'})
+ self.reopen(opts, {'file.locking': 'off'}, "Cannot change the option 'locking'")
+ self.reopen(opts, {}, "Option 'locking' cannot be reset to its default value")
+
+ # Trying to reopen the 'file' node directly does not make a difference
+ opts = opts['file']
+ self.reopen(opts, {'locking': 'on'})
+ self.reopen(opts, {'locking': 'off'}, "Cannot change the option 'locking'")
+ self.reopen(opts, {}, "Option 'locking' cannot be reset to its default value")
+
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+
+ ######################
+ ###### throttle ######
+ ######################
+ opts = { 'qom-type': 'throttle-group', 'id': 'group0',
+ 'props': { 'limits': { 'iops-total': 1000 } } }
+ result = self.vm.qmp('object-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ opts = { 'qom-type': 'throttle-group', 'id': 'group1',
+ 'props': { 'limits': { 'iops-total': 2000 } } }
+ result = self.vm.qmp('object-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # Add a throttle filter with group = group0
+ opts = { 'driver': 'throttle', 'node-name': 'throttle0',
+ 'throttle-group': 'group0', 'file': hd_opts(0) }
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # We can reopen it if we keep the same options
+ self.reopen(opts)
+
+ # We can also reopen if 'file' is a reference to the child
+ self.reopen(opts, {'file': 'hd0'})
+
+ # This is illegal
+ self.reopen(opts, {'throttle-group': 'notfound'}, "Throttle group 'notfound' does not exist")
+
+ # But it's possible to change the group to group1
+ self.reopen(opts, {'throttle-group': 'group1'})
+
+ # Now group1 is in use, it cannot be deleted
+ result = self.vm.qmp('object-del', id = 'group1')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc', "object 'group1' is in use, can not be deleted")
+
+ # Default options, this switches the group back to group0
+ self.reopen(opts)
+
+ # So now we cannot delete group0
+ result = self.vm.qmp('object-del', id = 'group0')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc', "object 'group0' is in use, can not be deleted")
+
+ # But group1 is free this time, and it can be deleted
+ result = self.vm.qmp('object-del', id = 'group1')
+ self.assert_qmp(result, 'return', {})
+
+ # Let's delete the filter node
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'throttle0')
+ self.assert_qmp(result, 'return', {})
+
+ # And we can finally get rid of group0
+ result = self.vm.qmp('object-del', id = 'group0')
+ self.assert_qmp(result, 'return', {})
+
+ # If an image has a backing file then the 'backing' option must be
+ # passed on reopen. We don't allow leaving the option out in this
+ # case because it's unclear what the correct semantics would be.
+ def test_missing_backing_options_1(self):
+ # hd2
+ opts = hd_opts(2)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # hd0
+ opts = hd_opts(0)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # hd0 has no backing file: we can omit the 'backing' option
+ self.reopen(opts)
+
+ # hd2 <- hd0
+ self.reopen(opts, {'backing': 'hd2'})
+
+ # hd0 has a backing file: we must set the 'backing' option
+ self.reopen(opts, {}, "backing is missing for 'hd0'")
+
+ # hd2 can't be removed because it's the backing file of hd0
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd2')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc', "Node 'hd2' is busy: node is used as backing hd of 'hd0'")
+
+ # Detach hd2 from hd0.
+ self.reopen(opts, {'backing': None})
+ self.reopen(opts, {}, "backing is missing for 'hd0'")
+
+ # Remove both hd0 and hd2
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd2')
+ self.assert_qmp(result, 'return', {})
+
+ # If an image has default backing file (as part of its metadata)
+ # then the 'backing' option must be passed on reopen. We don't
+ # allow leaving the option out in this case because it's unclear
+ # what the correct semantics would be.
+ def test_missing_backing_options_2(self):
+ # hd0 <- hd1
+ # (hd0 is hd1's default backing file)
+ opts = hd_opts(1)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # hd1 has a backing file: we can't omit the 'backing' option
+ self.reopen(opts, {}, "backing is missing for 'hd1'")
+
+ # Let's detach the backing file
+ self.reopen(opts, {'backing': None})
+
+ # No backing file attached to hd1 now, but we still can't omit the 'backing' option
+ self.reopen(opts, {}, "backing is missing for 'hd1'")
+
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1')
+ self.assert_qmp(result, 'return', {})
+
+ # Test that making 'backing' a reference to an existing child
+ # keeps its current options
+ def test_backing_reference(self):
+ # hd2 <- hd1 <- hd0
+ opts = hd_opts(0)
+ opts['backing'] = hd_opts(1)
+ opts['backing']['backing'] = hd_opts(2)
+ # Enable 'detect-zeroes' on all three nodes
+ opts['detect-zeroes'] = 'on'
+ opts['backing']['detect-zeroes'] = 'on'
+ opts['backing']['backing']['detect-zeroes'] = 'on'
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # Reopen the chain passing the minimum amount of required options.
+ # By making 'backing' a reference to hd1 (instead of a sub-dict)
+ # we tell QEMU to keep its current set of options.
+ opts = {'driver': iotests.imgfmt,
+ 'node-name': 'hd0',
+ 'file': 'hd0-file',
+ 'backing': 'hd1' }
+ self.reopen(opts)
+
+ # This has reset 'detect-zeroes' on hd0, but not on hd1 and hd2.
+ self.assert_qmp(self.get_node('hd0'), 'detect_zeroes', 'off')
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'on')
+ self.assert_qmp(self.get_node('hd2'), 'detect_zeroes', 'on')
+
+ # Test what happens if the graph changes due to other operations
+ # such as block-stream
+ def test_block_stream_1(self):
+ # hd1 <- hd0
+ opts = hd_opts(0)
+ opts['backing'] = hd_opts(1)
+ opts['backing']['backing'] = None
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # Stream hd1 into hd0 and wait until it's done
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0', device = 'hd0')
+ self.assert_qmp(result, 'return', {})
+ self.wait_until_completed(drive = 'stream0')
+
+ # Now we have only hd0
+ self.assertEqual(self.get_node('hd1'), None)
+
+ # We have backing.* options but there's no backing file anymore
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
+
+ # If we remove the 'backing' option then we can reopen hd0 just fine
+ del opts['backing']
+ self.reopen(opts)
+
+ # We can also reopen hd0 if we set 'backing' to null
+ self.reopen(opts, {'backing': None})
+
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+
+ # Another block_stream test
+ def test_block_stream_2(self):
+ # hd2 <- hd1 <- hd0
+ opts = hd_opts(0)
+ opts['backing'] = hd_opts(1)
+ opts['backing']['backing'] = hd_opts(2)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # Stream hd1 into hd0 and wait until it's done
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
+ device = 'hd0', base_node = 'hd2')
+ self.assert_qmp(result, 'return', {})
+ self.wait_until_completed(drive = 'stream0')
+
+ # The chain is hd2 <- hd0 now. hd1 is missing
+ self.assertEqual(self.get_node('hd1'), None)
+
+ # The backing options in the dict were meant for hd1, but we cannot
+ # use them with hd2 because hd1 had a backing file while hd2 does not.
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
+
+ # If we remove hd1's options from the dict then things work fine
+ opts['backing'] = opts['backing']['backing']
+ self.reopen(opts)
+
+ # We can also reopen hd0 if we use a reference to the backing file
+ self.reopen(opts, {'backing': 'hd2'})
+
+ # But we cannot leave the option out
+ del opts['backing']
+ self.reopen(opts, {}, "backing is missing for 'hd0'")
+
+ # Now we can delete hd0 (and hd2)
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
+ self.assert_qmp(result, 'return', {})
+ self.assertEqual(self.get_node('hd2'), None)
+
+ # Reopen the chain during a block-stream job (from hd1 to hd0)
+ def test_block_stream_3(self):
+ # hd2 <- hd1 <- hd0
+ opts = hd_opts(0)
+ opts['backing'] = hd_opts(1)
+ opts['backing']['backing'] = hd_opts(2)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # hd2 <- hd0
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
+ device = 'hd0', base_node = 'hd2', speed = 512 * 1024)
+ self.assert_qmp(result, 'return', {})
+
+ # We can't remove hd2 while the stream job is ongoing
+ opts['backing']['backing'] = None
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd1' to 'hd2'")
+
+ # We can't remove hd1 while the stream job is ongoing
+ opts['backing'] = None
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
+
+ self.wait_until_completed(drive = 'stream0')
+
+ # Reopen the chain during a block-stream job (from hd2 to hd1)
+ def test_block_stream_4(self):
+ # hd2 <- hd1 <- hd0
+ opts = hd_opts(0)
+ opts['backing'] = hd_opts(1)
+ opts['backing']['backing'] = hd_opts(2)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # hd1 <- hd0
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
+ device = 'hd1', speed = 512 * 1024)
+ self.assert_qmp(result, 'return', {})
+
+ # We can't reopen with the original options because that would
+ # make hd1 read-only and block-stream requires it to be read-write
+ self.reopen(opts, {}, "Can't set node 'hd1' to r/o with copy-on-read enabled")
+
+ # We can't remove hd2 while the stream job is ongoing
+ opts['backing']['backing'] = None
+ self.reopen(opts, {'backing.read-only': False}, "Cannot change 'backing' link from 'hd1' to 'hd2'")
+
+ # We can detach hd1 from hd0 because it doesn't affect the stream job
+ opts['backing'] = None
+ self.reopen(opts)
+
+ self.wait_until_completed(drive = 'stream0')
+
+ # Reopen the chain during a block-commit job (from hd0 to hd2)
+ def test_block_commit_1(self):
+ # hd2 <- hd1 <- hd0
+ opts = hd_opts(0)
+ opts['backing'] = hd_opts(1)
+ opts['backing']['backing'] = hd_opts(2)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
+ device = 'hd0', speed = 1024 * 1024)
+ self.assert_qmp(result, 'return', {})
+
+ # We can't remove hd2 while the commit job is ongoing
+ opts['backing']['backing'] = None
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd1' to 'hd2'")
+
+ # We can't remove hd1 while the commit job is ongoing
+ opts['backing'] = None
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
+
+ event = self.vm.event_wait(name='BLOCK_JOB_READY')
+ self.assert_qmp(event, 'data/device', 'commit0')
+ self.assert_qmp(event, 'data/type', 'commit')
+ self.assert_qmp_absent(event, 'data/error')
+
+ result = self.vm.qmp('block-job-complete', device='commit0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_until_completed(drive = 'commit0')
+
+ # Reopen the chain during a block-commit job (from hd1 to hd2)
+ def test_block_commit_2(self):
+ # hd2 <- hd1 <- hd0
+ opts = hd_opts(0)
+ opts['backing'] = hd_opts(1)
+ opts['backing']['backing'] = hd_opts(2)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
+ device = 'hd0', top_node = 'hd1', speed = 1024 * 1024)
+ self.assert_qmp(result, 'return', {})
+
+ # We can't remove hd2 while the commit job is ongoing
+ opts['backing']['backing'] = None
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
+
+ # We can't remove hd1 while the commit job is ongoing
+ opts['backing'] = None
+ self.reopen(opts, {}, "Cannot change backing link if 'hd0' has an implicit backing file")
+
+ # hd2 <- hd0
+ self.wait_until_completed(drive = 'commit0')
+
+ self.assert_qmp(self.get_node('hd0'), 'ro', False)
+ self.assertEqual(self.get_node('hd1'), None)
+ self.assert_qmp(self.get_node('hd2'), 'ro', True)
+
+ # We don't allow setting a backing file that uses a different AioContext
+ def test_iothreads(self):
+ opts = hd_opts(0)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ opts2 = hd_opts(2)
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('object-add', qom_type='iothread', id='iothread0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('object-add', qom_type='iothread', id='iothread1')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('x-blockdev-set-iothread', node_name='hd0', iothread='iothread0')
+ self.assert_qmp(result, 'return', {})
+
+ self.reopen(opts, {'backing': 'hd2'}, "Cannot use a new backing file with a different AioContext")
+
+ result = self.vm.qmp('x-blockdev-set-iothread', node_name='hd2', iothread='iothread1')
+ self.assert_qmp(result, 'return', {})
+
+ self.reopen(opts, {'backing': 'hd2'}, "Cannot use a new backing file with a different AioContext")
+
+ result = self.vm.qmp('x-blockdev-set-iothread', node_name='hd2', iothread='iothread0')
+ self.assert_qmp(result, 'return', {})
+
+ self.reopen(opts, {'backing': 'hd2'})
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=["qcow2"])
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
new file mode 100644
index 0000000000..71009c239f
--- /dev/null
+++ b/tests/qemu-iotests/245.out
@@ -0,0 +1,5 @@
+..................
+----------------------------------------------------------------------
+Ran 18 tests
+
+OK
diff --git a/tests/qemu-iotests/246 b/tests/qemu-iotests/246
new file mode 100755
index 0000000000..b0997a392f
--- /dev/null
+++ b/tests/qemu-iotests/246
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+#
+# Test persistent bitmap resizing.
+#
+# Copyright (c) 2019 John Snow for Red Hat, Inc.
+#
+# 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/>.
+#
+# owner=jsnow@redhat.com
+
+import iotests
+from iotests import log
+
+iotests.verify_image_format(supported_fmts=['qcow2'])
+size = 64 * 1024 * 1024 * 1024
+gran_small = 32 * 1024
+gran_large = 128 * 1024
+
+def query_bitmaps(vm):
+ res = vm.qmp("query-block")
+ return { "bitmaps": { device['device']: device.get('dirty-bitmaps', []) for
+ device in res['return'] } }
+
+with iotests.FilePath('img') as img_path, \
+ iotests.VM() as vm:
+
+ log('--- Preparing image & VM ---\n')
+ iotests.qemu_img_create('-f', iotests.imgfmt, img_path, str(size))
+ vm.add_drive(img_path)
+
+
+ log('--- 1st Boot (Establish Baseline Image) ---\n')
+ vm.launch()
+
+ log('\n--- Adding bitmaps Small, Medium, Large, and Transient ---\n')
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="Small", granularity=gran_small, persistent=True)
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="Medium", persistent=True)
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="Large", granularity=gran_large, persistent=True)
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="Transient", persistent=False)
+
+ log('--- Forcing flush of bitmaps to disk ---\n')
+ log(query_bitmaps(vm), indent=2)
+ vm.shutdown()
+
+
+ log('--- 2nd Boot (Grow Image) ---\n')
+ vm.launch()
+ log(query_bitmaps(vm), indent=2)
+
+ log('--- Adding new bitmap, growing image, and adding 2nd new bitmap ---')
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="New", persistent=True)
+ vm.qmp_log("human-monitor-command",
+ command_line="block_resize drive0 70G")
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="Newtwo", persistent=True)
+ log(query_bitmaps(vm), indent=2)
+
+ log('--- Forcing flush of bitmaps to disk ---\n')
+ vm.shutdown()
+
+
+ log('--- 3rd Boot (Shrink Image) ---\n')
+ vm.launch()
+ log(query_bitmaps(vm), indent=2)
+
+ log('--- Adding "NewB" bitmap, removing "New" bitmap ---')
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="NewB", persistent=True)
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0",
+ name="New")
+
+ log('--- Truncating image ---\n')
+ vm.qmp_log("human-monitor-command",
+ command_line="block_resize drive0 50G")
+
+ log('--- Adding "NewC" bitmap, removing "NewTwo" bitmap ---')
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="NewC", persistent=True)
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Newtwo")
+
+ log('--- Forcing flush of bitmaps to disk ---\n')
+ vm.shutdown()
+
+
+ log('--- 4th Boot (Verification and Cleanup) ---\n')
+ vm.launch()
+ log(query_bitmaps(vm), indent=2)
+
+ log('--- Removing all Bitmaps ---\n')
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Small")
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Medium")
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Large")
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="NewB")
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="NewC")
+ log(query_bitmaps(vm), indent=2)
+
+ log('\n--- Done ---')
+ vm.shutdown()
diff --git a/tests/qemu-iotests/246.out b/tests/qemu-iotests/246.out
new file mode 100644
index 0000000000..6671a11fdd
--- /dev/null
+++ b/tests/qemu-iotests/246.out
@@ -0,0 +1,295 @@
+--- Preparing image & VM ---
+
+--- 1st Boot (Establish Baseline Image) ---
+
+
+--- Adding bitmaps Small, Medium, Large, and Transient ---
+
+{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 32768, "name": "Small", "node": "drive0", "persistent": true}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-add", "arguments": {"name": "Medium", "node": "drive0", "persistent": true}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 131072, "name": "Large", "node": "drive0", "persistent": true}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-add", "arguments": {"name": "Transient", "node": "drive0", "persistent": false}}
+{"return": {}}
+--- Forcing flush of bitmaps to disk ---
+
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Transient",
+ "persistent": false,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 131072,
+ "name": "Large",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Medium",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 32768,
+ "name": "Small",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ }
+ ]
+ }
+}
+--- 2nd Boot (Grow Image) ---
+
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 32768,
+ "name": "Small",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Medium",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 131072,
+ "name": "Large",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ }
+ ]
+ }
+}
+--- Adding new bitmap, growing image, and adding 2nd new bitmap ---
+{"execute": "block-dirty-bitmap-add", "arguments": {"name": "New", "node": "drive0", "persistent": true}}
+{"return": {}}
+{"execute": "human-monitor-command", "arguments": {"command-line": "block_resize drive0 70G"}}
+{"return": ""}
+{"execute": "block-dirty-bitmap-add", "arguments": {"name": "Newtwo", "node": "drive0", "persistent": true}}
+{"return": {}}
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Newtwo",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "New",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 32768,
+ "name": "Small",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Medium",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 131072,
+ "name": "Large",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ }
+ ]
+ }
+}
+--- Forcing flush of bitmaps to disk ---
+
+--- 3rd Boot (Shrink Image) ---
+
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "New",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Newtwo",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 32768,
+ "name": "Small",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Medium",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 131072,
+ "name": "Large",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ }
+ ]
+ }
+}
+--- Adding "NewB" bitmap, removing "New" bitmap ---
+{"execute": "block-dirty-bitmap-add", "arguments": {"name": "NewB", "node": "drive0", "persistent": true}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "New", "node": "drive0"}}
+{"return": {}}
+--- Truncating image ---
+
+{"execute": "human-monitor-command", "arguments": {"command-line": "block_resize drive0 50G"}}
+{"return": ""}
+--- Adding "NewC" bitmap, removing "NewTwo" bitmap ---
+{"execute": "block-dirty-bitmap-add", "arguments": {"name": "NewC", "node": "drive0", "persistent": true}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Newtwo", "node": "drive0"}}
+{"return": {}}
+--- Forcing flush of bitmaps to disk ---
+
+--- 4th Boot (Verification and Cleanup) ---
+
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "NewB",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "NewC",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 32768,
+ "name": "Small",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 65536,
+ "name": "Medium",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ },
+ {
+ "busy": false,
+ "count": 0,
+ "granularity": 131072,
+ "name": "Large",
+ "persistent": true,
+ "recording": true,
+ "status": "active"
+ }
+ ]
+ }
+}
+--- Removing all Bitmaps ---
+
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Small", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Medium", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Large", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "NewB", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "NewC", "node": "drive0"}}
+{"return": {}}
+{
+ "bitmaps": {
+ "drive0": []
+ }
+}
+
+--- Done ---
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 36100b803c..7289309604 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -243,3 +243,5 @@
242 rw auto quick
243 rw auto quick
244 rw auto quick
+245 rw auto
+246 rw auto quick
diff --git a/tests/test-announce-self.c b/tests/test-announce-self.c
index 1644d34a3f..0e6d466aa4 100644
--- a/tests/test-announce-self.c
+++ b/tests/test-announce-self.c
@@ -21,18 +21,8 @@
#define ETH_P_RARP 0x8035
#endif
-static QTestState *test_init(int socket)
-{
- char *args;
-
- args = g_strdup_printf("-netdev socket,fd=%d,id=hs0 -device "
- "virtio-net-pci,netdev=hs0", socket);
-
- return qtest_start(args);
-}
-
-static void test_announce(int socket)
+static void test_announce(QTestState *qs, int socket)
{
char buffer[60];
int len;
@@ -40,7 +30,7 @@ static void test_announce(int socket)
int ret;
uint16_t *proto = (uint16_t *)&buffer[12];
- rsp = qmp("{ 'execute' : 'announce-self', "
+ rsp = qtest_qmp(qs, "{ 'execute' : 'announce-self', "
" 'arguments': {"
" 'initial': 50, 'max': 550,"
" 'rounds': 10, 'step': 50 } }");
@@ -59,14 +49,15 @@ static void test_announce(int socket)
static void setup(gconstpointer data)
{
QTestState *qs;
- void (*func) (int socket) = data;
+ void (*func) (QTestState *qs, int socket) = data;
int sv[2], ret;
ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
g_assert_cmpint(ret, !=, -1);
- qs = test_init(sv[1]);
- func(sv[0]);
+ qs = qtest_initf("-netdev socket,fd=%d,id=hs0 -device "
+ "virtio-net-pci,netdev=hs0", sv[1]);
+ func(qs, sv[0]);
/* End test */
close(sv[0]);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 0c965b3b1e..3817966010 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -178,7 +178,8 @@ static void append_mem_opts(TestServer *server, GString *cmd_line,
int size, enum test_memfd memfd)
{
if (memfd == TEST_MEMFD_AUTO) {
- memfd = qemu_memfd_check(0) ? TEST_MEMFD_YES : TEST_MEMFD_NO;
+ memfd = qemu_memfd_check(MFD_ALLOW_SEALING) ? TEST_MEMFD_YES
+ : TEST_MEMFD_NO;
}
if (memfd == TEST_MEMFD_YES) {
@@ -930,7 +931,7 @@ static void register_vhost_user_test(void)
"virtio-net",
test_read_guest_mem, &opts);
- if (qemu_memfd_check(0)) {
+ if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
opts.before = vhost_user_test_setup_memfd;
qos_add_test("vhost-user/read-guest-mem/memfd",
"virtio-net",
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index b02be0274e..b65365934b 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -751,7 +751,7 @@ static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
char *tmp_path = drive_create();
g_string_append_printf(cmd_line,
- " -drive if=none,id=drive0,file=%s,format=raw "
+ " -drive if=none,id=drive0,file=%s,format=raw,auto-read-only=off "
"-drive if=none,id=drive1,file=null-co://,format=raw ",
tmp_path);
diff --git a/thunk.c b/thunk.c
index 17f3d320bb..7f31cffe09 100644
--- a/thunk.c
+++ b/thunk.c
@@ -86,7 +86,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types)
#endif
/* now we can alloc the data */
- for(i = 0;i < 2; i++) {
+ for (i = 0; i < ARRAY_SIZE(se->field_offsets); i++) {
offset = 0;
max_align = 1;
se->field_offsets[i] = g_new(int, nb_fields);
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index fe1a7aed97..cc2bf5b180 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -46,8 +46,8 @@ endif
common-obj-$(CONFIG_CURSES) += curses.mo
curses.mo-objs := curses.o
-curses.mo-cflags := $(CURSES_CFLAGS)
-curses.mo-libs := $(CURSES_LIBS)
+curses.mo-cflags := $(CURSES_CFLAGS) $(ICONV_CFLAGS)
+curses.mo-libs := $(CURSES_LIBS) $(ICONV_LIBS)
common-obj-$(call land,$(CONFIG_SPICE),$(CONFIG_GIO)) += spice-app.mo
spice-app.mo-objs := spice-app.o
diff --git a/ui/curses.c b/ui/curses.c
index 37954ce1b0..3a7e8649f3 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -27,6 +27,10 @@
#include <sys/ioctl.h>
#include <termios.h>
#endif
+#include <locale.h>
+#include <wchar.h>
+#include <langinfo.h>
+#include <iconv.h>
#include "qapi/error.h"
#include "qemu-common.h"
@@ -54,25 +58,30 @@ static WINDOW *screenpad = NULL;
static int width, height, gwidth, gheight, invalidate;
static int px, py, sminx, sminy, smaxx, smaxy;
-static chtype vga_to_curses[256];
+static const char *font_charset = "CP437";
+static cchar_t vga_to_curses[256];
static void curses_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
console_ch_t *line;
- chtype curses_line[width];
+ cchar_t curses_line[width];
line = screen + y * width;
for (h += y; y < h; y ++, line += width) {
for (x = 0; x < width; x++) {
chtype ch = line[x] & 0xff;
chtype at = line[x] & ~0xff;
- if (vga_to_curses[ch]) {
- ch = vga_to_curses[ch];
+ if (vga_to_curses[ch].chars[0]) {
+ curses_line[x] = vga_to_curses[ch];
+ } else {
+ curses_line[x].chars[0] = ch;
+ curses_line[x].chars[1] = 0;
+ curses_line[x].attr = 0;
}
- curses_line[x] = ch | at;
+ curses_line[x].attr |= at;
}
- mvwaddchnstr(screenpad, y, 0, curses_line, width);
+ mvwadd_wchnstr(screenpad, y, 0, curses_line, width);
}
pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
@@ -391,6 +400,254 @@ static void curses_atexit(void)
endwin();
}
+/* Setup wchar glyph for one UCS-2 char */
+static void convert_ucs(int glyph, uint16_t ch, iconv_t conv)
+{
+ wchar_t wch;
+ char *pch, *pwch;
+ size_t sch, swch;
+
+ pch = (char *) &ch;
+ pwch = (char *) &wch;
+ sch = sizeof(ch);
+ swch = sizeof(wch);
+
+ if (iconv(conv, &pch, &sch, &pwch, &swch) == (size_t) -1) {
+ fprintf(stderr, "Could not convert 0x%04x from UCS-2 to WCHAR_T: %s\n",
+ ch, strerror(errno));
+ } else {
+ vga_to_curses[glyph].chars[0] = wch;
+ }
+}
+
+/* Setup wchar glyph for one font character */
+static void convert_font(unsigned char ch, iconv_t conv)
+{
+ wchar_t wch;
+ char *pch, *pwch;
+ size_t sch, swch;
+
+ pch = (char *) &ch;
+ pwch = (char *) &wch;
+ sch = sizeof(ch);
+ swch = sizeof(wch);
+
+ if (iconv(conv, &pch, &sch, &pwch, &swch) == (size_t) -1) {
+ fprintf(stderr, "Could not convert 0x%02x from %s to WCHAR_T: %s\n",
+ ch, font_charset, strerror(errno));
+ } else {
+ vga_to_curses[ch].chars[0] = wch;
+ }
+}
+
+/* Convert one wchar to UCS-2 */
+static uint16_t get_ucs(wchar_t wch, iconv_t conv)
+{
+ uint16_t ch;
+ char *pch, *pwch;
+ size_t sch, swch;
+
+ pch = (char *) &ch;
+ pwch = (char *) &wch;
+ sch = sizeof(ch);
+ swch = sizeof(wch);
+
+ if (iconv(conv, &pwch, &swch, &pch, &sch) == (size_t) -1) {
+ fprintf(stderr, "Could not convert 0x%02x from WCHAR_T to UCS-2: %s\n",
+ wch, strerror(errno));
+ return 0xFFFD;
+ }
+
+ return ch;
+}
+
+/*
+ * Setup mapping for vga to curses line graphics.
+ */
+static void font_setup(void)
+{
+ /*
+ * Control characters are normally non-printable, but VGA does have
+ * well-known glyphs for them.
+ */
+ static uint16_t control_characters[0x20] = {
+ 0x0020,
+ 0x263a,
+ 0x263b,
+ 0x2665,
+ 0x2666,
+ 0x2663,
+ 0x2660,
+ 0x2022,
+ 0x25d8,
+ 0x25cb,
+ 0x25d9,
+ 0x2642,
+ 0x2640,
+ 0x266a,
+ 0x266b,
+ 0x263c,
+ 0x25ba,
+ 0x25c4,
+ 0x2195,
+ 0x203c,
+ 0x00b6,
+ 0x00a7,
+ 0x25ac,
+ 0x21a8,
+ 0x2191,
+ 0x2193,
+ 0x2192,
+ 0x2190,
+ 0x221f,
+ 0x2194,
+ 0x25b2,
+ 0x25bc
+ };
+
+ iconv_t ucs_to_wchar_conv;
+ iconv_t wchar_to_ucs_conv;
+ iconv_t font_conv;
+ int i;
+
+ ucs_to_wchar_conv = iconv_open("WCHAR_T", "UCS-2");
+ if (ucs_to_wchar_conv == (iconv_t) -1) {
+ fprintf(stderr, "Could not convert font glyphs from UCS-2: '%s'\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ wchar_to_ucs_conv = iconv_open("UCS-2", "WCHAR_T");
+ if (wchar_to_ucs_conv == (iconv_t) -1) {
+ fprintf(stderr, "Could not convert font glyphs to UCS-2: '%s'\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ font_conv = iconv_open("WCHAR_T", font_charset);
+ if (font_conv == (iconv_t) -1) {
+ fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n",
+ font_charset, strerror(errno));
+ exit(1);
+ }
+
+ /* Control characters */
+ for (i = 0; i <= 0x1F; i++) {
+ convert_ucs(i, control_characters[i], ucs_to_wchar_conv);
+ }
+
+ for (i = 0x20; i <= 0xFF; i++) {
+ convert_font(i, font_conv);
+ }
+
+ /* DEL */
+ convert_ucs(0x7F, 0x2302, ucs_to_wchar_conv);
+
+ if (strcmp(nl_langinfo(CODESET), "UTF-8")) {
+ /* Non-Unicode capable, use termcap equivalents for those available */
+ for (i = 0; i <= 0xFF; i++) {
+ switch (get_ucs(vga_to_curses[i].chars[0], wchar_to_ucs_conv)) {
+ case 0x00a3:
+ vga_to_curses[i] = *WACS_STERLING;
+ break;
+ case 0x2591:
+ vga_to_curses[i] = *WACS_BOARD;
+ break;
+ case 0x2592:
+ vga_to_curses[i] = *WACS_CKBOARD;
+ break;
+ case 0x2502:
+ vga_to_curses[i] = *WACS_VLINE;
+ break;
+ case 0x2524:
+ vga_to_curses[i] = *WACS_RTEE;
+ break;
+ case 0x2510:
+ vga_to_curses[i] = *WACS_URCORNER;
+ break;
+ case 0x2514:
+ vga_to_curses[i] = *WACS_LLCORNER;
+ break;
+ case 0x2534:
+ vga_to_curses[i] = *WACS_BTEE;
+ break;
+ case 0x252c:
+ vga_to_curses[i] = *WACS_TTEE;
+ break;
+ case 0x251c:
+ vga_to_curses[i] = *WACS_LTEE;
+ break;
+ case 0x2500:
+ vga_to_curses[i] = *WACS_HLINE;
+ break;
+ case 0x253c:
+ vga_to_curses[i] = *WACS_PLUS;
+ break;
+ case 0x256c:
+ vga_to_curses[i] = *WACS_LANTERN;
+ break;
+ case 0x256a:
+ vga_to_curses[i] = *WACS_NEQUAL;
+ break;
+ case 0x2518:
+ vga_to_curses[i] = *WACS_LRCORNER;
+ break;
+ case 0x250c:
+ vga_to_curses[i] = *WACS_ULCORNER;
+ break;
+ case 0x2588:
+ vga_to_curses[i] = *WACS_BLOCK;
+ break;
+ case 0x03c0:
+ vga_to_curses[i] = *WACS_PI;
+ break;
+ case 0x00b1:
+ vga_to_curses[i] = *WACS_PLMINUS;
+ break;
+ case 0x2265:
+ vga_to_curses[i] = *WACS_GEQUAL;
+ break;
+ case 0x2264:
+ vga_to_curses[i] = *WACS_LEQUAL;
+ break;
+ case 0x00b0:
+ vga_to_curses[i] = *WACS_DEGREE;
+ break;
+ case 0x25a0:
+ vga_to_curses[i] = *WACS_BULLET;
+ break;
+ case 0x2666:
+ vga_to_curses[i] = *WACS_DIAMOND;
+ break;
+ case 0x2192:
+ vga_to_curses[i] = *WACS_RARROW;
+ break;
+ case 0x2190:
+ vga_to_curses[i] = *WACS_LARROW;
+ break;
+ case 0x2191:
+ vga_to_curses[i] = *WACS_UARROW;
+ break;
+ case 0x2193:
+ vga_to_curses[i] = *WACS_DARROW;
+ break;
+ case 0x23ba:
+ vga_to_curses[i] = *WACS_S1;
+ break;
+ case 0x23bb:
+ vga_to_curses[i] = *WACS_S3;
+ break;
+ case 0x23bc:
+ vga_to_curses[i] = *WACS_S7;
+ break;
+ case 0x23bd:
+ vga_to_curses[i] = *WACS_S9;
+ break;
+ }
+ }
+ }
+}
+
static void curses_setup(void)
{
int i, colour_default[8] = {
@@ -420,47 +677,7 @@ static void curses_setup(void)
init_pair(i, COLOR_WHITE, COLOR_BLACK);
}
- /*
- * Setup mapping for vga to curses line graphics.
- * FIXME: for better font, have to use ncursesw and setlocale()
- */
-#if 0
- /* FIXME: map from where? */
- ACS_S1;
- ACS_S3;
- ACS_S7;
- ACS_S9;
-#endif
- /* ACS_* is not constant. So, we can't initialize statically. */
- vga_to_curses['\0'] = ' ';
- vga_to_curses[0x04] = ACS_DIAMOND;
- vga_to_curses[0x18] = ACS_UARROW;
- vga_to_curses[0x19] = ACS_DARROW;
- vga_to_curses[0x1a] = ACS_RARROW;
- vga_to_curses[0x1b] = ACS_LARROW;
- vga_to_curses[0x9c] = ACS_STERLING;
- vga_to_curses[0xb0] = ACS_BOARD;
- vga_to_curses[0xb1] = ACS_CKBOARD;
- vga_to_curses[0xb3] = ACS_VLINE;
- vga_to_curses[0xb4] = ACS_RTEE;
- vga_to_curses[0xbf] = ACS_URCORNER;
- vga_to_curses[0xc0] = ACS_LLCORNER;
- vga_to_curses[0xc1] = ACS_BTEE;
- vga_to_curses[0xc2] = ACS_TTEE;
- vga_to_curses[0xc3] = ACS_LTEE;
- vga_to_curses[0xc4] = ACS_HLINE;
- vga_to_curses[0xc5] = ACS_PLUS;
- vga_to_curses[0xce] = ACS_LANTERN;
- vga_to_curses[0xd8] = ACS_NEQUAL;
- vga_to_curses[0xd9] = ACS_LRCORNER;
- vga_to_curses[0xda] = ACS_ULCORNER;
- vga_to_curses[0xdb] = ACS_BLOCK;
- vga_to_curses[0xe3] = ACS_PI;
- vga_to_curses[0xf1] = ACS_PLMINUS;
- vga_to_curses[0xf2] = ACS_GEQUAL;
- vga_to_curses[0xf3] = ACS_LEQUAL;
- vga_to_curses[0xf8] = ACS_DEGREE;
- vga_to_curses[0xfe] = ACS_BULLET;
+ font_setup();
}
static void curses_keyboard_setup(void)
@@ -493,6 +710,10 @@ static void curses_display_init(DisplayState *ds, DisplayOptions *opts)
}
#endif
+ setlocale(LC_CTYPE, "");
+ if (opts->u.curses.charset) {
+ font_charset = opts->u.curses.charset;
+ }
curses_setup();
curses_keyboard_setup();
atexit(curses_atexit);
diff --git a/ui/vnc.c b/ui/vnc.c
index 2d9e8f43b0..1871422e1d 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1019,16 +1019,16 @@ static void vnc_update_throttle_offset(VncState *vs)
int bps;
switch (vs->as.fmt) {
default:
- case AUD_FMT_U8:
- case AUD_FMT_S8:
+ case AUDIO_FORMAT_U8:
+ case AUDIO_FORMAT_S8:
bps = 1;
break;
- case AUD_FMT_U16:
- case AUD_FMT_S16:
+ case AUDIO_FORMAT_U16:
+ case AUDIO_FORMAT_S16:
bps = 2;
break;
- case AUD_FMT_U32:
- case AUD_FMT_S32:
+ case AUDIO_FORMAT_U32:
+ case AUDIO_FORMAT_S32:
bps = 4;
break;
}
@@ -2375,12 +2375,12 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
if (len == 4)
return 10;
switch (read_u8(data, 4)) {
- case 0: vs->as.fmt = AUD_FMT_U8; break;
- case 1: vs->as.fmt = AUD_FMT_S8; break;
- case 2: vs->as.fmt = AUD_FMT_U16; break;
- case 3: vs->as.fmt = AUD_FMT_S16; break;
- case 4: vs->as.fmt = AUD_FMT_U32; break;
- case 5: vs->as.fmt = AUD_FMT_S32; break;
+ case 0: vs->as.fmt = AUDIO_FORMAT_U8; break;
+ case 1: vs->as.fmt = AUDIO_FORMAT_S8; break;
+ case 2: vs->as.fmt = AUDIO_FORMAT_U16; break;
+ case 3: vs->as.fmt = AUDIO_FORMAT_S16; break;
+ case 4: vs->as.fmt = AUDIO_FORMAT_U32; break;
+ case 5: vs->as.fmt = AUDIO_FORMAT_S32; break;
default:
VNC_DEBUG("Invalid audio format %d\n", read_u8(data, 4));
vnc_client_error(vs);
@@ -3111,7 +3111,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
vs->as.freq = 44100;
vs->as.nchannels = 2;
- vs->as.fmt = AUD_FMT_S16;
+ vs->as.fmt = AUDIO_FORMAT_S16;
vs->as.endianness = 0;
qemu_mutex_init(&vs->output_mutex);
diff --git a/util/memfd.c b/util/memfd.c
index 8debd0d037..00334e5b21 100644
--- a/util/memfd.c
+++ b/util/memfd.c
@@ -40,6 +40,7 @@ static int memfd_create(const char *name, unsigned int flags)
#ifdef __NR_memfd_create
return syscall(__NR_memfd_create, name, flags);
#else
+ errno = ENOSYS;
return -1;
#endif
}
@@ -70,14 +71,18 @@ int qemu_memfd_create(const char *name, size_t size, bool hugetlb,
}
mfd = memfd_create(name, flags);
if (mfd < 0) {
+ error_setg_errno(errp, errno,
+ "failed to create memfd with flags 0x%x", flags);
goto err;
}
if (ftruncate(mfd, size) == -1) {
+ error_setg_errno(errp, errno, "failed to resize memfd to %zu", size);
goto err;
}
if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) {
+ error_setg_errno(errp, errno, "failed to add seals 0x%x", seals);
goto err;
}
@@ -87,8 +92,9 @@ err:
if (mfd >= 0) {
close(mfd);
}
+#else
+ error_setg_errno(errp, ENOSYS, "failed to create memfd");
#endif
- error_setg_errno(errp, errno, "failed to create memfd");
return -1;
}
@@ -188,7 +194,7 @@ bool qemu_memfd_alloc_check(void)
bool qemu_memfd_check(unsigned int flags)
{
#ifdef CONFIG_LINUX
- int mfd = memfd_create("test", flags);
+ int mfd = memfd_create("test", flags | MFD_CLOEXEC);
if (mfd >= 0) {
close(mfd);
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 326d92dcd2..88dda9cd39 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -512,6 +512,59 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
}
}
+uint64_t qemu_get_pmem_size(const char *filename, Error **errp)
+{
+ struct stat st;
+
+ if (stat(filename, &st) < 0) {
+ error_setg(errp, "unable to stat pmem file \"%s\"", filename);
+ return 0;
+ }
+
+#if defined(__linux__)
+ /* Special handling for devdax character devices */
+ if (S_ISCHR(st.st_mode)) {
+ char *subsystem_path = NULL;
+ char *subsystem = NULL;
+ char *size_path = NULL;
+ char *size_str = NULL;
+ uint64_t ret = 0;
+
+ subsystem_path = g_strdup_printf("/sys/dev/char/%d:%d/subsystem",
+ major(st.st_rdev), minor(st.st_rdev));
+ subsystem = g_file_read_link(subsystem_path, NULL);
+ if (!subsystem) {
+ error_setg(errp, "unable to read subsystem for pmem file \"%s\"",
+ filename);
+ goto devdax_err;
+ }
+
+ if (!g_str_has_suffix(subsystem, "/dax")) {
+ error_setg(errp, "pmem file \"%s\" is not a dax device", filename);
+ goto devdax_err;
+ }
+
+ size_path = g_strdup_printf("/sys/dev/char/%d:%d/size",
+ major(st.st_rdev), minor(st.st_rdev));
+ if (!g_file_get_contents(size_path, &size_str, NULL, NULL)) {
+ error_setg(errp, "unable to read size for pmem file \"%s\"",
+ size_path);
+ goto devdax_err;
+ }
+
+ ret = g_ascii_strtoull(size_str, NULL, 0);
+
+devdax_err:
+ g_free(size_str);
+ g_free(size_path);
+ g_free(subsystem);
+ g_free(subsystem_path);
+ return ret;
+ }
+#endif /* defined(__linux__) */
+
+ return st.st_size;
+}
char *qemu_get_pid_name(pid_t pid)
{
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index b4c17f5dfa..bd633afab6 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -560,6 +560,11 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
}
}
+uint64_t qemu_get_pmem_size(const char *filename, Error **errp)
+{
+ error_setg(errp, "pmem support not available");
+ return 0;
+}
char *qemu_get_pid_name(pid_t pid)
{
diff --git a/vl.c b/vl.c
index f46f8d769a..c1d5484e12 100644
--- a/vl.c
+++ b/vl.c
@@ -185,7 +185,6 @@ const char *prom_envs[MAX_PROM_ENVS];
int boot_menu;
bool boot_strict;
uint8_t *boot_splash_filedata;
-size_t boot_splash_filedata_size;
bool wakeup_suspend_enabled;
int icount_align_option;
@@ -1191,6 +1190,55 @@ static void default_drive(int enable, int snapshot, BlockInterfaceType type,
}
+typedef struct BlockdevOptionsQueueEntry {
+ BlockdevOptions *bdo;
+ Location loc;
+ QSIMPLEQ_ENTRY(BlockdevOptionsQueueEntry) entry;
+} BlockdevOptionsQueueEntry;
+
+typedef QSIMPLEQ_HEAD(, BlockdevOptionsQueueEntry) BlockdevOptionsQueue;
+
+static void configure_blockdev(BlockdevOptionsQueue *bdo_queue,
+ MachineClass *machine_class, int snapshot)
+{
+ /*
+ * If the currently selected machine wishes to override the
+ * units-per-bus property of its default HBA interface type, do so
+ * now.
+ */
+ if (machine_class->units_per_default_bus) {
+ override_max_devs(machine_class->block_default_type,
+ machine_class->units_per_default_bus);
+ }
+
+ /* open the virtual block devices */
+ while (!QSIMPLEQ_EMPTY(bdo_queue)) {
+ BlockdevOptionsQueueEntry *bdo = QSIMPLEQ_FIRST(bdo_queue);
+
+ QSIMPLEQ_REMOVE_HEAD(bdo_queue, entry);
+ loc_push_restore(&bdo->loc);
+ qmp_blockdev_add(bdo->bdo, &error_fatal);
+ loc_pop(&bdo->loc);
+ qapi_free_BlockdevOptions(bdo->bdo);
+ g_free(bdo);
+ }
+ if (snapshot || replay_mode != REPLAY_MODE_NONE) {
+ qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
+ NULL, NULL);
+ }
+ if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
+ &machine_class->block_default_type, &error_fatal)) {
+ /* We printed help */
+ exit(0);
+ }
+
+ default_drive(default_cdrom, snapshot, machine_class->block_default_type, 2,
+ CDROM_OPTS);
+ default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS);
+ default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS);
+
+}
+
static QemuOptsList qemu_smp_opts = {
.name = "smp-opts",
.implied_opt_name = "cpus",
@@ -2937,17 +2985,6 @@ static void user_register_global_props(void)
global_init_func, NULL, NULL);
}
-/*
- * Note: we should see that these properties are actually having a
- * priority: accel < machine < user. This means e.g. when user
- * specifies something in "-global", it'll always be used with highest
- * priority than either machine/accelerator compat properties.
- */
-static void register_global_properties(MachineState *ms)
-{
- user_register_global_props();
-}
-
int main(int argc, char **argv, char **envp)
{
int i;
@@ -2982,13 +3019,7 @@ int main(int argc, char **argv, char **envp)
Error *err = NULL;
bool list_data_dirs = false;
char *dir, **dirs;
- typedef struct BlockdevOptions_queue {
- BlockdevOptions *bdo;
- Location loc;
- QSIMPLEQ_ENTRY(BlockdevOptions_queue) entry;
- } BlockdevOptions_queue;
- QSIMPLEQ_HEAD(, BlockdevOptions_queue) bdo_queue
- = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
+ BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
module_call_init(MODULE_INIT_TRACE);
@@ -3112,12 +3143,12 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_blockdev:
{
Visitor *v;
- BlockdevOptions_queue *bdo;
+ BlockdevOptionsQueueEntry *bdo;
v = qobject_input_visitor_new_str(optarg, "driver",
&error_fatal);
- bdo = g_new(BlockdevOptions_queue, 1);
+ bdo = g_new(BlockdevOptionsQueueEntry, 1);
visit_type_BlockdevOptions(v, NULL, &bdo->bdo,
&error_fatal);
visit_free(v);
@@ -3170,7 +3201,7 @@ int main(int argc, char **argv, char **envp)
#ifdef CONFIG_CURSES
dpy.type = DISPLAY_TYPE_CURSES;
#else
- error_report("curses support is disabled");
+ error_report("curses or iconv support is disabled");
exit(1);
#endif
break;
@@ -3254,9 +3285,12 @@ int main(int argc, char **argv, char **envp)
add_device_config(DEV_BT, optarg);
break;
case QEMU_OPTION_audio_help:
- AUD_help ();
+ audio_legacy_help();
exit (0);
break;
+ case QEMU_OPTION_audiodev:
+ audio_parse_option(optarg);
+ break;
case QEMU_OPTION_soundhw:
select_soundhw (optarg);
break;
@@ -3942,6 +3976,8 @@ int main(int argc, char **argv, char **envp)
*/
loc_set_none();
+ user_register_global_props();
+
replay_configure(icount_opts);
if (incoming && !preconfig_exit_requested) {
@@ -3953,6 +3989,7 @@ int main(int argc, char **argv, char **envp)
configure_rtc(qemu_find_opts_singleton("rtc"));
machine_class = select_machine();
+ object_set_machine_compat_props(machine_class->compat_props);
set_memory_options(&ram_slots, &maxram_size, machine_class);
@@ -3997,6 +4034,10 @@ int main(int argc, char **argv, char **envp)
}
object_property_add_child(object_get_root(), "machine",
OBJECT(current_machine), &error_abort);
+ object_property_add_child(container_get(OBJECT(current_machine),
+ "/unattached"),
+ "sysbus", OBJECT(sysbus_get_default()),
+ NULL);
if (machine_class->minimum_page_bits) {
if (!set_preferred_target_page_bits(machine_class->minimum_page_bits)) {
@@ -4235,6 +4276,13 @@ int main(int argc, char **argv, char **envp)
exit(0);
}
+ /*
+ * Note: we need to create block backends before
+ * machine_set_property(), so machine properties can refer to
+ * them.
+ */
+ configure_blockdev(&bdo_queue, machine_class, snapshot);
+
machine_opts = qemu_get_machine_opts();
qemu_opt_foreach(machine_opts, machine_set_property, current_machine,
&error_fatal);
@@ -4250,12 +4298,6 @@ int main(int argc, char **argv, char **envp)
}
/*
- * Register all the global properties, including accel properties,
- * machine properties, and user-specified ones.
- */
- register_global_properties(current_machine);
-
- /*
* Migration object can only be created after global properties
* are applied correctly.
*/
@@ -4367,39 +4409,6 @@ int main(int argc, char **argv, char **envp)
ram_mig_init();
dirty_bitmap_mig_init();
- /* If the currently selected machine wishes to override the units-per-bus
- * property of its default HBA interface type, do so now. */
- if (machine_class->units_per_default_bus) {
- override_max_devs(machine_class->block_default_type,
- machine_class->units_per_default_bus);
- }
-
- /* open the virtual block devices */
- while (!QSIMPLEQ_EMPTY(&bdo_queue)) {
- BlockdevOptions_queue *bdo = QSIMPLEQ_FIRST(&bdo_queue);
-
- QSIMPLEQ_REMOVE_HEAD(&bdo_queue, entry);
- loc_push_restore(&bdo->loc);
- qmp_blockdev_add(bdo->bdo, &error_fatal);
- loc_pop(&bdo->loc);
- qapi_free_BlockdevOptions(bdo->bdo);
- g_free(bdo);
- }
- if (snapshot || replay_mode != REPLAY_MODE_NONE) {
- qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
- NULL, NULL);
- }
- if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
- &machine_class->block_default_type, &error_fatal)) {
- /* We printed help */
- exit(0);
- }
-
- default_drive(default_cdrom, snapshot, machine_class->block_default_type, 2,
- CDROM_OPTS);
- default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS);
- default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS);
-
qemu_opts_foreach(qemu_find_opts("mon"),
mon_init_func, NULL, &error_fatal);
@@ -4448,6 +4457,8 @@ int main(int argc, char **argv, char **envp)
/* do monitor/qmp handling at preconfig state if requested */
main_loop();
+ audio_init_audiodevs();
+
/* from here on runstate is RUN_STATE_PRELAUNCH */
machine_run_board_init(current_machine);